Commit 30227869482bbbdbfea153f2b45ef3bb9a9fd218

Authored by Riyad Preukschas
2 parents 8ee5fce9 aca0caa8

Merge commit 'master' into discussions

Conflicts:
	app/assets/stylesheets/sections/notes.scss
	app/contexts/notes/load_context.rb
	app/models/project.rb
	app/observers/note_observer.rb
	app/roles/votes.rb
	app/views/commit/show.html.haml
	app/views/merge_requests/_show.html.haml
	app/views/merge_requests/diffs.js.haml
	app/views/merge_requests/show.js.haml
	app/views/notes/_note.html.haml
	features/steps/project/project_merge_requests.rb
	spec/models/note_spec.rb
Showing 938 changed files with 81195 additions and 104503 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 938 files displayed.

@@ -19,8 +19,10 @@ config/gitlab.yml @@ -19,8 +19,10 @@ config/gitlab.yml
19 config/database.yml 19 config/database.yml
20 config/initializers/omniauth.rb 20 config/initializers/omniauth.rb
21 config/unicorn.rb 21 config/unicorn.rb
  22 +config/resque.yml
22 db/data.yml 23 db/data.yml
23 .idea 24 .idea
24 .DS_Store 25 .DS_Store
25 .chef 26 .chef
26 vendor/bundle/* 27 vendor/bundle/*
  28 +rails_best_practices_output.html
.simplecov 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +# .simplecov
  2 +SimpleCov.start 'rails' do
  3 + merge_timeout 3600
  4 +end
@@ -3,16 +3,12 @@ env: @@ -3,16 +3,12 @@ env:
3 - DB=mysql 3 - DB=mysql
4 before_install: 4 before_install:
5 - sudo apt-get install libicu-dev -y 5 - sudo apt-get install libicu-dev -y
6 - - wget -P /tmp http://phantomjs.googlecode.com/files/phantomjs-1.7.0-linux-i686.tar.bz2  
7 - - tar -xf /tmp/phantomjs-1.7.0-linux-i686.tar.bz2 -C /tmp/  
8 - - sudo rm -rf /usr/local/phantomjs  
9 - - sudo mv /tmp/phantomjs-1.7.0-linux-i686 /usr/local/phantomjs  
10 - gem install charlock_holmes -v="0.6.9" 6 - gem install charlock_holmes -v="0.6.9"
11 branches: 7 branches:
12 only: 8 only:
13 - 'master' 9 - 'master'
14 rvm: 10 rvm:
15 - - 1.9.3 11 + - 1.9.2
16 services: 12 services:
17 - mysql 13 - mysql
18 - postgresql 14 - postgresql
1 v 4.0.0 1 v 4.0.0
  2 + - Remove project code and path from API. Use id instead
  3 + - Return valid clonable url to repo for web hook
  4 + - Fixed backup issue
2 - Reorganized settings 5 - Reorganized settings
3 - Fixed commits compare 6 - Fixed commits compare
4 - Refactored scss 7 - Refactored scss
@@ -8,7 +8,7 @@ def linux_only(require_as) @@ -8,7 +8,7 @@ def linux_only(require_as)
8 RUBY_PLATFORM.include?('linux') && require_as 8 RUBY_PLATFORM.include?('linux') && require_as
9 end 9 end
10 10
11 -gem "rails", "3.2.9" 11 +gem "rails", "3.2.11"
12 12
13 # Supported DBs 13 # Supported DBs
14 gem "mysql2", group: :mysql 14 gem "mysql2", group: :mysql
@@ -23,11 +23,15 @@ gem 'omniauth-github' @@ -23,11 +23,15 @@ gem 'omniauth-github'
23 23
24 # GITLAB patched libs 24 # GITLAB patched libs
25 gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '7f35cb98ff17d534a07e3ce6ec3d580f67402837' 25 gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '7f35cb98ff17d534a07e3ce6ec3d580f67402837'
26 -gem "omniauth-ldap", git: "https://github.com/gitlabhq/omniauth-ldap.git", ref: 'f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e'  
27 -gem 'yaml_db', git: "https://github.com/gitlabhq/yaml_db.git", ref: '98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd'  
28 gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' 26 gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8'
29 gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e' 27 gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e'
30 28
  29 +# LDAP Auth
  30 +gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap"
  31 +
  32 +# Dump db to yml file. Mostly used to migrate from sqlite to mysql
  33 +gem 'gitlab_yaml_db', '1.0.0', require: "yaml_db"
  34 +
31 # Gitolite client (for work with gitolite-admin repo) 35 # Gitolite client (for work with gitolite-admin repo)
32 gem "gitolite", '1.1.0' 36 gem "gitolite", '1.1.0'
33 37
@@ -77,8 +81,9 @@ gem "acts-as-taggable-on", "2.3.3" @@ -77,8 +81,9 @@ gem "acts-as-taggable-on", "2.3.3"
77 gem "draper", "~> 0.18.0" 81 gem "draper", "~> 0.18.0"
78 82
79 # Background jobs 83 # Background jobs
80 -gem "resque", "~> 1.23.0"  
81 -gem 'resque_mailer' 84 +gem 'slim'
  85 +gem 'sinatra', :require => nil
  86 +gem 'sidekiq', '2.6.4'
82 87
83 # HTTP requests 88 # HTTP requests
84 gem "httparty" 89 gem "httparty"
@@ -104,7 +109,7 @@ group :assets do @@ -104,7 +109,7 @@ group :assets do
104 gem "jquery-rails", "2.1.3" 109 gem "jquery-rails", "2.1.3"
105 gem "jquery-ui-rails", "2.0.2" 110 gem "jquery-ui-rails", "2.0.2"
106 gem "modernizr", "2.6.2" 111 gem "modernizr", "2.6.2"
107 - gem "raphael-rails", "1.5.2" 112 + gem "raphael-rails", git: "https://github.com/gitlabhq/raphael-rails.git"
108 gem 'bootstrap-sass', "2.2.1.1" 113 gem 'bootstrap-sass', "2.2.1.1"
109 gem "font-awesome-sass-rails", "~> 2.0.0" 114 gem "font-awesome-sass-rails", "~> 2.0.0"
110 gem "gemoji", "~> 1.2.1", require: 'emoji/railtie' 115 gem "gemoji", "~> 1.2.1", require: 'emoji/railtie'
@@ -115,6 +120,14 @@ group :development do @@ -115,6 +120,14 @@ group :development do
115 gem "letter_opener" 120 gem "letter_opener"
116 gem 'quiet_assets', '~> 1.0.1' 121 gem 'quiet_assets', '~> 1.0.1'
117 gem 'rack-mini-profiler' 122 gem 'rack-mini-profiler'
  123 + # Better errors handler
  124 + gem 'better_errors'
  125 + gem 'binding_of_caller'
  126 +
  127 + gem 'rails_best_practices'
  128 +
  129 + # Docs generator
  130 + gem "sdoc"
118 end 131 end
119 132
120 group :development, :test do 133 group :development, :test do
@@ -145,7 +158,6 @@ group :test do @@ -145,7 +158,6 @@ group :test do
145 gem "simplecov", require: false 158 gem "simplecov", require: false
146 gem "shoulda-matchers", "1.3.0" 159 gem "shoulda-matchers", "1.3.0"
147 gem 'email_spec' 160 gem 'email_spec'
148 - gem 'resque_spec'  
149 gem "webmock" 161 gem "webmock"
150 gem 'test_after_commit' 162 gem 'test_after_commit'
151 end 163 end
@@ -40,17 +40,6 @@ GIT @@ -40,17 +40,6 @@ GIT
40 charlock_holmes (~> 0.6.9) 40 charlock_holmes (~> 0.6.9)
41 41
42 GIT 42 GIT
43 - remote: https://github.com/gitlabhq/omniauth-ldap.git  
44 - revision: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e  
45 - ref: f038dd852d7bd473a557e385d5d7c2fd5dc1dc2e  
46 - specs:  
47 - omniauth-ldap (1.0.2)  
48 - net-ldap (~> 0.2.2)  
49 - omniauth (~> 1.0)  
50 - pyu-ruby-sasl (~> 0.0.3.1)  
51 - rubyntlm (~> 0.1.1)  
52 -  
53 -GIT  
54 remote: https://github.com/gitlabhq/pygments.rb.git 43 remote: https://github.com/gitlabhq/pygments.rb.git
55 revision: db1da0343adf86b49bdc3add04d02d2e80438d38 44 revision: db1da0343adf86b49bdc3add04d02d2e80438d38
56 branch: master 45 branch: master
@@ -60,11 +49,10 @@ GIT @@ -60,11 +49,10 @@ GIT
60 yajl-ruby (~> 1.1.0) 49 yajl-ruby (~> 1.1.0)
61 50
62 GIT 51 GIT
63 - remote: https://github.com/gitlabhq/yaml_db.git  
64 - revision: 98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd  
65 - ref: 98e9a5dca43e3fedd3268c76a73af40d1bdf1dfd 52 + remote: https://github.com/gitlabhq/raphael-rails.git
  53 + revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58
66 specs: 54 specs:
67 - yaml_db (0.2.2) 55 + raphael-rails (2.1.0)
68 56
69 GIT 57 GIT
70 remote: https://github.com/jonleighton/poltergeist.git 58 remote: https://github.com/jonleighton/poltergeist.git
@@ -81,12 +69,12 @@ GIT @@ -81,12 +69,12 @@ GIT
81 GEM 69 GEM
82 remote: http://rubygems.org/ 70 remote: http://rubygems.org/
83 specs: 71 specs:
84 - actionmailer (3.2.9)  
85 - actionpack (= 3.2.9) 72 + actionmailer (3.2.11)
  73 + actionpack (= 3.2.11)
86 mail (~> 2.4.4) 74 mail (~> 2.4.4)
87 - actionpack (3.2.9)  
88 - activemodel (= 3.2.9)  
89 - activesupport (= 3.2.9) 75 + actionpack (3.2.11)
  76 + activemodel (= 3.2.11)
  77 + activesupport (= 3.2.11)
90 builder (~> 3.0.0) 78 builder (~> 3.0.0)
91 erubis (~> 2.7.0) 79 erubis (~> 2.7.0)
92 journey (~> 1.0.4) 80 journey (~> 1.0.4)
@@ -94,18 +82,18 @@ GEM @@ -94,18 +82,18 @@ GEM
94 rack-cache (~> 1.2) 82 rack-cache (~> 1.2)
95 rack-test (~> 0.6.1) 83 rack-test (~> 0.6.1)
96 sprockets (~> 2.2.1) 84 sprockets (~> 2.2.1)
97 - activemodel (3.2.9)  
98 - activesupport (= 3.2.9) 85 + activemodel (3.2.11)
  86 + activesupport (= 3.2.11)
99 builder (~> 3.0.0) 87 builder (~> 3.0.0)
100 - activerecord (3.2.9)  
101 - activemodel (= 3.2.9)  
102 - activesupport (= 3.2.9) 88 + activerecord (3.2.11)
  89 + activemodel (= 3.2.11)
  90 + activesupport (= 3.2.11)
103 arel (~> 3.0.2) 91 arel (~> 3.0.2)
104 tzinfo (~> 0.3.29) 92 tzinfo (~> 0.3.29)
105 - activeresource (3.2.9)  
106 - activemodel (= 3.2.9)  
107 - activesupport (= 3.2.9)  
108 - activesupport (3.2.9) 93 + activeresource (3.2.11)
  94 + activemodel (= 3.2.11)
  95 + activesupport (= 3.2.11)
  96 + activesupport (3.2.11)
109 i18n (~> 0.6) 97 i18n (~> 0.6)
110 multi_json (~> 1.0) 98 multi_json (~> 1.0)
111 acts-as-taggable-on (2.3.3) 99 acts-as-taggable-on (2.3.3)
@@ -115,6 +103,10 @@ GEM @@ -115,6 +103,10 @@ GEM
115 awesome_print (1.1.0) 103 awesome_print (1.1.0)
116 backports (2.6.5) 104 backports (2.6.5)
117 bcrypt-ruby (3.0.1) 105 bcrypt-ruby (3.0.1)
  106 + better_errors (0.3.2)
  107 + coderay (>= 1.0.0)
  108 + erubis (>= 2.7.0)
  109 + binding_of_caller (0.6.8)
118 blankslate (3.1.2) 110 blankslate (3.1.2)
119 bootstrap-sass (2.2.1.1) 111 bootstrap-sass (2.2.1.1)
120 sass (~> 3.2) 112 sass (~> 3.2)
@@ -129,12 +121,17 @@ GEM @@ -129,12 +121,17 @@ GEM
129 carrierwave (0.7.1) 121 carrierwave (0.7.1)
130 activemodel (>= 3.2.0) 122 activemodel (>= 3.2.0)
131 activesupport (>= 3.2.0) 123 activesupport (>= 3.2.0)
  124 + celluloid (0.12.4)
  125 + facter (>= 1.6.12)
  126 + timers (>= 1.0.0)
132 charlock_holmes (0.6.9) 127 charlock_holmes (0.6.9)
133 childprocess (0.3.6) 128 childprocess (0.3.6)
134 ffi (~> 1.0, >= 1.0.6) 129 ffi (~> 1.0, >= 1.0.6)
135 chosen-rails (0.9.8) 130 chosen-rails (0.9.8)
136 railties (~> 3.0) 131 railties (~> 3.0)
137 thor (~> 0.14) 132 thor (~> 0.14)
  133 + code_analyzer (0.3.1)
  134 + sexp_processor
138 coderay (1.0.8) 135 coderay (1.0.8)
139 coffee-rails (3.2.2) 136 coffee-rails (3.2.2)
140 coffee-script (>= 2.2.0) 137 coffee-script (>= 2.2.0)
@@ -145,6 +142,7 @@ GEM @@ -145,6 +142,7 @@ GEM
145 coffee-script-source (1.4.0) 142 coffee-script-source (1.4.0)
146 colored (1.2) 143 colored (1.2)
147 colorize (0.5.8) 144 colorize (0.5.8)
  145 + connection_pool (1.0.0)
148 crack (0.3.1) 146 crack (0.3.1)
149 daemons (1.1.9) 147 daemons (1.1.9)
150 devise (2.1.2) 148 devise (2.1.2)
@@ -164,6 +162,7 @@ GEM @@ -164,6 +162,7 @@ GEM
164 eventmachine (1.0.0) 162 eventmachine (1.0.0)
165 execjs (1.4.0) 163 execjs (1.4.0)
166 multi_json (~> 1.0) 164 multi_json (~> 1.0)
  165 + facter (1.6.17)
167 factory_girl (4.1.0) 166 factory_girl (4.1.0)
168 activesupport (>= 3.0.0) 167 activesupport (>= 3.0.0)
169 factory_girl_rails (4.1.0) 168 factory_girl_rails (4.1.0)
@@ -190,6 +189,12 @@ GEM @@ -190,6 +189,12 @@ GEM
190 pygments.rb (>= 0.2.13) 189 pygments.rb (>= 0.2.13)
191 github-markup (0.7.4) 190 github-markup (0.7.4)
192 gitlab_meta (4.0) 191 gitlab_meta (4.0)
  192 + gitlab_omniauth-ldap (1.0.2)
  193 + net-ldap (~> 0.2.2)
  194 + omniauth (~> 1.0)
  195 + pyu-ruby-sasl (~> 0.0.3.1)
  196 + rubyntlm (~> 0.1.1)
  197 + gitlab_yaml_db (1.0.0)
193 gitolite (1.1.0) 198 gitolite (1.1.0)
194 gratr19 (~> 0.4.4.1) 199 gratr19 (~> 0.4.4.1)
195 grit (~> 2.5.0) 200 grit (~> 2.5.0)
@@ -240,7 +245,7 @@ GEM @@ -240,7 +245,7 @@ GEM
240 jquery-ui-rails (2.0.2) 245 jquery-ui-rails (2.0.2)
241 jquery-rails 246 jquery-rails
242 railties (>= 3.1.0) 247 railties (>= 3.1.0)
243 - json (1.7.5) 248 + json (1.7.6)
244 jwt (0.1.5) 249 jwt (0.1.5)
245 multi_json (>= 1.0) 250 multi_json (>= 1.0)
246 kaminari (0.14.1) 251 kaminari (0.14.1)
@@ -264,7 +269,7 @@ GEM @@ -264,7 +269,7 @@ GEM
264 mime-types (1.19) 269 mime-types (1.19)
265 modernizr (2.6.2) 270 modernizr (2.6.2)
266 sprockets (~> 2.0) 271 sprockets (~> 2.0)
267 - multi_json (1.3.7) 272 + multi_json (1.5.0)
268 multi_xml (0.5.1) 273 multi_xml (0.5.1)
269 multipart-post (1.1.5) 274 multipart-post (1.1.5)
270 mysql2 (0.3.11) 275 mysql2 (0.3.11)
@@ -299,6 +304,7 @@ GEM @@ -299,6 +304,7 @@ GEM
299 pg (0.14.1) 304 pg (0.14.1)
300 polyglot (0.3.3) 305 polyglot (0.3.3)
301 posix-spawn (0.3.6) 306 posix-spawn (0.3.6)
  307 + progressbar (0.12.0)
302 pry (0.9.10) 308 pry (0.9.10)
303 coderay (~> 1.0.5) 309 coderay (~> 1.0.5)
304 method_source (~> 0.8) 310 method_source (~> 0.8)
@@ -306,7 +312,7 @@ GEM @@ -306,7 +312,7 @@ GEM
306 pyu-ruby-sasl (0.0.3.3) 312 pyu-ruby-sasl (0.0.3.3)
307 quiet_assets (1.0.1) 313 quiet_assets (1.0.1)
308 railties (~> 3.1) 314 railties (~> 3.1)
309 - rack (1.4.1) 315 + rack (1.4.3)
310 rack-accept (0.4.5) 316 rack-accept (0.4.5)
311 rack (>= 0.4) 317 rack (>= 0.4)
312 rack-cache (1.2) 318 rack-cache (1.2)
@@ -315,33 +321,40 @@ GEM @@ -315,33 +321,40 @@ GEM
315 rack (>= 1.1.3) 321 rack (>= 1.1.3)
316 rack-mount (0.8.3) 322 rack-mount (0.8.3)
317 rack (>= 1.0.0) 323 rack (>= 1.0.0)
318 - rack-protection (1.2.0) 324 + rack-protection (1.3.2)
319 rack 325 rack
320 rack-ssl (1.3.2) 326 rack-ssl (1.3.2)
321 rack 327 rack
322 rack-test (0.6.2) 328 rack-test (0.6.2)
323 rack (>= 1.0) 329 rack (>= 1.0)
324 - rails (3.2.9)  
325 - actionmailer (= 3.2.9)  
326 - actionpack (= 3.2.9)  
327 - activerecord (= 3.2.9)  
328 - activeresource (= 3.2.9)  
329 - activesupport (= 3.2.9) 330 + rails (3.2.11)
  331 + actionmailer (= 3.2.11)
  332 + actionpack (= 3.2.11)
  333 + activerecord (= 3.2.11)
  334 + activeresource (= 3.2.11)
  335 + activesupport (= 3.2.11)
330 bundler (~> 1.0) 336 bundler (~> 1.0)
331 - railties (= 3.2.9) 337 + railties (= 3.2.11)
332 rails-dev-tweaks (0.6.1) 338 rails-dev-tweaks (0.6.1)
333 actionpack (~> 3.1) 339 actionpack (~> 3.1)
334 railties (~> 3.1) 340 railties (~> 3.1)
335 - railties (3.2.9)  
336 - actionpack (= 3.2.9)  
337 - activesupport (= 3.2.9) 341 + rails_best_practices (1.13.2)
  342 + activesupport
  343 + awesome_print
  344 + code_analyzer
  345 + colored
  346 + erubis
  347 + i18n
  348 + progressbar
  349 + railties (3.2.11)
  350 + actionpack (= 3.2.11)
  351 + activesupport (= 3.2.11)
338 rack-ssl (~> 1.3.2) 352 rack-ssl (~> 1.3.2)
339 rake (>= 0.8.7) 353 rake (>= 0.8.7)
340 rdoc (~> 3.4) 354 rdoc (~> 3.4)
341 thor (>= 0.14.6, < 2.0) 355 thor (>= 0.14.6, < 2.0)
342 raindrops (0.10.0) 356 raindrops (0.10.0)
343 - rake (10.0.1)  
344 - raphael-rails (1.5.2) 357 + rake (10.0.3)
345 rb-fsevent (0.9.2) 358 rb-fsevent (0.9.2)
346 rb-inotify (0.8.8) 359 rb-inotify (0.8.8)
347 ffi (>= 0.5.0) 360 ffi (>= 0.5.0)
@@ -351,16 +364,6 @@ GEM @@ -351,16 +364,6 @@ GEM
351 redis (3.0.2) 364 redis (3.0.2)
352 redis-namespace (1.2.1) 365 redis-namespace (1.2.1)
353 redis (~> 3.0.0) 366 redis (~> 3.0.0)
354 - resque (1.23.0)  
355 - multi_json (~> 1.0)  
356 - redis-namespace (~> 1.0)  
357 - sinatra (>= 0.9.2)  
358 - vegas (~> 0.1.2)  
359 - resque_mailer (2.1.0)  
360 - actionmailer (~> 3.0)  
361 - resque_spec (0.12.5)  
362 - resque (>= 1.19.0)  
363 - rspec (>= 2.5.0)  
364 rspec (2.12.0) 367 rspec (2.12.0)
365 rspec-core (~> 2.12.0) 368 rspec-core (~> 2.12.0)
366 rspec-expectations (~> 2.12.0) 369 rspec-expectations (~> 2.12.0)
@@ -383,6 +386,9 @@ GEM @@ -383,6 +386,9 @@ GEM
383 railties (~> 3.2.0) 386 railties (~> 3.2.0)
384 sass (>= 3.1.10) 387 sass (>= 3.1.10)
385 tilt (~> 1.3) 388 tilt (~> 1.3)
  389 + sdoc (0.3.20)
  390 + json (>= 1.1.3)
  391 + rdoc (~> 3.10)
386 seed-fu (2.2.0) 392 seed-fu (2.2.0)
387 activerecord (~> 3.1) 393 activerecord (~> 3.1)
388 activesupport (~> 3.1) 394 activesupport (~> 3.1)
@@ -392,8 +398,15 @@ GEM @@ -392,8 +398,15 @@ GEM
392 multi_json (~> 1.0) 398 multi_json (~> 1.0)
393 rubyzip 399 rubyzip
394 settingslogic (2.0.8) 400 settingslogic (2.0.8)
  401 + sexp_processor (4.1.3)
395 shoulda-matchers (1.3.0) 402 shoulda-matchers (1.3.0)
396 activesupport (>= 3.0.0) 403 activesupport (>= 3.0.0)
  404 + sidekiq (2.6.4)
  405 + celluloid (~> 0.12.0)
  406 + connection_pool (~> 1.0)
  407 + multi_json (~> 1)
  408 + redis (~> 3)
  409 + redis-namespace
397 simplecov (0.7.1) 410 simplecov (0.7.1)
398 multi_json (~> 1.0) 411 multi_json (~> 1.0)
399 simplecov-html (~> 0.7.1) 412 simplecov-html (~> 0.7.1)
@@ -403,6 +416,9 @@ GEM @@ -403,6 +416,9 @@ GEM
403 rack-protection (~> 1.2) 416 rack-protection (~> 1.2)
404 tilt (~> 1.3, >= 1.3.3) 417 tilt (~> 1.3, >= 1.3.3)
405 six (0.2.0) 418 six (0.2.0)
  419 + slim (1.3.6)
  420 + temple (~> 0.5.5)
  421 + tilt (~> 1.3.3)
406 slop (3.3.3) 422 slop (3.3.3)
407 spinach (0.5.2) 423 spinach (0.5.2)
408 colorize 424 colorize
@@ -411,12 +427,13 @@ GEM @@ -411,12 +427,13 @@ GEM
411 capybara (~> 1) 427 capybara (~> 1)
412 railties (>= 3) 428 railties (>= 3)
413 spinach (>= 0.4) 429 spinach (>= 0.4)
414 - sprockets (2.2.1) 430 + sprockets (2.2.2)
415 hike (~> 1.2) 431 hike (~> 1.2)
416 multi_json (~> 1.0) 432 multi_json (~> 1.0)
417 rack (~> 1.0) 433 rack (~> 1.0)
418 tilt (~> 1.1, != 1.3.0) 434 tilt (~> 1.1, != 1.3.0)
419 stamp (0.3.0) 435 stamp (0.3.0)
  436 + temple (0.5.5)
420 test_after_commit (0.0.1) 437 test_after_commit (0.0.1)
421 therubyracer (0.10.2) 438 therubyracer (0.10.2)
422 libv8 (~> 3.3.10) 439 libv8 (~> 3.3.10)
@@ -426,6 +443,7 @@ GEM @@ -426,6 +443,7 @@ GEM
426 rack (>= 1.0.0) 443 rack (>= 1.0.0)
427 thor (0.16.0) 444 thor (0.16.0)
428 tilt (1.3.3) 445 tilt (1.3.3)
  446 + timers (1.0.2)
429 treetop (1.4.12) 447 treetop (1.4.12)
430 polyglot 448 polyglot
431 polyglot (>= 0.3.1) 449 polyglot (>= 0.3.1)
@@ -437,8 +455,6 @@ GEM @@ -437,8 +455,6 @@ GEM
437 kgio (~> 2.6) 455 kgio (~> 2.6)
438 rack 456 rack
439 raindrops (~> 0.7) 457 raindrops (~> 0.7)
440 - vegas (0.1.11)  
441 - rack (>= 1.0.0)  
442 virtus (0.5.2) 458 virtus (0.5.2)
443 backports (~> 2.6.1) 459 backports (~> 2.6.1)
444 warden (1.2.1) 460 warden (1.2.1)
@@ -458,6 +474,8 @@ DEPENDENCIES @@ -458,6 +474,8 @@ DEPENDENCIES
458 acts-as-taggable-on (= 2.3.3) 474 acts-as-taggable-on (= 2.3.3)
459 annotate! 475 annotate!
460 awesome_print 476 awesome_print
  477 + better_errors
  478 + binding_of_caller
461 bootstrap-sass (= 2.2.1.1) 479 bootstrap-sass (= 2.2.1.1)
462 capybara 480 capybara
463 carrierwave (~> 0.7.1) 481 carrierwave (~> 0.7.1)
@@ -477,6 +495,8 @@ DEPENDENCIES @@ -477,6 +495,8 @@ DEPENDENCIES
477 github-linguist (~> 2.3.4) 495 github-linguist (~> 2.3.4)
478 github-markup (~> 0.7.4) 496 github-markup (~> 0.7.4)
479 gitlab_meta (= 4.0) 497 gitlab_meta (= 4.0)
  498 + gitlab_omniauth-ldap (= 1.0.2)
  499 + gitlab_yaml_db (= 1.0.0)
480 gitolite (= 1.1.0) 500 gitolite (= 1.1.0)
481 grack! 501 grack!
482 grape (~> 0.2.1) 502 grape (~> 0.2.1)
@@ -498,7 +518,6 @@ DEPENDENCIES @@ -498,7 +518,6 @@ DEPENDENCIES
498 omniauth (~> 1.1.1) 518 omniauth (~> 1.1.1)
499 omniauth-github 519 omniauth-github
500 omniauth-google-oauth2 520 omniauth-google-oauth2
501 - omniauth-ldap!  
502 omniauth-twitter 521 omniauth-twitter
503 pg 522 pg
504 poltergeist! 523 poltergeist!
@@ -506,22 +525,24 @@ DEPENDENCIES @@ -506,22 +525,24 @@ DEPENDENCIES
506 pygments.rb! 525 pygments.rb!
507 quiet_assets (~> 1.0.1) 526 quiet_assets (~> 1.0.1)
508 rack-mini-profiler 527 rack-mini-profiler
509 - rails (= 3.2.9) 528 + rails (= 3.2.11)
510 rails-dev-tweaks 529 rails-dev-tweaks
511 - raphael-rails (= 1.5.2) 530 + rails_best_practices
  531 + raphael-rails!
512 rb-fsevent 532 rb-fsevent
513 rb-inotify 533 rb-inotify
514 redcarpet (~> 2.2.2) 534 redcarpet (~> 2.2.2)
515 - resque (~> 1.23.0)  
516 - resque_mailer  
517 - resque_spec  
518 rspec-rails 535 rspec-rails
519 sass-rails (~> 3.2.5) 536 sass-rails (~> 3.2.5)
  537 + sdoc
520 seed-fu 538 seed-fu
521 settingslogic 539 settingslogic
522 shoulda-matchers (= 1.3.0) 540 shoulda-matchers (= 1.3.0)
  541 + sidekiq (= 2.6.4)
523 simplecov 542 simplecov
  543 + sinatra
524 six 544 six
  545 + slim
525 spinach-rails 546 spinach-rails
526 stamp 547 stamp
527 test_after_commit 548 test_after_commit
@@ -530,4 +551,3 @@ DEPENDENCIES @@ -530,4 +551,3 @@ DEPENDENCIES
530 uglifier (~> 1.3.0) 551 uglifier (~> 1.3.0)
531 unicorn (~> 4.4.0) 552 unicorn (~> 4.4.0)
532 webmock 553 webmock
533 - yaml_db!  
1 web: bundle exec rails s -p $PORT 1 web: bundle exec rails s -p $PORT
2 -worker: bundle exec rake environment resque:work QUEUE=* VVERBOSE=1 2 +worker: bundle exec sidekiq -q post_receive,mailer,system_hook,common,default
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 2
3 GitLab is a free project and repository management application 3 GitLab is a free project and repository management application
4 4
  5 +![CI](http://ci.gitlab.org/projects/1/status?ref=master)
5 6
6 ## Application details 7 ## Application details
7 8
@@ -39,6 +40,6 @@ Email @@ -39,6 +40,6 @@ Email
39 40
40 ## Contribute 41 ## Contribute
41 42
42 -[Development Tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md) 43 +[Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide)
43 Want to help - send a pull request. 44 Want to help - send a pull request.
44 We'll accept good pull requests. 45 We'll accept good pull requests.
1 -4.0.0rc1 1 +4.1.0pre
app/assets/fonts/OFL.txt 0 → 100644
@@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
  1 +Copyright (c) 2010, Jan Gerner (post@yanone.de)
  2 +This Font Software is licensed under the SIL Open Font License, Version 1.1.
  3 +This license is copied below, and is also available with a FAQ at:
  4 +http://scripts.sil.org/OFL
  5 +
  6 +
  7 +-----------------------------------------------------------
  8 +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
  9 +-----------------------------------------------------------
  10 +
  11 +PREAMBLE
  12 +The goals of the Open Font License (OFL) are to stimulate worldwide
  13 +development of collaborative font projects, to support the font creation
  14 +efforts of academic and linguistic communities, and to provide a free and
  15 +open framework in which fonts may be shared and improved in partnership
  16 +with others.
  17 +
  18 +The OFL allows the licensed fonts to be used, studied, modified and
  19 +redistributed freely as long as they are not sold by themselves. The
  20 +fonts, including any derivative works, can be bundled, embedded,
  21 +redistributed and/or sold with any software provided that any reserved
  22 +names are not used by derivative works. The fonts and derivatives,
  23 +however, cannot be released under any other type of license. The
  24 +requirement for fonts to remain under this license does not apply
  25 +to any document created using the fonts or their derivatives.
  26 +
  27 +DEFINITIONS
  28 +"Font Software" refers to the set of files released by the Copyright
  29 +Holder(s) under this license and clearly marked as such. This may
  30 +include source files, build scripts and documentation.
  31 +
  32 +"Reserved Font Name" refers to any names specified as such after the
  33 +copyright statement(s).
  34 +
  35 +"Original Version" refers to the collection of Font Software components as
  36 +distributed by the Copyright Holder(s).
  37 +
  38 +"Modified Version" refers to any derivative made by adding to, deleting,
  39 +or substituting -- in part or in whole -- any of the components of the
  40 +Original Version, by changing formats or by porting the Font Software to a
  41 +new environment.
  42 +
  43 +"Author" refers to any designer, engineer, programmer, technical
  44 +writer or other person who contributed to the Font Software.
  45 +
  46 +PERMISSION & CONDITIONS
  47 +Permission is hereby granted, free of charge, to any person obtaining
  48 +a copy of the Font Software, to use, study, copy, merge, embed, modify,
  49 +redistribute, and sell modified and unmodified copies of the Font
  50 +Software, subject to the following conditions:
  51 +
  52 +1) Neither the Font Software nor any of its individual components,
  53 +in Original or Modified Versions, may be sold by itself.
  54 +
  55 +2) Original or Modified Versions of the Font Software may be bundled,
  56 +redistributed and/or sold with any software, provided that each copy
  57 +contains the above copyright notice and this license. These can be
  58 +included either as stand-alone text files, human-readable headers or
  59 +in the appropriate machine-readable metadata fields within text or
  60 +binary files as long as those fields can be easily viewed by the user.
  61 +
  62 +3) No Modified Version of the Font Software may use the Reserved Font
  63 +Name(s) unless explicit written permission is granted by the corresponding
  64 +Copyright Holder. This restriction only applies to the primary font name as
  65 +presented to the users.
  66 +
  67 +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
  68 +Software shall not be used to promote, endorse or advertise any
  69 +Modified Version, except to acknowledge the contribution(s) of the
  70 +Copyright Holder(s) and the Author(s) or with their explicit written
  71 +permission.
  72 +
  73 +5) The Font Software, modified or unmodified, in part or in whole,
  74 +must be distributed entirely under this license, and must not be
  75 +distributed under any other license. The requirement for fonts to
  76 +remain under this license does not apply to any document created
  77 +using the Font Software.
  78 +
  79 +TERMINATION
  80 +This license becomes null and void if any of the above conditions are
  81 +not met.
  82 +
  83 +DISCLAIMER
  84 +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  85 +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
  86 +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
  87 +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
  88 +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  89 +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
  90 +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  91 +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
  92 +OTHER DEALINGS IN THE FONT SOFTWARE.
app/assets/fonts/YanoneKaffeesatz-Light.ttf 0 → 100644
No preview for this file type
app/assets/fonts/korolev-medium-compressed.otf
No preview for this file type
app/assets/images/download.png

674 Bytes

app/assets/javascripts/dashboard.js.coffee 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +$ ->
  2 + dashboardPage()
  3 +
  4 +dashboardPage = ->
  5 + Pager.init 20, true
  6 + $(".event_filter_link").bind "click", (event) ->
  7 + event.preventDefault()
  8 + toggleFilter $(this)
  9 + reloadActivities()
  10 +
  11 +reloadActivities = ->
  12 + $(".content_list").html ''
  13 + Pager.init 20, true
  14 +
  15 +toggleFilter = (sender) ->
  16 + sender.parent().toggleClass "inactive"
  17 + event_filters = $.cookie("event_filter")
  18 + filter = sender.attr("id").split("_")[0]
  19 + if event_filters
  20 + event_filters = event_filters.split(",")
  21 + else
  22 + event_filters = new Array()
  23 +
  24 + index = event_filters.indexOf(filter)
  25 + if index is -1
  26 + event_filters.push filter
  27 + else
  28 + event_filters.splice index, 1
  29 +
  30 + $.cookie "event_filter", event_filters.join(",")
app/assets/javascripts/issues.js
@@ -11,7 +11,7 @@ function initIssuesSearch() { @@ -11,7 +11,7 @@ function initIssuesSearch() {
11 last_terms = terms; 11 last_terms = terms;
12 12
13 if (terms.length >= 2 || terms.length == 0) { 13 if (terms.length >= 2 || terms.length == 0) {
14 - $.get(href, { 'f': status, 'terms': terms, 'milestone_id': milestone_id }, function(response) { 14 + $.get(href, { 'status': status, 'terms': terms, 'milestone_id': milestone_id }, function(response) {
15 $('#issues-table').html(response); 15 $('#issues-table').html(response);
16 }); 16 });
17 } 17 }
app/assets/javascripts/merge_requests.js
@@ -1,132 +0,0 @@ @@ -1,132 +0,0 @@
1 -var MergeRequest = {  
2 - diffs_loaded: false,  
3 - commits_loaded: false,  
4 - opts: false,  
5 -  
6 - init:  
7 - function(opts) {  
8 - var self = this;  
9 - self.opts = opts;  
10 -  
11 - self.initTabs();  
12 - self.initMergeWidget();  
13 -  
14 - $(".mr_show_all_commits").bind("click", function() {  
15 - self.showAllCommits();  
16 - });  
17 - },  
18 -  
19 - initMergeWidget:  
20 - function() {  
21 - var self = this;  
22 - self.showState(self.opts.current_state);  
23 -  
24 - if($(".automerge_widget").length && self.opts.check_enable){  
25 - $.get(self.opts.url_to_automerge_check, function(data){  
26 - self.showState(data.state);  
27 - }, "json");  
28 - }  
29 -  
30 - if(self.opts.ci_enable){  
31 - $.get(self.opts.url_to_ci_check, function(data){  
32 - self.showCiState(data.status);  
33 - }, "json");  
34 - }  
35 - },  
36 -  
37 - initTabs:  
38 - function() {  
39 - $(".mr_nav_tabs a").live("click", function() {  
40 - $(".mr_nav_tabs a").parent().removeClass("active");  
41 - $(this).parent().addClass("active");  
42 - });  
43 -  
44 - var current_tab;  
45 - if(this.opts.action == "diffs") {  
46 - current_tab = $(".mr_nav_tabs .merge-diffs-tab");  
47 - } else {  
48 - current_tab = $(".mr_nav_tabs .merge-notes-tab");  
49 - }  
50 - current_tab.parent().addClass("active");  
51 -  
52 - this.initNotesTab();  
53 - this.initDiffTab();  
54 - },  
55 -  
56 - initNotesTab:  
57 - function() {  
58 - $(".mr_nav_tabs a.merge-notes-tab").live("click", function(e) {  
59 - $(".merge-request-diffs").hide();  
60 - $(".merge_request_notes").show();  
61 - var mr_path = $(".merge-notes-tab").attr("data-url");  
62 - history.pushState({ path: mr_path }, '', mr_path);  
63 - e.preventDefault();  
64 - });  
65 - },  
66 -  
67 - initDiffTab:  
68 - function() {  
69 - $(".mr_nav_tabs a.merge-diffs-tab").live("click", function(e) {  
70 - if(!MergeRequest.diffs_loaded) {  
71 - MergeRequest.loadDiff();  
72 - }  
73 - $(".merge_request_notes").hide();  
74 - $(".merge-request-diffs").show();  
75 - var mr_diff_path = $(".merge-diffs-tab").attr("data-url");  
76 - history.pushState({ path: mr_diff_path }, '', mr_diff_path);  
77 - e.preventDefault();  
78 - });  
79 -  
80 - },  
81 -  
82 - showState:  
83 - function(state){  
84 - $(".automerge_widget").hide();  
85 - $(".automerge_widget." + state).show();  
86 - },  
87 -  
88 - showCiState:  
89 - function(state){  
90 - $(".ci_widget").hide();  
91 - $(".ci_widget.ci-" + state).show();  
92 - },  
93 -  
94 - loadDiff:  
95 - function() {  
96 - $(".dashboard-loader").show();  
97 - $.ajax({  
98 - type: "GET",  
99 - url: $(".merge-diffs-tab").attr("data-url"),  
100 - beforeSend: function(){ $('.status').addClass("loading")},  
101 - complete: function(){  
102 - MergeRequest.diffs_loaded = true;  
103 - $(".merge_request_notes").hide();  
104 - $('.status').removeClass("loading");  
105 - },  
106 - dataType: "script"});  
107 - },  
108 -  
109 - showAllCommits:  
110 - function() {  
111 - $(".first_mr_commits").remove();  
112 - $(".all_mr_commits").removeClass("hide");  
113 - },  
114 -  
115 - already_cannot_be_merged:  
116 - function(){  
117 - $(".automerge_widget").hide();  
118 - $(".merge_in_progress").hide();  
119 - $(".automerge_widget.already_cannot_be_merged").show();  
120 - }  
121 -};  
122 -  
123 -/*  
124 - * Filter merge requests  
125 - */  
126 -function merge_requestsPage() {  
127 - $("#assignee_id").chosen();  
128 - $("#milestone_id").chosen();  
129 - $("#milestone_id, #assignee_id").on("change", function(){  
130 - $(this).closest("form").submit();  
131 - });  
132 -}  
app/assets/javascripts/merge_requests.js.coffee 0 → 100644
@@ -0,0 +1,97 @@ @@ -0,0 +1,97 @@
  1 +#
  2 +# * Filter merge requests
  3 +#
  4 +@merge_requestsPage = ->
  5 + $('#assignee_id').chosen()
  6 + $('#milestone_id').chosen()
  7 + $('#milestone_id, #assignee_id').on 'change', ->
  8 + $(this).closest('form').submit()
  9 +
  10 +class MergeRequest
  11 +
  12 + constructor: (@opts) ->
  13 + this.$el = $('.merge-request')
  14 + @diffs_loaded = false
  15 + @commits_loaded = false
  16 +
  17 + this.activateTab(@opts.action)
  18 +
  19 + this.bindEvents()
  20 +
  21 + this.initMergeWidget()
  22 + this.$('.show-all-commits').on 'click', =>
  23 + this.showAllCommits()
  24 +
  25 + # Local jQuery finder
  26 + $: (selector) ->
  27 + this.$el.find(selector)
  28 +
  29 + initMergeWidget: ->
  30 + this.showState( @opts.current_state )
  31 +
  32 + if this.$('.automerge_widget').length and @opts.check_enable
  33 + $.get @opts.url_to_automerge_check, (data) =>
  34 + this.showState( data.state )
  35 + , 'json'
  36 +
  37 + if @opts.ci_enable
  38 + $.get @opts.url_to_ci_check, (data) =>
  39 + this.showCiState data.status
  40 + , 'json'
  41 +
  42 + bindEvents: ->
  43 + this.$('.nav-tabs').on 'click', 'a', (event) =>
  44 + a = $(event.currentTarget)
  45 +
  46 + href = a.attr('href')
  47 + History.replaceState {path: href}, document.title, href
  48 +
  49 + event.preventDefault()
  50 +
  51 + this.$('.nav-tabs').on 'click', 'li', (event) =>
  52 + this.activateTab($(event.currentTarget).data('action'))
  53 +
  54 + activateTab: (action) ->
  55 + this.$('.nav-tabs li').removeClass 'active'
  56 + this.$('.tab-content').hide()
  57 + switch action
  58 + when 'diffs'
  59 + this.$('.nav-tabs .diffs-tab').addClass 'active'
  60 + this.loadDiff() unless @diffs_loaded
  61 + this.$('.diffs').show()
  62 + else
  63 + this.$('.nav-tabs .notes-tab').addClass 'active'
  64 + this.$('.notes').show()
  65 +
  66 + showState: (state) ->
  67 + $('.automerge_widget').hide()
  68 + $('.automerge_widget.' + state).show()
  69 +
  70 + showCiState: (state) ->
  71 + $('.ci_widget').hide()
  72 + $('.ci_widget.ci-' + state).show()
  73 +
  74 + loadDiff: (event) ->
  75 + $('.dashboard-loader').show()
  76 + $.ajax
  77 + type: 'GET'
  78 + url: this.$('.nav-tabs .diffs-tab a').attr('href')
  79 + beforeSend: =>
  80 + this.$('.status').addClass 'loading'
  81 +
  82 + complete: =>
  83 + @diffs_loaded = true
  84 + this.$('.status').removeClass 'loading'
  85 +
  86 + dataType: 'script'
  87 +
  88 + showAllCommits: ->
  89 + this.$('.first-commits').remove()
  90 + this.$('.all-commits').removeClass 'hide'
  91 +
  92 + alreadyOrCannotBeMerged: ->
  93 + this.$('.automerge_widget').hide()
  94 + this.$('.merge-in-progress').hide()
  95 + this.$('.automerge_widget.already_cannot_be_merged').show()
  96 +
  97 +this.MergeRequest = MergeRequest
