Commit c9a27655 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch '6-2-stable' of dev.gitlab.org:gitlab/gitlabhq into upstream/6-2-stable

Conflicts:
	VERSION
	app/models/group.rb
	app/views/groups/edit.html.haml
	db/schema.rb
	doc/api/groups.md
	doc/api/projects.md
	doc/install/installation.md
	lib/api/projects.rb
	spec/requests/api/groups_spec.rb
	spec/requests/api/projects_spec.rb
parents a430680a 9c3e95f6
...@@ -20,6 +20,7 @@ Vagrantfile ...@@ -20,6 +20,7 @@ Vagrantfile
config/gitlab.yml config/gitlab.yml
config/database.yml config/database.yml
config/initializers/omniauth.rb config/initializers/omniauth.rb
config/initializers/rack_attack.rb
config/unicorn.rb config/unicorn.rb
config/resque.yml config/resque.yml
config/aws.yml config/aws.yml
......
...@@ -8,7 +8,6 @@ branches: ...@@ -8,7 +8,6 @@ branches:
only: only:
- 'master' - 'master'
rvm: rvm:
- 1.9.3-p392
- 2.0.0 - 2.0.0
services: services:
- mysql - mysql
...@@ -16,7 +15,4 @@ services: ...@@ -16,7 +15,4 @@ services:
before_script: before_script:
- "cp config/database.yml.$DB config/database.yml" - "cp config/database.yml.$DB config/database.yml"
- "cp config/gitlab.yml.example config/gitlab.yml" - "cp config/gitlab.yml.example config/gitlab.yml"
- "bundle exec rake db:setup RAILS_ENV=test" script: "bundle exec rake gitlab:test --trace"
- "bundle exec rake db:seed_fu RAILS_ENV=test"
- "sh -e /etc/init.d/xvfb start"
script: "bundle exec rake travis --trace"
v 6.2.0
- Public project pages are now visible to everyone (files, issues, wik, etc.)
THIS MEANS YOUR ISSUES AND WIKI FOR PUBLIC PROJECTS ARE PUBLICLY VISIBLE AFTER THE UPGRADE
- Add group access to permissions page
- Require current password to change one
- Group owner or admin can remove other group owners
- Remove group transfer since we have multiple owners
- Respect authorization in Repository API
- Improve UI for Project#files page
- Add more security specs
- Added search for projects by name to api (Izaak Alpert)
- Make default user theme configurable (Izaak Alpert)
- Update logic for validates_merge_request for tree of MR (Andrew Kumanyaev)
- Rake tasks for web hooks management (Jonhnny Weslley)
- Extended User API to expose admin and can_create_group for user creation/updating (Boyan Tabakov)
- API: Remove group
- API: Remove project
- Avatar upload on profile page with a maximum of 200KB (Steven Thonus)
- Store the sessions in Redis instead of the cookie store
- Fixed relative links in markdown
- User must confirm his email if signup enabled
- User must confirm changed email
v 6.1.0 v 6.1.0
- Project specific IDs for issues, mr, milestones - Project specific IDs for issues, mr, milestones
Above items will get a new id and for example all bookmarked issue urls will change. Above items will get a new id and for example all bookmarked issue urls will change.
......
...@@ -16,6 +16,7 @@ gem "pg", group: :postgres ...@@ -16,6 +16,7 @@ gem "pg", group: :postgres
# Auth # Auth
gem "devise", '~> 2.2' gem "devise", '~> 2.2'
gem "devise-async"
gem 'omniauth', "~> 1.1.3" gem 'omniauth', "~> 1.1.3"
gem 'omniauth-google-oauth2' gem 'omniauth-google-oauth2'
gem 'omniauth-twitter' gem 'omniauth-twitter'
...@@ -23,7 +24,7 @@ gem 'omniauth-github' ...@@ -23,7 +24,7 @@ gem 'omniauth-github'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", '2.3.1' gem "gitlab_git", "~> 3.0.0.rc2"
# Ruby/Rack Git Smart-HTTP Server Handler # Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 1.0.1', require: 'grack' gem 'gitlab-grack', '~> 1.0.1', require: 'grack'
...@@ -112,6 +113,9 @@ gem 'tinder', '~> 1.9.2' ...@@ -112,6 +113,9 @@ gem 'tinder', '~> 1.9.2'
# HipChat integration # HipChat integration
gem "hipchat", "~> 0.9.0" gem "hipchat", "~> 0.9.0"
# Flowdock integration
gem "gitlab-flowdock-git-hook", "~> 0.4.2"
# d3 # d3
gem "d3_rails", "~> 3.1.4" gem "d3_rails", "~> 3.1.4"
...@@ -121,6 +125,9 @@ gem "underscore-rails", "~> 1.4.4" ...@@ -121,6 +125,9 @@ gem "underscore-rails", "~> 1.4.4"
# Sanitize user input # Sanitize user input
gem "sanitize" gem "sanitize"
# Protect against bruteforcing
gem "rack-attack"
group :assets do group :assets do
gem "sass-rails" gem "sass-rails"
gem "coffee-rails" gem "coffee-rails"
...@@ -143,10 +150,11 @@ group :assets do ...@@ -143,10 +150,11 @@ group :assets do
end end
group :development do group :development do
gem "annotate", git: "https://github.com/ctran/annotate_models.git" gem "annotate", "~> 2.6.0.beta2"
gem "letter_opener" gem "letter_opener"
gem 'quiet_assets', '~> 1.0.1' gem 'quiet_assets', '~> 1.0.1'
gem 'rack-mini-profiler' gem 'rack-mini-profiler'
# Better errors handler # Better errors handler
gem 'better_errors' gem 'better_errors'
gem 'binding_of_caller' gem 'binding_of_caller'
......
GIT
remote: https://github.com/ctran/annotate_models.git
revision: 18a4e2eb77c8f3ef695b563e4a7ca45dfede819b
specs:
annotate (2.6.0.beta2)
activerecord (>= 2.3.0)
rake (>= 0.8.7)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
...@@ -39,17 +31,20 @@ GEM ...@@ -39,17 +31,20 @@ GEM
acts-as-taggable-on (2.4.1) acts-as-taggable-on (2.4.1)
rails (>= 3, < 5) rails (>= 3, < 5)
addressable (2.3.4) addressable (2.3.4)
annotate (2.6.0.beta2)
activerecord (>= 2.3.0)
rake (>= 0.8.7)
arel (3.0.2) arel (3.0.2)
asciidoctor (0.1.3) asciidoctor (0.1.3)
awesome_print (1.1.0) awesome_print (1.2.0)
backports (3.3.2) backports (3.3.2)
bcrypt-ruby (3.1.1) bcrypt-ruby (3.1.1)
better_errors (0.9.0) better_errors (1.0.1)
coderay (>= 1.0.0) coderay (>= 1.0.0)
erubis (>= 2.6.6) erubis (>= 2.6.6)
binding_of_caller (0.7.2) binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
bootstrap-sass (2.3.2.0) bootstrap-sass (2.3.2.2)
sass (~> 3.2) sass (~> 3.2)
builder (3.0.4) builder (3.0.4)
capybara (2.1.0) capybara (2.1.0)
...@@ -73,7 +68,7 @@ GEM ...@@ -73,7 +68,7 @@ GEM
sass-rails (>= 3.2) sass-rails (>= 3.2)
chunky_png (1.2.8) chunky_png (1.2.8)
cliver (0.2.1) cliver (0.2.1)
code_analyzer (0.3.2) code_analyzer (0.4.3)
sexp_processor sexp_processor
coderay (1.0.9) coderay (1.0.9)
coffee-rails (3.2.2) coffee-rails (3.2.2)
...@@ -92,11 +87,11 @@ GEM ...@@ -92,11 +87,11 @@ GEM
compass-rails (1.0.3) compass-rails (1.0.3)
compass (>= 0.12.2, < 0.14) compass (>= 0.12.2, < 0.14)
connection_pool (1.1.0) connection_pool (1.1.0)
coveralls (0.6.7) coveralls (0.7.0)
colorize
multi_json (~> 1.3) multi_json (~> 1.3)
rest-client rest-client
simplecov (>= 0.7) simplecov (>= 0.7)
term-ansicolor
thor thor
crack (0.4.0) crack (0.4.0)
safe_yaml (~> 0.9.0) safe_yaml (~> 0.9.0)
...@@ -111,6 +106,8 @@ GEM ...@@ -111,6 +106,8 @@ GEM
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (~> 3.1) railties (~> 3.1)
warden (~> 1.2.1) warden (~> 1.2.1)
devise-async (0.8.0)
devise (>= 2.2, < 3.2)
diff-lcs (1.2.4) diff-lcs (1.2.4)
dotenv (0.8.0) dotenv (0.8.0)
email_spec (1.4.0) email_spec (1.4.0)
...@@ -133,7 +130,7 @@ GEM ...@@ -133,7 +130,7 @@ GEM
multipart-post (~> 1.1) multipart-post (~> 1.1)
faraday_middleware (0.9.0) faraday_middleware (0.9.0)
faraday (>= 0.7.4, < 0.9) faraday (>= 0.7.4, < 0.9)
ffaker (1.16.1) ffaker (1.18.0)
ffi (1.9.0) ffi (1.9.0)
fog (1.3.1) fog (1.3.1)
builder builder
...@@ -145,7 +142,7 @@ GEM ...@@ -145,7 +142,7 @@ GEM
net-ssh (>= 2.1.3) net-ssh (>= 2.1.3)
nokogiri (~> 1.5.0) nokogiri (~> 1.5.0)
ruby-hmac ruby-hmac
font-awesome-rails (3.2.1.2) font-awesome-rails (3.2.1.3)
railties (>= 3.2, < 5.0) railties (>= 3.2, < 5.0)
foreman (0.63.0) foreman (0.63.0)
dotenv (>= 0.7) dotenv (>= 0.7)
...@@ -161,6 +158,9 @@ GEM ...@@ -161,6 +158,9 @@ GEM
pygments.rb (>= 0.2.13) pygments.rb (>= 0.2.13)
github-markdown (0.5.3) github-markdown (0.5.3)
github-markup (0.7.5) github-markup (0.7.5)
gitlab-flowdock-git-hook (0.4.2.2)
gitlab-grit (>= 2.4.1)
multi_json
gitlab-gollum-lib (1.0.1) gitlab-gollum-lib (1.0.1)
github-markdown (~> 0.5.3) github-markdown (~> 0.5.3)
github-markup (>= 0.7.5, < 1.0.0) github-markup (>= 0.7.5, < 1.0.0)
...@@ -171,7 +171,7 @@ GEM ...@@ -171,7 +171,7 @@ GEM
stringex (~> 1.5.1) stringex (~> 1.5.1)
gitlab-grack (1.0.1) gitlab-grack (1.0.1)
rack (~> 1.4.1) rack (~> 1.4.1)
gitlab-grit (2.6.0) gitlab-grit (2.6.1)
charlock_holmes (~> 0.6.9) charlock_holmes (~> 0.6.9)
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (~> 1.15) mime-types (~> 1.15)
...@@ -179,10 +179,10 @@ GEM ...@@ -179,10 +179,10 @@ GEM
gitlab-pygments.rb (0.3.2) gitlab-pygments.rb (0.3.2)
posix-spawn (~> 0.3.6) posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0) yajl-ruby (~> 1.1.0)
gitlab_git (2.3.1) gitlab_git (3.0.0.rc2)
activesupport (~> 3.2.13) activesupport (~> 3.2.13)
github-linguist (~> 2.3.4) github-linguist (~> 2.3.4)
gitlab-grit (~> 2.6.0) gitlab-grit (~> 2.6.1)
gitlab_meta (6.0) gitlab_meta (6.0)
gitlab_omniauth-ldap (1.0.3) gitlab_omniauth-ldap (1.0.3)
net-ldap (~> 0.3.1) net-ldap (~> 0.3.1)
...@@ -278,7 +278,7 @@ GEM ...@@ -278,7 +278,7 @@ GEM
minitest (4.7.4) minitest (4.7.4)
modernizr (2.6.2) modernizr (2.6.2)
sprockets (~> 2.0) sprockets (~> 2.0)
multi_json (1.7.9) multi_json (1.8.0)
multi_xml (0.5.4) multi_xml (0.5.4)
multipart-post (1.2.0) multipart-post (1.2.0)
mysql2 (0.3.11) mysql2 (0.3.11)
...@@ -334,9 +334,11 @@ GEM ...@@ -334,9 +334,11 @@ GEM
rack (1.4.5) rack (1.4.5)
rack-accept (0.4.5) rack-accept (0.4.5)
rack (>= 0.4) rack (>= 0.4)
rack-attack (2.2.1)
rack
rack-cache (1.2) rack-cache (1.2)
rack (>= 0.4) rack (>= 0.4)
rack-mini-profiler (0.1.26) rack-mini-profiler (0.1.31)
rack (>= 1.1.3) rack (>= 1.1.3)
rack-mount (0.8.3) rack-mount (0.8.3)
rack (>= 1.0.0) rack (>= 1.0.0)
...@@ -357,13 +359,14 @@ GEM ...@@ -357,13 +359,14 @@ GEM
rails-dev-tweaks (0.6.1) rails-dev-tweaks (0.6.1)
actionpack (~> 3.1) actionpack (~> 3.1)
railties (~> 3.1) railties (~> 3.1)
rails_best_practices (1.13.8) rails_best_practices (1.14.4)
activesupport activesupport
awesome_print awesome_print
code_analyzer code_analyzer (>= 0.4.3)
colored colored
erubis erubis
i18n i18n
require_all
ruby-progressbar ruby-progressbar
railties (3.2.13) railties (3.2.13)
actionpack (= 3.2.13) actionpack (= 3.2.13)
...@@ -403,6 +406,7 @@ GEM ...@@ -403,6 +406,7 @@ GEM
redis-store (1.1.4) redis-store (1.1.4)
redis (>= 2.2) redis (>= 2.2)
ref (1.0.5) ref (1.0.5)
require_all (1.3.1)
rest-client (1.6.7) rest-client (1.6.7)
mime-types (>= 1.16) mime-types (>= 1.16)
rspec (2.13.0) rspec (2.13.0)
...@@ -427,7 +431,7 @@ GEM ...@@ -427,7 +431,7 @@ GEM
safe_yaml (0.9.3) safe_yaml (0.9.3)
sanitize (2.0.3) sanitize (2.0.3)
nokogiri (>= 1.4.4, < 1.6) nokogiri (>= 1.4.4, < 1.6)
sass (3.2.9) sass (3.2.11)
sass-rails (3.2.6) sass-rails (3.2.6)
railties (~> 3.2.0) railties (~> 3.2.0)
sass (>= 3.1.10) sass (>= 3.1.10)
...@@ -447,7 +451,7 @@ GEM ...@@ -447,7 +451,7 @@ GEM
rubyzip rubyzip
websocket (~> 1.0.4) websocket (~> 1.0.4)
settingslogic (2.0.9) settingslogic (2.0.9)
sexp_processor (4.2.1) sexp_processor (4.3.0)
shoulda-matchers (2.1.0) shoulda-matchers (2.1.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
sidekiq (2.14.0) sidekiq (2.14.0)
...@@ -487,7 +491,9 @@ GEM ...@@ -487,7 +491,9 @@ GEM
state_machine (1.2.0) state_machine (1.2.0)
stringex (1.5.1) stringex (1.5.1)
temple (0.6.5) temple (0.6.5)
test_after_commit (0.2.0) term-ansicolor (1.2.2)
tins (~> 0.8)
test_after_commit (0.2.1)
therubyracer (0.11.4) therubyracer (0.11.4)
libv8 (~> 3.11.8.12) libv8 (~> 3.11.8.12)
ref ref
...@@ -507,6 +513,7 @@ GEM ...@@ -507,6 +513,7 @@ GEM
mime-types (~> 1.19) mime-types (~> 1.19)
multi_json (~> 1.5) multi_json (~> 1.5)
twitter-stream (~> 0.1) twitter-stream (~> 0.1)
tins (0.11.0)
treetop (1.4.14) treetop (1.4.14)
polyglot polyglot
polyglot (>= 0.3.1) polyglot (>= 0.3.1)
...@@ -544,7 +551,7 @@ PLATFORMS ...@@ -544,7 +551,7 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
acts-as-taggable-on acts-as-taggable-on
annotate! annotate (~> 2.6.0.beta2)
asciidoctor asciidoctor
awesome_print awesome_print
better_errors better_errors
...@@ -559,6 +566,7 @@ DEPENDENCIES ...@@ -559,6 +566,7 @@ DEPENDENCIES
d3_rails (~> 3.1.4) d3_rails (~> 3.1.4)
database_cleaner database_cleaner
devise (~> 2.2) devise (~> 2.2)
devise-async
email_spec email_spec
enumerize enumerize
factory_girl_rails factory_girl_rails
...@@ -569,10 +577,11 @@ DEPENDENCIES ...@@ -569,10 +577,11 @@ DEPENDENCIES
gemoji (~> 1.2.1) gemoji (~> 1.2.1)
github-linguist github-linguist
github-markup (~> 0.7.4) github-markup (~> 0.7.4)
gitlab-flowdock-git-hook (~> 0.4.2)
gitlab-gollum-lib (~> 1.0.1) gitlab-gollum-lib (~> 1.0.1)
gitlab-grack (~> 1.0.1) gitlab-grack (~> 1.0.1)
gitlab-pygments.rb (~> 0.3.2) gitlab-pygments.rb (~> 0.3.2)
gitlab_git (= 2.3.1) gitlab_git (~> 3.0.0.rc2)
gitlab_meta (= 6.0) gitlab_meta (= 6.0)
gitlab_omniauth-ldap (= 1.0.3) gitlab_omniauth-ldap (= 1.0.3)
gon gon
...@@ -604,6 +613,7 @@ DEPENDENCIES ...@@ -604,6 +613,7 @@ DEPENDENCIES
poltergeist (~> 1.4.1) poltergeist (~> 1.4.1)
pry pry
quiet_assets (~> 1.0.1) quiet_assets (~> 1.0.1)
rack-attack
rack-mini-profiler rack-mini-profiler
rails (= 3.2.13) rails (= 3.2.13)
rails-dev-tweaks rails-dev-tweaks
......
...@@ -127,14 +127,17 @@ or start each component separately ...@@ -127,14 +127,17 @@ or start each component separately
### GitLab interfaces ### GitLab interfaces
* [GitLab API](doc/api/README.md) * [GitLab API doc](doc/api/README.md) or see the [GitLab API website](http://api.gitlab.org/)
* [Rake tasks](doc/raketasks) * [Rake tasks](doc/raketasks) including a [backup and restore procedure](doc/raketasks/backup_restore.md)
* [Directory structure](doc/install/structure.md) * [Directory structure](doc/install/structure.md)
* [Databases](doc/install/databases.md) * [Database installation](doc/install/databases.md)
* [Markdown specification](doc/markdown/markdown.md)
* [Security guide](doc/security/rack_attack.md) to throttle abusive requests
### Getting help ### Getting help
...@@ -157,10 +160,8 @@ or start each component separately ...@@ -157,10 +160,8 @@ or start each component separately
### Getting in touch ### Getting in touch
* [Core team](https://github.com/gitlabhq?tab=members) * [Core team](http://gitlab.org/team/)
* [Contributors](https://github.com/gitlabhq/gitlabhq/graphs/contributors)
* [Leader](https://github.com/randx) * [Contributors](http://contributors.gitlab.org/)
* [Contact page](http://gitlab.org/contact/) * [Community](http://gitlab.org/community/)
...@@ -16,3 +16,13 @@ $ -> ...@@ -16,3 +16,13 @@ $ ->
$('.update-notifications').on 'ajax:complete', -> $('.update-notifications').on 'ajax:complete', ->
$(this).find('.btn-save').enableButton() $(this).find('.btn-save').enableButton()
$('.js-choose-user-avatar-button').bind "click", ->
form = $(this).closest("form")
form.find(".js-user-avatar-input").click()
$('.js-user-avatar-input').bind "change", ->
form = $(this).closest("form")
filename = $(this).val().replace(/^.*[\\\/]/, '')
form.find(".js-avatar-filename").text(filename)
$ -> $ ->
userFormatResult = (user) -> userFormatResult = (user) ->
avatar = gon.gravatar_url if user.avatar
avatar = avatar.replace('%{hash}', md5(user.email)) avatar = user.avatar.url
avatar = avatar.replace('%{size}', '24') else
avatar = gon.gravatar_url
avatar = avatar.replace('%{hash}', md5(user.email))
avatar = avatar.replace('%{size}', '24')
markup = "<div class='user-result'>" markup = "<div class='user-result'>"
markup += "<div class='user-image'><img class='avatar s24' src='" + avatar + "'></div>" markup += "<div class='user-image'><img class='avatar s24' src='" + avatar + "'></div>"
markup += "<div class='user-name'>" + user.name + "</div>" markup += "<div class='user-name'>" + user.name + "</div>"
......
...@@ -140,27 +140,6 @@ p.time { ...@@ -140,27 +140,6 @@ p.time {
border-bottom: 2px solid #F90; border-bottom: 2px solid #F90;
} }
.status_info {
font-size: 14px;
padding: 5px 15px;
line-height: 26px;
text-align: center;
float: right;
position: relative;
top: -5px;
@include border-radius(4px);
&.success {
background: #4A4;
color: #FFF;
}
&.error {
background: #DA4E49;
color: #FFF;
}
}
.thin_area{ .thin_area{
height: 150px; height: 150px;
} }
...@@ -270,27 +249,6 @@ li.note { ...@@ -270,27 +249,6 @@ li.note {
} }
} }
.oauth_select_holder {
padding: 20px;
img {
padding: 5px;
margin-right: 10px;
}
.active {
img {
border: 1px solid #ccc;
background: $hover;
@include border-radius(5px);
}
}
}
.btn-build-token {
float: left;
padding: 6px 20px;
margin-right: 12px;
}
.gitlab-promo { .gitlab-promo {
a { a {
color: #aaa; color: #aaa;
...@@ -386,3 +344,8 @@ table { ...@@ -386,3 +344,8 @@ table {
width: 50px; width: 50px;
min-height: 100px; min-height: 100px;
} }
.navbar-gitlab .navbar-inner .nav > li .btn-sign-in {
@extend .btn-new;
padding: 5px 15px;
}
...@@ -62,6 +62,5 @@ $baseLineHeight: 18px !default; ...@@ -62,6 +62,5 @@ $baseLineHeight: 18px !default;
@import "gitlab_bootstrap/buttons.scss"; @import "gitlab_bootstrap/buttons.scss";
@import "gitlab_bootstrap/blocks.scss"; @import "gitlab_bootstrap/blocks.scss";
@import "gitlab_bootstrap/files.scss"; @import "gitlab_bootstrap/files.scss";
@import "gitlab_bootstrap/tables.scss";
@import "gitlab_bootstrap/lists.scss"; @import "gitlab_bootstrap/lists.scss";
@import "gitlab_bootstrap/forms.scss"; @import "gitlab_bootstrap/forms.scss";
...@@ -19,4 +19,5 @@ ...@@ -19,4 +19,5 @@
&.s32 { width: 32px; height: 32px; margin-right: 10px; } &.s32 { width: 32px; height: 32px; margin-right: 10px; }
&.s60 { width: 60px; height: 60px; margin-right: 12px; } &.s60 { width: 60px; height: 60px; margin-right: 12px; }
&.s90 { width: 90px; height: 90px; margin-right: 15px; } &.s90 { width: 90px; height: 90px; margin-right: 15px; }
&.s160 { width: 160px; height: 160px; margin-right: 20px; }
} }
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
.ui-box { .ui-box {
background: #FFF; background: #FFF;
margin-bottom: 20px; margin-bottom: 20px;
border: 1px solid #CCC; border: 1px solid #DDD;
word-wrap: break-word; word-wrap: break-word;
&.small-box { &.small-box {
...@@ -32,8 +32,12 @@ ...@@ -32,8 +32,12 @@
} }
&.ui-box-show { &.ui-box-show {
text-shadow: 0 1px 1px #fff;
color: #666;
margin:20px 0; margin:20px 0;
background: #FFF; background: #FFF;
box-shadow: inset 0 1px 0 #fff, 0 1px 5px #f1f1f1;
@include linear-gradient(#fafafa, #f1f1f1);
.control-group { .control-group {
margin-bottom: 0; margin-bottom: 0;
...@@ -69,7 +73,6 @@ ...@@ -69,7 +73,6 @@
.ui-box-head { .ui-box-head {
.box-title { .box-title {
color: $style_color;
font-size: 18px; font-size: 18px;
font-weight: normal; font-weight: normal;
line-height: 28px; line-height: 28px;
......
...@@ -87,3 +87,25 @@ pre.well-pre { ...@@ -87,3 +87,25 @@ pre.well-pre {
font-weight: bold; font-weight: bold;
@include box-shadow(inset 0 2px 4px rgba(0,0,0,.15)); @include box-shadow(inset 0 2px 4px rgba(0,0,0,.15));
} }
/** Big Labels **/
.state-label {
font-size: 14px;
padding: 5px 15px;
text-align: center;
float: right;
position: relative;
top: -5px;
@include border-radius(4px);
text-shadow: none;
&.state-label-green {
background: #4A4;
color: #FFF;
}
&.state-label-red {
background: #DA4E49;
color: #FFF;
}
}
...@@ -6,6 +6,10 @@ ...@@ -6,6 +6,10 @@
border: 1px solid #CCC; border: 1px solid #CCC;
margin-bottom: 1em; margin-bottom: 1em;
table {
@extend .table;
}
.file-title { .file-title {
border-bottom: 1px solid #bbb; border-bottom: 1px solid #bbb;
@include bg-dark-gray-gradient; @include bg-dark-gray-gradient;
...@@ -65,6 +69,12 @@ ...@@ -65,6 +69,12 @@
} }
&.blob-no-preview {
background: #eee;
text-shadow: 0 1px 2px #FFF;
padding: 100px 0;
}
/** /**
* Blame file * Blame file
*/ */
......
...@@ -95,6 +95,14 @@ ...@@ -95,6 +95,14 @@
font-size: 14px; font-size: 14px;
line-height: 1.5; line-height: 1.5;
} }
table {
@extend .table;
@extend .table-bordered;
th {
background: #EEE;
}
}
} }
@mixin page-title { @mixin page-title {
......
table {
@extend .table;
@extend .table-striped;
border: 1px solid #CCC;
width: 100%;
&.low {
td {
line-height: 18px;
}
}
&.headless {
tr:first-child td{
border-top: 1px solid #CCC;
}
}
th {
font-weight: bold;
vertical-align: middle;
border-bottom: 1px solid #CCC;
text-shadow: 0 1px 1px #fff;
@include bg-dark-gray-gradient;
ul.nav {
text-shadow: none;
margin: 0;
}
}
th, td {
padding: 10px;
line-height: 18px;
text-align: left;
}
td {
border-color: #f1f1f1;
line-height: 28px;
.s16 {
margin-top: 5px;
margin-right: 5px;
}
&:first-child {
border-left: 1px solid #CCC;
}
&:last-child {
border-right: 1px solid #CCC;
}
}
&.bordered {
@extend .table-bordered;
}
&.lite {
border: none;
box-shadow: none;
tr, td {
border: none;
background:none !important;
}
}
}
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
} }
table { table {
width: 100%;
font-family: $monospace_font; font-family: $monospace_font;
border: none; border: none;
margin: 0px; margin: 0px;
...@@ -418,7 +419,6 @@ ...@@ -418,7 +419,6 @@
.commit-title { .commit-title {
margin: 0; margin: 0;
font-size: 20px; font-size: 20px;
font-weight: bold;
} }
.commit-description { .commit-description {
......
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
} }
a { a {
border-color: #CCC !important; border-color: #DDD !important;
} }
} }
} }
...@@ -85,12 +85,18 @@ ...@@ -85,12 +85,18 @@
color: #666; color: #666;
} }
.last-activity, .owner-info { .last-activity {
color: #AAA; color: #AAA;
display: block; display: block;
margin-top: 5px; margin-top: 5px;
.date, .owner { .date {
color: #777; color: #777;
} }
} }
} }
.group-row {
.arrow {
padding: 2px 5px;
}
}
...@@ -46,8 +46,8 @@ ...@@ -46,8 +46,8 @@
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
.event-title { .event-title {
color: #333; color: #333;
font-weight: bold; font-weight: normal;
font-size: 14px; font-size: 15px;
.author_name { .author_name {
color: #333; color: #333;
} }
......
/* Login Page */ /* Login Page */
body.login-page{ body.login-page{
background: #474D57; .container > .content {
.container .content { padding-top: 4%; } padding-top: 20px;
}
} }
.login-box{ .login-box{
......
...@@ -135,11 +135,15 @@ ul.notes { ...@@ -135,11 +135,15 @@ ul.notes {
background-color: $white; background-color: $white;
border-width: 1px 0; border-width: 1px 0;
padding-top: 0; padding-top: 0;
li {
padding: 5px;
}
} }
} }
.reply-btn { .reply-btn {
margin-top: 8px; margin: 5px;
} }
} }
......
...@@ -4,3 +4,41 @@ ...@@ -4,3 +4,41 @@
margin-bottom: 0; margin-bottom: 0;
} }
} }
.account-page {
fieldset {
margin-bottom: 15px;
border-bottom: 1px dashed #ddd;
padding-bottom: 15px;
&:last-child {
border: none;
}
legend {
border: none;
margin: 0;
}
}
}
.oauth_select_holder {
img {
padding: 2px;
margin-right: 10px;
}
.active {
img {
border: 1px solid #4BD;
background: $hover;
@include border-radius(5px);
}
}
}
.btn-build-token {
float: left;
padding: 6px 20px;
margin-right: 12px;
}
...@@ -79,21 +79,6 @@ ul.nav.nav-projects-tabs { ...@@ -79,21 +79,6 @@ ul.nav.nav-projects-tabs {
margin: 0px; margin: 0px;
} }
.public-projects {
li {
.project-title {
font-size: 14px;
line-height: 2;
font-weight: normal;
}
.description {
margin-left: 15px;
color: #aaa;
}
}
}
.my-projects { .my-projects {
li { li {
.project-title { .project-title {
...@@ -110,7 +95,6 @@ ul.nav.nav-projects-tabs { ...@@ -110,7 +95,6 @@ ul.nav.nav-projects-tabs {
} }
} }
.public-clone { .public-clone {
background: #333; background: #333;
color: #f5f5f5; color: #f5f5f5;
...@@ -123,3 +107,11 @@ ul.nav.nav-projects-tabs { ...@@ -123,3 +107,11 @@ ul.nav.nav-projects-tabs {
position: relative; position: relative;
top: -5px; top: -5px;
} }
.public-projects .repo-info {
color: #777;
a {
color: #777;
}
}
...@@ -13,13 +13,21 @@ ...@@ -13,13 +13,21 @@
} }
.tree-table { .tree-table {
@extend .table;
@include border-radius(0); @include border-radius(0);
.tree-item {
td { tr {
td, th {
padding: 8px 10px; padding: 8px 10px;
strong { line-height: 20px;
font-weight: normal; }
} th {
font-weight: normal;
font-size: 15px;
border-bottom: 1px solid #CCC;
}
td {
border-color: #F1F1F1;
} }
&:hover { &:hover {
td { td {
...@@ -29,12 +37,11 @@ ...@@ -29,12 +37,11 @@
} }
cursor: pointer; cursor: pointer;
} }
&.selected { &.selected {
td { td {
background: $hover; background: #f5f5f5;
border-top: 1px solid #ADF; border-top: 1px solid #EEE;
border-bottom: 1px solid #ADF; border-bottom: 1px solid #EEE;
} }
} }
} }
...@@ -56,24 +63,8 @@ ...@@ -56,24 +63,8 @@
} }
} }
.tree-table {
th .btn {
margin: -2px -1px;
padding: 2px 10px;
}
td {
line-height: 20px;
background: #fafafa;
}
}
.tree_author { .tree_author {
padding-right: 8px; padding-right: 8px;
img.avatar {
margin-top: 0;
width: 16px;
}
} }
.tree_commit { .tree_commit {
......
...@@ -13,7 +13,7 @@ class SearchContext ...@@ -13,7 +13,7 @@ class SearchContext
projects = Project.where(id: project_ids) projects = Project.where(id: project_ids)
result[:projects] = projects.search(query).limit(20) result[:projects] = projects.search(query).limit(20)
# Search inside singe project # Search inside single project
project = projects.first if projects.length == 1 project = projects.first if projects.length == 1
if params[:search_code].present? if params[:search_code].present?
......
...@@ -20,9 +20,9 @@ class Admin::GroupsController < Admin::ApplicationController ...@@ -20,9 +20,9 @@ class Admin::GroupsController < Admin::ApplicationController
def create def create
@group = Group.new(params[:group]) @group = Group.new(params[:group])
@group.path = @group.name.dup.parameterize if @group.name @group.path = @group.name.dup.parameterize if @group.name
@group.owner = current_user
if @group.save if @group.save
@group.add_owner(current_user)
redirect_to [:admin, @group], notice: 'Group was successfully created.' redirect_to [:admin, @group], notice: 'Group was successfully created.'
else else
render "new" render "new"
...@@ -30,14 +30,7 @@ class Admin::GroupsController < Admin::ApplicationController ...@@ -30,14 +30,7 @@ class Admin::GroupsController < Admin::ApplicationController
end end
def update def update
group_params = params[:group].dup if @group.update_attributes(params[:group])
owner_id =group_params.delete(:owner_id)
if owner_id
@group.change_owner(User.find(owner_id))
end
if @group.update_attributes(group_params)
redirect_to [:admin, @group], notice: 'Group was successfully updated.' redirect_to [:admin, @group], notice: 'Group was successfully updated.'
else else
render "edit" render "edit"
......
...@@ -47,6 +47,8 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -47,6 +47,8 @@ class Admin::UsersController < Admin::ApplicationController
@user = User.build_user(params[:user].merge(opts), as: :admin) @user = User.build_user(params[:user].merge(opts), as: :admin)
@user.admin = (admin && admin.to_i > 0) @user.admin = (admin && admin.to_i > 0)
@user.created_by_id = current_user.id @user.created_by_id = current_user.id
@user.generate_password
@user.confirm!
respond_to do |format| respond_to do |format|
if @user.save if @user.save
...@@ -71,6 +73,7 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -71,6 +73,7 @@ class Admin::UsersController < Admin::ApplicationController
respond_to do |format| respond_to do |format|
if user.update_attributes(params[:user], as: :admin) if user.update_attributes(params[:user], as: :admin)
user.confirm!
format.html { redirect_to [:admin, user], notice: 'User was successfully updated.' } format.html { redirect_to [:admin, user], notice: 'User was successfully updated.' }
format.json { head :ok } format.json { head :ok }
else else
......
...@@ -2,7 +2,7 @@ class ApplicationController < ActionController::Base ...@@ -2,7 +2,7 @@ class ApplicationController < ActionController::Base
before_filter :authenticate_user! before_filter :authenticate_user!
before_filter :reject_blocked! before_filter :reject_blocked!
before_filter :check_password_expiration before_filter :check_password_expiration
before_filter :set_current_user_for_thread around_filter :set_current_user_for_thread
before_filter :add_abilities before_filter :add_abilities
before_filter :ldap_security_check before_filter :ldap_security_check
before_filter :dev_tools if Rails.env == 'development' before_filter :dev_tools if Rails.env == 'development'
...@@ -51,6 +51,11 @@ class ApplicationController < ActionController::Base ...@@ -51,6 +51,11 @@ class ApplicationController < ActionController::Base
def set_current_user_for_thread def set_current_user_for_thread
Thread.current[:current_user] = current_user Thread.current[:current_user] = current_user
begin
yield
ensure
Thread.current[:current_user] = nil
end
end end
def abilities def abilities
...@@ -64,6 +69,15 @@ class ApplicationController < ActionController::Base ...@@ -64,6 +69,15 @@ class ApplicationController < ActionController::Base
def project def project
id = params[:project_id] || params[:id] id = params[:project_id] || params[:id]
# Redirect from
# localhost/group/project.git
# to
# localhost/group/project
#
if id =~ /\.git\Z/
redirect_to request.original_url.gsub(/\.git\Z/, '') and return
end
@project = Project.find_with_namespace(id) @project = Project.find_with_namespace(id)
if @project and can?(current_user, :read_project, @project) if @project and can?(current_user, :read_project, @project)
......
...@@ -5,10 +5,14 @@ class DashboardController < ApplicationController ...@@ -5,10 +5,14 @@ class DashboardController < ApplicationController
before_filter :event_filter, only: :show before_filter :event_filter, only: :show
def show def show
# Fetch only 30 projects.
# If user needs more - point to Dashboard#projects page
@projects_limit = 30
@groups = current_user.authorized_groups.sort_by(&:human_name) @groups = current_user.authorized_groups.sort_by(&:human_name)
@has_authorized_projects = @projects.count > 0 @has_authorized_projects = @projects.count > 0
@projects_count = @projects.count @projects_count = @projects.count
@projects = @projects.limit(20) @projects = @projects.limit(@projects_limit)
@events = Event.in_projects(current_user.authorized_projects.pluck(:id)) @events = Event.in_projects(current_user.authorized_projects.pluck(:id))
@events = @event_filter.apply_filter(@events) @events = @event_filter.apply_filter(@events)
......
...@@ -21,9 +21,9 @@ class GroupsController < ApplicationController ...@@ -21,9 +21,9 @@ class GroupsController < ApplicationController
def create def create
@group = Group.new(params[:group]) @group = Group.new(params[:group])
@group.path = @group.name.dup.parameterize if @group.name @group.path = @group.name.dup.parameterize if @group.name
@group.owner = current_user
if @group.save if @group.save
@group.add_owner(current_user)
redirect_to @group, notice: 'Group was successfully created.' redirect_to @group, notice: 'Group was successfully created.'
else else
render action: "new" render action: "new"
...@@ -75,15 +75,7 @@ class GroupsController < ApplicationController ...@@ -75,15 +75,7 @@ class GroupsController < ApplicationController
end end
def update def update
group_params = params[:group].dup if @group.update_attributes(params[:group])
owner_id = group_params.delete(:owner_id)
if owner_id
@group.owner = User.find(owner_id)
@group.save
end
if @group.update_attributes(group_params)
redirect_to @group, notice: 'Group was successfully updated.' redirect_to @group, notice: 'Group was successfully updated.'
else else
render action: "edit" render action: "edit"
......
class Profiles::AccountsController < ApplicationController
layout "profile"
def show
@user = current_user
end
end
...@@ -8,8 +8,8 @@ class Profiles::GroupsController < ApplicationController ...@@ -8,8 +8,8 @@ class Profiles::GroupsController < ApplicationController
def leave def leave
@users_group = group.users_groups.where(user_id: current_user.id).first @users_group = group.users_groups.where(user_id: current_user.id).first
if group.owner == current_user if group.last_owner?(current_user)
redirect_to(profile_groups_path, alert: "You can't leave group. You must transfer it to another owner before leaving.") redirect_to(profile_groups_path, alert: "You can't leave group. You must add at least one more owner to it.")
else else
@users_group.destroy @users_group.destroy
redirect_to(profile_groups_path, info: "You left #{group.name} group.") redirect_to(profile_groups_path, info: "You left #{group.name} group.")
......
class Profiles::PasswordsController < ApplicationController class Profiles::PasswordsController < ApplicationController
layout 'navless' layout :determine_layout
skip_before_filter :check_password_expiration skip_before_filter :check_password_expiration, only: [:new, :create]
before_filter :set_user before_filter :set_user
before_filter :set_title before_filter :set_title
before_filter :authorize_change_password!
def new def new
end end
...@@ -26,6 +27,32 @@ class Profiles::PasswordsController < ApplicationController ...@@ -26,6 +27,32 @@ class Profiles::PasswordsController < ApplicationController
end end
end end
def edit
end
def update
password_attributes = params[:user].select do |key, value|
%w(password password_confirmation).include?(key.to_s)
end
unless @user.valid_password?(params[:user][:current_password])
redirect_to edit_profile_password_path, alert: 'You must provide a valid current password'
return
end
if @user.update_attributes(password_attributes)
flash[:notice] = "Password was successfully updated. Please login with it"
redirect_to new_user_session_path
else
render 'edit'
end
end
def reset
current_user.send_reset_password_instructions
redirect_to edit_profile_password_path, notice: 'We sent you an email with reset password instructions'
end
private private
def set_user def set_user
...@@ -35,4 +62,16 @@ class Profiles::PasswordsController < ApplicationController ...@@ -35,4 +62,16 @@ class Profiles::PasswordsController < ApplicationController
def set_title def set_title
@title = "New password" @title = "New password"
end end
def determine_layout
if [:new, :create].include?(action_name.to_sym)
'navless'
else
'profile'
end
end
def authorize_change_password!
return render_404 if @user.ldap_user?
end
end end
...@@ -2,7 +2,6 @@ class ProfilesController < ApplicationController ...@@ -2,7 +2,6 @@ class ProfilesController < ApplicationController
include ActionView::Helpers::SanitizeHelper include ActionView::Helpers::SanitizeHelper
before_filter :user before_filter :user
before_filter :authorize_change_password!, only: :update_password
before_filter :authorize_change_username!, only: :update_username before_filter :authorize_change_username!, only: :update_username
layout 'profile' layout 'profile'
...@@ -13,9 +12,6 @@ class ProfilesController < ApplicationController ...@@ -13,9 +12,6 @@ class ProfilesController < ApplicationController
def design def design
end end
def account
end
def update def update
if @user.update_attributes(params[:user]) if @user.update_attributes(params[:user])
flash[:notice] = "Profile was successfully updated" flash[:notice] = "Profile was successfully updated"
...@@ -29,26 +25,12 @@ class ProfilesController < ApplicationController ...@@ -29,26 +25,12 @@ class ProfilesController < ApplicationController
end end
end end
def token
end
def update_password
params[:user].reject!{ |k, v| k != "password" && k != "password_confirmation"}
if @user.update_attributes(params[:user])
flash[:notice] = "Password was successfully updated. Please login with it"
redirect_to new_user_session_path
else
render 'account'
end
end
def reset_private_token def reset_private_token
if current_user.reset_authentication_token! if current_user.reset_authentication_token!
flash[:notice] = "Token was successfully updated" flash[:notice] = "Token was successfully updated"
end end
redirect_to account_profile_path redirect_to profile_account_path
end end
def history def history
...@@ -69,10 +51,6 @@ class ProfilesController < ApplicationController ...@@ -69,10 +51,6 @@ class ProfilesController < ApplicationController
@user = current_user @user = current_user
end end
def authorize_change_password!
return render_404 if @user.ldap_user?
end
def authorize_change_username! def authorize_change_username!
return render_404 unless @user.can_change_username? return render_404 unless @user.can_change_username?
end end
......
class Projects::ApplicationController < ApplicationController class Projects::ApplicationController < ApplicationController
before_filter :project before_filter :project
before_filter :repository before_filter :repository
layout 'projects' layout :determine_layout
def authenticate_user!
# Restrict access to Projects area only
# for non-signed users
if !current_user
id = params[:project_id] || params[:id]
@project = Project.find_with_namespace(id)
return if @project && @project.public
end
super
end
def determine_layout
if current_user
'projects'
else
'public_projects'
end
end
end end
...@@ -8,7 +8,7 @@ class Projects::BlameController < Projects::ApplicationController ...@@ -8,7 +8,7 @@ class Projects::BlameController < Projects::ApplicationController
before_filter :require_non_empty_project before_filter :require_non_empty_project
def show def show
@blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path) @blob = @repository.blob_at(@commit.id, @path)
@blame = Gitlab::Git::Blame.new(project.repository, @commit.id, @path) @blame = Gitlab::Git::Blame.new(project.repository, @commit.id, @path)
end end
end end
...@@ -8,6 +8,8 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -8,6 +8,8 @@ class Projects::BlobController < Projects::ApplicationController
before_filter :require_non_empty_project before_filter :require_non_empty_project
def show def show
@blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path) @blob = @repository.blob_at(@commit.id, @path)
not_found! unless @blob
end end
end end
...@@ -10,7 +10,7 @@ class Projects::EditTreeController < Projects::ApplicationController ...@@ -10,7 +10,7 @@ class Projects::EditTreeController < Projects::ApplicationController
before_filter :edit_requirements, only: [:show, :update] before_filter :edit_requirements, only: [:show, :update]
def show def show
@last_commit = Gitlab::Git::Commit.last_for_path(@project.repository, @ref, @path).sha @last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
end end
def update def update
...@@ -32,9 +32,9 @@ class Projects::EditTreeController < Projects::ApplicationController ...@@ -32,9 +32,9 @@ class Projects::EditTreeController < Projects::ApplicationController
private private
def edit_requirements def edit_requirements
@blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path) @blob = @repository.blob_at(@commit.id, @path)
unless @blob.exists? && @blob.text? unless @blob
redirect_to project_blob_path(@project, @id), notice: "You can only edit text files" redirect_to project_blob_path(@project, @id), notice: "You can only edit text files"
end end
......
class Projects::HooksController < Projects::ApplicationController class Projects::HooksController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_admin_project!
before_filter :authorize_admin_project!, only: [:new, :create, :destroy]
respond_to :html respond_to :html
......
...@@ -157,12 +157,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -157,12 +157,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def validates_merge_request def validates_merge_request
# Show git not found page if target branch doesn't exist # Show git not found page
return invalid_mr unless @merge_request.target_project.repository.branch_names.include?(@merge_request.target_branch) # if there is no saved commits between source & target branch
if @merge_request.commits.blank?
# Show git not found page if source branch doesn't exist # and if source target doesn't exist
# and there is no saved commits between source & target branch return invalid_mr unless @merge_request.target_project.repository.branch_names.include?(@merge_request.target_branch)
return invalid_mr if !@merge_request.source_project.repository.branch_names.include?(@merge_request.source_branch) && @merge_request.commits.blank?
# or if source branch doesn't exist
return invalid_mr unless @merge_request.source_project.repository.branch_names.include?(@merge_request.source_branch)
end
end end
def define_show_vars def define_show_vars
......
...@@ -14,7 +14,7 @@ class Projects::MilestonesController < Projects::ApplicationController ...@@ -14,7 +14,7 @@ class Projects::MilestonesController < Projects::ApplicationController
@milestones = case params[:f] @milestones = case params[:f]
when 'all'; @project.milestones.order("state, due_date DESC") when 'all'; @project.milestones.order("state, due_date DESC")
when 'closed'; @project.milestones.closed.order("due_date DESC") when 'closed'; @project.milestones.closed.order("due_date DESC")
else @project.milestones.active.order("due_date DESC") else @project.milestones.active.order("due_date ASC")
end end
@milestones = @milestones.includes(:project) @milestones = @milestones.includes(:project)
......
...@@ -8,9 +8,9 @@ class Projects::RawController < Projects::ApplicationController ...@@ -8,9 +8,9 @@ class Projects::RawController < Projects::ApplicationController
before_filter :require_non_empty_project before_filter :require_non_empty_project
def show def show
@blob = Gitlab::Git::Blob.new(@repository, @commit.id, @ref, @path) @blob = @repository.blob_at(@commit.id, @path)
if @blob.exists? if @blob
type = if @blob.mime_type =~ /html|javascript/ type = if @blob.mime_type =~ /html|javascript/
'text/plain; charset=utf-8' 'text/plain; charset=utf-8'
else else
......
...@@ -24,13 +24,14 @@ class Projects::RefsController < Projects::ApplicationController ...@@ -24,13 +24,14 @@ class Projects::RefsController < Projects::ApplicationController
format.js do format.js do
@ref = params[:ref] @ref = params[:ref]
define_tree_vars define_tree_vars
tree
render "tree" render "tree"
end end
end end
end end
def logs_tree def logs_tree
contents = @tree.entries contents = tree.entries
@logs = contents.map do |content| @logs = contents.map do |content|
file = params[:path] ? File.join(params[:path], content.name) : content.name file = params[:path] ? File.join(params[:path], content.name) : content.name
last_commit = @repo.commits(@commit.id, file, 1).last last_commit = @repo.commits(@commit.id, file, 1).last
......
...@@ -14,8 +14,6 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -14,8 +14,6 @@ class Projects::SnippetsController < Projects::ApplicationController
# Allow destroy snippet # Allow destroy snippet
before_filter :authorize_admin_project_snippet!, only: [:destroy] before_filter :authorize_admin_project_snippet!, only: [:destroy]
layout 'projects'
respond_to :html respond_to :html
def index def index
......
class Projects::TeamMembersController < Projects::ApplicationController class Projects::TeamMembersController < Projects::ApplicationController
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_admin_project!
before_filter :authorize_admin_project!, except: [:index, :show]
layout "project_settings" layout "project_settings"
......
...@@ -8,6 +8,8 @@ class Projects::TreeController < Projects::ApplicationController ...@@ -8,6 +8,8 @@ class Projects::TreeController < Projects::ApplicationController
before_filter :require_non_empty_project before_filter :require_non_empty_project
def show def show
return not_found! if tree.entries.empty?
respond_to do |format| respond_to do |format|
format.html format.html
# Disable cache so browser history works # Disable cache so browser history works
......
class ProjectsController < Projects::ApplicationController class ProjectsController < ApplicationController
skip_before_filter :project, only: [:new, :create] skip_before_filter :authenticate_user!, only: [:show]
skip_before_filter :repository, only: [:new, :create] before_filter :project, except: [:new, :create]
before_filter :repository, except: [:new, :create]
# Authorize # Authorize
before_filter :authorize_read_project!, except: [:index, :new, :create] before_filter :authorize_read_project!, except: [:index, :new, :create]
...@@ -54,8 +55,9 @@ class ProjectsController < Projects::ApplicationController ...@@ -54,8 +55,9 @@ class ProjectsController < Projects::ApplicationController
end end
def show def show
limit = (params[:limit] || 20).to_i return authenticate_user! unless @project.public || current_user
limit = (params[:limit] || 20).to_i
@events = @project.events.recent @events = @project.events.recent
@events = event_filter.apply_filter(@events) @events = event_filter.apply_filter(@events)
@events = @events.limit(limit).offset(params[:offset] || 0) @events = @events.limit(limit).offset(params[:offset] || 0)
...@@ -67,10 +69,12 @@ class ProjectsController < Projects::ApplicationController ...@@ -67,10 +69,12 @@ class ProjectsController < Projects::ApplicationController
respond_to do |format| respond_to do |format|
format.html do format.html do
if @project.empty_repo? if @project.empty_repo?
render "projects/empty" render "projects/empty", layout: user_layout
else else
@last_push = current_user.recent_push(@project.id) if current_user
render :show @last_push = current_user.recent_push(@project.id)
end
render :show, layout: user_layout
end end
end end
format.js format.js
...@@ -121,4 +125,8 @@ class ProjectsController < Projects::ApplicationController ...@@ -121,4 +125,8 @@ class ProjectsController < Projects::ApplicationController
def set_title def set_title
@title = 'New Project' @title = 'New Project'
end end
def user_layout
current_user ? "projects" : "public_projects"
end
end end
class Public::ProjectsController < ApplicationController class Public::ProjectsController < ApplicationController
skip_before_filter :authenticate_user!, skip_before_filter :authenticate_user!,
:reject_blocked, :set_current_user_for_observers, :reject_blocked, :set_current_user_for_observers,
:add_abilities :add_abilities
layout 'public' layout 'public'
...@@ -10,15 +10,4 @@ class Public::ProjectsController < ApplicationController ...@@ -10,15 +10,4 @@ class Public::ProjectsController < ApplicationController
@projects = @projects.search(params[:search]) if params[:search].present? @projects = @projects.search(params[:search]) if params[:search].present?
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20) @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
end end
def show
@project = Project.public_only.find_with_namespace(params[:id])
render_404 and return unless @project
@repository = @project.repository
@recent_tags = @repository.tags.first(10)
@commit = @repository.commit(params[:ref])
@tree = Tree.new(@repository, @commit.id)
end
end end
...@@ -19,7 +19,7 @@ class UsersGroupsController < ApplicationController ...@@ -19,7 +19,7 @@ class UsersGroupsController < ApplicationController
def destroy def destroy
@users_group = @group.users_groups.find(params[:id]) @users_group = @group.users_groups.find(params[:id])
@users_group.destroy unless @users_group.user == @group.owner @users_group.destroy
respond_to do |format| respond_to do |format|
format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' } format.html { redirect_to members_group_path(@group), notice: 'User was successfully removed from group.' }
......
...@@ -49,6 +49,15 @@ module ApplicationHelper ...@@ -49,6 +49,15 @@ module ApplicationHelper
args.any? { |v| v.to_s.downcase == action_name } args.any? { |v| v.to_s.downcase == action_name }
end end
def avatar_icon(user_email = '', size = nil)
user = User.find_by_email(user_email)
if user && user.avatar.present?
user.avatar.url
else
gravatar_icon(user_email, size)
end
end
def gravatar_icon(user_email = '', size = nil) def gravatar_icon(user_email = '', size = nil)
size = 40 if size.nil? || size <= 0 size = 40 if size.nil? || size <= 0
...@@ -89,49 +98,6 @@ module ApplicationHelper ...@@ -89,49 +98,6 @@ module ApplicationHelper
grouped_options_for_select(options, @ref || @project.default_branch) grouped_options_for_select(options, @ref || @project.default_branch)
end end
def search_autocomplete_source
projects = current_user.authorized_projects.map { |p| { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) } }
groups = current_user.authorized_groups.map { |group| { label: "group: #{simple_sanitize(group.name)}", url: group_path(group) } }
default_nav = [
{ label: "My Profile", url: profile_path },
{ label: "My SSH Keys", url: profile_keys_path },
{ label: "My Dashboard", url: root_path },
{ label: "Admin Section", url: admin_root_path },
]
help_nav = [
{ label: "help: API Help", url: help_api_path },
{ label: "help: Markdown Help", url: help_markdown_path },
{ label: "help: Permissions Help", url: help_permissions_path },
{ label: "help: Public Access Help", url: help_public_access_path },
{ label: "help: Rake Tasks Help", url: help_raketasks_path },
{ label: "help: SSH Keys Help", url: help_ssh_path },
{ label: "help: System Hooks Help", url: help_system_hooks_path },
{ label: "help: Web Hooks Help", url: help_web_hooks_path },
{ label: "help: Workflow Help", url: help_workflow_path },
]
project_nav = []
if @project && @project.repository.exists? && @project.repository.root_ref
project_nav = [
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Files", url: project_tree_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Commits", url: project_commits_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Network", url: project_network_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Graph", url: project_graph_path(@project, @ref || @project.repository.root_ref) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Issues", url: project_issues_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Merge Requests", url: project_merge_requests_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Milestones", url: project_milestones_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Snippets", url: project_snippets_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Team", url: project_team_index_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Wall", url: project_wall_path(@project) },
{ label: "#{simple_sanitize(@project.name_with_namespace)} - Wiki", url: project_wikis_path(@project) },
]
end
[groups, projects, default_nav, project_nav, help_nav].flatten.to_json
end
def emoji_autocomplete_source def emoji_autocomplete_source
# should be an array of strings # should be an array of strings
# so to_s can be called, because it is sufficient and to_json is too slow # so to_s can be called, because it is sufficient and to_json is too slow
...@@ -181,7 +147,7 @@ module ApplicationHelper ...@@ -181,7 +147,7 @@ module ApplicationHelper
alt: "Sign in with #{provider.to_s.titleize}") alt: "Sign in with #{provider.to_s.titleize}")
end end
def simple_sanitize str def simple_sanitize(str)
sanitize(str, tags: %w(a span)) sanitize(str, tags: %w(a span))
end end
......
...@@ -108,7 +108,7 @@ module CommitsHelper ...@@ -108,7 +108,7 @@ module CommitsHelper
source_name = commit.send "#{options[:source]}_name".to_sym source_name = commit.send "#{options[:source]}_name".to_sym
source_email = commit.send "#{options[:source]}_email".to_sym source_email = commit.send "#{options[:source]}_email".to_sym
text = if options[:avatar] text = if options[:avatar]
avatar = image_tag(gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") avatar = image_tag(avatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
%Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>} %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>}
else else
source_name source_name
......
...@@ -34,7 +34,8 @@ module GitlabMarkdownHelper ...@@ -34,7 +34,8 @@ module GitlabMarkdownHelper
# see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch- # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
filter_html: true, filter_html: true,
with_toc_data: true, with_toc_data: true,
hard_wrap: true) hard_wrap: true,
safe_links_only: true)
@markdown = Redcarpet::Markdown.new(gitlab_renderer, @markdown = Redcarpet::Markdown.new(gitlab_renderer,
# see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use # see https://github.com/vmg/redcarpet#and-its-like-really-simple-to-use
no_intra_emphasis: true, no_intra_emphasis: true,
...@@ -57,4 +58,104 @@ module GitlabMarkdownHelper ...@@ -57,4 +58,104 @@ module GitlabMarkdownHelper
wiki_page.formatted_content.html_safe wiki_page.formatted_content.html_safe
end end
end end
# text - whole text from a markdown file
# project_path_with_namespace - namespace/projectname, eg. gitlabhq/gitlabhq
# ref - name of the branch or reference, eg. stable
# requested_path - path of request, eg. doc/api/README.md, used in special case when path is pointing to the .md file were the original request is coming from
# wiki - whether the markdown is from wiki or not
def create_relative_links(text, project_path_with_namespace, ref, requested_path, wiki = false)
paths = extract_paths(text)
paths.each do |file_path|
new_path = rebuild_path(project_path_with_namespace, file_path, requested_path, ref)
# Replacing old string with a new one with brackets ]() to prevent replacing occurence of a word
# e.g. If we have a markdown like [test](test) this will replace ](test) and not the word test
text.gsub!("](#{file_path})", "](/#{new_path})")
end
text
end
def extract_paths(markdown_text)
all_markdown_paths = pick_out_paths(markdown_text)
paths = remove_empty(all_markdown_paths)
select_relative(paths)
end
# Split the markdown text to each line and find all paths, this will match anything with - ]("some_text")
def pick_out_paths(markdown_text)
markdown_text.split("\n").map { |text| text.scan(/\]\(([^(]+)\)/) }
end
# Removes any empty result produced by not matching the regexp
def remove_empty(paths)
paths.reject{|l| l.empty? }.flatten
end
# Reject any path that contains ignored protocol
# eg. reject "https://gitlab.org} but accept "doc/api/README.md"
def select_relative(paths)
paths.reject{|path| ignored_protocols.map{|protocol| path.include?(protocol)}.any?}
end
def ignored_protocols
["http://","https://", "ftp://", "mailto:"]
end
def rebuild_path(path_with_namespace, path, requested_path, ref)
file_path = relative_file_path(path, requested_path)
[
path_with_namespace,
path_with_ref(file_path, ref),
file_path
].compact.join("/")
end
# Checks if the path exists in the repo
# eg. checks if doc/README.md exists, if it doesn't then it is a wiki link
def path_with_ref(path, ref)
if file_exists?(path)
"#{local_path(path)}/#{correct_ref(ref)}"
else
"wikis"
end
end
def relative_file_path(path, requested_path)
nested_path = build_nested_path(path, requested_path)
return nested_path if file_exists?(nested_path)
path
end
# Covering a special case, when the link is referencing file in the same directory eg:
# If we are at doc/api/README.md and the README.md contains relative links like [Users](users.md)
# this takes the request path(doc/api/README.md), and replaces the README.md with users.md so the path looks like doc/api/users.md
# If we are at doc/api and the README.md shown in below the tree view
# this takes the rquest path(doc/api) and adds users.md so the path looks like doc/api/users.md
def build_nested_path(path, request_path)
return path unless request_path
if local_path(request_path) == "tree"
base = request_path.split("/").push(path)
base.join("/")
else
base = request_path.split("/")
base.pop
base.push(path).join("/")
end
end
def file_exists?(path)
return false if path.nil? || path.empty?
File.exists?(Rails.root.join(path))
end
# Check if the path is pointing to a directory(tree) or a file(blob)
# eg. doc/api is directory and doc/README.md is file
def local_path(path)
File.directory?(Rails.root.join(path)) ? "tree" : "blob"
end
# We will assume that if no ref exists we can point to master
def correct_ref(ref)
ref ? ref : "master"
end
end end
...@@ -16,7 +16,7 @@ module IssuesHelper ...@@ -16,7 +16,7 @@ module IssuesHelper
def url_for_project_issues def url_for_project_issues
return "" if @project.nil? return "" if @project.nil?
if @project.used_default_issues_tracker? if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?
project_issues_path(@project) project_issues_path(@project)
else else
url = Gitlab.config.issues_tracker[@project.issues_tracker]["project_url"] url = Gitlab.config.issues_tracker[@project.issues_tracker]["project_url"]
...@@ -28,7 +28,7 @@ module IssuesHelper ...@@ -28,7 +28,7 @@ module IssuesHelper
def url_for_new_issue def url_for_new_issue
return "" if @project.nil? return "" if @project.nil?
if @project.used_default_issues_tracker? if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?
url = new_project_issue_path project_id: @project url = new_project_issue_path project_id: @project
else else
url = Gitlab.config.issues_tracker[@project.issues_tracker]["new_issue_url"] url = Gitlab.config.issues_tracker[@project.issues_tracker]["new_issue_url"]
...@@ -40,7 +40,7 @@ module IssuesHelper ...@@ -40,7 +40,7 @@ module IssuesHelper
def url_for_issue(issue_iid) def url_for_issue(issue_iid)
return "" if @project.nil? return "" if @project.nil?
if @project.used_default_issues_tracker? if @project.used_default_issues_tracker? || !external_issues_tracker_enabled?
url = project_issue_url project_id: @project, id: issue_iid url = project_issue_url project_id: @project, id: issue_iid
else else
url = Gitlab.config.issues_tracker[@project.issues_tracker]["issues_url"] url = Gitlab.config.issues_tracker[@project.issues_tracker]["issues_url"]
...@@ -59,4 +59,13 @@ module IssuesHelper ...@@ -59,4 +59,13 @@ module IssuesHelper
"" ""
end end
end end
# Checks if issues_tracker setting exists in gitlab.yml
def external_issues_tracker_enabled?
if Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any?
true
else
false
end
end
end end
...@@ -14,6 +14,6 @@ module ProfileHelper ...@@ -14,6 +14,6 @@ module ProfileHelper
end end
def show_profile_remove_tab? def show_profile_remove_tab?
Gitlab.config.gitlab.signup_enabled && !current_user.ldap_user? gitlab_config.signup_enabled && !current_user.ldap_user?
end end
end end
...@@ -5,10 +5,10 @@ module ProjectsHelper ...@@ -5,10 +5,10 @@ module ProjectsHelper
def link_to_project project def link_to_project project
link_to project do link_to project do
title = content_tag(:strong, project.name) title = content_tag(:span, project.name, class: 'projet-name')
if project.namespace if project.namespace
namespace = content_tag(:span, "#{project.namespace.human_name} / ", class: 'tiny') namespace = content_tag(:span, "#{project.namespace.human_name} / ", class: 'namespace-name')
title = namespace + title title = namespace + title
end end
...@@ -25,7 +25,7 @@ module ProjectsHelper ...@@ -25,7 +25,7 @@ module ProjectsHelper
author_html = "" author_html = ""
# Build avatar image tag # Build avatar image tag
author_html << image_tag(gravatar_icon(author.try(:email), opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar] author_html << image_tag(avatar_icon(author.try(:email), opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
# Build name span tag # Build name span tag
author_html << content_tag(:span, sanitize(author.name), class: 'author') if opts[:name] author_html << content_tag(:span, sanitize(author.name), class: 'author') if opts[:name]
...@@ -77,7 +77,19 @@ module ProjectsHelper ...@@ -77,7 +77,19 @@ module ProjectsHelper
end end
def project_active_milestones def project_active_milestones
@project.milestones.active.order("id desc").all @project.milestones.active.order("due_date, title ASC").all
end
def project_issues_trackers
values = Project.issues_tracker.values.map do |tracker_key|
if tracker_key.to_sym == :gitlab
['GitLab', tracker_key]
else
[Gitlab.config.issues_tracker[tracker_key]['title'] || tracker_key, tracker_key]
end
end
options_for_select(values)
end end
private private
...@@ -103,4 +115,29 @@ module ProjectsHelper ...@@ -103,4 +115,29 @@ module ProjectsHelper
nav_tabs.flatten nav_tabs.flatten
end end
def git_user_name
if current_user
current_user.name
else
"Your name"
end
end
def git_user_email
if current_user
current_user.email
else
"your@email.com"
end
end
def repository_size
"#{@project.repository.size} MB"
rescue
# In order to prevent 500 error
# when application cannot allocate memory
# to calculate repo size - just show 'Unknown'
'unknown'
end
end end
module SearchHelper
def search_autocomplete_source
return unless current_user
[
groups_autocomplete,
projects_autocomplete,
default_autocomplete,
project_autocomplete,
help_autocomplete
].flatten.to_json
end
private
# Autocomplete results for various settings pages
def default_autocomplete
[
{ label: "My Profile settings", url: profile_path },
{ label: "My SSH Keys", url: profile_keys_path },
{ label: "My Dashboard", url: root_path },
{ label: "Admin Section", url: admin_root_path },
]
end
# Autocomplete results for internal help pages
def help_autocomplete
[
{ label: "help: API Help", url: help_api_path },
{ label: "help: Markdown Help", url: help_markdown_path },
{ label: "help: Permissions Help", url: help_permissions_path },
{ label: "help: Public Access Help", url: help_public_access_path },
{ label: "help: Rake Tasks Help", url: help_raketasks_path },
{ label: "help: SSH Keys Help", url: help_ssh_path },
{ label: "help: System Hooks Help", url: help_system_hooks_path },
{ label: "help: Web Hooks Help", url: help_web_hooks_path },
{ label: "help: Workflow Help", url: help_workflow_path },
]
end
# Autocomplete results for the current project, if it's defined
def project_autocomplete
if @project && @project.repository.exists? && @project.repository.root_ref
prefix = simple_sanitize(@project.name_with_namespace)
ref = @ref || @project.repository.root_ref
[
{ label: "#{prefix} - Files", url: project_tree_path(@project, ref) },
{ label: "#{prefix} - Commits", url: project_commits_path(@project, ref) },
{ label: "#{prefix} - Network", url: project_network_path(@project, ref) },
{ label: "#{prefix} - Graph", url: project_graph_path(@project, ref) },
{ label: "#{prefix} - Issues", url: project_issues_path(@project) },
{ label: "#{prefix} - Merge Requests", url: project_merge_requests_path(@project) },
{ label: "#{prefix} - Milestones", url: project_milestones_path(@project) },
{ label: "#{prefix} - Snippets", url: project_snippets_path(@project) },
{ label: "#{prefix} - Team", url: project_team_index_path(@project) },
{ label: "#{prefix} - Wall", url: project_wall_path(@project) },
{ label: "#{prefix} - Wiki", url: project_wikis_path(@project) },
]
else
[]
end
end
# Autocomplete results for the current user's groups
def groups_autocomplete
current_user.authorized_groups.map do |group|
{ label: "group: #{simple_sanitize(group.name)}", url: group_path(group) }
end
end
# Autocomplete results for the current user's projects
def projects_autocomplete
current_user.authorized_projects.map do |p|
{ label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
end
end
end
...@@ -67,9 +67,9 @@ module TreeHelper ...@@ -67,9 +67,9 @@ module TreeHelper
end end
def tree_breadcrumbs(tree, max_links = 2) def tree_breadcrumbs(tree, max_links = 2)
if tree.path if @path.present?
part_path = "" part_path = ""
parts = tree.path.split("\/") parts = @path.split("\/")
yield('..', nil) if parts.count > max_links yield('..', nil) if parts.count > max_links
...@@ -78,14 +78,14 @@ module TreeHelper ...@@ -78,14 +78,14 @@ module TreeHelper
part_path = part if part_path.empty? part_path = part if part_path.empty?
next unless parts.last(2).include?(part) if parts.count > max_links next unless parts.last(2).include?(part) if parts.count > max_links
yield(part, tree_join(tree.ref, part_path)) yield(part, tree_join(@ref, part_path))
end end
end end
end end
def up_dir_path tree def up_dir_path tree
file = File.join(tree.path, "..") file = File.join(@path, "..")
tree_join(tree.ref, file) tree_join(@ref, file)
end end
def leave_edit_message def leave_edit_message
......
...@@ -18,7 +18,7 @@ module Emails ...@@ -18,7 +18,7 @@ module Emails
@note = Note.find(note_id) @note = Note.find(note_id)
@merge_request = @note.noteable @merge_request = @note.noteable
@project = @note.project @project = @note.project
mail(to: recipient(recipient_id), subject: subject("note for merge request !#{@merge_request.iid}")) mail(to: recipient(recipient_id), subject: subject("note for merge request ##{@merge_request.iid}"))
end end
def note_wall_email(recipient_id, note_id) def note_wall_email(recipient_id, note_id)
......
class Ability class Ability
class << self class << self
def allowed(user, subject) def allowed(user, subject)
return not_auth_abilities(user, subject) if user.nil?
return [] unless user.kind_of?(User) return [] unless user.kind_of?(User)
return [] if user.blocked? return [] if user.blocked?
...@@ -17,6 +18,34 @@ class Ability ...@@ -17,6 +18,34 @@ class Ability
end.concat(global_abilities(user)) end.concat(global_abilities(user))
end end
# List of possible abilities
# for non-authenticated user
def not_auth_abilities(user, subject)
project = if subject.kind_of?(Project)
subject
elsif subject.respond_to?(:project)
subject.project
else
nil
end
if project && project.public
[
:read_project,
:read_wiki,
:read_issue,
:read_milestone,
:read_project_snippet,
:read_team_member,
:read_merge_request,
:read_note,
:download_code
]
else
[]
end
end
def global_abilities(user) def global_abilities(user)
rules = [] rules = []
rules << :create_group if user.can_create_group rules << :create_group if user.can_create_group
...@@ -50,7 +79,7 @@ class Ability ...@@ -50,7 +79,7 @@ class Ability
rules << project_admin_rules rules << project_admin_rules
end end
if project.group && project.group.owners.include?(user) if project.group && project.group.has_owner?(user)
rules << project_admin_rules rules << project_admin_rules
end end
...@@ -58,19 +87,9 @@ class Ability ...@@ -58,19 +87,9 @@ class Ability
end end
def public_project_rules def public_project_rules
[ project_guest_rules + [
:download_code, :download_code,
:fork_project, :fork_project,
:read_project,
:read_wiki,
:read_issue,
:read_milestone,
:read_project_snippet,
:read_team_member,
:read_merge_request,
:read_note,
:write_issue,
:write_note
] ]
end end
...@@ -135,12 +154,12 @@ class Ability ...@@ -135,12 +154,12 @@ class Ability
def group_abilities user, group def group_abilities user, group
rules = [] rules = []
if group.users.include?(user) if group.users.include?(user) || user.admin?
rules << :read_group rules << :read_group
end end
# Only group owner and administrators can manage group # Only group owner and administrators can manage group
if group.owners.include?(user) || user.admin? if group.has_owner?(user) || user.admin?
rules << [ rules << [
:manage_group, :manage_group,
:manage_namespace :manage_namespace
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean default(FALSE), not null
# project_url :string(255)
#
require "flowdock-git-hook"
class FlowdockService < Service
validates :token, presence: true, if: :activated?
def title
'Flowdock'
end
def description
'Flowdock is a collaboration web app for technical teams.'
end
def to_param
'flowdock'
end
def fields
[
{ type: 'text', name: 'token', placeholder: '' }
]
end
def execute(push_data)
repo_path = File.join(Gitlab.config.gitlab_shell.repos_path, "#{project.path_with_namespace}.git")
Flowdock::Git.post(
push_data[:ref],
push_data[:before],
push_data[:after],
token: token,
repo: repo_path,
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s",
)
end
end
...@@ -45,6 +45,10 @@ class GollumWiki ...@@ -45,6 +45,10 @@ class GollumWiki
end end
end end
def empty?
pages.empty?
end
# Returns an Array of Gitlab WikiPage instances or an # Returns an Array of Gitlab WikiPage instances or an
# empty Array if this Wiki has no pages. # empty Array if this Wiki has no pages.
def pages def pages
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# id :integer not null, primary key # id :integer not null, primary key
# name :string(255) not null # name :string(255) not null
# path :string(255) not null # path :string(255) not null
# owner_id :integer not null # owner_id :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# type :string(255) # type :string(255)
...@@ -33,29 +33,33 @@ class Group < Namespace ...@@ -33,29 +33,33 @@ class Group < Namespace
end end
def owners def owners
@owners ||= (users_groups.owners.map(&:user) << owner).uniq @owners ||= users_groups.owners.map(&:user)
end end
def add_users(user_ids, group_access) def add_users(user_ids, group_access)
user_ids.compact.each do |user_id| user_ids.compact.each do |user_id|
self.users_groups.create(user_id: user_id, group_access: group_access) user = self.users_groups.find_or_initialize_by_user_id(user_id)
user.update_attributes(group_access: group_access)
end end
end end
def change_owner(user) def add_user(user, group_access)
self.owner = user self.users_groups.create(user_id: user.id, group_access: group_access)
membership = users_groups.where(user_id: user.id).first end
if membership def add_owner(user)
membership.update_attributes(group_access: UsersGroup::OWNER) self.add_user(user, UsersGroup::OWNER)
else
add_owner
end
end end
private def has_owner?(user)
owners.include?(user)
end
def last_owner?(user)
has_owner?(user) && owners.size == 1
end
def add_owner def members
self.add_users([owner.id], UsersGroup::OWNER) users_groups
end end
end end
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
# merge_status :string(255) # merge_status :string(255)
# target_project_id :integer not null # target_project_id :integer not null
# iid :integer # iid :integer
# description :text
# #
require Rails.root.join("app/models/commit") require Rails.root.join("app/models/commit")
...@@ -221,7 +222,11 @@ class MergeRequest < ActiveRecord::Base ...@@ -221,7 +222,11 @@ class MergeRequest < ActiveRecord::Base
def mr_and_commit_notes def mr_and_commit_notes
commit_ids = commits.map(&:id) commit_ids = commits.map(&:id)
Note.where("(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND commit_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids) project.notes.where(
"(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND commit_id IN (:commit_ids))",
mr_id: id,
commit_ids: commit_ids
)
end end
# Returns the raw diff for this merge request # Returns the raw diff for this merge request
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# id :integer not null, primary key # id :integer not null, primary key
# name :string(255) not null # name :string(255) not null
# path :string(255) not null # path :string(255) not null
# owner_id :integer not null # owner_id :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# type :string(255) # type :string(255)
...@@ -20,7 +20,7 @@ class Namespace < ActiveRecord::Base ...@@ -20,7 +20,7 @@ class Namespace < ActiveRecord::Base
has_many :projects, dependent: :destroy has_many :projects, dependent: :destroy
belongs_to :owner, class_name: "User" belongs_to :owner, class_name: "User"
validates :owner, presence: true validates :owner, presence: true, unless: ->(n) { n.type == "Group" }
validates :name, presence: true, uniqueness: true, validates :name, presence: true, uniqueness: true,
length: { within: 0..255 }, length: { within: 0..255 },
format: { with: Gitlab::Regex.name_regex, format: { with: Gitlab::Regex.name_regex,
......
require "grit"
module Network module Network
class Commit class Commit
include ActionView::Helpers::TagHelper include ActionView::Helpers::TagHelper
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
# commit_id :string(255) # commit_id :string(255)
# noteable_id :integer # noteable_id :integer
# st_diff :text # st_diff :text
# system :boolean default(FALSE), not null
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
......
...@@ -10,6 +10,9 @@ ...@@ -10,6 +10,9 @@
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# #
class PivotaltrackerService < Service class PivotaltrackerService < Service
......
...@@ -24,8 +24,6 @@ ...@@ -24,8 +24,6 @@
# import_url :string(255) # import_url :string(255)
# #
require "grit"
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
extend Enumerize extend Enumerize
...@@ -48,12 +46,14 @@ class Project < ActiveRecord::Base ...@@ -48,12 +46,14 @@ class Project < ActiveRecord::Base
has_one :campfire_service, dependent: :destroy has_one :campfire_service, dependent: :destroy
has_one :pivotaltracker_service, dependent: :destroy has_one :pivotaltracker_service, dependent: :destroy
has_one :hipchat_service, dependent: :destroy has_one :hipchat_service, dependent: :destroy
has_one :flowdock_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link has_one :forked_from_project, through: :forked_project_link
has_many :services, dependent: :destroy has_many :services, dependent: :destroy
has_many :events, dependent: :destroy has_many :events, dependent: :destroy
has_many :merge_requests, dependent: :destroy, foreign_key: "target_project_id" has_many :merge_requests, dependent: :destroy, foreign_key: "target_project_id"
has_many :fork_merge_requests,dependent: :destroy, foreign_key: "source_project_id", class_name: MergeRequest
has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC" has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC"
has_many :milestones, dependent: :destroy has_many :milestones, dependent: :destroy
has_many :notes, dependent: :destroy has_many :notes, dependent: :destroy
...@@ -224,7 +224,7 @@ class Project < ActiveRecord::Base ...@@ -224,7 +224,7 @@ class Project < ActiveRecord::Base
end end
def available_services_names def available_services_names
%w(gitlab_ci campfire hipchat pivotaltracker) %w(gitlab_ci campfire hipchat pivotaltracker flowdock)
end end
def gitlab_ci? def gitlab_ci?
...@@ -252,10 +252,10 @@ class Project < ActiveRecord::Base ...@@ -252,10 +252,10 @@ class Project < ActiveRecord::Base
end end
def owner def owner
if namespace if group
namespace_owner group
else else
creator namespace.try(:owner)
end end
end end
...@@ -279,10 +279,6 @@ class Project < ActiveRecord::Base ...@@ -279,10 +279,6 @@ class Project < ActiveRecord::Base
end end
end end
def namespace_owner
namespace.try(:owner)
end
def path_with_namespace def path_with_namespace
if namespace if namespace
namespace.path + '/' + path namespace.path + '/' + path
...@@ -320,8 +316,11 @@ class Project < ActiveRecord::Base ...@@ -320,8 +316,11 @@ class Project < ActiveRecord::Base
branch_name = ref.gsub("refs/heads/", "") branch_name = ref.gsub("refs/heads/", "")
c_ids = self.repository.commits_between(oldrev, newrev).map(&:id) c_ids = self.repository.commits_between(oldrev, newrev).map(&:id)
# Update code for merge requests # Update code for merge requests into project between project branches
mrs = self.merge_requests.opened.by_branch(branch_name).all mrs = self.merge_requests.opened.by_branch(branch_name).all
# Update code for merge requests between project and project fork
mrs += self.fork_merge_requests.opened.by_branch(branch_name).all
mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked } mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
# Close merge requests # Close merge requests
......
class Repository class Repository
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
attr_accessor :raw_repository attr_accessor :raw_repository, :path_with_namespace
def initialize(path_with_namespace, default_branch) def initialize(path_with_namespace, default_branch)
@raw_repository = Gitlab::Git::Repository.new(path_with_namespace, default_branch) @path_with_namespace = path_with_namespace
@raw_repository = Gitlab::Git::Repository.new(path_to_repo) if path_with_namespace
rescue Gitlab::Git::Repository::NoRepository rescue Gitlab::Git::Repository::NoRepository
nil nil
end end
def path_to_repo
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, path_with_namespace + ".git")
end
def exists? def exists?
raw_repository raw_repository
end end
...@@ -150,4 +155,8 @@ class Repository ...@@ -150,4 +155,8 @@ class Repository
super super
end end
def blob_at(sha, path)
Gitlab::Git::Blob.find(self, sha, path)
end
end end
class Tree class Tree
attr_accessor :raw attr_accessor :entries, :readme
def initialize(repository, sha, ref = nil, path = nil) def initialize(repository, sha, path = '/')
@raw = Gitlab::Git::Tree.new(repository, sha, ref, path) path = '/' if path.blank?
git_repo = repository.raw_repository
@entries = Gitlab::Git::Tree.where(git_repo, sha, path)
if readme_tree = @entries.find(&:readme?)
readme_path = path == '/' ? readme_tree.name : File.join(path, readme_tree.name)
@readme = Gitlab::Git::Blob.find(git_repo, sha, readme_path)
end
end end
def method_missing(m, *args, &block) def trees
@raw.send(m, *args, &block) @entries.select(&:dir?)
end end
def respond_to?(method) def blobs
return true if @raw.respond_to?(method) @entries.select(&:file?)
end
super def submodules
@entries.select(&:submodule?)
end end
end end
...@@ -38,13 +38,16 @@ ...@@ -38,13 +38,16 @@
# created_by_id :integer # created_by_id :integer
# #
require 'carrierwave/orm/activerecord'
require 'file_size_validator'
class User < ActiveRecord::Base class User < ActiveRecord::Base
devise :database_authenticatable, :token_authenticatable, :lockable, devise :database_authenticatable, :token_authenticatable, :lockable, :async,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :registerable :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :confirmable, :registerable
attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username, attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username,
:skype, :linkedin, :twitter, :color_scheme_id, :theme_id, :force_random_password, :skype, :linkedin, :twitter, :color_scheme_id, :theme_id, :force_random_password,
:extern_uid, :provider, :password_expires_at, :extern_uid, :provider, :password_expires_at, :avatar,
as: [:default, :admin] as: [:default, :admin]
attr_accessible :projects_limit, :can_create_group, attr_accessible :projects_limit, :can_create_group,
...@@ -113,6 +116,8 @@ class User < ActiveRecord::Base ...@@ -113,6 +116,8 @@ class User < ActiveRecord::Base
validate :namespace_uniq, if: ->(user) { user.username_changed? } validate :namespace_uniq, if: ->(user) { user.username_changed? }
validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
before_validation :generate_password, on: :create before_validation :generate_password, on: :create
before_validation :sanitize_attrs before_validation :sanitize_attrs
...@@ -135,7 +140,7 @@ class User < ActiveRecord::Base ...@@ -135,7 +140,7 @@ class User < ActiveRecord::Base
# Remove user from all groups # Remove user from all groups
user.users_groups.find_each do |membership| user.users_groups.find_each do |membership|
# skip owned resources # skip owned resources
next if membership.group.owners.include?(user) next if membership.group.last_owner?(user)
return false unless membership.destroy return false unless membership.destroy
end end
...@@ -150,6 +155,8 @@ class User < ActiveRecord::Base ...@@ -150,6 +155,8 @@ class User < ActiveRecord::Base
end end
end end
mount_uploader :avatar, AttachmentUploader
# Scopes # Scopes
scope :admins, -> { where(admin: true) } scope :admins, -> { where(admin: true) }
scope :blocked, -> { with_state(:blocked) } scope :blocked, -> { with_state(:blocked) }
...@@ -167,7 +174,7 @@ class User < ActiveRecord::Base ...@@ -167,7 +174,7 @@ class User < ActiveRecord::Base
# Class methods # Class methods
# #
class << self class << self
# Devise method overridden to allow sing in with email or username # Devise method overridden to allow sign in with email or username
def find_for_database_authentication(warden_conditions) def find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup conditions = warden_conditions.dup
if login = conditions.delete(:login) if login = conditions.delete(:login)
...@@ -192,11 +199,7 @@ class User < ActiveRecord::Base ...@@ -192,11 +199,7 @@ class User < ActiveRecord::Base
end end
def by_username_or_id(name_or_id) def by_username_or_id(name_or_id)
if (name_or_id.is_a?(Integer)) where('username = ? OR id = ?', name_or_id, name_or_id).first
User.find_by_id(name_or_id)
else
User.find_by_username(name_or_id)
end
end end
def build_user(attrs = {}, options= {}) def build_user(attrs = {}, options= {})
...@@ -211,7 +214,7 @@ class User < ActiveRecord::Base ...@@ -211,7 +214,7 @@ class User < ActiveRecord::Base
{ {
projects_limit: Gitlab.config.gitlab.default_projects_limit, projects_limit: Gitlab.config.gitlab.default_projects_limit,
can_create_group: Gitlab.config.gitlab.default_can_create_group, can_create_group: Gitlab.config.gitlab.default_can_create_group,
theme_id: Gitlab::Theme::MARS theme_id: Gitlab.config.gitlab.default_theme
} }
end end
end end
......
...@@ -14,6 +14,17 @@ class ProjectObserver < BaseObserver ...@@ -14,6 +14,17 @@ class ProjectObserver < BaseObserver
log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"") log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"")
end end
if project.wiki_enabled?
begin
# force the creation of a wiki,
GollumWiki.new(project, project.owner).wiki
rescue GollumWiki::CouldNotCreateWikiError => ex
# Prevent project observer crash
# if failed to create wiki
nil
end
end
end end
def after_update(project) def after_update(project)
......
...@@ -112,6 +112,7 @@ class GitPushService ...@@ -112,6 +112,7 @@ class GitPushService
# ref: String, # ref: String,
# user_id: String, # user_id: String,
# user_name: String, # user_name: String,
# project_id: String,
# repository: { # repository: {
# name: String, # name: String,
# url: String, # url: String,
...@@ -136,6 +137,7 @@ class GitPushService ...@@ -136,6 +137,7 @@ class GitPushService
ref: ref, ref: ref,
user_id: user.id, user_id: user.id,
user_name: user.name, user_name: user.name,
project_id: project.id,
repository: { repository: {
name: project.name, name: project.name,
url: project.url_to_repo, url: project.url_to_repo,
......
...@@ -23,18 +23,21 @@ class SystemHooksService ...@@ -23,18 +23,21 @@ class SystemHooksService
case model case model
when Project when Project
owner = model.owner
data.merge!({ data.merge!({
name: model.name, name: model.name,
path: model.path, path: model.path,
path_with_namespace: model.path_with_namespace, path_with_namespace: model.path_with_namespace,
project_id: model.id, project_id: model.id,
owner_name: model.owner.name, owner_name: owner.name,
owner_email: model.owner.email owner_email: owner.respond_to?(:email) ? owner.email : nil
}) })
when User when User
data.merge!({ data.merge!({
name: model.name, name: model.name,
email: model.email email: model.email,
user_id: model.id
}) })
when UsersProject when UsersProject
data.merge!({ data.merge!({
......
...@@ -2,3 +2,37 @@ ...@@ -2,3 +2,37 @@
%br %br
.ui-box .ui-box
%iframe{src: sidekiq_path, width: '100%', height: 900, style: "border: none"} %iframe{src: sidekiq_path, width: '100%', height: 900, style: "border: none"}
%h4 Sidekiq running processes
- sidekiq_processes = `ps -eo euser,pid,pcpu,pmem,stat,start,command | grep sidekiq | grep -v grep`
- if sidekiq_processes.empty?
%b There are no running sidekiq processes
%b Please restart GitLab
- else
.ui-box
%table.zebra-striped
%thead
%th USER
%th
%th PID
%th
%th CPU
%th
%th MEM
%th
%th STATE
%th
%th START
%th
%th COMMAND
%th
- sidekiq_processes.split("\n").each do |process|
- next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/)
- data = process.gsub!(/\s+/m, '|').strip.split('|')
%tr
- 6.times do
%td= data.shift
%td
%td= data.join(" ")
%b If '[25 of 25 busy]' is shown, restart GitLab with 'sudo service gitlab reload'.
%br
%b If more than one sidekiq process is listed, stop GitLab, kill the remaining sidekiq processes (sudo pkill -u git -f sidekiq) and restart GitLab.
%h3.page-title
Admin area
%p.light
You can manage projects, users and other GitLab data from here.
%hr
.admin_dash.row .admin_dash.row
.span4 .span4
.ui-box .light-well
.title Projects %h4 Projects
.data.padded .data
= link_to admin_projects_path do = link_to admin_projects_path do
%h1= Project.count %h1= Project.count
%hr %hr
= link_to 'New Project', new_project_path, class: "btn btn-small" = link_to 'New Project', new_project_path, class: "btn btn-new"
.span4 .span4
.ui-box .light-well
.title Users %h4 Users
.data.padded .data
= link_to admin_users_path do = link_to admin_users_path do
%h1= User.count %h1= User.count
%hr %hr
= link_to 'New User', new_admin_user_path, class: "btn btn-small" = link_to 'New User', new_admin_user_path, class: "btn btn-new"
.span4 .span4
.ui-box .light-well
.title Groups %h4 Groups
.data.padded .data
= link_to admin_groups_path do = link_to admin_groups_path do
%h1= Group.count %h1= Group.count
%hr %hr
= link_to 'New Group', new_admin_group_path, class: "btn btn-small" = link_to 'New Group', new_admin_group_path, class: "btn btn-new"
.row .row.prepend-top-10
.span4 .span4
%h4 Latest projects %h4 Latest projects
%hr %hr
......
...@@ -31,11 +31,8 @@ ...@@ -31,11 +31,8 @@
.clearfix.light.append-bottom-10 .clearfix.light.append-bottom-10
%span %span
%b Owner: %b Members:
- if group.owner %span.badge= group.members.size
= link_to group.owner_name, admin_user_path(group.owner)
- else
(deleted)
\| \|
%span %span
%b Projects: %b Projects:
......
...@@ -24,26 +24,6 @@ ...@@ -24,26 +24,6 @@
%strong %strong
= @group.description = @group.description
%li
%span.light Owned by:
%strong
- if @group.owner
= link_to @group.owner_name, admin_user_path(@group.owner)
- else
(deleted)
.pull-right
= link_to "#", class: "btn btn-small change-owner-link" do
%i.icon-edit
Change owner
%li.change-owner-holder.hide.bgred
.form-holder
%strong.cred New Owner:
= form_for [:admin, @group] do |f|
= users_select_tag(:"group[owner_id]")
.prepend-top-10
= f.submit 'Change Owner', class: "btn btn-remove"
= link_to "Cancel", "#", class: "btn change-owner-cancel-link"
%li %li
%span.light Created at: %span.light Created at:
%strong %strong
...@@ -92,4 +72,5 @@ ...@@ -92,4 +72,5 @@
= link_to user.name, admin_user_path(user) = link_to user.name, admin_user_path(user)
%span.pull-right.light %span.pull-right.light
= member.human_access = member.human_access
= link_to group_users_group_path(@group, member), confirm: remove_user_from_group_message(@group, user), method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
%i.icon-minus.icon-white
...@@ -52,7 +52,8 @@ ...@@ -52,7 +52,8 @@
"created_at": "2012-07-21T07:44:07Z", "created_at": "2012-07-21T07:44:07Z",
"email": "js@gitlabhq.com", "email": "js@gitlabhq.com",
"event_name": "user_create", "event_name": "user_create",
"name": "John Smith" "name": "John Smith",
"user_id": 41
} }
6. User removed: 6. User removed:
...@@ -60,7 +61,8 @@ ...@@ -60,7 +61,8 @@
"created_at": "2012-07-21T07:44:07Z", "created_at": "2012-07-21T07:44:07Z",
"email": "js@gitlabhq.com", "email": "js@gitlabhq.com",
"event_name": "user_destroy", "event_name": "user_destroy",
"name": "John Smith" "name": "John Smith",
"user_id": 41
} }
eos eos
......
.alert.alert-info %h3.page-title
%span System Hooks
Post-receive hooks for binding events.
%br %p.light
Read more about system hooks #{link_to "System hooks ", help_system_hooks_path, class: "vlink"} can be
%strong #{link_to "here", help_system_hooks_path, class: "vlink"} used for binding events when GitLab creates a User or Project.
%hr
= form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-inline' } do |f| = form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-inline' } do |f|
-if @hook.errors.any? -if @hook.errors.any?
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
%span.light Owned by: %span.light Owned by:
%strong %strong
- if @project.owner - if @project.owner
= link_to @project.owner_name, admin_user_path(@project.owner) = link_to @project.owner_name, [:admin, @project.owner]
- else - else
(deleted) (deleted)
......
%h3.page-title %h3.page-title
User: %span.cgray User:
= @user.name = @user.name
- if @user.blocked? - if @user.blocked?
%span.cred (Blocked) %span.cred (Blocked)
...@@ -10,8 +10,6 @@ ...@@ -10,8 +10,6 @@
= link_to edit_admin_user_path(@user), class: "btn grouped" do = link_to edit_admin_user_path(@user), class: "btn grouped" do
%i.icon-edit %i.icon-edit
Edit Edit
- if @user.blocked?
= link_to 'Unblock', unblock_admin_user_path(@user), method: :put, class: "btn grouped success"
%hr %hr
.row .row
...@@ -20,7 +18,7 @@ ...@@ -20,7 +18,7 @@
.title .title
Account: Account:
.pull-right .pull-right
= image_tag gravatar_icon(@user.email, 32), class: "avatar s32" = image_tag avatar_icon(@user.email, 32), class: "avatar s32"
%ul.well-list %ul.well-list
%li %li
%span.light Name: %span.light Name:
...@@ -67,17 +65,30 @@ ...@@ -67,17 +65,30 @@
= link_to @user.created_by.name, [:admin, @user.created_by] = link_to @user.created_by.name, [:admin, @user.created_by]
- unless @user == current_user - unless @user == current_user
.alert - if @user.blocked?
%h4 Block user .alert.alert-info
%br %h4 This user is blocked
%p Blocking user has the following effects: %br
%ul %p Blocking user has the following effects:
%li User will not be able to login %ul
%li User will not be able to access git repositories %li User will not be able to login
%li User will be removed from joined projects and groups %li User will not be able to access git repositories
%li Personal projects will be left %li User will be removed from joined projects and groups
%li Owned groups will be left %li Personal projects will be left
= link_to 'Block user', block_admin_user_path(@user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-remove" %li Owned groups will be left
= link_to 'Unblock user', unblock_admin_user_path(@user), method: :put, class: "btn btn-new", confirm: 'Are you sure?'
- else
.alert
%h4 Block this user
%br
%p Blocking user has the following effects:
%ul
%li User will not be able to login
%li User will not be able to access git repositories
%li User will be removed from joined projects and groups
%li Personal projects will be left
%li Owned groups will be left
= link_to 'Block user', block_admin_user_path(@user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-remove"
.alert.alert-error .alert.alert-error
%h4 %h4
...@@ -117,11 +128,7 @@ ...@@ -117,11 +128,7 @@
- tm = project.team.find_tm(@user.id) - tm = project.team.find_tm(@user.id)
%li.users_project %li.users_project
= link_to admin_project_path(project), class: dom_class(project) do = link_to admin_project_path(project), class: dom_class(project) do
- if project.namespace = project.name_with_namespace
= project.namespace.human_name
\/
%strong.well-title
= truncate(project.name, length: 45)
- if tm - if tm
.pull-right .pull-right
......
...@@ -14,9 +14,6 @@ ...@@ -14,9 +14,6 @@
= truncate(group.name, length: 35) = truncate(group.name, length: 35)
%span.arrow %span.arrow
%i.icon-angle-right %i.icon-angle-right
%span.owner-info
%span Owner:
%span.owner= group.owner_name
- if groups.blank? - if groups.blank?
%li %li
%h3.nothing_here_message You have no groups yet. %h3.nothing_here_message You have no groups yet.
= link_to project_path(project), class: dom_class(project) do
%span.namespace-name
- if project.namespace
= project.namespace.human_name
\/
%span.project-name.filter-title
= truncate(project.name, length: 25)
%span.arrow
%i.icon-angle-right
%span.last-activity
%span Last activity:
%span.date= project_last_activity(project)
...@@ -10,21 +10,16 @@ ...@@ -10,21 +10,16 @@
%ul.well-list.dash-list %ul.well-list.dash-list
- projects.each do |project| - projects.each do |project|
%li.project-row %li.project-row
= link_to project_path(project), class: dom_class(project) do = render "project", project: project
%span.namespace-name
- if project.namespace
= project.namespace.human_name
\/
%span.project-name.filter-title
= truncate(project.name, length: 25)
%span.arrow
%i.icon-angle-right
%span.last-activity
%span Last activity:
%span.date= project_last_activity(project)
- if projects.blank? - if projects.blank?
%li %li
%h3.nothing_here_message There are no projects here. %h3.nothing_here_message There are no projects here.
- if @projects_count > 20 - if @projects_count > @projects_limit
%li.bottom %li.bottom
%strong= link_to "show all projects", projects_dashboard_path %span.light
#{@projects_limit} of #{pluralize(@projects_count, 'project')} displayed.
.pull-right.append-right-10
= link_to projects_dashboard_path do
Show all
%i.icon-angle-right
...@@ -12,7 +12,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -12,7 +12,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link :href => project_issue_url(issue.project, issue) xml.link :href => project_issue_url(issue.project, issue)
xml.title truncate(issue.title, :length => 80) xml.title truncate(issue.title, :length => 80)
xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(issue.author_email) xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(issue.author_email)
xml.author do |author| xml.author do |author|
xml.name issue.author_name xml.name issue.author_name
xml.email issue.author_email xml.email issue.author_email
......
...@@ -17,7 +17,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -17,7 +17,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link :href => event_link xml.link :href => event_link
xml.title truncate(event_title, :length => 80) xml.title truncate(event_title, :length => 80)
xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(event.author_email) xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(event.author_email)
xml.author do |author| xml.author do |author|
xml.name event.author_name xml.name event.author_name
xml.email event.author_email xml.email event.author_email
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
= render 'devise/sessions/oauth_providers' if devise_mapping.omniauthable? = render 'devise/sessions/oauth_providers' if devise_mapping.omniauthable?
- if Gitlab.config.gitlab.signup_enabled - if gitlab_config.signup_enabled
%hr %hr
%div %div
Don't have an account? Don't have an account?
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<%= link_to "Sign in", new_session_path(resource_name), class: "btn" %><br /> <%= link_to "Sign in", new_session_path(resource_name), class: "btn" %><br />
<% end -%> <% end -%>
<%- if devise_mapping.registerable? && controller_name != 'registrations' %> <%- if devise_mapping.registerable? && controller_name != 'registrations' && gitlab_config.signup_enabled %>
<%= link_to "Sign up", new_registration_path(resource_name) %><br /> <%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end -%> <% end -%>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#{time_ago_in_words(event.created_at)} ago. #{time_ago_in_words(event.created_at)} ago.
= cache event do = cache event do
= image_tag gravatar_icon(event.author_email), class: "avatar s24", alt:'' = image_tag avatar_icon(event.author_email), class: "avatar s24", alt:''
- if event.push? - if event.push?
= render "events/event/push", event: event = render "events/event/push", event: event
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
= link_to project_commits_path(event.project, event.ref_name) do = link_to project_commits_path(event.project, event.ref_name) do
%strong= truncate(event.ref_name, length: 30) %strong= truncate(event.ref_name, length: 30)
at at
%strong= link_to_project event.project = link_to_project event.project
- if event.push_with_commits? - if event.push_with_commits?
- project = event.project - project = event.project
......
...@@ -11,8 +11,6 @@ ...@@ -11,8 +11,6 @@
Projects Projects
%li %li
= link_to 'LDAP', '#tab-ldap', 'data-toggle' => 'tab' = link_to 'LDAP', '#tab-ldap', 'data-toggle' => 'tab'
%li
= link_to 'Transfer', '#tab-transfer', 'data-toggle' => 'tab'
%li %li
= link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab' = link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab'
...@@ -87,17 +85,6 @@ ...@@ -87,17 +85,6 @@
.form-actions .form-actions
= f.submit 'Save group', class: "btn btn-save" = f.submit 'Save group', class: "btn btn-save"
.tab-pane#tab-transfer
.ui-box.ui-box-danger
.title Transfer group
.ui-box-body
%p
Transferring group will cause loss of admin control over group and all child projects
= form_for @group do |f|
= users_select_tag(:'group[owner_id]')
%hr
= f.submit 'Transfer group', class: "btn btn-small btn-remove"
.tab-pane#tab-remove .tab-pane#tab-remove
.ui-box.ui-box-danger .ui-box.ui-box-danger
.title Remove group .title Remove group
......
...@@ -12,7 +12,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -12,7 +12,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link :href => project_issue_url(issue.project, issue) xml.link :href => project_issue_url(issue.project, issue)
xml.title truncate(issue.title, :length => 80) xml.title truncate(issue.title, :length => 80)
xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(issue.author_email) xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(issue.author_email)
xml.author do |author| xml.author do |author|
xml.name issue.author_name xml.name issue.author_name
xml.email issue.author_email xml.email issue.author_email
......
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
Group members Group members
%p.light %p.light
Members of group have access to all group projects. Members of group have access to all group projects.
Read more about permissions
%strong= link_to "here", help_permissions_path, class: "vlink"
%hr %hr
- can_manage_group = current_user.can? :manage_group, @group - can_manage_group = current_user.can? :manage_group, @group
.ui-box .ui-box
......
...@@ -16,7 +16,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear ...@@ -16,7 +16,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.link :href => event_link xml.link :href => event_link
xml.title truncate(event_title, :length => 80) xml.title truncate(event_title, :length => 80)
xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(event.author_email) xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(event.author_email)
xml.author do |author| xml.author do |author|
xml.name event.author_name xml.name event.author_name
xml.email event.author_email xml.email event.author_email
......
...@@ -30,5 +30,8 @@ ...@@ -30,5 +30,8 @@
%li %li
%strong= link_to "Public Access", help_public_access_path %strong= link_to "Public Access", help_public_access_path
%li
%strong= link_to "Security", help_security_path
.span9.pull-right .span9.pull-right
= yield = yield
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
%p Get familiar with GitLab's permission levels. %p Get familiar with GitLab's permission levels.
%li %li
%strong= link_to "API", help_api_path %strong= link_to "API", help_api_file_path(category: 'README')
%p Explore how you can access GitLab via a simple and powerful API. %p Explore how you can access GitLab via a simple and powerful API.
%li %li
...@@ -80,3 +80,7 @@ ...@@ -80,3 +80,7 @@
%li %li
%strong= link_to "Public Access", help_public_access_path %strong= link_to "Public Access", help_public_access_path
%p Learn how you can allow public access to a project. %p Learn how you can allow public access to a project.
%li
%strong= link_to "Security", help_security_path
%p Learn what you can do to secure your GitLab instance.
= render layout: 'help/layout' do = render layout: 'help/layout' do
%h3.page-title Permissions %h3.page-title Permissions
%p.light Users have different abilities depending on the access level they have in particular group or project.
%p.light If a user is both in a project group and in the project itself the highest permission level is used.
%p.light If a user is a GitLab administrator they receive all permissions.
%hr
%h4 Project:
%table.table %table.table
%thead %thead
%tr %tr
...@@ -158,3 +163,50 @@ ...@@ -158,3 +163,50 @@
%td %td
%td %td
%td.permission-x &#10003; %td.permission-x &#10003;
%h4 Group
%table.table
%thead
%tr
%th Action
%th Guest
%th Reporter
%th Developer
%th Master
%th Owner
%tbody
%tr
%td Browse group
%td.permission-x &#10003;
%td.permission-x &#10003;
%td.permission-x &#10003;
%td.permission-x &#10003;
%td.permission-x &#10003;
%tr
%td Edit group
%td
%td
%td
%td
%td.permission-x &#10003;
%tr
%td Create project in group
%td
%td
%td
%td
%td.permission-x &#10003;
%tr
%td Manage group members
%td
%td
%td
%td
%td.permission-x &#10003;
%tr
%td Remove group
%td
%td
%td
%td
%td.permission-x &#10003;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment