Commit 30227869482bbbdbfea153f2b45ef3bb9a9fd218
Exists in
master
and in
4 other branches
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.
.gitignore
@@ -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 |
.travis.yml
@@ -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 |
CHANGELOG
Gemfile
@@ -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 |
Gemfile.lock
@@ -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! |
Procfile
README.md
@@ -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 | + | ||
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. |
VERSION
@@ -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. |
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
@@ -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 | -} |
@@ -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
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 < BaseContext | @@ -9,16 +9,16 @@ class CommitLoadContext < 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] |
@@ -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 < BaseContext | @@ -4,7 +4,7 @@ class IssuesListContext < 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 < AdminController | @@ -3,10 +3,6 @@ class Admin::DashboardController < 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 < AdminController | @@ -12,6 +12,8 @@ class Admin::GroupsController < 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 < AdminController | @@ -65,7 +67,14 @@ class Admin::GroupsController < 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 < AdminController | @@ -10,6 +10,7 @@ class Admin::ProjectsController < 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 < AdminController | @@ -19,7 +20,7 @@ class Admin::ProjectsController < 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 < AdminController | @@ -35,6 +36,9 @@ class Admin::ProjectsController < 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 < AdminController | @@ -3,13 +3,13 @@ class Admin::UsersController < 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 < AdminController | @@ -19,9 +19,9 @@ class Admin::UsersController < 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 < AdminController | @@ -98,7 +98,7 @@ class Admin::UsersController < 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 < ActionController::Base | @@ -76,6 +76,12 @@ class ApplicationController < 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 < ProjectResourceController | @@ -9,10 +9,10 @@ class CommitsController < 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 < ApplicationController | @@ -20,7 +20,7 @@ class DashboardController < 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 < ApplicationController | @@ -36,14 +36,14 @@ class DashboardController < 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 < ApplicationController | @@ -60,25 +60,7 @@ class DashboardController < 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 < ApplicationController | @@ -21,15 +21,16 @@ class GroupsController < 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 < ApplicationController | @@ -44,6 +45,7 @@ class GroupsController < 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 < ApplicationController | @@ -53,9 +55,16 @@ class GroupsController < 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 < ApplicationController | @@ -63,7 +72,7 @@ class GroupsController < 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 < ProjectResourceController | @@ -74,6 +74,8 @@ class MergeRequestsController < 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 < ProjectResourceController | @@ -88,12 +90,12 @@ class MergeRequestsController < 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
app/controllers/projects_controller.rb
@@ -2,6 +2,7 @@ require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder') | @@ -2,6 +2,7 @@ require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder') | ||
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 < ProjectResourceController | @@ -58,7 +59,7 @@ class ProjectsController < 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 < ProjectResourceController | @@ -102,11 +103,10 @@ class ProjectsController < 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 < ProjectResourceController | @@ -12,7 +12,7 @@ class RefsController < 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 < ProjectResourceController | @@ -31,7 +31,7 @@ class RefsController < 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 < ProjectResourceController | @@ -45,10 +45,10 @@ class RefsController < 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 < ProjectResourceController | @@ -5,19 +5,19 @@ class RepositoriesController < 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 < ProjectResourceController | @@ -27,7 +27,7 @@ class RepositoriesController < 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 < ProjectResourceController | @@ -26,7 +26,7 @@ class ServicesController < 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 < ProjectResourceController | @@ -16,7 +16,7 @@ class SnippetsController < 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 < ProjectResourceController | @@ -16,10 +16,9 @@ class TeamMembersController < 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 < ProjectResourceController | @@ -50,7 +49,7 @@ class TeamMembersController < 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 < ProjectResourceController | @@ -22,7 +22,7 @@ class TreeController < 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 < ApplicationDecorator | @@ -6,16 +6,14 @@ class TreeDecorator < 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 < ApplicationDecorator | @@ -26,7 +24,7 @@ class TreeDecorator < 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 | + " " | ||
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 |
@@ -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 < ActionMailer::Base | @@ -87,7 +88,7 @@ class Notify < 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 < ActionMailer::Base | @@ -147,12 +148,15 @@ class Notify < 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. |
@@ -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 < ActiveRecord::Base | @@ -113,26 +110,6 @@ class Event < 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 < ActiveRecord::Base | @@ -170,4 +147,143 @@ class Event < 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 < Service | @@ -23,20 +23,12 @@ class GitlabCiService < 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 < Namespace | @@ -21,4 +29,8 @@ class Group < 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
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 < ActiveRecord::Base | @@ -29,7 +29,7 @@ class Milestone < 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 < ActiveRecord::Base | @@ -58,7 +58,13 @@ class Milestone < 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 < ActiveRecord::Base | @@ -27,10 +27,13 @@ class Namespace < 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 < ActiveRecord::Base | @@ -48,8 +51,17 @@ class Namespace < 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 < ActiveRecord::Base | @@ -59,16 +71,25 @@ class Namespace < 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 < ActiveRecord::Base | @@ -41,11 +42,11 @@ class Note < 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 < ActiveRecord::Base | @@ -126,7 +127,7 @@ class Note < 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 < ActiveRecord::Base | @@ -40,10 +36,10 @@ class Project < 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 < ActiveRecord::Base | @@ -62,9 +58,11 @@ class Project < 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 < ActiveRecord::Base | @@ -77,19 +75,14 @@ class Project < 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 < ActiveRecord::Base | @@ -101,8 +94,10 @@ class Project < 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 < ActiveRecord::Base | @@ -122,7 +117,7 @@ class Project < 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 < ActiveRecord::Base | @@ -162,6 +157,20 @@ class Project < 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 < ActiveRecord::Base | @@ -171,8 +180,8 @@ class Project < 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 < ActiveRecord::Base | @@ -198,30 +207,10 @@ class Project < 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 < ActiveRecord::Base | @@ -262,7 +251,282 @@ class Project < 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 < ActiveRecord::Base | @@ -22,10 +22,10 @@ class ProtectedBranch < 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 |
@@ -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 < ActiveRecord::Base | @@ -20,4 +20,8 @@ class Service < 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 < WebHook | @@ -19,6 +19,6 @@ class SystemHook < 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 |
@@ -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 < ActiveRecord::Base | @@ -51,7 +49,6 @@ class User < 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 < ActiveRecord::Base | @@ -70,6 +67,8 @@ class User < 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 < ActiveRecord::Base | @@ -77,11 +76,14 @@ class User < 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 < ActiveRecord::Base | @@ -93,6 +95,14 @@ class User < 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 < ActiveRecord::Base | @@ -118,9 +128,158 @@ class User < 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 < ActiveRecord::Base | @@ -23,87 +23,96 @@ class UsersProject < 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 < ActiveRecord::Base | @@ -116,12 +125,8 @@ class UsersProject < 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 < ActiveRecord::Base | @@ -131,4 +136,8 @@ class UsersProject < 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
app/observers/issue_observer.rb
@@ -3,7 +3,7 @@ class IssueObserver < ActiveRecord::Observer | @@ -3,7 +3,7 @@ class IssueObserver < 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 < ActiveRecord::Observer | @@ -16,7 +16,7 @@ class IssueObserver < 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 < ActiveRecord::Observer | @@ -27,7 +27,7 @@ class IssueObserver < 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 < ActiveRecord::Observer | @@ -3,7 +3,7 @@ class MergeRequestObserver < 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 < ActiveRecord::Observer | @@ -25,7 +25,7 @@ class MergeRequestObserver < 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 < ActiveRecord::Observer | @@ -11,7 +11,7 @@ class NoteObserver < 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 < ActiveRecord::Observer | @@ -26,7 +26,7 @@ class NoteObserver < 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 < ActiveRecord::Observer | @@ -2,7 +2,7 @@ class UserObserver < 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 < ActiveRecord::Observer | @@ -14,7 +14,7 @@ class UserObserver < 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 |