app/assets/javascripts/milestones.js.coffee
1 $ -> 1 $ ->
2 - $('.milestone-issue-filter tr[data-closed]').addClass('hide') 2 + $('.milestone-issue-filter li[data-closed]').addClass('hide')
3 3
4 $('.milestone-issue-filter ul.nav li a').click -> 4 $('.milestone-issue-filter ul.nav li a').click ->
5 $('.milestone-issue-filter li').toggleClass('active') 5 $('.milestone-issue-filter li').toggleClass('active')
6 - $('.milestone-issue-filter tr[data-closed]').toggleClass('hide') 6 + $('.milestone-issue-filter li[data-closed]').toggleClass('hide')
7 false 7 false
8 8
9 - $('.milestone-merge-requests-filter tr[data-closed]').addClass('hide') 9 + $('.milestone-merge-requests-filter li[data-closed]').addClass('hide')
10 10
11 $('.milestone-merge-requests-filter ul.nav li a').click -> 11 $('.milestone-merge-requests-filter ul.nav li a').click ->
12 $('.milestone-merge-requests-filter li').toggleClass('active') 12 $('.milestone-merge-requests-filter li').toggleClass('active')
13 - $('.milestone-merge-requests-filter tr[data-closed]').toggleClass('hide') 13 + $('.milestone-merge-requests-filter li[data-closed]').toggleClass('hide')
14 false 14 false
app/assets/javascripts/pager.js
@@ -4,9 +4,16 @@ var Pager = { @@ -4,9 +4,16 @@ var Pager = {
4 disable:false, 4 disable:false,
5 5
6 init: 6 init:
7 - function(limit) { 7 + function(limit, preload) {
8 this.limit=limit; 8 this.limit=limit;
9 - this.offset=limit; 9 +
  10 + if(preload) {
  11 + this.offset = 0;
  12 + this.getOld();
  13 + } else {
  14 + this.offset = limit;
  15 + }
  16 +
10 this.initLoadMore(); 17 this.initLoadMore();
11 }, 18 },
12 19
app/assets/stylesheets/common.scss
@@ -117,34 +117,10 @@ span.update-author { @@ -117,34 +117,10 @@ span.update-author {
117 } 117 }
118 118
119 .label { 119 .label {
120 - background-color: #474D57;  
121 -  
122 - &.label-tag {  
123 - background: none;  
124 - border: none;  
125 - padding: 4px 6px;  
126 - color: #444;  
127 - text-shadow: 0 0 1px #fff;  
128 -  
129 - &.grouped {  
130 - float: left;  
131 - margin-right: 6px;  
132 - padding: 6px;  
133 - }  
134 - }  
135 - &.label-issue {  
136 - background-color: #eee;  
137 - border: 1px solid #ccc;  
138 - padding: 4px 6px;  
139 - color: #444;  
140 - text-shadow: 0 0 1px #fff;  
141 -  
142 - &.grouped {  
143 - float: left;  
144 - margin-right: 6px;  
145 - padding: 6px;  
146 - }  
147 - } 120 + padding: 0px 4px;
  121 + font-size: 10px;
  122 + font-style: normal;
  123 + background-color: $link_color;
148 124
149 &.label-success { 125 &.label-success {
150 background-color: #8D8; 126 background-color: #8D8;
@@ -425,7 +401,7 @@ li.note { @@ -425,7 +401,7 @@ li.note {
425 401
426 402
427 .supp_diff_link, 403 .supp_diff_link,
428 -.mr_show_all_commits { 404 +.show-all-commits {
429 cursor: pointer; 405 cursor: pointer;
430 } 406 }
431 407
app/assets/stylesheets/gitlab_bootstrap/blocks.scss
1 /** 1 /**
2 * =================================== 2 * ===================================
3 - * Contain 3 main UI block elements:  
4 - * .main_box - for show pages  
5 - * .ui-box - for simple block & widgets 3 + * Contain UI block elements:
  4 + * .ui-box - for any block & widgets
6 * =================================== 5 * ===================================
7 */ 6 */
8 7
9 /** 8 /**
10 - * UI box element  
11 - * contains top, middle, bottom blocks 9 + * UI Block
12 * 10 *
13 */ 11 */
14 -.main_box {  
15 - @extend .borders;  
16 - @extend .prepend-top-20;  
17 - @extend .append-bottom-20;  
18 - border-width: 1px; 12 +.ui-box {
  13 + background: #F9F9F9;
  14 + margin-bottom: 25px;
  15 + border: 1px solid #CCC;
19 @include solid-shade; 16 @include solid-shade;
20 17
  18 + &.ui-box-show {
  19 + margin:20px 0;
  20 + background: #FFF;
  21 + }
21 22
22 img { max-width: 100%; } 23 img { max-width: 100%; }
23 24
@@ -27,9 +28,9 @@ @@ -27,9 +28,9 @@
27 } 28 }
28 } 29 }
29 30
30 - .top_box_content,  
31 - .middle_box_content,  
32 - .bottom_box_content { 31 + .ui-box-head,
  32 + .ui-box-body,
  33 + .ui-box-bottom {
33 padding: 15px; 34 padding: 15px;
34 word-wrap: break-word; 35 word-wrap: break-word;
35 36
@@ -39,19 +40,25 @@ @@ -39,19 +40,25 @@
39 border: none; 40 border: none;
40 padding: 0; 41 padding: 0;
41 } 42 }
  43 +
  44 + .clearfix {
  45 + margin: 0;
  46 + }
42 } 47 }
43 48
44 - .top_box_content { 49 + .ui-box-head {
45 .box-title { 50 .box-title {
46 color: $style_color; 51 color: $style_color;
47 font-size: 18px; 52 font-size: 18px;
48 font-weight: normal; 53 font-weight: normal;
49 line-height: 28px; 54 line-height: 28px;
50 } 55 }
  56 + h3 {
  57 + margin: 0;
  58 + }
51 } 59 }
52 60
53 - .middle_box_content {  
54 - @include border-radius(0); 61 + .ui-box-body {
55 border: none; 62 border: none;
56 font-size: 12px; 63 font-size: 12px;
57 background-color: #f5f5f5; 64 background-color: #f5f5f5;
@@ -59,24 +66,9 @@ @@ -59,24 +66,9 @@
59 border-top: 1px solid #eee; 66 border-top: 1px solid #eee;
60 } 67 }
61 68
62 - .bottom_box_content { 69 + .ui-box-bottom {
63 border-top: 1px solid #eee; 70 border-top: 1px solid #eee;
64 } 71 }
65 -}  
66 -  
67 -/**  
68 - * Big UI Block for show page content  
69 - *  
70 - */  
71 -.ui-box {  
72 - background: #F9F9F9;  
73 - margin-bottom: 25px;  
74 -  
75 - border: 1px solid #eaeaea;  
76 - @include border-radius(4px);  
77 -  
78 - border-color: #CCC;  
79 - @include solid-shade;  
80 72
81 &.white { 73 &.white {
82 background: #fff; 74 background: #fff;
@@ -86,47 +78,47 @@ @@ -86,47 +78,47 @@
86 margin: 0; 78 margin: 0;
87 } 79 }
88 80
89 - h5, .title {  
90 - padding: 0 10px;  
91 - @include border-radius(4px 4px 0 0); 81 + .title {
92 @include bg-gray-gradient; 82 @include bg-gray-gradient;
93 - border-top: 1px solid #eaeaea;  
94 - border-bottom: 1px solid #bbb; 83 + border-bottom: 1px solid #CCC;
  84 + color: #456;
  85 + font-size: 16px;
  86 + text-shadow: 0 1px 1px #fff;
  87 + padding: 0px 10px;
  88 + line-height: 36px;
  89 + font-size: 14px;
  90 + font-weight: normal;
95 91
96 > a { 92 > a {
97 text-shadow: 0 1px 1px #fff; 93 text-shadow: 0 1px 1px #fff;
98 } 94 }
99 95
100 - &.small {  
101 - line-height: 28px;  
102 - font-size: 14px;  
103 - line-height: 28px;  
104 - text-shadow: 0 1px 1px white;  
105 - }  
106 -  
107 form { 96 form {
108 - padding: 9px 0;  
109 - margin: 0px; 97 + margin-bottom: 0;
  98 + margin-top: 3px;
110 } 99 }
111 100
112 .nav-pills { 101 .nav-pills {
113 - li {  
114 - padding: 3px 0;  
115 - &.active a { background-color: $style_color; }  
116 - a {  
117 - @include border-radius(7px); 102 + > li {
  103 + > a {
  104 + padding: 13px;
  105 + margin: 0;
  106 + font-size: 13px;
  107 + }
  108 + &.active {
  109 + > a {
  110 + background: #D5D5D5;
  111 + color: $style_color;
  112 + @include border-radius(0);
  113 + border-radius: 0;
  114 + border-left: 1px solid #CCC;
  115 + border-right: 1px solid #CCC;
  116 + }
118 } 117 }
119 } 118 }
120 } 119 }
121 } 120 }
122 121
123 - .bottom {  
124 - @include bg-gray-gradient;  
125 - @include border-radius(0 0 4px 4px);  
126 - border-bottom: none;  
127 - border-top: 1px solid #bbb;  
128 - }  
129 -  
130 &.padded { 122 &.padded {
131 h5, .title { 123 h5, .title {
132 margin: -20px; 124 margin: -20px;
@@ -143,6 +135,7 @@ @@ -143,6 +135,7 @@
143 color: #777; 135 color: #777;
144 } 136 }
145 } 137 }
  138 +
146 .row_title { 139 .row_title {
147 font-weight: bold; 140 font-weight: bold;
148 color: #444; 141 color: #444;
@@ -151,8 +144,4 @@ @@ -151,8 +144,4 @@
151 text-decoration: underline; 144 text-decoration: underline;
152 } 145 }
153 } 146 }
154 -  
155 - .ui-box-body {  
156 - padding: 10px;  
157 - }  
158 } 147 }
app/assets/stylesheets/gitlab_bootstrap/buttons.scss
@@ -7,6 +7,10 @@ @@ -7,6 +7,10 @@
7 color: #333; 7 color: #333;
8 } 8 }
9 9
  10 + &.btn-white {
  11 + background: #FFF;
  12 + }
  13 +
10 &.primary { 14 &.primary {
11 background: #2a79A3; 15 background: #2a79A3;
12 @include linear-gradient(#47A7b7, #2585b5); 16 @include linear-gradient(#47A7b7, #2585b5);
app/assets/stylesheets/gitlab_bootstrap/common.scss
@@ -17,20 +17,43 @@ @@ -17,20 +17,43 @@
17 .padded { padding:20px } 17 .padded { padding:20px }
18 .ipadded { padding:20px!important } 18 .ipadded { padding:20px!important }
19 .lborder { border-left:1px solid #eee } 19 .lborder { border-left:1px solid #eee }
20 -.no-padding { padding:0 !important; }  
21 -.underlined { border-bottom: 1px solid #CCC; }  
22 -.no-borders { border: none; }  
23 -.vlink { color: $link_color !important; }  
24 .underlined_link { text-decoration: underline; } 20 .underlined_link { text-decoration: underline; }
25 -.borders { border: 1px solid #ccc; @include shade; }  
26 .hint { font-style: italic; color: #999; } 21 .hint { font-style: italic; color: #999; }
27 .light { color: #888 } 22 .light { color: #888 }
28 .tiny { font-weight: normal } 23 .tiny { font-weight: normal }
29 24
30 /** PILLS & TABS**/ 25 /** PILLS & TABS**/
31 -.nav-pills a:hover { background-color: #888; }  
32 -.nav-pills .active a { background-color: $style_color; } 26 +.nav-pills {
  27 + .active a {
  28 + background: $primary_color;
  29 + }
  30 +
  31 + > li > a {
  32 + @include border-radius(0);
  33 + }
  34 + &.nav-stacked {
  35 + > li > a {
  36 + border-left: 4px solid #EEE;
  37 + padding: 12px;
  38 + }
  39 + > .active > a {
  40 + border-color: #29B;
  41 + border-radius: 0;
  42 + background: #F1F1F1;
  43 + color: $style_color;
  44 + font-weight: bold;
  45 + }
  46 + }
  47 +}
  48 +
33 .nav-pills > .active > a > i[class^="icon-"] { background: inherit; } 49 .nav-pills > .active > a > i[class^="icon-"] { background: inherit; }
  50 +
  51 +
  52 +
  53 +/**
  54 + * nav-tabs
  55 + *
  56 + */
34 .nav-tabs > li > a, .nav-pills > li > a { color: $style_color; } 57 .nav-tabs > li > a, .nav-pills > li > a { color: $style_color; }
35 .nav.nav-tabs { 58 .nav.nav-tabs {
36 li { 59 li {
app/assets/stylesheets/gitlab_bootstrap/fonts.scss
1 -@font-face{  
2 - font-family: Korolev;  
3 - src: font-url('korolev-medium-compressed.otf'); 1 +@font-face{
  2 + font-family: Yanone;
  3 + src: font-url('YanoneKaffeesatz-Light.ttf');
4 } 4 }
5 5
6 /** Typo **/ 6 /** Typo **/
7 -$monospace: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;  
8 \ No newline at end of file 7 \ No newline at end of file
  8 +$monospace: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;
app/assets/stylesheets/gitlab_bootstrap/lists.scss
@@ -23,14 +23,12 @@ @@ -23,14 +23,12 @@
23 border-bottom: 1px solid #ADF; 23 border-bottom: 1px solid #ADF;
24 } 24 }
25 25
26 - &:first-child {  
27 - @include border-radius(4px 4px 0 0);  
28 - border-top: none;  
29 - }  
30 -  
31 &:last-child { 26 &:last-child {
32 - @include border-radius(0 0 4px 4px);  
33 - border: none; 27 + border-bottom: none;
  28 +
  29 + &.bottom {
  30 + background: #f5f5f5;
  31 + }
34 } 32 }
35 33
36 .author { color: #999; } 34 .author { color: #999; }
app/assets/stylesheets/gitlab_bootstrap/mixins.scss
@@ -62,8 +62,8 @@ @@ -62,8 +62,8 @@
62 @mixin header-font { 62 @mixin header-font {
63 color: $style_color; 63 color: $style_color;
64 text-shadow: 0 1px 1px #FFF; 64 text-shadow: 0 1px 1px #FFF;
65 - font-family: 'Korolev', sans-serif;  
66 - font-size: 28px;  
67 - line-height: 48px; 65 + font-family: 'Yanone', sans-serif;
  66 + font-size: 26px;
  67 + line-height: 42px;
68 font-weight: normal; 68 font-weight: normal;
69 } 69 }
app/assets/stylesheets/gitlab_bootstrap/tables.scss
@@ -25,7 +25,7 @@ table { @@ -25,7 +25,7 @@ table {
25 } 25 }
26 26
27 th, td { 27 th, td {
28 - padding: 8px; 28 + padding: 10px;
29 line-height: 18px; 29 line-height: 18px;
30 text-align: left; 30 text-align: left;
31 } 31 }
app/assets/stylesheets/sections/commits.scss
1 -.commit-box {  
2 - @extend .main_box;  
3 -  
4 - .commit-head {  
5 - @extend .top_box_content;  
6 -  
7 - .commit-title {  
8 - line-height: 26px;  
9 - margin: 0;  
10 - }  
11 -  
12 - .commit-description {  
13 - font-size: 14px;  
14 - border: none;  
15 - background-color: white;  
16 - padding-top: 10px;  
17 - }  
18 -  
19 - .browse-button {  
20 - @extend .btn;  
21 - @extend .btn-small;  
22 - float: right;  
23 - }  
24 - }  
25 -  
26 - .commit-info {  
27 - @extend .middle_box_content;  
28 - @extend .clearfix;  
29 -  
30 - .sha-block {  
31 - text-align: right;  
32 - &:first-child {  
33 - padding-bottom: 6px;  
34 - }  
35 -  
36 - a {  
37 - border-bottom: 1px solid #aaa;  
38 - margin-left: 9px;  
39 - }  
40 - }  
41 -  
42 - &.merge-commit .sha-block {  
43 - clear: right;  
44 - }  
45 -  
46 - .committer {  
47 - padding-left: 32px;  
48 - }  
49 -  
50 - .author a,  
51 - .committer a {  
52 - font-size: 14px;  
53 - line-height: 22px;  
54 - text-shadow: 0 1px 1px #fff;  
55 - color: #777;  
56 - &:hover {  
57 - color: #999;  
58 - }  
59 - }  
60 -  
61 - .avatar {  
62 - margin-right: 10px;  
63 - }  
64 - }  
65 -}  
66 -  
67 /** 1 /**
68 * 2 *
69 * COMMIT SHOw 3 * COMMIT SHOw
70 * 4 *
71 */ 5 */
  6 +.commit-committer-link,
  7 +.commit-author-link {
  8 + font-size: 13px;
  9 + color: #555;
  10 + &:hover {
  11 + color: #999;
  12 + }
  13 +}
  14 +
72 .diff_file { 15 .diff_file {
73 border: 1px solid #CCC; 16 border: 1px solid #CCC;
74 margin-bottom: 1em; 17 margin-bottom: 1em;
@@ -258,13 +201,6 @@ @@ -258,13 +201,6 @@
258 min-width: 65px; 201 min-width: 65px;
259 font-family: $monospace; 202 font-family: $monospace;
260 } 203 }
261 -  
262 - .commit-author-name {  
263 - color: #777;  
264 - &:hover {  
265 - color: #999;  
266 - }  
267 - }  
268 } 204 }
269 205
270 .diff_file_header a, 206 .diff_file_header a,
app/assets/stylesheets/sections/events.scss
@@ -47,6 +47,12 @@ @@ -47,6 +47,12 @@
47 .event-info { 47 .event-info {
48 color: #666; 48 color: #666;
49 } 49 }
  50 + .event-note {
  51 + padding-top: 5px;
  52 + padding-left: 5px;
  53 + display: inline-block;
  54 + color: #777;
  55 + }
50 } 56 }
51 .avatar { 57 .avatar {
52 position: relative; 58 position: relative;
app/assets/stylesheets/sections/header.scss
@@ -33,22 +33,29 @@ header { @@ -33,22 +33,29 @@ header {
33 * 33 *
34 */ 34 */
35 .app_logo { 35 .app_logo {
36 - width: 170px;  
37 float: left; 36 float: left;
  37 + margin-right: 15px;
  38 + position: relative;
  39 + top: -5px;
  40 + padding-top: 5px;
  41 +
38 a { 42 a {
39 float: left; 43 float: left;
40 padding: 0px; 44 padding: 0px;
  45 + margin: 0 10px;
41 46
42 h1 { 47 h1 {
43 - width: 90px;  
44 background: url('logo_dark.png') no-repeat 0px 2px; 48 background: url('logo_dark.png') no-repeat 0px 2px;
45 float: left; 49 float: left;
46 - margin-left: 2px;  
47 - padding-left: 45px;  
48 height: 40px; 50 height: 40px;
  51 + width: 40px;
49 @include header-font; 52 @include header-font;
  53 + text-indent: -9999px;
50 } 54 }
51 } 55 }
  56 + &:hover {
  57 + background-color: #EEE;
  58 + }
52 } 59 }
53 60
54 /** 61 /**
@@ -60,7 +67,7 @@ header { @@ -60,7 +67,7 @@ header {
60 position: relative; 67 position: relative;
61 float: left; 68 float: left;
62 margin: 0; 69 margin: 0;
63 - margin-right: 30px; 70 + margin-left: 15px;
64 @include header-font; 71 @include header-font;
65 } 72 }
66 73
@@ -233,7 +240,7 @@ header { @@ -233,7 +240,7 @@ header {
233 .app_logo { 240 .app_logo {
234 a { 241 a {
235 h1 { 242 h1 {
236 - background: url('logo_white.png') no-repeat 0px 2px; 243 + background: url('logo_white.png') no-repeat center center;
237 color: #fff; 244 color: #fff;
238 text-shadow: 0 1px 1px #111; 245 text-shadow: 0 1px 1px #111;
239 } 246 }
@@ -244,5 +251,23 @@ header { @@ -244,5 +251,23 @@ header {
244 text-shadow: 0 1px 1px #111; 251 text-shadow: 0 1px 1px #111;
245 } 252 }
246 } 253 }
  254 +
  255 + .app_logo {
  256 + .separator {
  257 + margin-left: 0;
  258 + margin-right: 0;
  259 + }
  260 + }
  261 +
  262 + .separator {
  263 + float: left;
  264 + height: 60px;
  265 + width: 1px;
  266 + background: white;
  267 + border-left: 1px solid #DDD;
  268 + margin-top: -10px;
  269 + margin-left: 10px;
  270 + margin-right: 10px;
  271 + }
247 } 272 }
248 273
app/assets/stylesheets/sections/issues.scss
1 -.issue_form_box {  
2 - @extend .main_box;  
3 - .issue_title {  
4 - @extend .top_box_content;  
5 - .clearfix {  
6 - margin-bottom: 0px;  
7 - input {  
8 - @extend .span8;  
9 - }  
10 - }  
11 - }  
12 - .issue_middle_block {  
13 - @extend .middle_box_content;  
14 - height: 30px;  
15 - .issue_assignee {  
16 - @extend .span6;  
17 - float: left;  
18 - }  
19 - .issue_milestone {  
20 - @extend .span4;  
21 - float: left;  
22 - }  
23 - }  
24 - .issue_description {  
25 - @extend .bottom_box_content;  
26 - }  
27 -}  
28 -  
29 .issues_table { 1 .issues_table {
30 .issue { 2 .issue {
31 - padding: 7px 10px; 3 + padding: 10px;
32 4
33 .issue_check { 5 .issue_check {
34 float: left; 6 float: left;
@@ -82,38 +54,34 @@ input.check_all_issues { @@ -82,38 +54,34 @@ input.check_all_issues {
82 } 54 }
83 } 55 }
84 56
85 -@media (min-width: 800px) { .issues_filters select { width: 160px; } }  
86 -@media (min-width: 1000px) { .issues_filters select { width: 200px; } } 57 +@media (min-width: 800px) { .issues_filters select { width: 160px; } }
87 @media (min-width: 1200px) { .issues_filters select { width: 220px; } } 58 @media (min-width: 1200px) { .issues_filters select { width: 220px; } }
88 59
  60 +@media (min-width: 800px) { .issues_bulk_update select { width: 120px; } }
  61 +@media (min-width: 1200px) { .issues_bulk_update select { width: 160px; } }
89 62
90 #issues-table-holder { 63 #issues-table-holder {
91 .issues_filters { 64 .issues_filters {
92 - form {  
93 - padding: 0;  
94 - margin: 0;  
95 - margin-top:7px  
96 - }  
97 } 65 }
98 66
99 .issues_bulk_update { 67 .issues_bulk_update {
100 margin: 0; 68 margin: 0;
101 form { 69 form {
102 - padding: 0;  
103 - margin: 0;  
104 - margin-top:7px 70 + float:left;
105 } 71 }
  72 +
106 .update_selected_issues { 73 .update_selected_issues {
107 position: relative; 74 position: relative;
108 - top:-2px; 75 + top:5px;
109 margin-left: 4px; 76 margin-left: 4px;
110 float: left; 77 float: left;
111 } 78 }
112 79
113 .update_issues_text { 80 .update_issues_text {
114 padding: 3px; 81 padding: 3px;
115 - line-height: 18px; 82 + line-height: 28px;
116 float: left; 83 float: left;
  84 + color: #479;
117 } 85 }
118 } 86 }
119 } 87 }
app/assets/stylesheets/sections/merge_requests.scss
1 -/**  
2 - * MR form  
3 - *  
4 - */  
5 -  
6 -.mr_branch_box {  
7 - @extend .ui-box;  
8 - margin-bottom: 20px;  
9 -  
10 - .body {  
11 - background: #f1f1f1;  
12 - }  
13 -  
14 -}  
15 1
16 /** 2 /**
17 * MR -> show: Automerge widget 3 * MR -> show: Automerge widget
@@ -47,6 +33,7 @@ @@ -47,6 +33,7 @@
47 } 33 }
48 label { 34 label {
49 color: #444; 35 color: #444;
  36 + text-align: left
50 } 37 }
51 } 38 }
52 39
@@ -56,7 +43,7 @@ @@ -56,7 +43,7 @@
56 } 43 }
57 } 44 }
58 45
59 -.mr_nav_tabs { 46 +.merge-request .nav-tabs{
60 li { 47 li {
61 a { 48 a {
62 font-weight: bold; 49 font-weight: bold;
@@ -67,7 +54,7 @@ @@ -67,7 +54,7 @@
67 } 54 }
68 55
69 li.merge_request { 56 li.merge_request {
70 - padding: 7px 10px; 57 + padding: 10px;
71 img.avatar { 58 img.avatar {
72 width: 32px; 59 width: 32px;
73 margin-top: 1px; 60 margin-top: 1px;
@@ -78,7 +65,7 @@ li.merge_request { @@ -78,7 +65,7 @@ li.merge_request {
78 } 65 }
79 } 66 }
80 67
81 -.merge_in_progress { 68 +.merge-in-progress {
82 @extend .padded; 69 @extend .padded;
83 @extend .append-bottom-10; 70 @extend .append-bottom-10;
84 } 71 }
@@ -120,19 +107,3 @@ li.merge_request { @@ -120,19 +107,3 @@ li.merge_request {
120 .mr_direction_tip { 107 .mr_direction_tip {
121 margin-top:40px 108 margin-top:40px
122 } 109 }
123 -  
124 -.merge_requests_form_box {  
125 - @extend .main_box;  
126 - .merge_requests_middle_box {  
127 - @extend .middle_box_content;  
128 - height: 30px;  
129 - .merge_requests_assignee {  
130 - @extend .span6;  
131 - float: left;  
132 - }  
133 - .merge_requests_milestone {  
134 - @extend .span4;  
135 - float: left;  
136 - }  
137 - }  
138 -}  
app/assets/stylesheets/sections/notes.scss
@@ -294,6 +294,8 @@ ul.notes { @@ -294,6 +294,8 @@ ul.notes {
294 padding: 4px 6px; 294 padding: 4px 6px;
295 } 295 }
296 .note_text { 296 .note_text {
  297 + border: 1px solid #DDD;
  298 + box-shadow: none;
297 font-size: 14px; 299 font-size: 14px;
298 height: 80px; 300 height: 80px;
299 width: 98.6%; 301 width: 98.6%;
app/assets/stylesheets/sections/projects.scss
@@ -8,16 +8,12 @@ @@ -8,16 +8,12 @@
8 8
9 .groups_box, 9 .groups_box,
10 .projects_box { 10 .projects_box {
11 - > h5 {  
12 - color: $style_color;  
13 - font-size: 16px;  
14 - text-shadow: 0 1px 1px #fff;  
15 - padding: 2px 10px;  
16 - line-height: 32px;  
17 - font-size: 14px; 11 + > .title {
  12 + padding: 2px 15px;
18 } 13 }
19 .nav-projects-tabs li { padding: 0; } 14 .nav-projects-tabs li { padding: 0; }
20 .well-list { 15 .well-list {
  16 + li { padding: 15px; }
21 .arrow { 17 .arrow {
22 float: right; 18 float: right;
23 padding: 10px; 19 padding: 10px;
@@ -109,7 +105,7 @@ ul.nav.nav-projects-tabs { @@ -109,7 +105,7 @@ ul.nav.nav-projects-tabs {
109 105
110 li { 106 li {
111 a { 107 a {
112 - padding: 4px 20px; 108 + padding: 6px 25px;
113 margin-top: 2px; 109 margin-top: 2px;
114 border-color: #DDD; 110 border-color: #DDD;
115 background-color: #EEE; 111 background-color: #EEE;
app/assets/stylesheets/themes/ui_basic.scss
@@ -4,21 +4,8 @@ @@ -4,21 +4,8 @@
4 * 4 *
5 */ 5 */
6 .ui_basic { 6 .ui_basic {
7 - .app_logo {  
8 - .separator {  
9 - margin-left: 0;  
10 - margin-right: 0;  
11 - }  
12 - }  
13 -  
14 .separator { 7 .separator {
15 - float: left;  
16 - height: 60px;  
17 - width: 1px;  
18 background: white; 8 background: white;
19 border-left: 1px solid #DDD; 9 border-left: 1px solid #DDD;
20 - margin-top: -10px;  
21 - margin-left: 10px;  
22 - margin-right: 10px;  
23 } 10 }
24 } 11 }
app/assets/stylesheets/themes/ui_color.scss
@@ -17,6 +17,15 @@ @@ -17,6 +17,15 @@
17 &.navbar-gitlab { 17 &.navbar-gitlab {
18 .navbar-inner { 18 .navbar-inner {
19 background: #657; 19 background: #657;
  20 + .app_logo {
  21 + &:hover {
  22 + background-color: #6A5A7A;
  23 + }
  24 + }
  25 + .separator {
  26 + background: #546;
  27 + border-left: 1px solid #706080;
  28 + }
20 } 29 }
21 } 30 }
22 } 31 }
app/assets/stylesheets/themes/ui_gray.scss
@@ -17,6 +17,15 @@ @@ -17,6 +17,15 @@
17 &.navbar-gitlab { 17 &.navbar-gitlab {
18 .navbar-inner { 18 .navbar-inner {
19 background: #708090; 19 background: #708090;
  20 + .app_logo {
  21 + &:hover {
  22 + background-color: #6A7A8A;
  23 + }
  24 + }
  25 + .separator {
  26 + background: #607080;
  27 + border-left: 1px solid #8090A0;
  28 + }
20 } 29 }
21 } 30 }
22 } 31 }
app/assets/stylesheets/themes/ui_mars.scss
@@ -46,21 +46,26 @@ @@ -46,21 +46,26 @@
46 .app_logo { 46 .app_logo {
47 a { 47 a {
48 h1 { 48 h1 {
49 - background: url('logo_white.png') no-repeat 0px 2px; 49 + background: url('logo_white.png') no-repeat center center;
50 color: #eee; 50 color: #eee;
51 text-shadow: 0 1px 1px #111; 51 text-shadow: 0 1px 1px #111;
52 } 52 }
53 } 53 }
54 - .separator {  
55 - display: none; 54 + &:hover {
  55 + background-color: #41464e;
56 } 56 }
57 -  
58 } 57 }
59 .project_name { 58 .project_name {
60 color: #eee; 59 color: #eee;
61 text-shadow: 0 1px 1px #111; 60 text-shadow: 0 1px 1px #111;
62 } 61 }
63 } 62 }
  63 +
  64 + .separator {
  65 + background: #31363E;
  66 + border-left: 1px solid #666;
  67 + }
  68 +
64 /* 69 /*
65 * End of Application Header 70 * End of Application Header
66 * 71 *
app/assets/stylesheets/themes/ui_modern.scss
@@ -17,6 +17,15 @@ @@ -17,6 +17,15 @@
17 &.navbar-gitlab { 17 &.navbar-gitlab {
18 .navbar-inner { 18 .navbar-inner {
19 background: #567; 19 background: #567;
  20 + .app_logo {
  21 + &:hover {
  22 + background-color: #516171;
  23 + }
  24 + }
  25 + .separator {
  26 + background: #456;
  27 + border-left: 1px solid #678;
  28 + }
20 } 29 }
21 } 30 }
22 } 31 }
app/contexts/commit_load_context.rb
@@ -9,16 +9,16 @@ class CommitLoadContext &lt; BaseContext @@ -9,16 +9,16 @@ class CommitLoadContext &lt; BaseContext
9 status: :ok 9 status: :ok
10 } 10 }
11 11
12 - commit = project.commit(params[:id]) 12 + commit = project.repository.commit(params[:id])
13 13
14 if commit 14 if commit
15 commit = CommitDecorator.decorate(commit) 15 commit = CommitDecorator.decorate(commit)
16 - line_notes = project.commit_line_notes(commit) 16 + line_notes = project.notes.for_commit_id(commit.id).inline
17 17
18 result[:commit] = commit 18 result[:commit] = commit
19 result[:note] = project.build_commit_note(commit) 19 result[:note] = project.build_commit_note(commit)
20 result[:line_notes] = line_notes 20 result[:line_notes] = line_notes
21 - result[:notes_count] = line_notes.count + project.commit_notes(commit).count 21 + result[:notes_count] = project.notes.for_commit_id(commit.id).count
22 22
23 begin 23 begin
24 result[:suppress_diff] = true if commit.diffs.size > Commit::DIFF_SAFE_SIZE && !params[:force_show_diff] 24 result[:suppress_diff] = true if commit.diffs.size > Commit::DIFF_SAFE_SIZE && !params[:force_show_diff]
app/contexts/filter_context.rb 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +class FilterContext
  2 + attr_accessor :items, :params
  3 +
  4 + def initialize(items, params)
  5 + @items = items
  6 + @params = params
  7 + end
  8 +
  9 + def execute
  10 + apply_filter(items)
  11 + end
  12 +
  13 + def apply_filter items
  14 + if params[:project_id]
  15 + items = items.where(project_id: params[:project_id])
  16 + end
  17 +
  18 + if params[:search].present?
  19 + items = items.search(params[:search])
  20 + end
  21 +
  22 + case params[:status]
  23 + when 'closed'
  24 + items.closed
  25 + when 'all'
  26 + items
  27 + else
  28 + items.opened
  29 + end
  30 + end
  31 +end
app/contexts/issues_list_context.rb
@@ -4,7 +4,7 @@ class IssuesListContext &lt; BaseContext @@ -4,7 +4,7 @@ class IssuesListContext &lt; BaseContext
4 attr_accessor :issues 4 attr_accessor :issues
5 5
6 def execute 6 def execute
7 - @issues = case params[:f] 7 + @issues = case params[:status]
8 when issues_filter[:all] then @project.issues 8 when issues_filter[:all] then @project.issues
9 when issues_filter[:closed] then @project.issues.closed 9 when issues_filter[:closed] then @project.issues.closed
10 when issues_filter[:to_me] then @project.issues.opened.assigned(current_user) 10 when issues_filter[:to_me] then @project.issues.opened.assigned(current_user)
app/contexts/notes/load_context.rb
@@ -9,7 +9,7 @@ module Notes @@ -9,7 +9,7 @@ module Notes
9 9
10 @notes = case target_type 10 @notes = case target_type
11 when "commit" 11 when "commit"
12 - project.commit_notes(project.commit(target_id)).fresh 12 + project.notes.for_commit_id(target_id).not_inline.fresh
13 when "issue" 13 when "issue"
14 project.issues.find(target_id).notes.inc_author.fresh 14 project.issues.find(target_id).notes.inc_author.fresh
15 when "merge_request" 15 when "merge_request"
@@ -18,7 +18,7 @@ module Notes @@ -18,7 +18,7 @@ module Notes
18 project.snippets.find(target_id).notes.fresh 18 project.snippets.find(target_id).notes.fresh
19 when "wall" 19 when "wall"
20 # this is the only case, where the order is DESC 20 # this is the only case, where the order is DESC
21 - project.common_notes.order("created_at DESC, id DESC").limit(50) 21 + project.notes.common.inc_author_project.order("created_at DESC, id DESC").limit(50)
22 end 22 end
23 23
24 @notes = if after_id 24 @notes = if after_id
app/contexts/test_hook_context.rb
1 class TestHookContext < BaseContext 1 class TestHookContext < BaseContext
2 def execute 2 def execute
3 hook = project.hooks.find(params[:id]) 3 hook = project.hooks.find(params[:id])
4 - commits = project.commits(project.default_branch, nil, 3) 4 + commits = project.repository.commits(project.default_branch, nil, 3)
5 data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) 5 data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user)
6 hook.execute(data) 6 hook.execute(data)
7 end 7 end
app/controllers/admin/dashboard_controller.rb
@@ -3,10 +3,6 @@ class Admin::DashboardController &lt; AdminController @@ -3,10 +3,6 @@ class Admin::DashboardController &lt; AdminController
3 @projects = Project.order("created_at DESC").limit(10) 3 @projects = Project.order("created_at DESC").limit(10)
4 @users = User.order("created_at DESC").limit(10) 4 @users = User.order("created_at DESC").limit(10)
5 5
6 - @resque_accessible = true  
7 - @workers = Resque.workers  
8 - @pending_jobs = Resque.size(:post_receive)  
9 -  
10 rescue Redis::InheritedError 6 rescue Redis::InheritedError
11 @resque_accessible = false 7 @resque_accessible = false
12 end 8 end
app/controllers/admin/groups_controller.rb
1 class Admin::GroupsController < AdminController 1 class Admin::GroupsController < AdminController
2 - before_filter :group, only: [:edit, :show, :update, :destroy, :project_update] 2 + before_filter :group, only: [:edit, :show, :update, :destroy, :project_update, :project_teams_update]
3 3
4 def index 4 def index
5 @groups = Group.order('name ASC') 5 @groups = Group.order('name ASC')
@@ -12,6 +12,8 @@ class Admin::GroupsController &lt; AdminController @@ -12,6 +12,8 @@ class Admin::GroupsController &lt; AdminController
12 @projects = @projects.not_in_group(@group) if @group.projects.present? 12 @projects = @projects.not_in_group(@group) if @group.projects.present?
13 @projects = @projects.all 13 @projects = @projects.all
14 @projects.reject!(&:empty_repo?) 14 @projects.reject!(&:empty_repo?)
  15 +
  16 + @users = User.active
15 end 17 end
16 18
17 def new 19 def new
@@ -65,7 +67,14 @@ class Admin::GroupsController &lt; AdminController @@ -65,7 +67,14 @@ class Admin::GroupsController &lt; AdminController
65 redirect_to :back, notice: 'Group was successfully updated.' 67 redirect_to :back, notice: 'Group was successfully updated.'
66 end 68 end
67 69
  70 + def project_teams_update
  71 + @group.add_users_to_project_teams(params[:user_ids], params[:project_access])
  72 + redirect_to [:admin, @group], notice: 'Users was successfully added.'
  73 + end
  74 +
68 def destroy 75 def destroy
  76 + @group.truncate_teams
  77 +
69 @group.destroy 78 @group.destroy
70 79
71 redirect_to admin_groups_path, notice: 'Group was successfully deleted.' 80 redirect_to admin_groups_path, notice: 'Group was successfully deleted.'
app/controllers/admin/projects_controller.rb
@@ -10,6 +10,7 @@ class Admin::ProjectsController &lt; AdminController @@ -10,6 +10,7 @@ class Admin::ProjectsController &lt; AdminController
10 end 10 end
11 11
12 def show 12 def show
  13 + @repository = @project.repository
13 @users = User.active 14 @users = User.active
14 @users = @users.not_in_project(@project) if @project.users.present? 15 @users = @users.not_in_project(@project) if @project.users.present?
15 @users = @users.all 16 @users = @users.all
@@ -19,7 +20,7 @@ class Admin::ProjectsController &lt; AdminController @@ -19,7 +20,7 @@ class Admin::ProjectsController &lt; AdminController
19 end 20 end
20 21
21 def team_update 22 def team_update
22 - @project.add_users_ids_to_team(params[:user_ids], params[:project_access]) 23 + @project.team.add_users_ids(params[:user_ids], params[:project_access])
23 24
24 redirect_to [:admin, @project], notice: 'Project was successfully updated.' 25 redirect_to [:admin, @project], notice: 'Project was successfully updated.'
25 end 26 end
@@ -35,6 +36,9 @@ class Admin::ProjectsController &lt; AdminController @@ -35,6 +36,9 @@ class Admin::ProjectsController &lt; AdminController
35 end 36 end
36 37
37 def destroy 38 def destroy
  39 + # Delete team first in order to prevent multiple gitolite calls
  40 + @project.team.truncate
  41 +
38 @project.destroy 42 @project.destroy
39 43
40 redirect_to admin_projects_path, notice: 'Project was successfully deleted.' 44 redirect_to admin_projects_path, notice: 'Project was successfully deleted.'
app/controllers/admin/users_controller.rb
@@ -3,13 +3,13 @@ class Admin::UsersController &lt; AdminController @@ -3,13 +3,13 @@ class Admin::UsersController &lt; AdminController
3 @admin_users = User.scoped 3 @admin_users = User.scoped
4 @admin_users = @admin_users.filter(params[:filter]) 4 @admin_users = @admin_users.filter(params[:filter])
5 @admin_users = @admin_users.search(params[:name]) if params[:name].present? 5 @admin_users = @admin_users.search(params[:name]) if params[:name].present?
6 - @admin_users = @admin_users.order("name ASC").page(params[:page]) 6 + @admin_users = @admin_users.alphabetically.page(params[:page])
7 end 7 end
8 8
9 def show 9 def show
10 @admin_user = User.find(params[:id]) 10 @admin_user = User.find(params[:id])
11 11
12 - @projects = if @admin_user.projects.empty? 12 + @projects = if @admin_user.authorized_projects.empty?
13 Project 13 Project
14 else 14 else
15 Project.without_user(@admin_user) 15 Project.without_user(@admin_user)
@@ -19,9 +19,9 @@ class Admin::UsersController &lt; AdminController @@ -19,9 +19,9 @@ class Admin::UsersController &lt; AdminController
19 def team_update 19 def team_update
20 @admin_user = User.find(params[:id]) 20 @admin_user = User.find(params[:id])
21 21
22 - UsersProject.user_bulk_import(  
23 - @admin_user, 22 + UsersProject.add_users_into_projects(
24 params[:project_ids], 23 params[:project_ids],
  24 + [@admin_user.id],
25 params[:project_access] 25 params[:project_access]
26 ) 26 )
27 27
@@ -98,7 +98,7 @@ class Admin::UsersController &lt; AdminController @@ -98,7 +98,7 @@ class Admin::UsersController &lt; AdminController
98 98
99 def destroy 99 def destroy
100 @admin_user = User.find(params[:id]) 100 @admin_user = User.find(params[:id])
101 - if @admin_user.my_own_projects.count > 0 101 + if @admin_user.personal_projects.count > 0
102 redirect_to admin_users_path, alert: "User is a project owner and can't be removed." and return 102 redirect_to admin_users_path, alert: "User is a project owner and can't be removed." and return
103 end 103 end
104 @admin_user.destroy 104 @admin_user.destroy
app/controllers/application_controller.rb
@@ -76,6 +76,12 @@ class ApplicationController &lt; ActionController::Base @@ -76,6 +76,12 @@ class ApplicationController &lt; ActionController::Base
76 end 76 end
77 end 77 end
78 78
  79 + def repository
  80 + @repository ||= project.repository
  81 + rescue Grit::NoSuchPathError
  82 + nil
  83 + end
  84 +
79 def add_abilities 85 def add_abilities
80 abilities << Ability 86 abilities << Ability
81 end 87 end
app/controllers/commits_controller.rb
@@ -9,10 +9,10 @@ class CommitsController &lt; ProjectResourceController @@ -9,10 +9,10 @@ class CommitsController &lt; ProjectResourceController
9 before_filter :require_non_empty_project 9 before_filter :require_non_empty_project
10 10
11 def show 11 def show
12 - @repo = @project.repo 12 + @repo = @project.repository
13 @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) 13 @limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
14 14
15 - @commits = @project.commits(@ref, @path, @limit, @offset) 15 + @commits = @repo.commits(@ref, @path, @limit, @offset)
16 @commits = CommitDecorator.decorate(@commits) 16 @commits = CommitDecorator.decorate(@commits)
17 17
18 respond_to do |format| 18 respond_to do |format|
app/controllers/dashboard_controller.rb
@@ -20,7 +20,7 @@ class DashboardController &lt; ApplicationController @@ -20,7 +20,7 @@ class DashboardController &lt; ApplicationController
20 20
21 @projects = @projects.page(params[:page]).per(30) 21 @projects = @projects.page(params[:page]).per(30)
22 22
23 - @events = Event.in_projects(current_user.project_ids) 23 + @events = Event.in_projects(current_user.authorized_projects.pluck(:id))
24 @events = @event_filter.apply_filter(@events) 24 @events = @event_filter.apply_filter(@events)
25 @events = @events.limit(20).offset(params[:offset] || 0) 25 @events = @events.limit(20).offset(params[:offset] || 0)
26 26
@@ -36,14 +36,14 @@ class DashboardController &lt; ApplicationController @@ -36,14 +36,14 @@ class DashboardController &lt; ApplicationController
36 # Get authored or assigned open merge requests 36 # Get authored or assigned open merge requests
37 def merge_requests 37 def merge_requests
38 @merge_requests = current_user.cared_merge_requests 38 @merge_requests = current_user.cared_merge_requests
39 - @merge_requests = dashboard_filter(@merge_requests) 39 + @merge_requests = FilterContext.new(@merge_requests, params).execute
40 @merge_requests = @merge_requests.recent.page(params[:page]).per(20) 40 @merge_requests = @merge_requests.recent.page(params[:page]).per(20)
41 end 41 end
42 42
43 # Get only assigned issues 43 # Get only assigned issues
44 def issues 44 def issues
45 @issues = current_user.assigned_issues 45 @issues = current_user.assigned_issues
46 - @issues = dashboard_filter(@issues) 46 + @issues = FilterContext.new(@issues, params).execute
47 @issues = @issues.recent.page(params[:page]).per(20) 47 @issues = @issues.recent.page(params[:page]).per(20)
48 @issues = @issues.includes(:author, :project) 48 @issues = @issues.includes(:author, :project)
49 49
@@ -60,25 +60,7 @@ class DashboardController &lt; ApplicationController @@ -60,25 +60,7 @@ class DashboardController &lt; ApplicationController
60 end 60 end
61 61
62 def event_filter 62 def event_filter
63 - @event_filter ||= EventFilter.new(params[:event_filter])  
64 - end  
65 -  
66 - def dashboard_filter items  
67 - if params[:project_id]  
68 - items = items.where(project_id: params[:project_id])  
69 - end  
70 -  
71 - if params[:search].present?  
72 - items = items.search(params[:search])  
73 - end  
74 -  
75 - case params[:status]  
76 - when 'closed'  
77 - items.closed  
78 - when 'all'  
79 - items  
80 - else  
81 - items.opened  
82 - end 63 + filters = cookies['event_filter'].split(',') if cookies['event_filter']
  64 + @event_filter ||= EventFilter.new(filters)
83 end 65 end
84 end 66 end
app/controllers/groups_controller.rb
@@ -21,15 +21,16 @@ class GroupsController &lt; ApplicationController @@ -21,15 +21,16 @@ class GroupsController &lt; ApplicationController
21 21
22 # Get authored or assigned open merge requests 22 # Get authored or assigned open merge requests
23 def merge_requests 23 def merge_requests
24 - @merge_requests = current_user.cared_merge_requests.opened  
25 - @merge_requests = @merge_requests.of_group(@group).recent.page(params[:page]).per(20) 24 + @merge_requests = current_user.cared_merge_requests.of_group(@group)
  25 + @merge_requests = FilterContext.new(@merge_requests, params).execute
  26 + @merge_requests = @merge_requests.recent.page(params[:page]).per(20)
26 end 27 end
27 28
28 # Get only assigned issues 29 # Get only assigned issues
29 def issues 30 def issues
30 - @user = current_user  
31 - @issues = current_user.assigned_issues.opened  
32 - @issues = @issues.of_group(@group).recent.page(params[:page]).per(20) 31 + @issues = current_user.assigned_issues.of_group(@group)
  32 + @issues = FilterContext.new(@issues, params).execute
  33 + @issues = @issues.recent.page(params[:page]).per(20)
33 @issues = @issues.includes(:author, :project) 34 @issues = @issues.includes(:author, :project)
34 35
35 respond_to do |format| 36 respond_to do |format|
@@ -44,6 +45,7 @@ class GroupsController &lt; ApplicationController @@ -44,6 +45,7 @@ class GroupsController &lt; ApplicationController
44 @projects = result[:projects] 45 @projects = result[:projects]
45 @merge_requests = result[:merge_requests] 46 @merge_requests = result[:merge_requests]
46 @issues = result[:issues] 47 @issues = result[:issues]
  48 + @wiki_pages = result[:wiki_pages]
47 end 49 end
48 50
49 def people 51 def people
@@ -53,9 +55,16 @@ class GroupsController &lt; ApplicationController @@ -53,9 +55,16 @@ class GroupsController &lt; ApplicationController
53 55
54 if @project 56 if @project
55 @team_member = @project.users_projects.new 57 @team_member = @project.users_projects.new
  58 + else
  59 + @team_member = UsersProject.new
56 end 60 end
57 end 61 end
58 62
  63 + def team_members
  64 + @group.add_users_to_project_teams(params[:user_ids], params[:project_access])
  65 + redirect_to people_group_path(@group), notice: 'Users was successfully added.'
  66 + end
  67 +
59 protected 68 protected
60 69
61 def group 70 def group
@@ -63,7 +72,7 @@ class GroupsController &lt; ApplicationController @@ -63,7 +72,7 @@ class GroupsController &lt; ApplicationController
63 end 72 end
64 73
65 def projects 74 def projects
66 - @projects ||= group.projects.authorized_for(current_user).sorted_by_activity 75 + @projects ||= current_user.authorized_projects.where(namespace_id: group.id).sorted_by_activity
67 end 76 end
68 77
69 def project_ids 78 def project_ids
app/controllers/merge_requests_controller.rb
@@ -74,6 +74,8 @@ class MergeRequestsController &lt; ProjectResourceController @@ -74,6 +74,8 @@ class MergeRequestsController &lt; ProjectResourceController
74 @merge_request.check_if_can_be_merged 74 @merge_request.check_if_can_be_merged
75 end 75 end
76 render json: {state: @merge_request.human_state} 76 render json: {state: @merge_request.human_state}
  77 + rescue Gitlab::SatelliteNotExistError
  78 + render json: {state: :no_satellite}
77 end 79 end
78 80
79 def automerge 81 def automerge
@@ -88,12 +90,12 @@ class MergeRequestsController &lt; ProjectResourceController @@ -88,12 +90,12 @@ class MergeRequestsController &lt; ProjectResourceController
88 end 90 end
89 91
90 def branch_from 92 def branch_from
91 - @commit = project.commit(params[:ref]) 93 + @commit = @repository.commit(params[:ref])
92 @commit = CommitDecorator.decorate(@commit) 94 @commit = CommitDecorator.decorate(@commit)
93 end 95 end
94 96
95 def branch_to 97 def branch_to
96 - @commit = project.commit(params[:ref]) 98 + @commit = @repository.commit(params[:ref])
97 @commit = CommitDecorator.decorate(@commit) 99 @commit = CommitDecorator.decorate(@commit)
98 end 100 end
99 101
app/controllers/project_resource_controller.rb
1 class ProjectResourceController < ApplicationController 1 class ProjectResourceController < ApplicationController
2 before_filter :project 2 before_filter :project
  3 + before_filter :repository
3 end 4 end
app/controllers/projects_controller.rb
@@ -2,6 +2,7 @@ require Rails.root.join(&#39;lib&#39;, &#39;gitlab&#39;, &#39;graph&#39;, &#39;json_builder&#39;) @@ -2,6 +2,7 @@ require Rails.root.join(&#39;lib&#39;, &#39;gitlab&#39;, &#39;graph&#39;, &#39;json_builder&#39;)
2 2
3 class ProjectsController < ProjectResourceController 3 class ProjectsController < ProjectResourceController
4 skip_before_filter :project, only: [:new, :create] 4 skip_before_filter :project, only: [:new, :create]
  5 + skip_before_filter :repository, only: [:new, :create]
5 6
6 # Authorize 7 # Authorize
7 before_filter :authorize_read_project!, except: [:index, :new, :create] 8 before_filter :authorize_read_project!, except: [:index, :new, :create]
@@ -58,7 +59,7 @@ class ProjectsController &lt; ProjectResourceController @@ -58,7 +59,7 @@ class ProjectsController &lt; ProjectResourceController
58 59
59 respond_to do |format| 60 respond_to do |format|
60 format.html do 61 format.html do
61 - unless @project.empty_repo? 62 + if @project.repository && !@project.repository.empty?
62 @last_push = current_user.recent_push(@project.id) 63 @last_push = current_user.recent_push(@project.id)
63 render :show 64 render :show
64 else 65 else
@@ -102,11 +103,10 @@ class ProjectsController &lt; ProjectResourceController @@ -102,11 +103,10 @@ class ProjectsController &lt; ProjectResourceController
102 def destroy 103 def destroy
103 return access_denied! unless can?(current_user, :remove_project, project) 104 return access_denied! unless can?(current_user, :remove_project, project)
104 105
105 - # Disable the UsersProject update_repository call, otherwise it will be  
106 - # called once for every person removed from the project  
107 - UsersProject.skip_callback(:destroy, :after, :update_repository) 106 + # Delete team first in order to prevent multiple gitolite calls
  107 + project.team.truncate
  108 +
108 project.destroy 109 project.destroy
109 - UsersProject.set_callback(:destroy, :after, :update_repository)  
110 110
111 respond_to do |format| 111 respond_to do |format|
112 format.html { redirect_to root_path } 112 format.html { redirect_to root_path }
app/controllers/refs_controller.rb
@@ -12,7 +12,7 @@ class RefsController &lt; ProjectResourceController @@ -12,7 +12,7 @@ class RefsController &lt; ProjectResourceController
12 respond_to do |format| 12 respond_to do |format|
13 format.html do 13 format.html do
14 new_path = if params[:destination] == "tree" 14 new_path = if params[:destination] == "tree"
15 - project_tree_path(@project, @ref) 15 + project_tree_path(@project, (@ref + "/" + params[:path]))
16 else 16 else
17 project_commits_path(@project, @ref) 17 project_commits_path(@project, @ref)
18 end 18 end
@@ -31,7 +31,7 @@ class RefsController &lt; ProjectResourceController @@ -31,7 +31,7 @@ class RefsController &lt; ProjectResourceController
31 contents = @tree.contents 31 contents = @tree.contents
32 @logs = contents.map do |content| 32 @logs = contents.map do |content|
33 file = params[:path] ? File.join(params[:path], content.name) : content.name 33 file = params[:path] ? File.join(params[:path], content.name) : content.name
34 - last_commit = @project.commits(@commit.id, file, 1).last 34 + last_commit = @repo.commits(@commit.id, file, 1).last
35 last_commit = CommitDecorator.decorate(last_commit) 35 last_commit = CommitDecorator.decorate(last_commit)
36 { 36 {
37 file_name: content.name, 37 file_name: content.name,
@@ -45,10 +45,10 @@ class RefsController &lt; ProjectResourceController @@ -45,10 +45,10 @@ class RefsController &lt; ProjectResourceController
45 def define_tree_vars 45 def define_tree_vars
46 params[:path] = nil if params[:path].blank? 46 params[:path] = nil if params[:path].blank?
47 47
48 - @repo = project.repo  
49 - @commit = project.commit(@ref) 48 + @repo = project.repository
  49 + @commit = @repo.commit(@ref)
50 @commit = CommitDecorator.decorate(@commit) 50 @commit = CommitDecorator.decorate(@commit)
51 - @tree = Tree.new(@commit.tree, project, @ref, params[:path]) 51 + @tree = Tree.new(@commit.tree, @ref, params[:path])
52 @tree = TreeDecorator.new(@tree) 52 @tree = TreeDecorator.new(@tree)
53 @hex_path = Digest::SHA1.hexdigest(params[:path] || "") 53 @hex_path = Digest::SHA1.hexdigest(params[:path] || "")
54 54
app/controllers/repositories_controller.rb
@@ -5,19 +5,19 @@ class RepositoriesController &lt; ProjectResourceController @@ -5,19 +5,19 @@ class RepositoriesController &lt; ProjectResourceController
5 before_filter :require_non_empty_project 5 before_filter :require_non_empty_project
6 6
7 def show 7 def show
8 - @activities = @project.commits_with_refs(20) 8 + @activities = @repository.commits_with_refs(20)
9 end 9 end
10 10
11 def branches 11 def branches
12 - @branches = @project.branches 12 + @branches = @repository.branches
13 end 13 end
14 14
15 def tags 15 def tags
16 - @tags = @project.tags 16 + @tags = @repository.tags
17 end 17 end
18 18
19 def stats 19 def stats
20 - @stats = Gitlab::GitStats.new(@project.repo, @project.root_ref) 20 + @stats = Gitlab::GitStats.new(@repository.raw, @repository.root_ref)
21 @graph = @stats.graph 21 @graph = @stats.graph
22 end 22 end
23 23
@@ -27,7 +27,7 @@ class RepositoriesController &lt; ProjectResourceController @@ -27,7 +27,7 @@ class RepositoriesController &lt; ProjectResourceController
27 end 27 end
28 28
29 29
30 - file_path = @project.archive_repo(params[:ref]) 30 + file_path = @repository.archive_repo(params[:ref])
31 31
32 if file_path 32 if file_path
33 # Send file to user 33 # Send file to user
app/controllers/search_controller.rb
1 class SearchController < ApplicationController 1 class SearchController < ApplicationController
2 def show 2 def show
3 - result = SearchContext.new(current_user.project_ids, params).execute 3 + result = SearchContext.new(current_user.authorized_projects.map(&:id), params).execute
4 4
5 @projects = result[:projects] 5 @projects = result[:projects]
6 @merge_requests = result[:merge_requests] 6 @merge_requests = result[:merge_requests]
app/controllers/services_controller.rb
@@ -26,7 +26,7 @@ class ServicesController &lt; ProjectResourceController @@ -26,7 +26,7 @@ class ServicesController &lt; ProjectResourceController
26 end 26 end
27 27
28 def test 28 def test
29 - commits = project.commits(project.default_branch, nil, 3) 29 + commits = project.repository.commits(project.default_branch, nil, 3)
30 data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) 30 data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user)
31 31
32 @service = project.gitlab_ci_service 32 @service = project.gitlab_ci_service
app/controllers/snippets_controller.rb
@@ -16,7 +16,7 @@ class SnippetsController &lt; ProjectResourceController @@ -16,7 +16,7 @@ class SnippetsController &lt; ProjectResourceController
16 respond_to :html 16 respond_to :html
17 17
18 def index 18 def index
19 - @snippets = @project.snippets.fresh 19 + @snippets = @project.snippets.fresh.non_expired
20 end 20 end
21 21
22 def new 22 def new
app/controllers/team_members_controller.rb
@@ -16,10 +16,9 @@ class TeamMembersController &lt; ProjectResourceController @@ -16,10 +16,9 @@ class TeamMembersController &lt; ProjectResourceController
16 end 16 end
17 17
18 def create 18 def create
19 - @project.add_users_ids_to_team(  
20 - params[:user_ids],  
21 - params[:project_access]  
22 - ) 19 + users = User.where(id: params[:user_ids])
  20 +
  21 + @project.team << [users, params[:project_access]]
23 22
24 if params[:redirect_to] 23 if params[:redirect_to]
25 redirect_to params[:redirect_to] 24 redirect_to params[:redirect_to]
@@ -50,7 +49,7 @@ class TeamMembersController &lt; ProjectResourceController @@ -50,7 +49,7 @@ class TeamMembersController &lt; ProjectResourceController
50 49
51 def apply_import 50 def apply_import
52 giver = Project.find(params[:source_project_id]) 51 giver = Project.find(params[:source_project_id])
53 - status = UsersProject.import_team(giver, project) 52 + status = @project.team.import(giver)
54 notice = status ? "Succesfully imported" : "Import failed" 53 notice = status ? "Succesfully imported" : "Import failed"
55 54
56 redirect_to project_team_members_path(project), notice: notice 55 redirect_to project_team_members_path(project), notice: notice
app/controllers/tree_controller.rb
@@ -22,7 +22,7 @@ class TreeController &lt; ProjectResourceController @@ -22,7 +22,7 @@ class TreeController &lt; ProjectResourceController
22 end 22 end
23 23
24 def edit 24 def edit
25 - @last_commit = @project.last_commit_for(@ref, @path).sha 25 + @last_commit = @project.repository.last_commit_for(@ref, @path).sha
26 end 26 end
27 27
28 def update 28 def update
app/decorators/tree_decorator.rb
@@ -6,16 +6,14 @@ class TreeDecorator &lt; ApplicationDecorator @@ -6,16 +6,14 @@ class TreeDecorator &lt; ApplicationDecorator
6 part_path = "" 6 part_path = ""
7 parts = path.split("\/") 7 parts = path.split("\/")
8 8
9 - #parts = parts[0...-1] if is_blob?  
10 -  
11 - yield(h.link_to("..", "#")) if parts.count > max_links 9 + yield('..', nil) if parts.count > max_links
12 10
13 parts.each do |part| 11 parts.each do |part|
14 part_path = File.join(part_path, part) unless part_path.empty? 12 part_path = File.join(part_path, part) unless part_path.empty?
15 part_path = part if part_path.empty? 13 part_path = part if part_path.empty?
16 14
17 next unless parts.last(2).include?(part) if parts.count > max_links 15 next unless parts.last(2).include?(part) if parts.count > max_links
18 - yield(h.link_to(h.truncate(part, length: 40), h.project_tree_path(project, h.tree_join(ref, part_path)))) 16 + yield(part, h.tree_join(ref, part_path))
19 end 17 end
20 end 18 end
21 end 19 end
@@ -26,7 +24,7 @@ class TreeDecorator &lt; ApplicationDecorator @@ -26,7 +24,7 @@ class TreeDecorator &lt; ApplicationDecorator
26 24
27 def up_dir_path 25 def up_dir_path
28 file = File.join(path, "..") 26 file = File.join(path, "..")
29 - h.project_tree_path(project, h.tree_join(ref, file)) 27 + h.tree_join(ref, file)
30 end 28 end
31 29
32 def readme 30 def readme
app/helpers/application_helper.rb
@@ -53,7 +53,7 @@ module ApplicationHelper @@ -53,7 +53,7 @@ module ApplicationHelper
53 53
54 def last_commit(project) 54 def last_commit(project)
55 if project.repo_exists? 55 if project.repo_exists?
56 - time_ago_in_words(project.commit.committed_date) + " ago" 56 + time_ago_in_words(project.repository.commit.committed_date) + " ago"
57 else 57 else
58 "Never" 58 "Never"
59 end 59 end
@@ -62,9 +62,11 @@ module ApplicationHelper @@ -62,9 +62,11 @@ module ApplicationHelper
62 end 62 end
63 63
64 def grouped_options_refs(destination = :tree) 64 def grouped_options_refs(destination = :tree)
  65 + repository = @project.repository
  66 +
65 options = [ 67 options = [
66 - ["Branch", @project.branch_names ],  
67 - [ "Tag", @project.tag_names ] 68 + ["Branch", repository.branch_names ],
  69 + [ "Tag", repository.tag_names ]
68 ] 70 ]
69 71
70 # If reference is commit id - 72 # If reference is commit id -
@@ -78,7 +80,8 @@ module ApplicationHelper @@ -78,7 +80,8 @@ module ApplicationHelper
78 end 80 end
79 81
80 def search_autocomplete_source 82 def search_autocomplete_source
81 - projects = current_user.projects.map{ |p| { label: p.name_with_namespace, url: project_path(p) } } 83 + projects = current_user.authorized_projects.map { |p| { label: p.name_with_namespace, url: project_path(p) } }
  84 + groups = current_user.authorized_groups.map { |group| { label: "<group> #{group.name}", url: group_path(group) } }
82 85
83 default_nav = [ 86 default_nav = [
84 { label: "My Profile", url: profile_path }, 87 { label: "My Profile", url: profile_path },
@@ -99,21 +102,21 @@ module ApplicationHelper @@ -99,21 +102,21 @@ module ApplicationHelper
99 ] 102 ]
100 103
101 project_nav = [] 104 project_nav = []
102 - if @project && !@project.new_record? 105 + if @project && @project.repository && @project.repository.root_ref
103 project_nav = [ 106 project_nav = [
104 { label: "#{@project.name} Issues", url: project_issues_path(@project) }, 107 { label: "#{@project.name} Issues", url: project_issues_path(@project) },
105 - { label: "#{@project.name} Commits", url: project_commits_path(@project, @ref || @project.root_ref) }, 108 + { label: "#{@project.name} Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) },
106 { label: "#{@project.name} Merge Requests", url: project_merge_requests_path(@project) }, 109 { label: "#{@project.name} Merge Requests", url: project_merge_requests_path(@project) },
107 { label: "#{@project.name} Milestones", url: project_milestones_path(@project) }, 110 { label: "#{@project.name} Milestones", url: project_milestones_path(@project) },
108 { label: "#{@project.name} Snippets", url: project_snippets_path(@project) }, 111 { label: "#{@project.name} Snippets", url: project_snippets_path(@project) },
109 { label: "#{@project.name} Team", url: project_team_index_path(@project) }, 112 { label: "#{@project.name} Team", url: project_team_index_path(@project) },
110 - { label: "#{@project.name} Tree", url: project_tree_path(@project, @ref || @project.root_ref) }, 113 + { label: "#{@project.name} Tree", url: project_tree_path(@project, @ref || @project.repository.root_ref) },
111 { label: "#{@project.name} Wall", url: wall_project_path(@project) }, 114 { label: "#{@project.name} Wall", url: wall_project_path(@project) },
112 { label: "#{@project.name} Wiki", url: project_wikis_path(@project) }, 115 { label: "#{@project.name} Wiki", url: project_wikis_path(@project) },
113 ] 116 ]
114 end 117 end
115 118
116 - [projects, default_nav, project_nav, help_nav].flatten.to_json 119 + [groups, projects, default_nav, project_nav, help_nav].flatten.to_json
117 end 120 end
118 121
119 def emoji_autocomplete_source 122 def emoji_autocomplete_source
@@ -139,6 +142,7 @@ module ApplicationHelper @@ -139,6 +142,7 @@ module ApplicationHelper
139 event.last_push_to_non_root? && 142 event.last_push_to_non_root? &&
140 !event.rm_ref? && 143 !event.rm_ref? &&
141 event.project && 144 event.project &&
  145 + event.project.repository &&
142 event.project.merge_requests_enabled 146 event.project.merge_requests_enabled
143 end 147 end
144 148
app/helpers/commits_helper.rb
@@ -70,4 +70,12 @@ module CommitsHelper @@ -70,4 +70,12 @@ module CommitsHelper
70 escape_javascript(render 'commits/commit', commit: commit) 70 escape_javascript(render 'commits/commit', commit: commit)
71 end 71 end
72 end 72 end
  73 +
  74 + def diff_line_content(line)
  75 + if line.blank?
  76 + " &nbsp;"
  77 + else
  78 + line
  79 + end
  80 + end
73 end 81 end
app/helpers/events_helper.rb
@@ -20,25 +20,8 @@ module EventsHelper @@ -20,25 +20,8 @@ module EventsHelper
20 [event.action_name, target].join(" ") 20 [event.action_name, target].join(" ")
21 end 21 end
22 22
23 - def event_image event  
24 - event_image_path = if event.push?  
25 - "event_push.png"  
26 - elsif event.merged?  
27 - "event_mr_merged.png"  
28 - end  
29 -  
30 - return nil unless event_image_path  
31 -  
32 - content_tag :div, class: 'event_icon' do  
33 - image_tag event_image_path  
34 - end  
35 - end  
36 -  
37 def event_filter_link key, tooltip 23 def event_filter_link key, tooltip
38 key = key.to_s 24 key = key.to_s
39 -  
40 - filter = @event_filter.options key  
41 -  
42 inactive = if @event_filter.active? key 25 inactive = if @event_filter.active? key
43 nil 26 nil
44 else 27 else
@@ -46,7 +29,7 @@ module EventsHelper @@ -46,7 +29,7 @@ module EventsHelper
46 end 29 end
47 30
48 content_tag :div, class: "filter_icon #{inactive}" do 31 content_tag :div, class: "filter_icon #{inactive}" do
49 - link_to dashboard_path(event_filter: filter), class: 'has_tooltip', 'data-original-title' => tooltip do 32 + link_to dashboard_path, class: 'has_tooltip event_filter_link', id: "#{key}_event_filter", 'data-original-title' => tooltip do
50 image_tag "event_filter_#{key}.png" 33 image_tag "event_filter_#{key}.png"
51 end 34 end
52 end 35 end
app/helpers/groups_helper.rb 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +module GroupsHelper
  2 + def group_filter_path(entity, options={})
  3 + exist_opts = {
  4 + status: params[:status],
  5 + project_id: params[:project_id],
  6 + }
  7 +
  8 + options = exist_opts.merge(options)
  9 +
  10 + case entity
  11 + when 'issue' then
  12 + issues_group_path(@group, options)
  13 + when 'merge_request'
  14 + merge_requests_group_path(@group, options)
  15 + end
  16 + end
  17 +end
app/helpers/merge_requests_helper.rb
@@ -4,7 +4,7 @@ module MergeRequestsHelper @@ -4,7 +4,7 @@ module MergeRequestsHelper
4 event.project, 4 event.project,
5 merge_request: { 5 merge_request: {
6 source_branch: event.branch_name, 6 source_branch: event.branch_name,
7 - target_branch: event.project.root_ref, 7 + target_branch: event.project.repository.root_ref,
8 title: event.branch_name.titleize 8 title: event.branch_name.titleize
9 } 9 }
10 ) 10 )
app/helpers/namespaces_helper.rb
1 module NamespacesHelper 1 module NamespacesHelper
2 def namespaces_options(selected = :current_user, scope = :default) 2 def namespaces_options(selected = :current_user, scope = :default)
3 - groups = current_user.namespaces.select {|n| n.type == 'Group'} 3 + groups = current_user.owned_groups.select {|n| n.type == 'Group'}
4 4
5 users = if scope == :all 5 users = if scope == :all
6 Namespace.root 6 Namespace.root
app/mailers/notify.rb
1 class Notify < ActionMailer::Base 1 class Notify < ActionMailer::Base
2 - include Resque::Mailer 2 +
3 add_template_helper ApplicationHelper 3 add_template_helper ApplicationHelper
4 add_template_helper GitlabMarkdownHelper 4 add_template_helper GitlabMarkdownHelper
5 5
6 default_url_options[:host] = Gitlab.config.gitlab.host 6 default_url_options[:host] = Gitlab.config.gitlab.host
7 default_url_options[:protocol] = Gitlab.config.gitlab.protocol 7 default_url_options[:protocol] = Gitlab.config.gitlab.protocol
8 default_url_options[:port] = Gitlab.config.gitlab.port if Gitlab.config.gitlab_on_non_standard_port? 8 default_url_options[:port] = Gitlab.config.gitlab.port if Gitlab.config.gitlab_on_non_standard_port?
  9 + default_url_options[:script_name] = Gitlab.config.gitlab.relative_url_root
9 10
10 default from: Gitlab.config.gitlab.email_from 11 default from: Gitlab.config.gitlab.email_from
11 12
@@ -87,7 +88,7 @@ class Notify &lt; ActionMailer::Base @@ -87,7 +88,7 @@ class Notify &lt; ActionMailer::Base
87 def note_wall_email(recipient_id, note_id) 88 def note_wall_email(recipient_id, note_id)
88 @note = Note.find(note_id) 89 @note = Note.find(note_id)
89 @project = @note.project 90 @project = @note.project
90 - mail(to: recipient(recipient_id), subject: subject) 91 + mail(to: recipient(recipient_id), subject: subject("note on wall"))
91 end 92 end
92 93
93 94
@@ -147,12 +148,15 @@ class Notify &lt; ActionMailer::Base @@ -147,12 +148,15 @@ class Notify &lt; ActionMailer::Base
147 # >> @project = Project.last 148 # >> @project = Project.last
148 # => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...> 149 # => #<Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...>
149 # >> subject('Lorem ipsum') 150 # >> subject('Lorem ipsum')
150 - # => "GitLab | Lorem ipsum | Ruby on Rails" 151 + # => "GitLab | Ruby on Rails | Lorem ipsum "
151 # 152 #
152 # # Accepts multiple arguments 153 # # Accepts multiple arguments
153 # >> subject('Lorem ipsum', 'Dolor sit amet') 154 # >> subject('Lorem ipsum', 'Dolor sit amet')
154 # => "GitLab | Lorem ipsum | Dolor sit amet" 155 # => "GitLab | Lorem ipsum | Dolor sit amet"
155 def subject(*extra) 156 def subject(*extra)
156 - "GitLab | " << extra.join(' | ') << (@project ? " | #{@project.name}" : "") 157 + subject = "GitLab"
  158 + subject << (@project ? " | #{@project.name_with_namespace}" : "")
  159 + subject << " | " + extra.join(' | ') if extra.present?
  160 + subject
157 end 161 end
158 end 162 end
app/models/ability.rb
@@ -15,35 +15,26 @@ class Ability @@ -15,35 +15,26 @@ class Ability
15 def project_abilities(user, project) 15 def project_abilities(user, project)
16 rules = [] 16 rules = []
17 17
  18 + team = project.team
  19 +
18 # Rules based on role in project 20 # Rules based on role in project
19 - if project.master_access_for?(user) 21 + if team.masters.include?(user)
20 rules << project_master_rules 22 rules << project_master_rules
21 23
22 - elsif project.dev_access_for?(user) 24 + elsif team.developers.include?(user)
23 rules << project_dev_rules 25 rules << project_dev_rules
24 26
25 - elsif project.report_access_for?(user) 27 + elsif team.reporters.include?(user)
26 rules << project_report_rules 28 rules << project_report_rules
27 29
28 - elsif project.guest_access_for?(user) 30 + elsif team.guests.include?(user)
29 rules << project_guest_rules 31 rules << project_guest_rules
30 end 32 end
31 33
32 - if project.namespace  
33 - # If user own project namespace  
34 - # (Ex. group owner or account owner)  
35 - if project.namespace.owner == user  
36 - rules << project_admin_rules  
37 - end  
38 - else  
39 - # For compatibility with global projects  
40 - # use projects.owner_id  
41 - if project.owner == user  
42 - rules << project_admin_rules  
43 - end 34 + if project.owner == user
  35 + rules << project_admin_rules
44 end 36 end
45 37
46 -  
47 rules.flatten 38 rules.flatten
48 end 39 end
49 40
@@ -107,9 +98,12 @@ class Ability @@ -107,9 +98,12 @@ class Ability
107 def group_abilities user, group 98 def group_abilities user, group
108 rules = [] 99 rules = []
109 100
110 - rules << [  
111 - :manage_group  
112 - ] if group.owner == user 101 + # Only group owner and administrators can manage group
  102 + if group.owner == user || user.admin?
  103 + rules << [
  104 + :manage_group
  105 + ]
  106 + end
113 107
114 rules.flatten 108 rules.flatten
115 end 109 end
app/models/commit.rb
@@ -11,7 +11,7 @@ class Commit @@ -11,7 +11,7 @@ class Commit
11 attr_accessor :commit, :head, :refs 11 attr_accessor :commit, :head, :refs
12 12
13 delegate :message, :authored_date, :committed_date, :parents, :sha, 13 delegate :message, :authored_date, :committed_date, :parents, :sha,
14 - :date, :committer, :author, :message, :diffs, :tree, :id, 14 + :date, :committer, :author, :diffs, :tree, :id, :stats,
15 :to_patch, to: :commit 15 :to_patch, to: :commit
16 16
17 class << self 17 class << self
@@ -83,8 +83,8 @@ class Commit @@ -83,8 +83,8 @@ class Commit
83 83
84 return result unless from && to 84 return result unless from && to
85 85
86 - first = project.commit(to.try(:strip))  
87 - last = project.commit(from.try(:strip)) 86 + first = project.repository.commit(to.try(:strip))
  87 + last = project.repository.commit(from.try(:strip))
88 88
89 if first && last 89 if first && last
90 result[:same] = (first.id == last.id) 90 result[:same] = (first.id == last.id)
@@ -98,6 +98,8 @@ class Commit @@ -98,6 +98,8 @@ class Commit
98 end 98 end
99 99
100 def initialize(raw_commit, head = nil) 100 def initialize(raw_commit, head = nil)
  101 + raise "Nil as raw commit passed" unless raw_commit
  102 +
101 @commit = raw_commit 103 @commit = raw_commit
102 @head = head 104 @head = head
103 end 105 end
@@ -136,17 +138,17 @@ class Commit @@ -136,17 +138,17 @@ class Commit
136 end 138 end
137 139
138 def prev_commit 140 def prev_commit
139 - parents.try :first 141 + @prev_commit ||= if parents.present?
  142 + Commit.new(parents.first)
  143 + else
  144 + nil
  145 + end
140 end 146 end
141 147
142 def prev_commit_id 148 def prev_commit_id
143 prev_commit.try :id 149 prev_commit.try :id
144 end 150 end
145 151
146 - def parents_count  
147 - parents && parents.count || 0  
148 - end  
149 -  
150 # Shows the diff between the commit's parent and the commit. 152 # Shows the diff between the commit's parent and the commit.
151 # 153 #
152 # Cuts out the header and stats from #to_patch and returns only the diff. 154 # Cuts out the header and stats from #to_patch and returns only the diff.
app/models/concerns/issuable.rb 0 → 100644
@@ -0,0 +1,106 @@ @@ -0,0 +1,106 @@
  1 +# == Issuable concern
  2 +#
  3 +# Contains common functionality shared between Issues and MergeRequests
  4 +#
  5 +# Used by Issue, MergeRequest
  6 +#
  7 +module Issuable
  8 + extend ActiveSupport::Concern
  9 +
  10 + included do
  11 + belongs_to :project
  12 + belongs_to :author, class_name: "User"
  13 + belongs_to :assignee, class_name: "User"
  14 + belongs_to :milestone
  15 + has_many :notes, as: :noteable, dependent: :destroy
  16 +
  17 + validates :project, presence: true
  18 + validates :author, presence: true
  19 + validates :title, presence: true, length: { within: 0..255 }
  20 + validates :closed, inclusion: { in: [true, false] }
  21 +
  22 + scope :opened, where(closed: false)
  23 + scope :closed, where(closed: true)
  24 + scope :of_group, ->(group) { where(project_id: group.project_ids) }
  25 + scope :assigned, ->(u) { where(assignee_id: u.id)}
  26 + scope :recent, order("created_at DESC")
  27 +
  28 + delegate :name,
  29 + :email,
  30 + to: :author,
  31 + prefix: true
  32 +
  33 + delegate :name,
  34 + :email,
  35 + to: :assignee,
  36 + allow_nil: true,
  37 + prefix: true
  38 +
  39 + attr_accessor :author_id_of_changes
  40 + end
  41 +
  42 + module ClassMethods
  43 + def search(query)
  44 + where("title like :query", query: "%#{query}%")
  45 + end
  46 + end
  47 +
  48 + def today?
  49 + Date.today == created_at.to_date
  50 + end
  51 +
  52 + def new?
  53 + today? && created_at == updated_at
  54 + end
  55 +
  56 + def is_assigned?
  57 + !!assignee_id
  58 + end
  59 +
  60 + def is_being_reassigned?
  61 + assignee_id_changed?
  62 + end
  63 +
  64 + def is_being_closed?
  65 + closed_changed? && closed
  66 + end
  67 +
  68 + def is_being_reopened?
  69 + closed_changed? && !closed
  70 + end
  71 +
  72 + #
  73 + # Votes
  74 + #
  75 +
  76 + # Return the number of -1 comments (downvotes)
  77 + def downvotes
  78 + notes.select(&:downvote?).size
  79 + end
  80 +
  81 + def downvotes_in_percent
  82 + if votes_count.zero?
  83 + 0
  84 + else
  85 + 100.0 - upvotes_in_percent
  86 + end
  87 + end
  88 +
  89 + # Return the number of +1 comments (upvotes)
  90 + def upvotes
  91 + notes.select(&:upvote?).size
  92 + end
  93 +
  94 + def upvotes_in_percent
  95 + if votes_count.zero?
  96 + 0
  97 + else
  98 + 100.0 / votes_count * upvotes
  99 + end
  100 + end
  101 +
  102 + # Return the total number of votes
  103 + def votes_count
  104 + upvotes + downvotes
  105 + end
  106 +end
app/models/event.rb
@@ -15,9 +15,6 @@ @@ -15,9 +15,6 @@
15 # 15 #
16 16
17 class Event < ActiveRecord::Base 17 class Event < ActiveRecord::Base
18 - include NoteEvent  
19 - include PushEvent  
20 -  
21 attr_accessible :project, :action, :data, :author_id, :project_id, 18 attr_accessible :project, :action, :data, :author_id, :project_id,
22 :target_id, :target_type 19 :target_id, :target_type
23 20
@@ -113,26 +110,6 @@ class Event &lt; ActiveRecord::Base @@ -113,26 +110,6 @@ class Event &lt; ActiveRecord::Base
113 target_type == "MergeRequest" 110 target_type == "MergeRequest"
114 end 111 end
115 112
116 - def new_issue?  
117 - target_type == "Issue" &&  
118 - action == Created  
119 - end  
120 -  
121 - def new_merge_request?  
122 - target_type == "MergeRequest" &&  
123 - action == Created  
124 - end  
125 -  
126 - def changed_merge_request?  
127 - target_type == "MergeRequest" &&  
128 - [Closed, Reopened].include?(action)  
129 - end  
130 -  
131 - def changed_issue?  
132 - target_type == "Issue" &&  
133 - [Closed, Reopened].include?(action)  
134 - end  
135 -  
136 def joined? 113 def joined?
137 action == Joined 114 action == Joined
138 end 115 end
@@ -170,4 +147,143 @@ class Event &lt; ActiveRecord::Base @@ -170,4 +147,143 @@ class Event &lt; ActiveRecord::Base
170 "opened" 147 "opened"
171 end 148 end
172 end 149 end
  150 +
  151 + def valid_push?
  152 + data[:ref]
  153 + rescue => ex
  154 + false
  155 + end
  156 +
  157 + def tag?
  158 + data[:ref]["refs/tags"]
  159 + end
  160 +
  161 + def branch?
  162 + data[:ref]["refs/heads"]
  163 + end
  164 +
  165 + def new_branch?
  166 + commit_from =~ /^00000/
  167 + end
  168 +
  169 + def new_ref?
  170 + commit_from =~ /^00000/
  171 + end
  172 +
  173 + def rm_ref?
  174 + commit_to =~ /^00000/
  175 + end
  176 +
  177 + def md_ref?
  178 + !(rm_ref? || new_ref?)
  179 + end
  180 +
  181 + def commit_from
  182 + data[:before]
  183 + end
  184 +
  185 + def commit_to
  186 + data[:after]
  187 + end
  188 +
  189 + def ref_name
  190 + if tag?
  191 + tag_name
  192 + else
  193 + branch_name
  194 + end
  195 + end
  196 +
  197 + def branch_name
  198 + @branch_name ||= data[:ref].gsub("refs/heads/", "")
  199 + end
  200 +
  201 + def tag_name
  202 + @tag_name ||= data[:ref].gsub("refs/tags/", "")
  203 + end
  204 +
  205 + # Max 20 commits from push DESC
  206 + def commits
  207 + @commits ||= data[:commits].map { |commit| repository.commit(commit[:id]) }.reverse
  208 + end
  209 +
  210 + def commits_count
  211 + data[:total_commits_count] || commits.count || 0
  212 + end
  213 +
  214 + def ref_type
  215 + tag? ? "tag" : "branch"
  216 + end
  217 +
  218 + def push_action_name
  219 + if new_ref?
  220 + "pushed new"
  221 + elsif rm_ref?
  222 + "deleted"
  223 + else
  224 + "pushed to"
  225 + end
  226 + end
  227 +
  228 + def repository
  229 + project.repository
  230 + end
  231 +
  232 + def parent_commit
  233 + repository.commit(commit_from)
  234 + rescue => ex
  235 + nil
  236 + end
  237 +
  238 + def last_commit
  239 + repository.commit(commit_to)
  240 + rescue => ex
  241 + nil
  242 + end
  243 +
  244 + def push_with_commits?
  245 + md_ref? && commits.any? && parent_commit && last_commit
  246 + rescue Grit::NoSuchPathError
  247 + false
  248 + end
  249 +
  250 + def last_push_to_non_root?
  251 + branch? && project.default_branch != branch_name
  252 + end
  253 +
  254 + def note_commit_id
  255 + target.commit_id
  256 + end
  257 +
  258 + def note_short_commit_id
  259 + note_commit_id[0..8]
  260 + end
  261 +
  262 + def note_commit?
  263 + target.noteable_type == "Commit"
  264 + end
  265 +
  266 + def note_target
  267 + target.noteable
  268 + end
  269 +
  270 + def note_target_id
  271 + if note_commit?
  272 + target.commit_id
  273 + else
  274 + target.noteable_id.to_s
  275 + end
  276 + end
  277 +
  278 + def wall_note?
  279 + target.noteable_type.blank?
  280 + end
  281 +
  282 + def note_target_type
  283 + if target.noteable_type.present?
  284 + target.noteable_type.titleize
  285 + else
  286 + "Wall"
  287 + end.downcase
  288 + end
173 end 289 end
app/models/gitlab_ci_service.rb
@@ -23,20 +23,12 @@ class GitlabCiService &lt; Service @@ -23,20 +23,12 @@ class GitlabCiService &lt; Service
23 23
24 after_save :compose_service_hook, if: :activated? 24 after_save :compose_service_hook, if: :activated?
25 25
26 - def activated?  
27 - active  
28 - end  
29 -  
30 def compose_service_hook 26 def compose_service_hook
31 hook = service_hook || build_service_hook 27 hook = service_hook || build_service_hook
32 hook.url = [project_url, "/build", "?token=#{token}"].join("") 28 hook.url = [project_url, "/build", "?token=#{token}"].join("")
33 hook.save 29 hook.save
34 end 30 end
35 31
36 - def commit_badge_path sha  
37 - project_url + "/status?sha=#{sha}"  
38 - end  
39 -  
40 def commit_status_path sha 32 def commit_status_path sha
41 project_url + "/builds/#{sha}/status.json?token=#{token}" 33 project_url + "/builds/#{sha}/status.json?token=#{token}"
42 end 34 end
app/models/group.rb
@@ -12,6 +12,14 @@ @@ -12,6 +12,14 @@
12 # 12 #
13 13
14 class Group < Namespace 14 class Group < Namespace
  15 + def add_users_to_project_teams(user_ids, project_access)
  16 + UsersProject.add_users_into_projects(
  17 + projects.map(&:id),
  18 + user_ids,
  19 + project_access
  20 + )
  21 + end
  22 +
15 def users 23 def users
16 users = User.joins(:users_projects).where(users_projects: {project_id: project_ids}) 24 users = User.joins(:users_projects).where(users_projects: {project_id: project_ids})
17 users = users << owner 25 users = users << owner
@@ -21,4 +29,8 @@ class Group &lt; Namespace @@ -21,4 +29,8 @@ class Group &lt; Namespace
21 def human_name 29 def human_name
22 name 30 name
23 end 31 end
  32 +
  33 + def truncate_teams
  34 + UsersProject.truncate_teams(project_ids)
  35 + end
24 end 36 end
app/models/issue.rb
@@ -17,8 +17,7 @@ @@ -17,8 +17,7 @@
17 # 17 #
18 18
19 class Issue < ActiveRecord::Base 19 class Issue < ActiveRecord::Base
20 - include IssueCommonality  
21 - include Votes 20 + include Issuable
22 21
23 attr_accessible :title, :assignee_id, :closed, :position, :description, 22 attr_accessible :title, :assignee_id, :closed, :position, :description,
24 :milestone_id, :label_list, :author_id_of_changes 23 :milestone_id, :label_list, :author_id_of_changes
app/models/key.rb
@@ -73,7 +73,7 @@ class Key &lt; ActiveRecord::Base @@ -73,7 +73,7 @@ class Key &lt; ActiveRecord::Base
73 if is_deploy_key 73 if is_deploy_key
74 [project] 74 [project]
75 else 75 else
76 - user.projects 76 + user.authorized_projects
77 end 77 end
78 end 78 end
79 79
app/models/merge_request.rb
@@ -20,11 +20,10 @@ @@ -20,11 +20,10 @@
20 # 20 #
21 21
22 require Rails.root.join("app/models/commit") 22 require Rails.root.join("app/models/commit")
23 -require Rails.root.join("app/roles/static_model") 23 +require Rails.root.join("lib/static_model")
24 24
25 class MergeRequest < ActiveRecord::Base 25 class MergeRequest < ActiveRecord::Base
26 - include IssueCommonality  
27 - include Votes 26 + include Issuable
28 27
29 attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, :milestone_id, 28 attr_accessible :title, :assignee_id, :closed, :target_branch, :source_branch, :milestone_id,
30 :author_id_of_changes 29 :author_id_of_changes
app/models/milestone.rb
@@ -29,7 +29,7 @@ class Milestone &lt; ActiveRecord::Base @@ -29,7 +29,7 @@ class Milestone &lt; ActiveRecord::Base
29 29
30 def expired? 30 def expired?
31 if due_date 31 if due_date
32 - due_date < Date.today 32 + due_date.past?
33 else 33 else
34 false 34 false
35 end 35 end
@@ -58,7 +58,13 @@ class Milestone &lt; ActiveRecord::Base @@ -58,7 +58,13 @@ class Milestone &lt; ActiveRecord::Base
58 end 58 end
59 59
60 def expires_at 60 def expires_at
61 - "expires at #{due_date.stamp("Aug 21, 2011")}" if due_date 61 + if due_date
  62 + if due_date.past?
  63 + "expired at #{due_date.stamp("Aug 21, 2011")}"
  64 + else
  65 + "expires at #{due_date.stamp("Aug 21, 2011")}"
  66 + end
  67 + end
62 end 68 end
63 69
64 def can_be_closed? 70 def can_be_closed?
app/models/namespace.rb
@@ -27,10 +27,13 @@ class Namespace &lt; ActiveRecord::Base @@ -27,10 +27,13 @@ class Namespace &lt; ActiveRecord::Base
27 27
28 after_create :ensure_dir_exist 28 after_create :ensure_dir_exist
29 after_update :move_dir 29 after_update :move_dir
  30 + after_commit :update_gitolite, on: :update, if: :require_update_gitolite
30 after_destroy :rm_dir 31 after_destroy :rm_dir
31 32
32 scope :root, where('type IS NULL') 33 scope :root, where('type IS NULL')
33 34
  35 + attr_accessor :require_update_gitolite
  36 +
34 def self.search query 37 def self.search query
35 where("name LIKE :query OR path LIKE :query", query: "%#{query}%") 38 where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
36 end 39 end
@@ -48,8 +51,17 @@ class Namespace &lt; ActiveRecord::Base @@ -48,8 +51,17 @@ class Namespace &lt; ActiveRecord::Base
48 end 51 end
49 52
50 def ensure_dir_exist 53 def ensure_dir_exist
51 - namespace_dir_path = File.join(Gitlab.config.gitolite.repos_path, path)  
52 - system("mkdir -m 770 #{namespace_dir_path}") unless File.exists?(namespace_dir_path) 54 + unless dir_exists?
  55 + FileUtils.mkdir( namespace_full_path, mode: 0770 )
  56 + end
  57 + end
  58 +
  59 + def dir_exists?
  60 + File.exists?(namespace_full_path)
  61 + end
  62 +
  63 + def namespace_full_path
  64 + @namespace_full_path ||= File.join(Gitlab.config.gitolite.repos_path, path)
53 end 65 end
54 66
55 def move_dir 67 def move_dir
@@ -59,16 +71,25 @@ class Namespace &lt; ActiveRecord::Base @@ -59,16 +71,25 @@ class Namespace &lt; ActiveRecord::Base
59 if File.exists?(new_path) 71 if File.exists?(new_path)
60 raise "Already exists" 72 raise "Already exists"
61 end 73 end
62 -  
63 - if system("mv #{old_path} #{new_path}") 74 +
  75 + begin
  76 + FileUtils.mv( old_path, new_path )
64 send_update_instructions 77 send_update_instructions
  78 + @require_update_gitolite = true
  79 + rescue Exception => e
  80 + raise "Namespace move error #{old_path} #{new_path}"
65 end 81 end
66 end 82 end
67 end 83 end
68 84
  85 + def update_gitolite
  86 + @require_update_gitolite = false
  87 + projects.each(&:update_repository)
  88 + end
  89 +
69 def rm_dir 90 def rm_dir
70 dir_path = File.join(Gitlab.config.gitolite.repos_path, path) 91 dir_path = File.join(Gitlab.config.gitolite.repos_path, path)
71 - system("rm -rf #{dir_path}") 92 + FileUtils.rm_r( dir_path, force: true )
72 end 93 end
73 94
74 def send_update_instructions 95 def send_update_instructions
app/models/note.rb
@@ -4,7 +4,6 @@ @@ -4,7 +4,6 @@
4 # 4 #
5 # id :integer not null, primary key 5 # id :integer not null, primary key
6 # note :text 6 # note :text
7 -# noteable_id :string(255)  
8 # noteable_type :string(255) 7 # noteable_type :string(255)
9 # author_id :integer 8 # author_id :integer
10 # created_at :datetime not null 9 # created_at :datetime not null
@@ -12,6 +11,8 @@ @@ -12,6 +11,8 @@
12 # project_id :integer 11 # project_id :integer
13 # attachment :string(255) 12 # attachment :string(255)
14 # line_code :string(255) 13 # line_code :string(255)
  14 +# commit_id :string(255)
  15 +# noteable_id :integer
15 # 16 #
16 17
17 require 'carrierwave/orm/activerecord' 18 require 'carrierwave/orm/activerecord'
@@ -41,11 +42,11 @@ class Note &lt; ActiveRecord::Base @@ -41,11 +42,11 @@ class Note &lt; ActiveRecord::Base
41 mount_uploader :attachment, AttachmentUploader 42 mount_uploader :attachment, AttachmentUploader
42 43
43 # Scopes 44 # Scopes
44 - scope :for_commits, ->{ where(noteable_type: "Commit") }  
45 - scope :common, ->{ where(noteable_id: nil, commit_id: nil) }  
46 - scope :today, ->{ where("created_at >= :date", date: Date.today) }  
47 - scope :last_week, ->{ where("created_at >= :date", date: (Date.today - 7.days)) }  
48 - scope :since, ->(day) { where("created_at >= :date", date: (day)) } 45 + scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) }
  46 + scope :inline, where("line_code IS NOT NULL")
  47 + scope :not_inline, where("line_code IS NULL")
  48 +
  49 + scope :common, ->{ where(noteable_type: ["", nil]) }
49 scope :fresh, ->{ order("created_at ASC, id ASC") } 50 scope :fresh, ->{ order("created_at ASC, id ASC") }
50 scope :inc_author_project, ->{ includes(:project, :author) } 51 scope :inc_author_project, ->{ includes(:project, :author) }
51 scope :inc_author, ->{ includes(:author) } 52 scope :inc_author, ->{ includes(:author) }
@@ -126,7 +127,7 @@ class Note &lt; ActiveRecord::Base @@ -126,7 +127,7 @@ class Note &lt; ActiveRecord::Base
126 # override to return commits, which are not active record 127 # override to return commits, which are not active record
127 def noteable 128 def noteable
128 if for_commit? 129 if for_commit?
129 - project.commit(commit_id) 130 + project.repository.commit(commit_id)
130 else 131 else
131 super 132 super
132 end 133 end
app/models/project.rb
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 # created_at :datetime not null 9 # created_at :datetime not null
10 # updated_at :datetime not null 10 # updated_at :datetime not null
11 # private_flag :boolean default(TRUE), not null 11 # private_flag :boolean default(TRUE), not null
12 -# owner_id :integer 12 +# creator_id :integer
13 # default_branch :string(255) 13 # default_branch :string(255)
14 # issues_enabled :boolean default(TRUE), not null 14 # issues_enabled :boolean default(TRUE), not null
15 # wall_enabled :boolean default(TRUE), not null 15 # wall_enabled :boolean default(TRUE), not null
@@ -21,18 +21,14 @@ @@ -21,18 +21,14 @@
21 require "grit" 21 require "grit"
22 22
23 class Project < ActiveRecord::Base 23 class Project < ActiveRecord::Base
24 - include Repository  
25 - include PushObserver  
26 - include Authority  
27 - include Team  
28 - include NamespacedProject 24 + include Gitolited
29 25
30 class TransferError < StandardError; end 26 class TransferError < StandardError; end
31 27
32 attr_accessible :name, :path, :description, :default_branch, :issues_enabled, 28 attr_accessible :name, :path, :description, :default_branch, :issues_enabled,
33 :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin] 29 :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin]
34 30
35 - attr_accessible :namespace_id, :owner_id, as: :admin 31 + attr_accessible :namespace_id, :creator_id, as: :admin
36 32
37 attr_accessor :error_code 33 attr_accessor :error_code
38 34
@@ -40,10 +36,10 @@ class Project &lt; ActiveRecord::Base @@ -40,10 +36,10 @@ class Project &lt; ActiveRecord::Base
40 belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'" 36 belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'"
41 belongs_to :namespace 37 belongs_to :namespace
42 38
43 - # TODO: replace owner with creator.  
44 - # With namespaces a project owner will be a namespace owner  
45 - # so this field makes sense only for global projects  
46 - belongs_to :owner, class_name: "User" 39 + belongs_to :creator,
  40 + class_name: "User",
  41 + foreign_key: "creator_id"
  42 +
47 has_many :users, through: :users_projects 43 has_many :users, through: :users_projects
48 has_many :events, dependent: :destroy 44 has_many :events, dependent: :destroy
49 has_many :merge_requests, dependent: :destroy 45 has_many :merge_requests, dependent: :destroy
@@ -62,9 +58,11 @@ class Project &lt; ActiveRecord::Base @@ -62,9 +58,11 @@ class Project &lt; ActiveRecord::Base
62 delegate :name, to: :owner, allow_nil: true, prefix: true 58 delegate :name, to: :owner, allow_nil: true, prefix: true
63 59
64 # Validations 60 # Validations
65 - validates :owner, presence: true 61 + validates :creator, presence: true
66 validates :description, length: { within: 0..2000 } 62 validates :description, length: { within: 0..2000 }
67 - validates :name, presence: true, length: { within: 0..255 } 63 + validates :name, presence: true, length: { within: 0..255 },
  64 + format: { with: Gitlab::Regex.project_name_regex,
  65 + message: "only letters, digits, spaces & '_' '-' '.' allowed. Letter should be first" }
68 validates :path, presence: true, length: { within: 0..255 }, 66 validates :path, presence: true, length: { within: 0..255 },
69 format: { with: Gitlab::Regex.path_regex, 67 format: { with: Gitlab::Regex.path_regex,
70 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } 68 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
@@ -77,19 +75,14 @@ class Project &lt; ActiveRecord::Base @@ -77,19 +75,14 @@ class Project &lt; ActiveRecord::Base
77 validate :check_limit, :repo_name 75 validate :check_limit, :repo_name
78 76
79 # Scopes 77 # Scopes
80 - scope :public_only, where(private_flag: false)  
81 - scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.projects.map(&:id) ) } 78 + scope :without_user, ->(user) { where("id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) }
82 scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) } 79 scope :not_in_group, ->(group) { where("id NOT IN (:ids)", ids: group.project_ids ) }
  80 + scope :in_namespace, ->(namespace) { where(namespace_id: namespace.id) }
83 scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") } 81 scope :sorted_by_activity, ->() { order("(SELECT max(events.created_at) FROM events WHERE events.project_id = projects.id) DESC") }
84 scope :personal, ->(user) { where(namespace_id: user.namespace_id) } 82 scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
85 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } 83 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
86 84
87 class << self 85 class << self
88 - def authorized_for user  
89 - projects = includes(:users_projects, :namespace)  
90 - projects = projects.where("users_projects.user_id = :user_id or projects.owner_id = :user_id or namespaces.owner_id = :user_id", user_id: user.id)  
91 - end  
92 -  
93 def active 86 def active
94 joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") 87 joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC")
95 end 88 end
@@ -101,8 +94,10 @@ class Project &lt; ActiveRecord::Base @@ -101,8 +94,10 @@ class Project &lt; ActiveRecord::Base
101 def find_with_namespace(id) 94 def find_with_namespace(id)
102 if id.include?("/") 95 if id.include?("/")
103 id = id.split("/") 96 id = id.split("/")
104 - namespace_id = Namespace.find_by_path(id.first).id  
105 - where(namespace_id: namespace_id).find_by_path(id.last) 97 + namespace = Namespace.find_by_path(id.first)
  98 + return nil unless namespace
  99 +
  100 + where(namespace_id: namespace.id).find_by_path(id.second)
106 else 101 else
107 where(path: id, namespace_id: nil).last 102 where(path: id, namespace_id: nil).last
108 end 103 end
@@ -122,7 +117,7 @@ class Project &lt; ActiveRecord::Base @@ -122,7 +117,7 @@ class Project &lt; ActiveRecord::Base
122 # 117 #
123 project.path = project.name.dup.parameterize 118 project.path = project.name.dup.parameterize
124 119
125 - project.owner = user 120 + project.creator = user
126 121
127 # Apply namespace if user has access to it 122 # Apply namespace if user has access to it
128 # else fallback to user namespace 123 # else fallback to user namespace
@@ -162,6 +157,20 @@ class Project &lt; ActiveRecord::Base @@ -162,6 +157,20 @@ class Project &lt; ActiveRecord::Base
162 end 157 end
163 end 158 end
164 159
  160 + def team
  161 + @team ||= Team.new(self)
  162 + end
  163 +
  164 + def repository
  165 + if path
  166 + @repository ||= Repository.new(path_with_namespace, default_branch)
  167 + else
  168 + nil
  169 + end
  170 + rescue Grit::NoSuchPathError
  171 + nil
  172 + end
  173 +
165 def git_error? 174 def git_error?
166 error_code == :gitolite 175 error_code == :gitolite
167 end 176 end
@@ -171,8 +180,8 @@ class Project &lt; ActiveRecord::Base @@ -171,8 +180,8 @@ class Project &lt; ActiveRecord::Base
171 end 180 end
172 181
173 def check_limit 182 def check_limit
174 - unless owner.can_create_project?  
175 - errors[:base] << ("Your own projects limit is #{owner.projects_limit}! Please contact administrator to increase it") 183 + unless creator.can_create_project?
  184 + errors[:base] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it")
176 end 185 end
177 rescue 186 rescue
178 errors[:base] << ("Can't check your ability to create project") 187 errors[:base] << ("Can't check your ability to create project")
@@ -198,30 +207,10 @@ class Project &lt; ActiveRecord::Base @@ -198,30 +207,10 @@ class Project &lt; ActiveRecord::Base
198 [Gitlab.config.gitlab.url, path_with_namespace].join("/") 207 [Gitlab.config.gitlab.url, path_with_namespace].join("/")
199 end 208 end
200 209
201 - def common_notes  
202 - notes.where(noteable_type: ["", nil]).inc_author_project  
203 - end  
204 -  
205 def build_commit_note(commit) 210 def build_commit_note(commit)
206 notes.new(commit_id: commit.id, noteable_type: "Commit") 211 notes.new(commit_id: commit.id, noteable_type: "Commit")
207 end 212 end
208 213
209 - def commit_notes(commit)  
210 - notes.where(commit_id: commit.id, noteable_type: "Commit").where('line_code IS NULL OR line_code = ""')  
211 - end  
212 -  
213 - def commit_line_notes(commit)  
214 - notes.where(commit_id: commit.id, noteable_type: "Commit").where("line_code IS NOT NULL")  
215 - end  
216 -  
217 - def public?  
218 - !private_flag  
219 - end  
220 -  
221 - def private?  
222 - private_flag  
223 - end  
224 -  
225 def last_activity 214 def last_activity
226 last_event 215 last_event
227 end 216 end
@@ -262,7 +251,282 @@ class Project &lt; ActiveRecord::Base @@ -262,7 +251,282 @@ class Project &lt; ActiveRecord::Base
262 251
263 def send_move_instructions 252 def send_move_instructions
264 self.users_projects.each do |member| 253 self.users_projects.each do |member|
265 - Notify.project_was_moved_email(member.id).deliver 254 + Notify.delay.project_was_moved_email(member.id)
  255 + end
  256 + end
  257 +
  258 + def owner
  259 + if namespace
  260 + namespace_owner
  261 + else
  262 + creator
  263 + end
  264 + end
  265 +
  266 + def team_member_by_name_or_email(name = nil, email = nil)
  267 + user = users.where("name like ? or email like ?", name, email).first
  268 + users_projects.where(user: user) if user
  269 + end
  270 +
  271 + # Get Team Member record by user id
  272 + def team_member_by_id(user_id)
  273 + users_projects.find_by_user_id(user_id)
  274 + end
  275 +
  276 + def transfer(new_namespace)
  277 + Project.transaction do
  278 + old_namespace = namespace
  279 + self.namespace = new_namespace
  280 +
  281 + old_dir = old_namespace.try(:path) || ''
  282 + new_dir = new_namespace.try(:path) || ''
  283 +
  284 + old_repo = if old_dir.present?
  285 + File.join(old_dir, self.path)
  286 + else
  287 + self.path
  288 + end
  289 +
  290 + if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present?
  291 + raise TransferError.new("Project with same path in target namespace already exists")
  292 + end
  293 +
  294 + Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
  295 +
  296 + gitolite.move_repository(old_repo, self)
  297 +
  298 + save!
  299 + end
  300 + rescue Gitlab::ProjectMover::ProjectMoveError => ex
  301 + raise Project::TransferError.new(ex.message)
  302 + end
  303 +
  304 + def name_with_namespace
  305 + @name_with_namespace ||= begin
  306 + if namespace
  307 + namespace.human_name + " / " + name
  308 + else
  309 + name
  310 + end
  311 + end
  312 + end
  313 +
  314 + def namespace_owner
  315 + namespace.try(:owner)
  316 + end
  317 +
  318 + def path_with_namespace
  319 + if namespace
  320 + namespace.path + '/' + path
  321 + else
  322 + path
  323 + end
  324 + end
  325 +
  326 + # This method will be called after each post receive and only if the provided
  327 + # user is present in GitLab.
  328 + #
  329 + # All callbacks for post receive should be placed here.
  330 + def trigger_post_receive(oldrev, newrev, ref, user)
  331 + data = post_receive_data(oldrev, newrev, ref, user)
  332 +
  333 + # Create push event
  334 + self.observe_push(data)
  335 +
  336 + if push_to_branch? ref, oldrev
  337 + # Close merged MR
  338 + self.update_merge_requests(oldrev, newrev, ref, user)
  339 +
  340 + # Execute web hooks
  341 + self.execute_hooks(data.dup)
  342 +
  343 + # Execute project services
  344 + self.execute_services(data.dup)
  345 + end
  346 +
  347 + # Create satellite
  348 + self.satellite.create unless self.satellite.exists?
  349 +
  350 + # Discover the default branch, but only if it hasn't already been set to
  351 + # something else
  352 + if repository && default_branch.nil?
  353 + update_attributes(default_branch: self.repository.discover_default_branch)
  354 + end
  355 + end
  356 +
  357 + def push_to_branch? ref, oldrev
  358 + ref_parts = ref.split('/')
  359 +
  360 + # Return if this is not a push to a branch (e.g. new commits)
  361 + !(ref_parts[1] !~ /heads/ || oldrev == "00000000000000000000000000000000")
  362 + end
  363 +
  364 + def observe_push(data)
  365 + Event.create(
  366 + project: self,
  367 + action: Event::Pushed,
  368 + data: data,
  369 + author_id: data[:user_id]
  370 + )
  371 + end
  372 +
  373 + def execute_hooks(data)
  374 + hooks.each { |hook| hook.execute(data) }
  375 + end
  376 +
  377 + def execute_services(data)
  378 + services.each do |service|
  379 +
  380 + # Call service hook only if it is active
  381 + service.execute(data) if service.active
  382 + end
  383 + end
  384 +
  385 + # Produce a hash of post-receive data
  386 + #
  387 + # data = {
  388 + # before: String,
  389 + # after: String,
  390 + # ref: String,
  391 + # user_id: String,
  392 + # user_name: String,
  393 + # repository: {
  394 + # name: String,
  395 + # url: String,
  396 + # description: String,
  397 + # homepage: String,
  398 + # },
  399 + # commits: Array,
  400 + # total_commits_count: Fixnum
  401 + # }
  402 + #
  403 + def post_receive_data(oldrev, newrev, ref, user)
  404 +
  405 + push_commits = repository.commits_between(oldrev, newrev)
  406 +
  407 + # Total commits count
  408 + push_commits_count = push_commits.size
  409 +
  410 + # Get latest 20 commits ASC
  411 + push_commits_limited = push_commits.last(20)
  412 +
  413 + # Hash to be passed as post_receive_data
  414 + data = {
  415 + before: oldrev,
  416 + after: newrev,
  417 + ref: ref,
  418 + user_id: user.id,
  419 + user_name: user.name,
  420 + repository: {
  421 + name: name,
  422 + url: url_to_repo,
  423 + description: description,
  424 + homepage: web_url,
  425 + },
  426 + commits: [],
  427 + total_commits_count: push_commits_count
  428 + }
  429 +
  430 + # For perfomance purposes maximum 20 latest commits
  431 + # will be passed as post receive hook data.
  432 + #
  433 + push_commits_limited.each do |commit|
  434 + data[:commits] << {
  435 + id: commit.id,
  436 + message: commit.safe_message,
  437 + timestamp: commit.date.xmlschema,
  438 + url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{commit.id}",
  439 + author: {
  440 + name: commit.author_name,
  441 + email: commit.author_email
  442 + }
  443 + }
266 end 444 end
  445 +
  446 + data
  447 + end
  448 +
  449 + def update_merge_requests(oldrev, newrev, ref, user)
  450 + return true unless ref =~ /heads/
  451 + branch_name = ref.gsub("refs/heads/", "")
  452 + c_ids = self.repository.commits_between(oldrev, newrev).map(&:id)
  453 +
  454 + # Update code for merge requests
  455 + mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all
  456 + mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
  457 +
  458 + # Close merge requests
  459 + mrs = self.merge_requests.opened.where(target_branch: branch_name).all
  460 + mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
  461 + mrs.each { |merge_request| merge_request.merge!(user.id) }
  462 +
  463 + true
  464 + end
  465 +
  466 + def valid_repo?
  467 + repo
  468 + rescue
  469 + errors.add(:path, "Invalid repository path")
  470 + false
  471 + end
  472 +
  473 + def empty_repo?
  474 + !repository || repository.empty?
  475 + end
  476 +
  477 + def satellite
  478 + @satellite ||= Gitlab::Satellite::Satellite.new(self)
  479 + end
  480 +
  481 + def repo
  482 + repository.raw
  483 + end
  484 +
  485 + def url_to_repo
  486 + gitolite.url_to_repo(path_with_namespace)
  487 + end
  488 +
  489 + def namespace_dir
  490 + namespace.try(:path) || ''
  491 + end
  492 +
  493 + def update_repository
  494 + gitolite.update_repository(self)
  495 + end
  496 +
  497 + def destroy_repository
  498 + gitolite.remove_repository(self)
  499 + end
  500 +
  501 + def repo_exists?
  502 + @repo_exists ||= (repository && repository.branches.present?)
  503 + rescue
  504 + @repo_exists = false
  505 + end
  506 +
  507 + def open_branches
  508 + if protected_branches.empty?
  509 + self.repo.heads
  510 + else
  511 + pnames = protected_branches.map(&:name)
  512 + self.repo.heads.reject { |h| pnames.include?(h.name) }
  513 + end.sort_by(&:name)
  514 + end
  515 +
  516 + def root_ref?(branch)
  517 + repository.root_ref == branch
  518 + end
  519 +
  520 + def ssh_url_to_repo
  521 + url_to_repo
  522 + end
  523 +
  524 + def http_url_to_repo
  525 + http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
  526 + end
  527 +
  528 + # Check if current branch name is marked as protected in the system
  529 + def protected_branch? branch_name
  530 + protected_branches.map(&:name).include?(branch_name)
267 end 531 end
268 end 532 end
app/models/protected_branch.rb
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 # 10 #
11 11
12 class ProtectedBranch < ActiveRecord::Base 12 class ProtectedBranch < ActiveRecord::Base
13 - include GitHost 13 + include Gitolited
14 14
15 attr_accessible :name 15 attr_accessible :name
16 16
@@ -22,10 +22,10 @@ class ProtectedBranch &lt; ActiveRecord::Base @@ -22,10 +22,10 @@ class ProtectedBranch &lt; ActiveRecord::Base
22 after_destroy :update_repository 22 after_destroy :update_repository
23 23
24 def update_repository 24 def update_repository
25 - git_host.update_repository(project) 25 + gitolite.update_repository(project)
26 end 26 end
27 27
28 def commit 28 def commit
29 - project.commit(self.name) 29 + project.repository.commit(self.name)
30 end 30 end
31 end 31 end
app/models/repository.rb 0 → 100644
@@ -0,0 +1,169 @@ @@ -0,0 +1,169 @@
  1 +class Repository
  2 + # Repository directory name with namespace direcotry
  3 + # Examples:
  4 + # gitlab/gitolite
  5 + # diaspora
  6 + #
  7 + attr_accessor :path_with_namespace
  8 +
  9 + # Grit repo object
  10 + attr_accessor :repo
  11 +
  12 + # Default branch in the repository
  13 + attr_accessor :root_ref
  14 +
  15 + def initialize(path_with_namespace, root_ref = 'master')
  16 + @root_ref = root_ref || "master"
  17 + @path_with_namespace = path_with_namespace
  18 +
  19 + # Init grit repo object
  20 + repo
  21 + end
  22 +
  23 + def raw
  24 + repo
  25 + end
  26 +
  27 + def path_to_repo
  28 + @path_to_repo ||= File.join(Gitlab.config.gitolite.repos_path, "#{path_with_namespace}.git")
  29 + end
  30 +
  31 + def repo
  32 + @repo ||= Grit::Repo.new(path_to_repo)
  33 + end
  34 +
  35 + def commit(commit_id = nil)
  36 + Commit.find_or_first(repo, commit_id, root_ref)
  37 + end
  38 +
  39 + def fresh_commits(n = 10)
  40 + Commit.fresh_commits(repo, n)
  41 + end
  42 +
  43 + def commits_with_refs(n = 20)
  44 + Commit.commits_with_refs(repo, n)
  45 + end
  46 +
  47 + def commits_since(date)
  48 + Commit.commits_since(repo, date)
  49 + end
  50 +
  51 + def commits(ref, path = nil, limit = nil, offset = nil)
  52 + Commit.commits(repo, ref, path, limit, offset)
  53 + end
  54 +
  55 + def last_commit_for(ref, path = nil)
  56 + commits(ref, path, 1).first
  57 + end
  58 +
  59 + def commits_between(from, to)
  60 + Commit.commits_between(repo, from, to)
  61 + end
  62 +
  63 + def has_post_receive_file?
  64 + !!hook_file
  65 + end
  66 +
  67 + def valid_post_receive_file?
  68 + valid_hook_file == hook_file
  69 + end
  70 +
  71 + def valid_hook_file
  72 + @valid_hook_file ||= File.read(Rails.root.join('lib', 'hooks', 'post-receive'))
  73 + end
  74 +
  75 + def hook_file
  76 + @hook_file ||= begin
  77 + hook_path = File.join(path_to_repo, 'hooks', 'post-receive')
  78 + File.read(hook_path) if File.exists?(hook_path)
  79 + end
  80 + end
  81 +
  82 + # Returns an Array of branch names
  83 + def branch_names
  84 + repo.branches.collect(&:name).sort
  85 + end
  86 +
  87 + # Returns an Array of Branches
  88 + def branches
  89 + repo.branches.sort_by(&:name)
  90 + end
  91 +
  92 + # Returns an Array of tag names
  93 + def tag_names
  94 + repo.tags.collect(&:name).sort.reverse
  95 + end
  96 +
  97 + # Returns an Array of Tags
  98 + def tags
  99 + repo.tags.sort_by(&:name).reverse
  100 + end
  101 +
  102 + # Returns an Array of branch and tag names
  103 + def ref_names
  104 + [branch_names + tag_names].flatten
  105 + end
  106 +
  107 + def heads
  108 + @heads ||= repo.heads
  109 + end
  110 +
  111 + def tree(fcommit, path = nil)
  112 + fcommit = commit if fcommit == :head
  113 + tree = fcommit.tree
  114 + path ? (tree / path) : tree
  115 + end
  116 +
  117 + def has_commits?
  118 + !!commit
  119 + rescue Grit::NoSuchPathError
  120 + false
  121 + end
  122 +
  123 + def empty?
  124 + !has_commits?
  125 + end
  126 +
  127 + # Discovers the default branch based on the repository's available branches
  128 + #
  129 + # - If no branches are present, returns nil
  130 + # - If one branch is present, returns its name
  131 + # - If two or more branches are present, returns the one that has a name
  132 + # matching root_ref (default_branch or 'master' if default_branch is nil)
  133 + def discover_default_branch
  134 + if branch_names.length == 0
  135 + nil
  136 + elsif branch_names.length == 1
  137 + branch_names.first
  138 + else
  139 + branch_names.select { |v| v == root_ref }.first
  140 + end
  141 + end
  142 +
  143 + # Archive Project to .tar.gz
  144 + #
  145 + # Already packed repo archives stored at
  146 + # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz
  147 + #
  148 + def archive_repo(ref)
  149 + ref = ref || self.root_ref
  150 + commit = self.commit(ref)
  151 + return nil unless commit
  152 +
  153 + # Build file path
  154 + file_name = self.path + "-" + commit.id.to_s + ".tar.gz"
  155 + storage_path = Rails.root.join("tmp", "repositories", self.path_with_namespace)
  156 + file_path = File.join(storage_path, file_name)
  157 +
  158 + # Put files into a directory before archiving
  159 + prefix = self.path + "/"
  160 +
  161 + # Create file if not exists
  162 + unless File.exists?(file_path)
  163 + FileUtils.mkdir_p storage_path
  164 + file = self.repo.archive_to_file(ref, prefix, file_path)
  165 + end
  166 +
  167 + file_path
  168 + end
  169 +end
app/models/service.rb
@@ -20,4 +20,8 @@ class Service &lt; ActiveRecord::Base @@ -20,4 +20,8 @@ class Service &lt; ActiveRecord::Base
20 has_one :service_hook 20 has_one :service_hook
21 21
22 validates :project_id, presence: true 22 validates :project_id, presence: true
  23 +
  24 + def activated?
  25 + active
  26 + end
23 end 27 end
app/models/system_hook.rb
@@ -19,6 +19,6 @@ class SystemHook &lt; WebHook @@ -19,6 +19,6 @@ class SystemHook &lt; WebHook
19 end 19 end
20 20
21 def async_execute(data) 21 def async_execute(data)
22 - Resque.enqueue(SystemHookWorker, id, data) 22 + Sidekiq::Client.enqueue(SystemHookWorker, id, data)
23 end 23 end
24 end 24 end
app/models/team.rb 0 → 100644
@@ -0,0 +1,118 @@ @@ -0,0 +1,118 @@
  1 +class Team
  2 + attr_accessor :project
  3 +
  4 + def initialize(project)
  5 + @project = project
  6 + end
  7 +
  8 + # Shortcut to add users
  9 + #
  10 + # Use:
  11 + # @team << [@user, :master]
  12 + # @team << [@users, :master]
  13 + #
  14 + def << args
  15 + users = args.first
  16 +
  17 + if users.respond_to?(:each)
  18 + add_users(users, args.second)
  19 + else
  20 + add_user(users, args.second)
  21 + end
  22 + end
  23 +
  24 + def add_user(user, access)
  25 + add_users_ids([user.id], access)
  26 + end
  27 +
  28 + def add_users(users, access)
  29 + add_users_ids(users.map(&:id), access)
  30 + end
  31 +
  32 + def add_users_ids(user_ids, access)
  33 + UsersProject.add_users_into_projects(
  34 + [project.id],
  35 + user_ids,
  36 + access
  37 + )
  38 + end
  39 +
  40 + # Remove all users from project team
  41 + def truncate
  42 + UsersProject.truncate_team(project)
  43 + end
  44 +
  45 + def members
  46 + project.users_projects
  47 + end
  48 +
  49 + def guests
  50 + members.guests.map(&:user)
  51 + end
  52 +
  53 + def reporters
  54 + members.reporters.map(&:user)
  55 + end
  56 +
  57 + def developers
  58 + members.developers.map(&:user)
  59 + end
  60 +
  61 + def masters
  62 + members.masters.map(&:user)
  63 + end
  64 +
  65 + def repository_readers
  66 + repository_members[UsersProject::REPORTER]
  67 + end
  68 +
  69 + def repository_writers
  70 + repository_members[UsersProject::DEVELOPER]
  71 + end
  72 +
  73 + def repository_masters
  74 + repository_members[UsersProject::MASTER]
  75 + end
  76 +
  77 + def repository_members
  78 + keys = Hash.new {|h,k| h[k] = [] }
  79 + UsersProject.select("keys.identifier, project_access").
  80 + joins(user: :keys).where(project_id: project.id).
  81 + each {|row| keys[row.project_access] << [row.identifier] }
  82 +
  83 + keys[UsersProject::REPORTER] += project.deploy_keys.pluck(:identifier)
  84 + keys
  85 + end
  86 +
  87 + def import(source_project)
  88 + target_project = project
  89 +
  90 + source_team = source_project.users_projects.all
  91 + target_team = target_project.users_projects.all
  92 + target_user_ids = target_team.map(&:user_id)
  93 +
  94 + source_team.reject! do |tm|
  95 + # Skip if user already present in team
  96 + target_user_ids.include?(tm.user_id)
  97 + end
  98 +
  99 + source_team.map! do |tm|
  100 + new_tm = tm.dup
  101 + new_tm.id = nil
  102 + new_tm.project_id = target_project.id
  103 + new_tm.skip_git = true
  104 + new_tm
  105 + end
  106 +
  107 + UsersProject.transaction do
  108 + source_team.each do |tm|
  109 + tm.save
  110 + end
  111 + target_project.update_repository
  112 + end
  113 +
  114 + true
  115 + rescue
  116 + false
  117 + end
  118 +end
app/models/tree.rb
1 class Tree 1 class Tree
2 include Linguist::BlobHelper 2 include Linguist::BlobHelper
3 - attr_accessor :path, :tree, :project, :ref 3 +
  4 + attr_accessor :path, :tree, :ref
4 5
5 delegate :contents, :basename, :name, :data, :mime_type, 6 delegate :contents, :basename, :name, :data, :mime_type,
6 :mode, :size, :text?, :colorize, to: :tree 7 :mode, :size, :text?, :colorize, to: :tree
7 8
8 - def initialize(raw_tree, project, ref = nil, path = nil)  
9 - @project, @ref, @path = project, ref, path 9 + def initialize(raw_tree, ref = nil, path = nil)
  10 + @ref, @path = ref, path
10 @tree = if path.present? 11 @tree = if path.present?
11 raw_tree / path 12 raw_tree / path
12 else 13 else
app/models/user.rb
@@ -34,8 +34,6 @@ @@ -34,8 +34,6 @@
34 # 34 #
35 35
36 class User < ActiveRecord::Base 36 class User < ActiveRecord::Base
37 - include Account  
38 -  
39 devise :database_authenticatable, :token_authenticatable, :lockable, 37 devise :database_authenticatable, :token_authenticatable, :lockable,
40 :recoverable, :rememberable, :trackable, :validatable, :omniauthable 38 :recoverable, :rememberable, :trackable, :validatable, :omniauthable
41 39
@@ -51,7 +49,6 @@ class User &lt; ActiveRecord::Base @@ -51,7 +49,6 @@ class User &lt; ActiveRecord::Base
51 has_many :groups, class_name: "Group", foreign_key: :owner_id 49 has_many :groups, class_name: "Group", foreign_key: :owner_id
52 50
53 has_many :keys, dependent: :destroy 51 has_many :keys, dependent: :destroy
54 - has_many :projects, through: :users_projects  
55 has_many :users_projects, dependent: :destroy 52 has_many :users_projects, dependent: :destroy
56 has_many :issues, foreign_key: :author_id, dependent: :destroy 53 has_many :issues, foreign_key: :author_id, dependent: :destroy
57 has_many :notes, foreign_key: :author_id, dependent: :destroy 54 has_many :notes, foreign_key: :author_id, dependent: :destroy
@@ -70,6 +67,8 @@ class User &lt; ActiveRecord::Base @@ -70,6 +67,8 @@ class User &lt; ActiveRecord::Base
70 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } 67 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
71 68
72 69
  70 + validate :namespace_uniq, if: ->(user) { user.username_changed? }
  71 +
73 before_validation :generate_password, on: :create 72 before_validation :generate_password, on: :create
74 before_save :ensure_authentication_token 73 before_save :ensure_authentication_token
75 alias_attribute :private_token, :authentication_token 74 alias_attribute :private_token, :authentication_token
@@ -77,11 +76,14 @@ class User &lt; ActiveRecord::Base @@ -77,11 +76,14 @@ class User &lt; ActiveRecord::Base
77 delegate :path, to: :namespace, allow_nil: true, prefix: true 76 delegate :path, to: :namespace, allow_nil: true, prefix: true
78 77
79 # Scopes 78 # Scopes
80 - scope :not_in_project, ->(project) { where("id not in (:ids)", ids: project.users.map(&:id) ) }  
81 scope :admins, where(admin: true) 79 scope :admins, where(admin: true)
82 scope :blocked, where(blocked: true) 80 scope :blocked, where(blocked: true)
83 scope :active, where(blocked: false) 81 scope :active, where(blocked: false)
  82 + scope :alphabetically, order('name ASC')
84 83
  84 + #
  85 + # Class methods
  86 + #
85 class << self 87 class << self
86 def filter filter_name 88 def filter filter_name
87 case filter_name 89 case filter_name
@@ -93,6 +95,14 @@ class User &lt; ActiveRecord::Base @@ -93,6 +95,14 @@ class User &lt; ActiveRecord::Base
93 end 95 end
94 end 96 end
95 97
  98 + def not_in_project(project)
  99 + if project.users.present?
  100 + where("id not in (:ids)", ids: project.users.map(&:id) )
  101 + else
  102 + scoped
  103 + end
  104 + end
  105 +
96 def without_projects 106 def without_projects
97 where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') 107 where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
98 end 108 end
@@ -118,9 +128,158 @@ class User &lt; ActiveRecord::Base @@ -118,9 +128,158 @@ class User &lt; ActiveRecord::Base
118 end 128 end
119 end 129 end
120 130
  131 + #
  132 + # Instance methods
  133 + #
121 def generate_password 134 def generate_password
122 if self.force_random_password 135 if self.force_random_password
123 self.password = self.password_confirmation = Devise.friendly_token.first(8) 136 self.password = self.password_confirmation = Devise.friendly_token.first(8)
124 end 137 end
125 end 138 end
  139 +
  140 + def namespace_uniq
  141 + namespace_name = self.username
  142 + if Namespace.find_by_path(namespace_name)
  143 + self.errors.add :username, "already exist"
  144 + end
  145 + end
  146 +
  147 + # Namespaces user has access to
  148 + def namespaces
  149 + namespaces = []
  150 +
  151 + # Add user account namespace
  152 + namespaces << self.namespace if self.namespace
  153 +
  154 + # Add groups you can manage
  155 + namespaces += if admin
  156 + Group.all
  157 + else
  158 + groups.all
  159 + end
  160 + namespaces
  161 + end
  162 +
  163 + # Groups where user is an owner
  164 + def owned_groups
  165 + groups
  166 + end
  167 +
  168 + # Groups user has access to
  169 + def authorized_groups
  170 + @authorized_groups ||= begin
  171 + groups = Group.where(id: self.authorized_projects.pluck(:namespace_id)).all
  172 + groups = groups + self.groups
  173 + groups.uniq
  174 + end
  175 + end
  176 +
  177 +
  178 + # Projects user has access to
  179 + def authorized_projects
  180 + project_ids = users_projects.pluck(:project_id)
  181 + project_ids = project_ids | owned_projects.pluck(:id)
  182 + Project.where(id: project_ids)
  183 + end
  184 +
  185 + # Projects in user namespace
  186 + def personal_projects
  187 + Project.personal(self)
  188 + end
  189 +
  190 + # Projects where user is an owner
  191 + def owned_projects
  192 + Project.where("(projects.namespace_id IN (:namespaces)) OR
  193 + (projects.namespace_id IS NULL AND projects.creator_id = :user_id)",
  194 + namespaces: namespaces.map(&:id), user_id: self.id)
  195 + end
  196 +
  197 + # Team membership in personal projects
  198 + def tm_in_personal_projects
  199 + UsersProject.where(project_id: personal_projects.map(&:id), user_id: self.id)
  200 + end
  201 +
  202 + # Returns a string for use as a Gitolite user identifier
  203 + #
  204 + # Note that Gitolite 2.x requires the following pattern for users:
  205 + #
  206 + # ^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$
  207 + def identifier
  208 + # Replace non-word chars with underscores, then make sure it starts with
  209 + # valid chars
  210 + email.gsub(/\W/, '_').gsub(/\A([\W\_])+/, '')
  211 + end
  212 +
  213 + def is_admin?
  214 + admin
  215 + end
  216 +
  217 + def require_ssh_key?
  218 + keys.count == 0
  219 + end
  220 +
  221 + def can_create_project?
  222 + projects_limit > personal_projects.count
  223 + end
  224 +
  225 + def can_create_group?
  226 + is_admin?
  227 + end
  228 +
  229 + def abilities
  230 + @abilities ||= begin
  231 + abilities = Six.new
  232 + abilities << Ability
  233 + abilities
  234 + end
  235 + end
  236 +
  237 + def can? action, subject
  238 + abilities.allowed?(self, action, subject)
  239 + end
  240 +
  241 + def first_name
  242 + name.split.first unless name.blank?
  243 + end
  244 +
  245 + def cared_merge_requests
  246 + MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id)
  247 + end
  248 +
  249 + # Remove user from all projects and
  250 + # set blocked attribute to true
  251 + def block
  252 + users_projects.find_each do |membership|
  253 + return false unless membership.destroy
  254 + end
  255 +
  256 + self.blocked = true
  257 + save
  258 + end
  259 +
  260 + def projects_limit_percent
  261 + return 100 if projects_limit.zero?
  262 + (personal_projects.count.to_f / projects_limit) * 100
  263 + end
  264 +
  265 + def recent_push project_id = nil
  266 + # Get push events not earlier than 2 hours ago
  267 + events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours)
  268 + events = events.where(project_id: project_id) if project_id
  269 +
  270 + # Take only latest one
  271 + events = events.recent.limit(1).first
  272 + end
  273 +
  274 + def projects_sorted_by_activity
  275 + authorized_projects.sorted_by_activity
  276 + end
  277 +
  278 + def several_namespaces?
  279 + namespaces.size > 1
  280 + end
  281 +
  282 + def namespace_id
  283 + namespace.try :id
  284 + end
126 end 285 end
app/models/users_project.rb
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 # 11 #
12 12
13 class UsersProject < ActiveRecord::Base 13 class UsersProject < ActiveRecord::Base
14 - include GitHost 14 + include Gitolited
15 15
16 GUEST = 10 16 GUEST = 10
17 REPORTER = 20 17 REPORTER = 20
@@ -23,87 +23,96 @@ class UsersProject &lt; ActiveRecord::Base @@ -23,87 +23,96 @@ class UsersProject &lt; ActiveRecord::Base
23 belongs_to :user 23 belongs_to :user
24 belongs_to :project 24 belongs_to :project
25 25
26 - after_save :update_repository  
27 - after_destroy :update_repository 26 + attr_accessor :skip_git
  27 +
  28 + after_save :update_repository, unless: :skip_git?
  29 + after_destroy :update_repository, unless: :skip_git?
28 30
29 validates :user, presence: true 31 validates :user, presence: true
30 - validates :user_id, uniqueness: { :scope => [:project_id], message: "already exists in project" } 32 + validates :user_id, uniqueness: { scope: [:project_id], message: "already exists in project" }
31 validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true 33 validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true
32 validates :project, presence: true 34 validates :project, presence: true
33 35
34 delegate :name, :email, to: :user, prefix: true 36 delegate :name, :email, to: :user, prefix: true
35 37
  38 + scope :guests, where(project_access: GUEST)
  39 + scope :reporters, where(project_access: REPORTER)
  40 + scope :developers, where(project_access: DEVELOPER)
  41 + scope :masters, where(project_access: MASTER)
  42 + scope :in_project, ->(project) { where(project_id: project.id) }
  43 +
36 class << self 44 class << self
37 - def import_team(source_project, target_project)  
38 - UsersProject.without_repository_callback do  
39 - UsersProject.transaction do  
40 - team = source_project.users_projects.all  
41 -  
42 - team.each do |tm|  
43 - # Skip if user already present in team  
44 - next if target_project.users.include?(tm.user)  
45 -  
46 - new_tm = tm.dup  
47 - new_tm.id = nil  
48 - new_tm.project_id = target_project.id  
49 - new_tm.save 45 +
  46 + # Add users to project teams with passed access option
  47 + #
  48 + # access can be an integer representing a access code
  49 + # or symbol like :master representing role
  50 + #
  51 + # Ex.
  52 + # add_users_into_projects(
  53 + # project_ids,
  54 + # user_ids,
  55 + # UsersProject::MASTER
  56 + # )
  57 + #
  58 + # add_users_into_projects(
  59 + # project_ids,
  60 + # user_ids,
  61 + # :master
  62 + # )
  63 + #
  64 + def add_users_into_projects(project_ids, user_ids, access)
  65 + project_access = if roles_hash.has_key?(access)
  66 + roles_hash[access]
  67 + elsif roles_hash.values.include?(access.to_i)
  68 + access
  69 + else
  70 + raise "Non valid access"
  71 + end
  72 +
  73 + UsersProject.transaction do
  74 + project_ids.each do |project_id|
  75 + user_ids.each do |user_id|
  76 + users_project = UsersProject.new(project_access: project_access, user_id: user_id)
  77 + users_project.project_id = project_id
  78 + users_project.skip_git = true
  79 + users_project.save
50 end 80 end
51 end 81 end
  82 + Gitlab::Gitolite.new.update_repositories(Project.where(id: project_ids))
52 end 83 end
53 84
54 - target_project.update_repository  
55 true 85 true
56 rescue 86 rescue
57 false 87 false
58 end 88 end
59 89
60 - def without_repository_callback  
61 - UsersProject.skip_callback(:destroy, :after, :update_repository)  
62 - yield  
63 - UsersProject.set_callback(:destroy, :after, :update_repository)  
64 - end  
65 -  
66 - def bulk_delete(project, user_ids) 90 + def truncate_teams(project_ids)
67 UsersProject.transaction do 91 UsersProject.transaction do
68 - UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| 92 + users_projects = UsersProject.where(project_id: project_ids)
  93 + users_projects.each do |users_project|
  94 + users_project.skip_git = true
69 users_project.destroy 95 users_project.destroy
70 end 96 end
  97 + Gitlab::Gitolite.new.update_repositories(Project.where(id: project_ids))
71 end 98 end
72 - end  
73 99
74 - def bulk_update(project, user_ids, project_access)  
75 - UsersProject.transaction do  
76 - UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project|  
77 - users_project.project_access = project_access  
78 - users_project.save  
79 - end  
80 - end 100 + true
  101 + rescue
  102 + false
81 end 103 end
82 104
83 - def bulk_import(project, user_ids, project_access)  
84 - UsersProject.transaction do  
85 - user_ids.each do |user_id|  
86 - users_project = UsersProject.new(  
87 - project_access: project_access,  
88 - user_id: user_id  
89 - )  
90 - users_project.project = project  
91 - users_project.save  
92 - end  
93 - end 105 + def truncate_team project
  106 + truncate_teams [project.id]
94 end 107 end
95 108
96 - def user_bulk_import(user, project_ids, project_access)  
97 - UsersProject.transaction do  
98 - project_ids.each do |project_id|  
99 - users_project = UsersProject.new(  
100 - project_access: project_access,  
101 - )  
102 - users_project.project_id = project_id  
103 - users_project.user_id = user.id  
104 - users_project.save  
105 - end  
106 - end 109 + def roles_hash
  110 + {
  111 + guest: GUEST,
  112 + reporter: REPORTER,
  113 + developer: DEVELOPER,
  114 + master: MASTER
  115 + }
107 end 116 end
108 117
109 def access_roles 118 def access_roles
@@ -116,12 +125,8 @@ class UsersProject &lt; ActiveRecord::Base @@ -116,12 +125,8 @@ class UsersProject &lt; ActiveRecord::Base
116 end 125 end
117 end 126 end
118 127
119 - def role_access  
120 - project_access  
121 - end  
122 -  
123 def update_repository 128 def update_repository
124 - git_host.update_repository(project) 129 + gitolite.update_repository(project)
125 end 130 end
126 131
127 def project_access_human 132 def project_access_human
@@ -131,4 +136,8 @@ class UsersProject &lt; ActiveRecord::Base @@ -131,4 +136,8 @@ class UsersProject &lt; ActiveRecord::Base
131 def repo_access_human 136 def repo_access_human
132 self.class.access_roles.invert[self.project_access] 137 self.class.access_roles.invert[self.project_access]
133 end 138 end
  139 +
  140 + def skip_git?
  141 + !!@skip_git
  142 + end
134 end 143 end
app/models/wiki.rb
@@ -50,5 +50,4 @@ class Wiki &lt; ActiveRecord::Base @@ -50,5 +50,4 @@ class Wiki &lt; ActiveRecord::Base
50 def set_slug 50 def set_slug
51 self.slug = self.title.parameterize 51 self.slug = self.title.parameterize
52 end 52 end
53 -  
54 end 53 end
app/observers/issue_observer.rb
@@ -3,7 +3,7 @@ class IssueObserver &lt; ActiveRecord::Observer @@ -3,7 +3,7 @@ class IssueObserver &lt; ActiveRecord::Observer
3 3
4 def after_create(issue) 4 def after_create(issue)
5 if issue.assignee && issue.assignee != current_user 5 if issue.assignee && issue.assignee != current_user
6 - Notify.new_issue_email(issue.id).deliver 6 + Notify.delay.new_issue_email(issue.id)
7 end 7 end
8 end 8 end
9 9
@@ -16,7 +16,7 @@ class IssueObserver &lt; ActiveRecord::Observer @@ -16,7 +16,7 @@ class IssueObserver &lt; ActiveRecord::Observer
16 if status 16 if status
17 Note.create_status_change_note(issue, current_user, status) 17 Note.create_status_change_note(issue, current_user, status)
18 [issue.author, issue.assignee].compact.each do |recipient| 18 [issue.author, issue.assignee].compact.each do |recipient|
19 - Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user.id).deliver 19 + Notify.delay.issue_status_changed_email(recipient.id, issue.id, status, current_user.id)
20 end 20 end
21 end 21 end
22 end 22 end
@@ -27,7 +27,7 @@ class IssueObserver &lt; ActiveRecord::Observer @@ -27,7 +27,7 @@ class IssueObserver &lt; ActiveRecord::Observer
27 recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id } 27 recipient_ids = [issue.assignee_id, issue.assignee_id_was].keep_if {|id| id && id != current_user.id }
28 28
29 recipient_ids.each do |recipient_id| 29 recipient_ids.each do |recipient_id|
30 - Notify.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was).deliver 30 + Notify.delay.reassigned_issue_email(recipient_id, issue.id, issue.assignee_id_was)
31 end 31 end
32 end 32 end
33 end 33 end
app/observers/key_observer.rb
1 class KeyObserver < ActiveRecord::Observer 1 class KeyObserver < ActiveRecord::Observer
2 - include GitHost 2 + include Gitolited
3 3
4 def after_save(key) 4 def after_save(key)
5 - git_host.set_key(key.identifier, key.key, key.projects) 5 + gitolite.set_key(key.identifier, key.key, key.projects)
6 end 6 end
7 7
8 def after_destroy(key) 8 def after_destroy(key)
9 return if key.is_deploy_key && !key.last_deploy? 9 return if key.is_deploy_key && !key.last_deploy?
10 - git_host.remove_key(key.identifier, key.projects) 10 + gitolite.remove_key(key.identifier, key.projects)
11 end 11 end
12 end 12 end
app/observers/merge_request_observer.rb
@@ -3,7 +3,7 @@ class MergeRequestObserver &lt; ActiveRecord::Observer @@ -3,7 +3,7 @@ class MergeRequestObserver &lt; ActiveRecord::Observer
3 3
4 def after_create(merge_request) 4 def after_create(merge_request)
5 if merge_request.assignee && merge_request.assignee != current_user 5 if merge_request.assignee && merge_request.assignee != current_user
6 - Notify.new_merge_request_email(merge_request.id).deliver 6 + Notify.delay.new_merge_request_email(merge_request.id)
7 end 7 end
8 end 8 end
9 9
@@ -25,7 +25,7 @@ class MergeRequestObserver &lt; ActiveRecord::Observer @@ -25,7 +25,7 @@ class MergeRequestObserver &lt; ActiveRecord::Observer
25 recipients_ids.delete current_user.id 25 recipients_ids.delete current_user.id
26 26
27 recipients_ids.each do |recipient_id| 27 recipients_ids.each do |recipient_id|
28 - Notify.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was).deliver 28 + Notify.delay.reassigned_merge_request_email(recipient_id, merge_request.id, merge_request.assignee_id_was)
29 end 29 end
30 end 30 end
31 end 31 end
app/observers/note_observer.rb
@@ -11,7 +11,7 @@ class NoteObserver &lt; ActiveRecord::Observer @@ -11,7 +11,7 @@ class NoteObserver &lt; ActiveRecord::Observer
11 notify_team(note) 11 notify_team(note)
12 elsif note.notify_author 12 elsif note.notify_author
13 # Notify only author of resource 13 # Notify only author of resource
14 - Notify.note_commit_email(note.noteable.author_email, note.id).deliver 14 + Notify.delay.note_commit_email(note.noteable.author_email, note.id)
15 else 15 else
16 # Otherwise ignore it 16 # Otherwise ignore it
17 nil 17 nil
@@ -26,7 +26,7 @@ class NoteObserver &lt; ActiveRecord::Observer @@ -26,7 +26,7 @@ class NoteObserver &lt; ActiveRecord::Observer
26 26
27 if Notify.respond_to? notify_method 27 if Notify.respond_to? notify_method
28 team_without_note_author(note).map do |u| 28 team_without_note_author(note).map do |u|
29 - Notify.send(notify_method, u.id, note.id).deliver 29 + Notify.delay.send(notify_method, u.id, note.id)
30 end 30 end
31 end 31 end
32 end 32 end
app/observers/user_observer.rb
@@ -2,7 +2,7 @@ class UserObserver &lt; ActiveRecord::Observer @@ -2,7 +2,7 @@ class UserObserver &lt; ActiveRecord::Observer
2 def after_create(user) 2 def after_create(user)
3 log_info("User \"#{user.name}\" (#{user.email}) was created") 3 log_info("User \"#{user.name}\" (#{user.email}) was created")
4 4
5 - Notify.new_user_email(user.id, user.password).deliver 5 + Notify.delay.new_user_email(user.id, user.password)
6 end 6 end
7 7
8 def after_destroy user 8 def after_destroy user
@@ -14,7 +14,7 @@ class UserObserver &lt; ActiveRecord::Observer @@ -14,7 +14,7 @@ class UserObserver &lt; ActiveRecord::Observer
14 if user.namespace 14 if user.namespace
15 user.namespace.update_attributes(path: user.username) 15 user.namespace.update_attributes(path: user.username)
16 else 16 else
17 - user.create_namespace!(path: user.username, name: user.name) 17 + user.create_namespace!(path: user.username, name: user.username)
18 end 18 end
19 end 19 end
20 end 20 end
app/observers/users_project_observer.rb
1 class UsersProjectObserver < ActiveRecord::Observer 1 class UsersProjectObserver < ActiveRecord::Observer
2 def after_commit(users_project) 2 def after_commit(users_project)
3 return if users_project.destroyed? 3 return if users_project.destroyed?
4 - Notify.project_access_granted_email(users_project.id).deliver 4 + Notify.delay.project_access_granted_email(users_project.id)
5 end 5 end
6 6
7 def after_create(users_project) 7 def after_create(users_project)
app/roles/account.rb
@@ -1,124 +0,0 @@ @@ -1,124 +0,0 @@
1 -module Account  
2 - # Returns a string for use as a Gitolite user identifier  
3 - #  
4 - # Note that Gitolite 2.x requires the following pattern for users:  
5 - #  
6 - # ^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$  
7 - def identifier  
8 - # Replace non-word chars with underscores, then make sure it starts with  
9 - # valid chars  
10 - email.gsub(/\W/, '_').gsub(/\A([\W\_])+/, '')  
11 - end  
12 -  
13 - def is_admin?  
14 - admin  
15 - end  
16 -  
17 - def require_ssh_key?  
18 - keys.count == 0  
19 - end  
20 -  
21 - def can_create_project?  
22 - projects_limit > my_own_projects.count  
23 - end  
24 -  
25 - def can_create_group?  
26 - is_admin?  
27 - end  
28 -  
29 - def abilities  
30 - @abilities ||= begin  
31 - abilities = Six.new  
32 - abilities << Ability  
33 - abilities  
34 - end  
35 - end  
36 -  
37 - def can? action, subject  
38 - abilities.allowed?(self, action, subject)  
39 - end  
40 -  
41 - def last_activity_project  
42 - projects.first  
43 - end  
44 -  
45 - def first_name  
46 - name.split.first unless name.blank?  
47 - end  
48 -  
49 - def cared_merge_requests  
50 - MergeRequest.where("author_id = :id or assignee_id = :id", id: self.id)  
51 - end  
52 -  
53 - def project_ids  
54 - projects.map(&:id)  
55 - end  
56 -  
57 - # Remove user from all projects and  
58 - # set blocked attribute to true  
59 - def block  
60 - users_projects.find_each do |membership|  
61 - return false unless membership.destroy  
62 - end  
63 -  
64 - self.blocked = true  
65 - save  
66 - end  
67 -  
68 - def projects_limit_percent  
69 - return 100 if projects_limit.zero?  
70 - (my_own_projects.count.to_f / projects_limit) * 100  
71 - end  
72 -  
73 - def recent_push project_id = nil  
74 - # Get push events not earlier than 2 hours ago  
75 - events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours)  
76 - events = events.where(project_id: project_id) if project_id  
77 -  
78 - # Take only latest one  
79 - events = events.recent.limit(1).first  
80 - end  
81 -  
82 - def projects_sorted_by_activity  
83 - projects.sorted_by_activity  
84 - end  
85 -  
86 - def namespaces  
87 - namespaces = []  
88 -  
89 - # Add user account namespace  
90 - namespaces << self.namespace if self.namespace  
91 -  
92 - # Add groups you can manage  
93 - namespaces += if admin  
94 - Group.all  
95 - else  
96 - groups.all  
97 - end  
98 - namespaces  
99 - end  
100 -  
101 - def several_namespaces?  
102 - namespaces.size > 1  
103 - end  
104 -  
105 - def namespace_id  
106 - namespace.try :id  
107 - end  
108 -  
109 - def authorized_groups  
110 - @authorized_groups ||= begin  
111 - groups = Group.where(id: self.projects.pluck(:namespace_id)).all  
112 - groups = groups + self.groups  
113 - groups.uniq  
114 - end  
115 - end  
116 -  
117 - def authorized_projects  
118 - Project.authorized_for(self)  
119 - end  
120 -  
121 - def my_own_projects  
122 - Project.personal(self)  
123 - end  
124 -end  
app/roles/authority.rb
@@ -1,58 +0,0 @@ @@ -1,58 +0,0 @@
1 -module Authority  
2 - # Compatible with all access rights  
3 - # Should be rewrited for new access rights  
4 - def add_access(user, *access)  
5 - access = if access.include?(:admin)  
6 - { project_access: UsersProject::MASTER }  
7 - elsif access.include?(:write)  
8 - { project_access: UsersProject::DEVELOPER }  
9 - else  
10 - { project_access: UsersProject::REPORTER }  
11 - end  
12 - opts = { user: user }  
13 - opts.merge!(access)  
14 - users_projects.create(opts)  
15 - end  
16 -  
17 - def reset_access(user)  
18 - users_projects.where(project_id: self.id, user_id: user.id).destroy if self.id  
19 - end  
20 -  
21 - def repository_readers  
22 - keys = Key.joins({user: :users_projects}).  
23 - where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::REPORTER)  
24 - keys.map(&:identifier) + deploy_keys.map(&:identifier)  
25 - end  
26 -  
27 - def repository_writers  
28 - keys = Key.joins({user: :users_projects}).  
29 - where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::DEVELOPER)  
30 - keys.map(&:identifier)  
31 - end  
32 -  
33 - def repository_masters  
34 - keys = Key.joins({user: :users_projects}).  
35 - where("users_projects.project_id = ? AND users_projects.project_access = ?", id, UsersProject::MASTER)  
36 - keys.map(&:identifier)  
37 - end  
38 -  
39 - def allow_read_for?(user)  
40 - !users_projects.where(user_id: user.id).empty?  
41 - end  
42 -  
43 - def guest_access_for?(user)  
44 - !users_projects.where(user_id: user.id).empty?  
45 - end  
46 -  
47 - def report_access_for?(user)  
48 - !users_projects.where(user_id: user.id, project_access: [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty?  
49 - end  
50 -  
51 - def dev_access_for?(user)  
52 - !users_projects.where(user_id: user.id, project_access: [UsersProject::DEVELOPER, UsersProject::MASTER]).empty?  
53 - end  
54 -  
55 - def master_access_for?(user)  
56 - !users_projects.where(user_id: user.id, project_access: [UsersProject::MASTER]).empty?  
57 - end  
58 -end