Commit 465499928835d3319e6838f43f04d5079a197850

Authored by Marin Jankovski
2 parents 5b23a7bb e8d1e827

Merge branch 'master' into relative_links_in_documentation

Showing 71 changed files with 467 additions and 330 deletions   Show diff stats
@@ -13,6 +13,7 @@ v 6.2.0 @@ -13,6 +13,7 @@ v 6.2.0
13 - Rake tasks for web hooks management (Jonhnny Weslley) 13 - Rake tasks for web hooks management (Jonhnny Weslley)
14 - Extended User API to expose admin and can_create_group for user creation/updating (Boyan Tabakov) 14 - Extended User API to expose admin and can_create_group for user creation/updating (Boyan Tabakov)
15 - API: Remove group 15 - API: Remove group
  16 + - Avatar upload on profile page with a maximum of 200KB (Steven Thonus)
16 17
17 v 6.1.0 18 v 6.1.0
18 - Project specific IDs for issues, mr, milestones 19 - Project specific IDs for issues, mr, milestones
@@ -16,6 +16,7 @@ gem "pg", group: :postgres @@ -16,6 +16,7 @@ gem "pg", group: :postgres
16 16
17 # Auth 17 # Auth
18 gem "devise", '~> 2.2' 18 gem "devise", '~> 2.2'
  19 +gem "devise-async"
19 gem 'omniauth', "~> 1.1.3" 20 gem 'omniauth', "~> 1.1.3"
20 gem 'omniauth-google-oauth2' 21 gem 'omniauth-google-oauth2'
21 gem 'omniauth-twitter' 22 gem 'omniauth-twitter'
@@ -106,6 +106,8 @@ GEM @@ -106,6 +106,8 @@ GEM
106 orm_adapter (~> 0.1) 106 orm_adapter (~> 0.1)
107 railties (~> 3.1) 107 railties (~> 3.1)
108 warden (~> 1.2.1) 108 warden (~> 1.2.1)
  109 + devise-async (0.8.0)
  110 + devise (>= 2.2, < 3.2)
109 diff-lcs (1.2.4) 111 diff-lcs (1.2.4)
110 dotenv (0.8.0) 112 dotenv (0.8.0)
111 email_spec (1.4.0) 113 email_spec (1.4.0)
@@ -564,6 +566,7 @@ DEPENDENCIES @@ -564,6 +566,7 @@ DEPENDENCIES
564 d3_rails (~> 3.1.4) 566 d3_rails (~> 3.1.4)
565 database_cleaner 567 database_cleaner
566 devise (~> 2.2) 568 devise (~> 2.2)
  569 + devise-async
567 email_spec 570 email_spec
568 enumerize 571 enumerize
569 factory_girl_rails 572 factory_girl_rails
app/assets/javascripts/profile.js.coffee
@@ -16,3 +16,13 @@ $ -&gt; @@ -16,3 +16,13 @@ $ -&gt;
16 16
17 $('.update-notifications').on 'ajax:complete', -> 17 $('.update-notifications').on 'ajax:complete', ->
18 $(this).find('.btn-save').enableButton() 18 $(this).find('.btn-save').enableButton()
  19 +
  20 +
  21 + $('.js-choose-user-avatar-button').bind "click", ->
  22 + form = $(this).closest("form")
  23 + form.find(".js-user-avatar-input").click()
  24 +
  25 + $('.js-user-avatar-input').bind "change", ->
  26 + form = $(this).closest("form")
  27 + filename = $(this).val().replace(/^.*[\\\/]/, '')
  28 + form.find(".js-avatar-filename").text(filename)
app/assets/javascripts/users_select.js.coffee
1 $ -> 1 $ ->
2 userFormatResult = (user) -> 2 userFormatResult = (user) ->
3 - avatar = gon.gravatar_url  
4 - avatar = avatar.replace('%{hash}', md5(user.email))  
5 - avatar = avatar.replace('%{size}', '24')  
6 - 3 + if user.avatar
  4 + avatar = user.avatar.url
  5 + else
  6 + avatar = gon.gravatar_url
  7 + avatar = avatar.replace('%{hash}', md5(user.email))
  8 + avatar = avatar.replace('%{size}', '24')
7 markup = "<div class='user-result'>" 9 markup = "<div class='user-result'>"
8 markup += "<div class='user-image'><img class='avatar s24' src='" + avatar + "'></div>" 10 markup += "<div class='user-image'><img class='avatar s24' src='" + avatar + "'></div>"
9 markup += "<div class='user-name'>" + user.name + "</div>" 11 markup += "<div class='user-name'>" + user.name + "</div>"
app/assets/stylesheets/common.scss
@@ -270,27 +270,6 @@ li.note { @@ -270,27 +270,6 @@ li.note {
270 } 270 }
271 } 271 }
272 272
273 -.oauth_select_holder {  
274 - padding: 20px;  
275 - img {  
276 - padding: 5px;  
277 - margin-right: 10px;  
278 - }  
279 - .active {  
280 - img {  
281 - border: 1px solid #ccc;  
282 - background: $hover;  
283 - @include border-radius(5px);  
284 - }  
285 - }  
286 -}  
287 -  
288 -.btn-build-token {  
289 - float: left;  
290 - padding: 6px 20px;  
291 - margin-right: 12px;  
292 -}  
293 -  
294 .gitlab-promo { 273 .gitlab-promo {
295 a { 274 a {
296 color: #aaa; 275 color: #aaa;
app/assets/stylesheets/gitlab_bootstrap/avatar.scss
@@ -19,4 +19,5 @@ @@ -19,4 +19,5 @@
19 &.s32 { width: 32px; height: 32px; margin-right: 10px; } 19 &.s32 { width: 32px; height: 32px; margin-right: 10px; }
20 &.s60 { width: 60px; height: 60px; margin-right: 12px; } 20 &.s60 { width: 60px; height: 60px; margin-right: 12px; }
21 &.s90 { width: 90px; height: 90px; margin-right: 15px; } 21 &.s90 { width: 90px; height: 90px; margin-right: 15px; }
  22 + &.s160 { width: 160px; height: 160px; margin-right: 20px; }
22 } 23 }
app/assets/stylesheets/sections/profile.scss
@@ -4,3 +4,41 @@ @@ -4,3 +4,41 @@
4 margin-bottom: 0; 4 margin-bottom: 0;
5 } 5 }
6 } 6 }
  7 +
  8 +.account-page {
  9 + fieldset {
  10 + margin-bottom: 15px;
  11 + border-bottom: 1px dashed #ddd;
  12 + padding-bottom: 15px;
  13 +
  14 + &:last-child {
  15 + border: none;
  16 + }
  17 +
  18 + legend {
  19 + border: none;
  20 + margin: 0;
  21 + }
  22 + }
  23 +}
  24 +
  25 +.oauth_select_holder {
  26 + img {
  27 + padding: 2px;
  28 + margin-right: 10px;
  29 + }
  30 + .active {
  31 + img {
  32 + border: 1px solid #4BD;
  33 + background: $hover;
  34 + @include border-radius(5px);
  35 + }
  36 + }
  37 +}
  38 +
  39 +.btn-build-token {
  40 + float: left;
  41 + padding: 6px 20px;
  42 + margin-right: 12px;
  43 +}
  44 +
app/controllers/profiles/accounts_controller.rb 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +class Profiles::AccountsController < ApplicationController
  2 + layout "profile"
  3 +
  4 + def show
  5 + @user = current_user
  6 + end
  7 +end
app/controllers/profiles/passwords_controller.rb
1 class Profiles::PasswordsController < ApplicationController 1 class Profiles::PasswordsController < ApplicationController
2 - layout 'navless' 2 + layout :determine_layout
3 3
4 - skip_before_filter :check_password_expiration 4 + skip_before_filter :check_password_expiration, only: [:new, :create]
5 5
6 before_filter :set_user 6 before_filter :set_user
7 before_filter :set_title 7 before_filter :set_title
  8 + before_filter :authorize_change_password!
8 9
9 def new 10 def new
10 end 11 end
@@ -26,6 +27,32 @@ class Profiles::PasswordsController &lt; ApplicationController @@ -26,6 +27,32 @@ class Profiles::PasswordsController &lt; ApplicationController
26 end 27 end
27 end 28 end
28 29
  30 + def edit
  31 + end
  32 +
  33 + def update
  34 + password_attributes = params[:user].select do |key, value|
  35 + %w(password password_confirmation).include?(key.to_s)
  36 + end
  37 +
  38 + unless @user.valid_password?(params[:user][:current_password])
  39 + redirect_to edit_profile_password_path, alert: 'You must provide a valid current password'
  40 + return
  41 + end
  42 +
  43 + if @user.update_attributes(password_attributes)
  44 + flash[:notice] = "Password was successfully updated. Please login with it"
  45 + redirect_to new_user_session_path
  46 + else
  47 + render 'edit'
  48 + end
  49 + end
  50 +
  51 + def reset
  52 + current_user.send_reset_password_instructions
  53 + redirect_to edit_profile_password_path, notice: 'We sent you an email with reset password instructions'
  54 + end
  55 +
29 private 56 private
30 57
31 def set_user 58 def set_user
@@ -35,4 +62,16 @@ class Profiles::PasswordsController &lt; ApplicationController @@ -35,4 +62,16 @@ class Profiles::PasswordsController &lt; ApplicationController
35 def set_title 62 def set_title
36 @title = "New password" 63 @title = "New password"
37 end 64 end
  65 +
  66 + def determine_layout
  67 + if [:new, :create].include?(action_name.to_sym)
  68 + 'navless'
  69 + else
  70 + 'profile'
  71 + end
  72 + end
  73 +
  74 + def authorize_change_password!
  75 + return render_404 if @user.ldap_user?
  76 + end
38 end 77 end
app/controllers/profiles_controller.rb
@@ -2,7 +2,6 @@ class ProfilesController &lt; ApplicationController @@ -2,7 +2,6 @@ class ProfilesController &lt; ApplicationController
2 include ActionView::Helpers::SanitizeHelper 2 include ActionView::Helpers::SanitizeHelper
3 3
4 before_filter :user 4 before_filter :user
5 - before_filter :authorize_change_password!, only: :update_password  
6 before_filter :authorize_change_username!, only: :update_username 5 before_filter :authorize_change_username!, only: :update_username
7 6
8 layout 'profile' 7 layout 'profile'
@@ -13,9 +12,6 @@ class ProfilesController &lt; ApplicationController @@ -13,9 +12,6 @@ class ProfilesController &lt; ApplicationController
13 def design 12 def design
14 end 13 end
15 14
16 - def account  
17 - end  
18 -  
19 def update 15 def update
20 if @user.update_attributes(params[:user]) 16 if @user.update_attributes(params[:user])
21 flash[:notice] = "Profile was successfully updated" 17 flash[:notice] = "Profile was successfully updated"
@@ -29,33 +25,12 @@ class ProfilesController &lt; ApplicationController @@ -29,33 +25,12 @@ class ProfilesController &lt; ApplicationController
29 end 25 end
30 end 26 end
31 27
32 - def token  
33 - end  
34 -  
35 - def update_password  
36 - password_attributes = params[:user].select do |key, value|  
37 - %w(password password_confirmation).include?(key.to_s)  
38 - end  
39 -  
40 - unless @user.valid_password?(params[:user][:current_password])  
41 - redirect_to account_profile_path, alert: 'You must provide a valid current password'  
42 - return  
43 - end  
44 -  
45 - if @user.update_attributes(password_attributes)  
46 - flash[:notice] = "Password was successfully updated. Please login with it"  
47 - redirect_to new_user_session_path  
48 - else  
49 - render 'account'  
50 - end  
51 - end  
52 -  
53 def reset_private_token 28 def reset_private_token
54 if current_user.reset_authentication_token! 29 if current_user.reset_authentication_token!
55 flash[:notice] = "Token was successfully updated" 30 flash[:notice] = "Token was successfully updated"
56 end 31 end
57 32
58 - redirect_to account_profile_path 33 + redirect_to profile_account_path
59 end 34 end
60 35
61 def history 36 def history
@@ -76,10 +51,6 @@ class ProfilesController &lt; ApplicationController @@ -76,10 +51,6 @@ class ProfilesController &lt; ApplicationController
76 @user = current_user 51 @user = current_user
77 end 52 end
78 53
79 - def authorize_change_password!  
80 - return render_404 if @user.ldap_user?  
81 - end  
82 -  
83 def authorize_change_username! 54 def authorize_change_username!
84 return render_404 unless @user.can_change_username? 55 return render_404 unless @user.can_change_username?
85 end 56 end
app/helpers/application_helper.rb
@@ -49,6 +49,15 @@ module ApplicationHelper @@ -49,6 +49,15 @@ module ApplicationHelper
49 args.any? { |v| v.to_s.downcase == action_name } 49 args.any? { |v| v.to_s.downcase == action_name }
50 end 50 end
51 51
  52 + def avatar_icon(user_email = '', size = nil)
  53 + user = User.find_by_email(user_email)
  54 + if user && user.avatar.present?
  55 + user.avatar.url
  56 + else
  57 + gravatar_icon(user_email, size)
  58 + end
  59 + end
  60 +
52 def gravatar_icon(user_email = '', size = nil) 61 def gravatar_icon(user_email = '', size = nil)
53 size = 40 if size.nil? || size <= 0 62 size = 40 if size.nil? || size <= 0
54 63
app/helpers/commits_helper.rb
@@ -108,7 +108,7 @@ module CommitsHelper @@ -108,7 +108,7 @@ module CommitsHelper
108 source_name = commit.send "#{options[:source]}_name".to_sym 108 source_name = commit.send "#{options[:source]}_name".to_sym
109 source_email = commit.send "#{options[:source]}_email".to_sym 109 source_email = commit.send "#{options[:source]}_email".to_sym
110 text = if options[:avatar] 110 text = if options[:avatar]
111 - avatar = image_tag(gravatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "") 111 + avatar = image_tag(avatar_icon(source_email, options[:size]), class: "avatar #{"s#{options[:size]}" if options[:size]}", width: options[:size], alt: "")
112 %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>} 112 %Q{#{avatar} <span class="commit-#{options[:source]}-name">#{source_name}</span>}
113 else 113 else
114 source_name 114 source_name
app/helpers/projects_helper.rb
@@ -5,10 +5,10 @@ module ProjectsHelper @@ -5,10 +5,10 @@ module ProjectsHelper
5 5
6 def link_to_project project 6 def link_to_project project
7 link_to project do 7 link_to project do
8 - title = content_tag(:strong, project.name) 8 + title = content_tag(:span, project.name, class: 'projet-name')
9 9
10 if project.namespace 10 if project.namespace
11 - namespace = content_tag(:span, "#{project.namespace.human_name} / ", class: 'tiny') 11 + namespace = content_tag(:span, "#{project.namespace.human_name} / ", class: 'namespace-name')
12 title = namespace + title 12 title = namespace + title
13 end 13 end
14 14
@@ -25,7 +25,7 @@ module ProjectsHelper @@ -25,7 +25,7 @@ module ProjectsHelper
25 author_html = "" 25 author_html = ""
26 26
27 # Build avatar image tag 27 # Build avatar image tag
28 - 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] 28 + 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]
29 29
30 # Build name span tag 30 # Build name span tag
31 author_html << content_tag(:span, sanitize(author.name), class: 'author') if opts[:name] 31 author_html << content_tag(:span, sanitize(author.name), class: 'author') if opts[:name]
@@ -80,6 +80,18 @@ module ProjectsHelper @@ -80,6 +80,18 @@ module ProjectsHelper
80 @project.milestones.active.order("id desc").all 80 @project.milestones.active.order("id desc").all
81 end 81 end
82 82
  83 + def project_issues_trackers
  84 + values = Project.issues_tracker.values.map do |tracker_key|
  85 + if tracker_key.to_sym == :gitlab
  86 + ['GitLab', tracker_key]
  87 + else
  88 + [Gitlab.config.issues_tracker[tracker_key]['title'] || tracker_key, tracker_key]
  89 + end
  90 + end
  91 +
  92 + options_for_select(values)
  93 + end
  94 +
83 private 95 private
84 96
85 def get_project_nav_tabs(project, current_user) 97 def get_project_nav_tabs(project, current_user)
@@ -119,4 +131,13 @@ module ProjectsHelper @@ -119,4 +131,13 @@ module ProjectsHelper
119 "your@email.com" 131 "your@email.com"
120 end 132 end
121 end 133 end
  134 +
  135 + def repository_size
  136 + "#{@project.repository.size} MB"
  137 + rescue
  138 + # In order to prevent 500 error
  139 + # when application cannot allocate memory
  140 + # to calculate repo size - just show 'Unknown'
  141 + 'unknown'
  142 + end
122 end 143 end
app/models/user.rb
@@ -38,13 +38,16 @@ @@ -38,13 +38,16 @@
38 # created_by_id :integer 38 # created_by_id :integer
39 # 39 #
40 40
  41 +require 'carrierwave/orm/activerecord'
  42 +require 'file_size_validator'
  43 +
41 class User < ActiveRecord::Base 44 class User < ActiveRecord::Base
42 - devise :database_authenticatable, :token_authenticatable, :lockable, 45 + devise :database_authenticatable, :token_authenticatable, :lockable, :async,
43 :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :registerable 46 :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :registerable
44 47
45 attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username, 48 attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username,
46 :skype, :linkedin, :twitter, :color_scheme_id, :theme_id, :force_random_password, 49 :skype, :linkedin, :twitter, :color_scheme_id, :theme_id, :force_random_password,
47 - :extern_uid, :provider, :password_expires_at, 50 + :extern_uid, :provider, :password_expires_at, :avatar,
48 as: [:default, :admin] 51 as: [:default, :admin]
49 52
50 attr_accessible :projects_limit, :can_create_group, 53 attr_accessible :projects_limit, :can_create_group,
@@ -113,6 +116,8 @@ class User &lt; ActiveRecord::Base @@ -113,6 +116,8 @@ class User &lt; ActiveRecord::Base
113 116
114 validate :namespace_uniq, if: ->(user) { user.username_changed? } 117 validate :namespace_uniq, if: ->(user) { user.username_changed? }
115 118
  119 + validates :avatar, file_size: { maximum: 100.kilobytes.to_i }
  120 +
116 before_validation :generate_password, on: :create 121 before_validation :generate_password, on: :create
117 before_validation :sanitize_attrs 122 before_validation :sanitize_attrs
118 123
@@ -150,6 +155,8 @@ class User &lt; ActiveRecord::Base @@ -150,6 +155,8 @@ class User &lt; ActiveRecord::Base
150 end 155 end
151 end 156 end
152 157
  158 + mount_uploader :avatar, AttachmentUploader
  159 +
153 # Scopes 160 # Scopes
154 scope :admins, -> { where(admin: true) } 161 scope :admins, -> { where(admin: true) }
155 scope :blocked, -> { with_state(:blocked) } 162 scope :blocked, -> { with_state(:blocked) }
@@ -391,4 +398,4 @@ class User &lt; ActiveRecord::Base @@ -391,4 +398,4 @@ class User &lt; ActiveRecord::Base
391 398
392 self 399 self
393 end 400 end
394 -end 401 -end
  402 +end
395 \ No newline at end of file 403 \ No newline at end of file
app/views/admin/users/show.html.haml
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 .title 20 .title
21 Account: 21 Account:
22 .pull-right 22 .pull-right
23 - = image_tag gravatar_icon(@user.email, 32), class: "avatar s32" 23 + = image_tag avatar_icon(@user.email, 32), class: "avatar s32"
24 %ul.well-list 24 %ul.well-list
25 %li 25 %li
26 %span.light Name: 26 %span.light Name:
@@ -117,11 +117,7 @@ @@ -117,11 +117,7 @@
117 - tm = project.team.find_tm(@user.id) 117 - tm = project.team.find_tm(@user.id)
118 %li.users_project 118 %li.users_project
119 = link_to admin_project_path(project), class: dom_class(project) do 119 = link_to admin_project_path(project), class: dom_class(project) do
120 - - if project.namespace  
121 - = project.namespace.human_name  
122 - \/  
123 - %strong.well-title  
124 - = truncate(project.name, length: 45) 120 + = project.name_with_namespace
125 121
126 - if tm 122 - if tm
127 .pull-right 123 .pull-right
app/views/dashboard/issues.atom.builder
@@ -12,7 +12,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear @@ -12,7 +12,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear
12 xml.link :href => project_issue_url(issue.project, issue) 12 xml.link :href => project_issue_url(issue.project, issue)
13 xml.title truncate(issue.title, :length => 80) 13 xml.title truncate(issue.title, :length => 80)
14 xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") 14 xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
15 - xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(issue.author_email) 15 + xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(issue.author_email)
16 xml.author do |author| 16 xml.author do |author|
17 xml.name issue.author_name 17 xml.name issue.author_name
18 xml.email issue.author_email 18 xml.email issue.author_email
app/views/dashboard/show.atom.builder
@@ -17,7 +17,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear @@ -17,7 +17,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear
17 xml.link :href => event_link 17 xml.link :href => event_link
18 xml.title truncate(event_title, :length => 80) 18 xml.title truncate(event_title, :length => 80)
19 xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") 19 xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
20 - xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(event.author_email) 20 + xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(event.author_email)
21 xml.author do |author| 21 xml.author do |author|
22 xml.name event.author_name 22 xml.name event.author_name
23 xml.email event.author_email 23 xml.email event.author_email
app/views/events/_event.html.haml
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 #{time_ago_in_words(event.created_at)} ago. 4 #{time_ago_in_words(event.created_at)} ago.
5 5
6 = cache event do 6 = cache event do
7 - = image_tag gravatar_icon(event.author_email), class: "avatar s24", alt:'' 7 + = image_tag avatar_icon(event.author_email), class: "avatar s24", alt:''
8 8
9 - if event.push? 9 - if event.push?
10 = render "events/event/push", event: event 10 = render "events/event/push", event: event
app/views/events/event/_push.html.haml
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 = link_to project_commits_path(event.project, event.ref_name) do 7 = link_to project_commits_path(event.project, event.ref_name) do
8 %strong= truncate(event.ref_name, length: 30) 8 %strong= truncate(event.ref_name, length: 30)
9 at 9 at
10 - %strong= link_to_project event.project 10 + = link_to_project event.project
11 11
12 - if event.push_with_commits? 12 - if event.push_with_commits?
13 - project = event.project 13 - project = event.project
app/views/groups/issues.atom.builder
@@ -12,7 +12,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear @@ -12,7 +12,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear
12 xml.link :href => project_issue_url(issue.project, issue) 12 xml.link :href => project_issue_url(issue.project, issue)
13 xml.title truncate(issue.title, :length => 80) 13 xml.title truncate(issue.title, :length => 80)
14 xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") 14 xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
15 - xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(issue.author_email) 15 + xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(issue.author_email)
16 xml.author do |author| 16 xml.author do |author|
17 xml.name issue.author_name 17 xml.name issue.author_name
18 xml.email issue.author_email 18 xml.email issue.author_email
app/views/groups/show.atom.builder
@@ -16,7 +16,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear @@ -16,7 +16,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear
16 xml.link :href => event_link 16 xml.link :href => event_link
17 xml.title truncate(event_title, :length => 80) 17 xml.title truncate(event_title, :length => 80)
18 xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") 18 xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
19 - xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(event.author_email) 19 + xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(event.author_email)
20 xml.author do |author| 20 xml.author do |author|
21 xml.name event.author_name 21 xml.name event.author_name
22 xml.email event.author_email 22 xml.email event.author_email
app/views/layouts/_head_panel.html.haml
@@ -37,4 +37,4 @@ @@ -37,4 +37,4 @@
37 %i.icon-signout 37 %i.icon-signout
38 %li 38 %li
39 = link_to current_user, class: "profile-pic", id: 'profile-pic' do 39 = link_to current_user, class: "profile-pic", id: 'profile-pic' do
40 - = image_tag gravatar_icon(current_user.email, 26), alt: '' 40 + = image_tag avatar_icon(current_user.email, 26), alt: ''
app/views/layouts/nav/_profile.html.haml
@@ -2,8 +2,11 @@ @@ -2,8 +2,11 @@
2 = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do 2 = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
3 = link_to profile_path, title: "Profile" do 3 = link_to profile_path, title: "Profile" do
4 %i.icon-home 4 %i.icon-home
5 - = nav_link(path: 'profiles#account') do  
6 - = link_to "Account", account_profile_path 5 + = nav_link(controller: :accounts) do
  6 + = link_to "Account", profile_account_path
  7 + - unless current_user.ldap_user?
  8 + = nav_link(controller: :passwords) do
  9 + = link_to "Password", edit_profile_password_path
7 = nav_link(controller: :notifications) do 10 = nav_link(controller: :notifications) do
8 = link_to "Notifications", profile_notifications_path 11 = link_to "Notifications", profile_notifications_path
9 = nav_link(controller: :keys) do 12 = nav_link(controller: :keys) do
app/views/profiles/account.html.haml
@@ -1,141 +0,0 @@ @@ -1,141 +0,0 @@
1 -%h3.page-title  
2 - Account settings  
3 -%p.light  
4 - You can change your password, username and private token here.  
5 - - if current_user.ldap_user?  
6 - Some options are unavailable for LDAP accounts  
7 -%hr  
8 -  
9 -  
10 -.row  
11 - .span2  
12 - %ul.nav.nav-pills.nav-stacked.nav-stacked-menu  
13 - %li.active  
14 - = link_to '#tab-token', 'data-toggle' => 'tab' do  
15 - Private Token  
16 - %li  
17 - = link_to '#tab-password', 'data-toggle' => 'tab' do  
18 - Password  
19 -  
20 - - if show_profile_social_tab?  
21 - %li  
22 - = link_to '#tab-social', 'data-toggle' => 'tab' do  
23 - Social Accounts  
24 -  
25 - - if show_profile_username_tab?  
26 - %li  
27 - = link_to '#tab-username', 'data-toggle' => 'tab' do  
28 - Change Username  
29 -  
30 - - if show_profile_remove_tab?  
31 - %li  
32 - = link_to '#tab-remove', 'data-toggle' => 'tab' do  
33 - Remove Account  
34 - .span10  
35 - .tab-content  
36 - .tab-pane.active#tab-token  
37 - %fieldset.update-token  
38 - %legend  
39 - Private token  
40 - %span.cred.pull-right  
41 - keep it secret!  
42 - %div  
43 - = form_for @user, url: reset_private_token_profile_path, method: :put do |f|  
44 - .data  
45 - %p.slead  
46 - Your private token is used to access application resources without authentication.  
47 - %br  
48 - It can be used for atom feeds or the API.  
49 - %p.cgray  
50 - - if current_user.private_token  
51 - = text_field_tag "token", current_user.private_token, class: "input-xxlarge large_text input-xpadding"  
52 - = f.submit 'Reset', confirm: "Are you sure?", class: "btn btn-primary btn-build-token"  
53 - - else  
54 - %span You don`t have one yet. Click generate to fix it.  
55 - = f.submit 'Generate', class: "btn success btn-build-token"  
56 -  
57 - .tab-pane#tab-password  
58 - %fieldset.update-password  
59 - %legend Password  
60 - - if current_user.ldap_user?  
61 - %h3.nothing_here_message Not available for LDAP user  
62 - - else  
63 - = form_for @user, url: update_password_profile_path, method: :put do |f|  
64 - %div  
65 - %p.slead  
66 - You must provide current password in order to change it.  
67 - %br  
68 - After a successful password update you will be redirected to login page where you should login with your new password  
69 - -if @user.errors.any?  
70 - .alert.alert-error  
71 - %ul  
72 - - @user.errors.full_messages.each do |msg|  
73 - %li= msg  
74 - .control-group  
75 - = f.label :current_password, class: 'cgreen'  
76 - .controls= f.password_field :current_password, required: true  
77 - .control-group  
78 - = f.label :password, 'New password'  
79 - .controls= f.password_field :password, required: true  
80 - .control-group  
81 - = f.label :password_confirmation  
82 - .controls  
83 - = f.password_field :password_confirmation, required: true  
84 - .control-group  
85 - .controls  
86 - = f.submit 'Save password', class: "btn btn-save"  
87 -  
88 - - if show_profile_social_tab?  
89 - .tab-pane#tab-social  
90 - %fieldset  
91 - %legend Social Accounts  
92 - .oauth_select_holder  
93 - %p.hint Tip: Click on icon to activate signin with one of the following services  
94 - - enabled_social_providers.each do |provider|  
95 - %span{class: oauth_active_class(provider) }  
96 - = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider)  
97 -  
98 - - if show_profile_username_tab?  
99 - .tab-pane#tab-username  
100 - %fieldset.update-username  
101 - %legend  
102 - Username  
103 - %small.cred.pull-right  
104 - Changing your username can have unintended side effects!  
105 - = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f|  
106 - %div  
107 - .control-group  
108 - = f.label :username  
109 - .controls  
110 - = f.text_field :username, required: true  
111 - &nbsp;  
112 - %span.loading-gif.hide= image_tag "ajax_loader.gif"  
113 - %span.update-success.cgreen.hide  
114 - %i.icon-ok  
115 - Saved  
116 - %span.update-failed.cred.hide  
117 - %i.icon-remove  
118 - Failed  
119 - %ul.cred  
120 - %li This will change the web URL for personal projects.  
121 - %li This will change the git path to repositories for personal projects.  
122 - .controls  
123 - = f.submit 'Save username', class: "btn btn-save"  
124 -  
125 - - if show_profile_remove_tab?  
126 - .tab-pane#tab-remove  
127 - %fieldset.remove-account  
128 - %legend  
129 - Remove account  
130 - %div  
131 - %p Deleting an account has the following effects:  
132 - %ul  
133 - %li All user content like authored issues, snippets, comments will be removed  
134 - - rp = current_user.personal_projects.count  
135 - - unless rp.zero?  
136 - %li #{pluralize rp, 'personal project'} will be removed and cannot be restored  
137 - - if current_user.solo_owned_groups.present?  
138 - %li  
139 - Next groups will be abandoned. You should transfer or remove them:  
140 - %strong #{current_user.solo_owned_groups.map(&:name).join(', ')}  
141 - = link_to 'Delete account', user_registration_path, confirm: "REMOVE #{current_user.name}? Are you sure?", method: :delete, class: "btn btn-remove"  
app/views/profiles/accounts/show.html.haml 0 → 100644
@@ -0,0 +1,73 @@ @@ -0,0 +1,73 @@
  1 +%h3.page-title
  2 + Account settings
  3 +%p.light
  4 + You can change your username and private token here.
  5 + - if current_user.ldap_user?
  6 + Some options are unavailable for LDAP accounts
  7 +%hr
  8 +
  9 +
  10 +.account-page
  11 + %fieldset.update-token
  12 + %legend
  13 + Private token
  14 + %div
  15 + = form_for @user, url: reset_private_token_profile_path, method: :put do |f|
  16 + .data
  17 + %p
  18 + Your private token is used to access application resources without authentication.
  19 + %br
  20 + It can be used for atom feeds or the API.
  21 + %span.cred
  22 + Keep it secret!
  23 +
  24 + %p.cgray
  25 + - if current_user.private_token
  26 + = text_field_tag "token", current_user.private_token, class: "input-xlarge input-xpadding pull-left"
  27 + = f.submit 'Reset', confirm: "Are you sure?", class: "btn btn-primary btn-build-token prepend-left-10"
  28 + - else
  29 + %span You don`t have one yet. Click generate to fix it.
  30 + = f.submit 'Generate', class: "btn success btn-build-token"
  31 +
  32 +
  33 + - if show_profile_social_tab?
  34 + %fieldset
  35 + %legend Social Accounts
  36 + .oauth_select_holder.append-bottom-10
  37 + %p Click on icon to activate signin with one of the following services
  38 + - enabled_social_providers.each do |provider|
  39 + %span{class: oauth_active_class(provider) }
  40 + = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider)
  41 +
  42 + - if show_profile_username_tab?
  43 + %fieldset.update-username
  44 + %legend
  45 + Username
  46 + = form_for @user, url: update_username_profile_path, method: :put, remote: true do |f|
  47 + %p
  48 + Changing your username will change path to all personl projects!
  49 + %div
  50 + = f.text_field :username, required: true, class: 'input-xlarge input-xpadding'
  51 + &nbsp;
  52 + %span.loading-gif.hide= image_tag "ajax_loader.gif"
  53 + %p.light
  54 + = user_url(@user)
  55 + %div
  56 + = f.submit 'Save username', class: "btn btn-save"
  57 +
  58 + - if show_profile_remove_tab?
  59 + %fieldset.remove-account
  60 + %legend
  61 + Remove account
  62 + %div
  63 + %p Deleting an account has the following effects:
  64 + %ul
  65 + %li All user content like authored issues, snippets, comments will be removed
  66 + - rp = current_user.personal_projects.count
  67 + - unless rp.zero?
  68 + %li #{pluralize rp, 'personal project'} will be removed and cannot be restored
  69 + - if current_user.solo_owned_groups.present?
  70 + %li
  71 + Next groups will be abandoned. You should transfer or remove them:
  72 + %strong #{current_user.solo_owned_groups.map(&:name).join(', ')}
  73 + = link_to 'Delete account', user_registration_path, confirm: "REMOVE #{current_user.name}? Are you sure?", method: :delete, class: "btn btn-remove"
app/views/profiles/passwords/edit.html.haml 0 → 100644
@@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
  1 +%h3.page-title Password
  2 +%p.light
  3 + Change your password or recover your current one.
  4 +%hr
  5 +.update-password
  6 + = form_for @user, url: profile_password_path, method: :put do |f|
  7 + %div
  8 + %p.slead
  9 + You must provide current password in order to change it.
  10 + %br
  11 + After a successful password update you will be redirected to login page where you should login with your new password
  12 + -if @user.errors.any?
  13 + .alert.alert-error
  14 + %ul
  15 + - @user.errors.full_messages.each do |msg|
  16 + %li= msg
  17 + .control-group
  18 + = f.label :current_password
  19 + .controls
  20 + = f.password_field :current_password, required: true
  21 + %div
  22 + = link_to "Forgot your password?", reset_profile_password_path, method: :put
  23 +
  24 + .control-group
  25 + = f.label :password, 'New password'
  26 + .controls= f.password_field :password, required: true
  27 + .control-group
  28 + = f.label :password_confirmation
  29 + .controls
  30 + = f.password_field :password_confirmation, required: true
  31 + .form-actions
  32 + = f.submit 'Save password', class: "btn btn-save"
app/views/profiles/show.html.haml
1 -= image_tag gravatar_icon(@user.email, 60), alt: '', class: 'avatar s60'  
2 %h3.page-title 1 %h3.page-title
3 - = @user.name  
4 - %br  
5 - %small  
6 - = @user.email  
7 -  
8 - .pull-right  
9 - = link_to destroy_user_session_path, class: "logout", method: :delete do  
10 - %small  
11 - %i.icon-signout  
12 - Logout 2 + Profile settings
  3 +%p.light
  4 + This information appears on your profile.
  5 + - if current_user.ldap_user?
  6 + Some options are unavailable for LDAP accounts
13 %hr 7 %hr
14 8
15 -= form_for @user, url: profile_path, method: :put, html: { class: "edit_user form-horizontal" } do |f| 9 +
  10 +
  11 += form_for @user, url: profile_path, method: :put, html: { multipart: true, class: "edit_user form-horizontal" } do |f|
16 -if @user.errors.any? 12 -if @user.errors.any?
17 %div.alert.alert-error 13 %div.alert.alert-error
18 %ul 14 %ul
@@ -29,7 +25,7 @@ @@ -29,7 +25,7 @@
29 = f.label :email, class: "control-label" 25 = f.label :email, class: "control-label"
30 .controls 26 .controls
31 = f.text_field :email, class: "input-xlarge", required: true 27 = f.text_field :email, class: "input-xlarge", required: true
32 - %span.help-block We also use email for avatar detection. 28 + %span.help-block We also use email for avatar detection if no avatar is uploaded.
33 .control-group 29 .control-group
34 = f.label :skype, class: "control-label" 30 = f.label :skype, class: "control-label"
35 .controls= f.text_field :skype, class: "input-xlarge" 31 .controls= f.text_field :skype, class: "input-xlarge"
@@ -46,45 +42,23 @@ @@ -46,45 +42,23 @@
46 %span.help-block Tell us about yourself in fewer than 250 characters. 42 %span.help-block Tell us about yourself in fewer than 250 characters.
47 43
48 .span5.pull-right 44 .span5.pull-right
49 - %fieldset.tips  
50 - %legend Tips:  
51 - %ul  
52 - %li  
53 - %p You can change your password on the Account page  
54 - - if Gitlab.config.gravatar.enabled  
55 - %li  
56 - %p You can change your avatar at #{link_to "gravatar.com", "http://gravatar.com"}  
57 -  
58 - - if Gitlab.config.omniauth.enabled && @user.provider?  
59 - %li  
60 - %p  
61 - You can login through #{@user.provider.titleize}!  
62 - = link_to "click here to change", account_profile_path  
63 - - if current_user.can_create_group?  
64 - %li  
65 - %p  
66 - Need a group for several dependent projects?  
67 - = link_to new_group_path, class: "btn btn-tiny" do  
68 - Create a group  
69 - - unless current_user.projects_limit_left > 100  
70 - %fieldset  
71 - %legend  
72 - Personal projects:  
73 - %small.pull-right  
74 - %span= current_user.personal_projects.count  
75 - of  
76 - %span= current_user.projects_limit  
77 - .padded  
78 - .progress  
79 - .bar{style: "width: #{current_user.projects_limit_percent}%;"} 45 + .light-well
  46 + = image_tag avatar_icon(@user.email, 160), alt: '', class: 'avatar s160'
80 47
81 - %fieldset  
82 - %legend  
83 - SSH public keys:  
84 - %span.pull-right  
85 - = link_to pluralize(current_user.keys.count, 'key'), profile_keys_path  
86 - .padded  
87 - = link_to "Add Public Key", new_profile_key_path, class: "btn btn-small" 48 + .clearfix
  49 + .profile-avatar-form-option
  50 + %p.light
  51 + You can upload an avatar here
  52 + %br
  53 + or change it at #{link_to "gravatar.com", "http://gravatar.com"}
  54 + %hr
  55 + %a.choose-btn.btn.btn-small.js-choose-user-avatar-button
  56 + %i.icon-paper-clip
  57 + %span Choose File ...
  58 + &nbsp;
  59 + %span.file_name.js-avatar-filename File name...
  60 + = f.file_field :avatar, class: "js-user-avatar-input hide"
  61 + %span.help-block The maximum file size allowed is 200KB.
88 62
89 .form-actions 63 .form-actions
90 = f.submit 'Save changes', class: "btn btn-save" 64 = f.submit 'Save changes', class: "btn btn-save"
app/views/profiles/update_username.js.haml
1 - if @user.valid? 1 - if @user.valid?
2 :plain 2 :plain
3 - $('.update-username .update-success').show(); 3 + new Flash("Username sucessfully changed", "notice")
4 - else 4 - else
5 :plain 5 :plain
6 - $('.update-username .update-failed').show(); 6 + new Flash("Username change failed - #{@user.errors.full_messages.first}", "alert")
app/views/projects/branches/_branch.html.haml
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 %p 24 %p
25 = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do 25 = link_to project_commit_path(@project, commit.id), class: 'commit_short_id' do
26 = commit.short_id 26 = commit.short_id
27 - = image_tag gravatar_icon(commit.author_email), class: "avatar s16", alt: '' 27 + = image_tag avatar_icon(commit.author_email), class: "avatar s16", alt: ''
28 %span.light 28 %span.light
29 = gfm escape_once(truncate(commit.title, length: 40)) 29 = gfm escape_once(truncate(commit.title, length: 40))
30 %span 30 %span
app/views/projects/commits/show.atom.builder
@@ -12,7 +12,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear @@ -12,7 +12,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear
12 xml.link :href => project_commit_url(@project, :id => commit.id) 12 xml.link :href => project_commit_url(@project, :id => commit.id)
13 xml.title truncate(commit.title, :length => 80) 13 xml.title truncate(commit.title, :length => 80)
14 xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ") 14 xml.updated commit.committed_date.strftime("%Y-%m-%dT%H:%M:%SZ")
15 - xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(commit.author_email) 15 + xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(commit.author_email)
16 xml.author do |author| 16 xml.author do |author|
17 xml.name commit.author_name 17 xml.name commit.author_name
18 xml.email commit.author_email 18 xml.email commit.author_email
app/views/projects/edit.html.haml
@@ -67,7 +67,7 @@ @@ -67,7 +67,7 @@
67 - if Project.issues_tracker.values.count > 1 67 - if Project.issues_tracker.values.count > 1
68 .control-group 68 .control-group
69 = f.label :issues_tracker, "Issues tracker", class: 'control-label' 69 = f.label :issues_tracker, "Issues tracker", class: 'control-label'
70 - .controls= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled }) 70 + .controls= f.select(:issues_tracker, project_issues_trackers, {}, { disabled: !@project.issues_enabled })
71 71
72 .control-group 72 .control-group
73 = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label' 73 = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
app/views/projects/issues/_issues.html.haml
@@ -52,7 +52,7 @@ @@ -52,7 +52,7 @@
52 - @project.team.members.sort_by(&:name).each do |user| 52 - @project.team.members.sort_by(&:name).each do |user|
53 %li 53 %li
54 = link_to project_filter_path(assignee_id: user.id) do 54 = link_to project_filter_path(assignee_id: user.id) do
55 - = image_tag gravatar_icon(user.email), class: "avatar s16", alt: '' 55 + = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
56 = user.name 56 = user.name
57 57
58 .dropdown.inline.prepend-left-10 58 .dropdown.inline.prepend-left-10
app/views/projects/issues/index.atom.builder
@@ -12,7 +12,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear @@ -12,7 +12,7 @@ xml.feed &quot;xmlns&quot; =&gt; &quot;http://www.w3.org/2005/Atom&quot;, &quot;xmlns:media&quot; =&gt; &quot;http://sear
12 xml.link :href => project_issue_url(@project, issue) 12 xml.link :href => project_issue_url(@project, issue)
13 xml.title truncate(issue.title, :length => 80) 13 xml.title truncate(issue.title, :length => 80)
14 xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") 14 xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
15 - xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(issue.author_email) 15 + xml.media :thumbnail, :width => "40", :height => "40", :url => avatar_icon(issue.author_email)
16 xml.author do |author| 16 xml.author do |author|
17 xml.name issue.author_name 17 xml.name issue.author_name
18 xml.email issue.author_email 18 xml.email issue.author_email
app/views/projects/merge_requests/index.html.haml
@@ -35,7 +35,7 @@ @@ -35,7 +35,7 @@
35 - @project.team.members.sort_by(&:name).each do |user| 35 - @project.team.members.sort_by(&:name).each do |user|
36 %li 36 %li
37 = link_to project_filter_path(assignee_id: user.id) do 37 = link_to project_filter_path(assignee_id: user.id) do
38 - = image_tag gravatar_icon(user.email), class: "avatar s16", alt: '' 38 + = image_tag avatar_icon(user.email), class: "avatar s16", alt: ''
39 = user.name 39 = user.name
40 40
41 .dropdown.inline.prepend-left-10 41 .dropdown.inline.prepend-left-10
app/views/projects/milestones/_issues.html.haml
@@ -8,4 +8,4 @@ @@ -8,4 +8,4 @@
8 = link_to_gfm truncate(issue.title, length: 40), [@project, issue] 8 = link_to_gfm truncate(issue.title, length: 40), [@project, issue]
9 - if issue.assignee 9 - if issue.assignee
10 .pull-right 10 .pull-right
11 - = image_tag gravatar_icon(issue.assignee.email, 16), class: "avatar s16" 11 + = image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16"
app/views/projects/milestones/show.html.haml
@@ -99,7 +99,7 @@ @@ -99,7 +99,7 @@
99 - @users.each do |user| 99 - @users.each do |user|
100 %li 100 %li
101 = link_to user, title: user.name, class: "dark" do 101 = link_to user, title: user.name, class: "dark" do
102 - = image_tag gravatar_icon(user.email, 32), class: "avatar s32" 102 + = image_tag avatar_icon(user.email, 32), class: "avatar s32"
103 %strong= truncate(user.name, lenght: 40) 103 %strong= truncate(user.name, lenght: 40)
104 %br 104 %br
105 %small.cgray= user.username 105 %small.cgray= user.username
app/views/projects/network/show.json.erb
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 author: { 9 author: {
10 name: c.author_name, 10 name: c.author_name,
11 email: c.author_email, 11 email: c.author_email,
12 - icon: gravatar_icon(c.author_email, 20) 12 + icon: avatar_icon(c.author_email, 20)
13 }, 13 },
14 time: c.time, 14 time: c.time,
15 space: c.spaces.first, 15 space: c.spaces.first,
app/views/projects/notes/_discussion.html.haml
@@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
8 = link_to "javascript:;", class: "js-details-target turn-off js-toggler-target" do 8 = link_to "javascript:;", class: "js-details-target turn-off js-toggler-target" do
9 %i.icon-eye-open 9 %i.icon-eye-open
10 Show discussion 10 Show discussion
11 - = image_tag gravatar_icon(note.author_email), class: "avatar s32" 11 + = image_tag avatar_icon(note.author_email), class: "avatar s32"
12 %div 12 %div
13 = link_to_member(@project, note.author, avatar: false) 13 = link_to_member(@project, note.author, avatar: false)
14 - if note.for_merge_request? 14 - if note.for_merge_request?
app/views/projects/notes/_note.html.haml
@@ -13,7 +13,7 @@ @@ -13,7 +13,7 @@
13 = link_to project_note_path(@project, note), title: "Remove comment", method: :delete, confirm: 'Are you sure you want to remove this comment?', remote: true, class: "danger js-note-delete" do 13 = link_to project_note_path(@project, note), title: "Remove comment", method: :delete, confirm: 'Are you sure you want to remove this comment?', remote: true, class: "danger js-note-delete" do
14 %i.icon-trash.cred 14 %i.icon-trash.cred
15 Remove 15 Remove
16 - = image_tag gravatar_icon(note.author_email), class: "avatar s32" 16 + = image_tag avatar_icon(note.author_email), class: "avatar s32"
17 = link_to_member(@project, note.author, avatar: false) 17 = link_to_member(@project, note.author, avatar: false)
18 %span.note-last-update 18 %span.note-last-update
19 = note_timestamp(note) 19 = note_timestamp(note)
app/views/projects/repositories/_feed.html.haml
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 %div 11 %div
12 = link_to project_commits_path(@project, commit.id) do 12 = link_to project_commits_path(@project, commit.id) do
13 %code= commit.short_id 13 %code= commit.short_id
14 - = image_tag gravatar_icon(commit.author_email), class: "", width: 16, alt: '' 14 + = image_tag avatar_icon(commit.author_email), class: "", width: 16, alt: ''
15 = gfm escape_once(truncate(commit.title, length: 40)) 15 = gfm escape_once(truncate(commit.title, length: 40))
16 %td 16 %td
17 %span.pull-right.cgray 17 %span.pull-right.cgray
app/views/projects/repositories/stats.html.haml
@@ -19,7 +19,7 @@ @@ -19,7 +19,7 @@
19 %ol.styled 19 %ol.styled
20 - @stats.authors[0...50].each do |author| 20 - @stats.authors[0...50].each do |author|
21 %li 21 %li
22 - = image_tag gravatar_icon(author.email, 16), class: 'avatar s16', alt: '' 22 + = image_tag avatar_icon(author.email, 16), class: 'avatar s16', alt: ''
23 = author.name 23 = author.name
24 %small.light= author.email 24 %small.light= author.email
25 .pull-right 25 .pull-right
app/views/projects/show.html.haml
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 %p 17 %p
18 %p 18 %p
19 %span.light Repo size is 19 %span.light Repo size is
20 - #{@project.repository.size} MB 20 + = repository_size
21 %p 21 %p
22 %span.light Created at 22 %span.light Created at
23 #{@project.created_at.stamp('Aug 22, 2013')} 23 #{@project.created_at.stamp('Aug 22, 2013')}
app/views/projects/snippets/_snippet.html.haml
@@ -16,6 +16,6 @@ @@ -16,6 +16,6 @@
16 = "##{snippet.id}" 16 = "##{snippet.id}"
17 %span 17 %span
18 by 18 by
19 - = image_tag gravatar_icon(snippet.author_email), class: "avatar avatar-inline s16" 19 + = image_tag avatar_icon(snippet.author_email), class: "avatar avatar-inline s16"
20 = snippet.author_name 20 = snippet.author_name
21 %span.light #{time_ago_in_words(snippet.created_at)} ago 21 %span.light #{time_ago_in_words(snippet.created_at)} ago
app/views/projects/snippets/show.html.haml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 = "##{@snippet.id}" 5 = "##{@snippet.id}"
6 %span.light 6 %span.light
7 by 7 by
8 - = image_tag gravatar_icon(@snippet.author_email), class: "avatar avatar-inline s16" 8 + = image_tag avatar_icon(@snippet.author_email), class: "avatar avatar-inline s16"
9 = @snippet.author_name 9 = @snippet.author_name
10 %div= render 'projects/snippets/blob' 10 %div= render 'projects/snippets/blob'
11 %div#notes= render "projects/notes/notes_with_form" 11 %div#notes= render "projects/notes/notes_with_form"
app/views/projects/team_members/_team_member.html.haml
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 &nbsp; 9 &nbsp;
10 = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do 10 = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do
11 %i.icon-minus.icon-white 11 %i.icon-minus.icon-white
12 - = image_tag gravatar_icon(user.email, 32), class: "avatar s32" 12 + = image_tag avatar_icon(user.email, 32), class: "avatar s32"
13 %p 13 %p
14 %strong= user.name 14 %strong= user.name
15 %span.cgray= user.username 15 %span.cgray= user.username
app/views/snippets/_snippet.html.haml
@@ -18,6 +18,6 @@ @@ -18,6 +18,6 @@
18 %span 18 %span
19 by 19 by
20 = link_to user_snippets_path(snippet.author) do 20 = link_to user_snippets_path(snippet.author) do
21 - = image_tag gravatar_icon(snippet.author_email), class: "avatar avatar-inline s16", alt: '' 21 + = image_tag avatar_icon(snippet.author_email), class: "avatar avatar-inline s16", alt: ''
22 = snippet.author_name 22 = snippet.author_name
23 %span.light #{time_ago_in_words(snippet.created_at)} ago 23 %span.light #{time_ago_in_words(snippet.created_at)} ago
app/views/snippets/show.html.haml
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 %span.light 17 %span.light
18 by 18 by
19 = link_to user_snippets_path(@snippet.author) do 19 = link_to user_snippets_path(@snippet.author) do
20 - = image_tag gravatar_icon(@snippet.author_email), class: "avatar avatar-inline s16" 20 + = image_tag avatar_icon(@snippet.author_email), class: "avatar avatar-inline s16"
21 = @snippet.author_name 21 = @snippet.author_name
22 22
23 .back-link 23 .back-link
app/views/snippets/user_index.html.haml
1 %h3.page-title 1 %h3.page-title
2 - = image_tag gravatar_icon(@user.email), class: "avatar s24" 2 + = image_tag avatar_icon(@user.email), class: "avatar s24"
3 = @user.name 3 = @user.name
4 %span 4 %span
5 \/ 5 \/
app/views/users/_projects.html.haml
@@ -3,9 +3,4 @@ @@ -3,9 +3,4 @@
3 %ul.well-list 3 %ul.well-list
4 - @projects.each do |project| 4 - @projects.each do |project|
5 %li 5 %li
6 - = link_to project_path(project), class: dom_class(project) do  
7 - - if project.namespace  
8 - = project.namespace.human_name  
9 - \/  
10 - %strong.well-title  
11 - = truncate(project.name, length: 45) 6 + = link_to_project project
app/views/users/show.html.haml
1 .row 1 .row
2 .span8 2 .span8
3 %h3.page-title 3 %h3.page-title
4 - = image_tag gravatar_icon(@user.email, 90), class: "avatar s90", alt: '' 4 + = image_tag avatar_icon(@user.email, 90), class: "avatar s90", alt: ''
5 = @user.name 5 = @user.name
6 - if @user == current_user 6 - if @user == current_user
7 .pull-right 7 .pull-right
app/views/users_groups/_users_group.html.haml
1 - user = member.user 1 - user = member.user
2 - return unless user 2 - return unless user
3 %li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)} 3 %li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
4 - = image_tag gravatar_icon(user.email, 16), class: "avatar s16" 4 + = image_tag avatar_icon(user.email, 16), class: "avatar s16"
5 %strong= user.name 5 %strong= user.name
6 %span.cgray= user.username 6 %span.cgray= user.username
7 - if user == current_user 7 - if user == current_user
config/gitlab.yml.example
@@ -73,6 +73,7 @@ production: &amp;base @@ -73,6 +73,7 @@ production: &amp;base
73 ## External issues trackers 73 ## External issues trackers
74 issues_tracker: 74 issues_tracker:
75 # redmine: 75 # redmine:
  76 + # title: "Redmine"
76 # ## If not nil, link 'Issues' on project page will be replaced with this 77 # ## If not nil, link 'Issues' on project page will be replaced with this
77 # ## Use placeholders: 78 # ## Use placeholders:
78 # ## :project_id - GitLab project identifier 79 # ## :project_id - GitLab project identifier
@@ -93,6 +94,7 @@ production: &amp;base @@ -93,6 +94,7 @@ production: &amp;base
93 # new_issue_url: "http://redmine.sample/projects/:issues_tracker_id/issues/new" 94 # new_issue_url: "http://redmine.sample/projects/:issues_tracker_id/issues/new"
94 # 95 #
95 # jira: 96 # jira:
  97 + # title: "Atlassian Jira"
96 # project_url: "http://jira.sample/issues/?jql=project=:issues_tracker_id" 98 # project_url: "http://jira.sample/issues/?jql=project=:issues_tracker_id"
97 # issues_url: "http://jira.sample/browse/:id" 99 # issues_url: "http://jira.sample/browse/:id"
98 # new_issue_url: "http://jira.sample/secure/CreateIssue.jspa" 100 # new_issue_url: "http://jira.sample/secure/CreateIssue.jspa"
@@ -206,6 +208,7 @@ test: @@ -206,6 +208,7 @@ test:
206 <<: *base 208 <<: *base
207 issues_tracker: 209 issues_tracker:
208 redmine: 210 redmine:
  211 + title: "Redmine"
209 project_url: "http://redmine/projects/:issues_tracker_id" 212 project_url: "http://redmine/projects/:issues_tracker_id"
210 issues_url: "http://redmine/:project_id/:issues_tracker_id/:id" 213 issues_url: "http://redmine/:project_id/:issues_tracker_id/:id"
211 new_issue_url: "http://redmine/projects/:issues_tracker_id/issues/new" 214 new_issue_url: "http://redmine/projects/:issues_tracker_id/issues/new"
config/initializers/devise_async.rb 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +Devise::Async.backend = :sidekiq
config/routes.rb
@@ -99,19 +99,21 @@ Gitlab::Application.routes.draw do @@ -99,19 +99,21 @@ Gitlab::Application.routes.draw do
99 # 99 #
100 resource :profile, only: [:show, :update] do 100 resource :profile, only: [:show, :update] do
101 member do 101 member do
102 - get :account  
103 get :history 102 get :history
104 - get :token  
105 get :design 103 get :design
106 104
107 - put :update_password  
108 put :reset_private_token 105 put :reset_private_token
109 put :update_username 106 put :update_username
110 end 107 end
111 108
112 scope module: :profiles do 109 scope module: :profiles do
  110 + resource :account, only: [:show, :update]
113 resource :notifications, only: [:show, :update] 111 resource :notifications, only: [:show, :update]
114 - resource :password, only: [:new, :create] 112 + resource :password, only: [:new, :create, :edit, :update] do
  113 + member do
  114 + put :reset
  115 + end
  116 + end
115 resources :keys 117 resources :keys
116 resources :groups, only: [:index] do 118 resources :groups, only: [:index] do
117 member do 119 member do
db/migrate/20131005191208_add_avatar_to_users.rb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +class AddAvatarToUsers < ActiveRecord::Migration
  2 + def change
  3 + add_column :users, :avatar, :string
  4 + end
  5 +end
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 # 11 #
12 # It's strongly recommended to check this file into your version control system. 12 # It's strongly recommended to check this file into your version control system.
13 13
14 -ActiveRecord::Schema.define(:version => 20130926081215) do 14 +ActiveRecord::Schema.define(:version => 20131005191208) do
15 15
16 create_table "deploy_keys_projects", :force => true do |t| 16 create_table "deploy_keys_projects", :force => true do |t|
17 t.integer "deploy_key_id", :null => false 17 t.integer "deploy_key_id", :null => false
@@ -283,6 +283,7 @@ ActiveRecord::Schema.define(:version =&gt; 20130926081215) do @@ -283,6 +283,7 @@ ActiveRecord::Schema.define(:version =&gt; 20130926081215) do
283 t.integer "notification_level", :default => 1, :null => false 283 t.integer "notification_level", :default => 1, :null => false
284 t.datetime "password_expires_at" 284 t.datetime "password_expires_at"
285 t.integer "created_by_id" 285 t.integer "created_by_id"
  286 + t.string "avatar"
286 end 287 end
287 288
288 add_index "users", ["admin"], :name => "index_users_on_admin" 289 add_index "users", ["admin"], :name => "index_users_on_admin"
doc/api/projects.md
@@ -244,6 +244,18 @@ Parameters: @@ -244,6 +244,18 @@ Parameters:
244 + `public` (optional) 244 + `public` (optional)
245 245
246 246
  247 +## Remove project
  248 +
  249 +Removes project with all resources(issues, merge requests etc)
  250 +
  251 +```
  252 +DELETE /projects/:id
  253 +```
  254 +
  255 +Parameters:
  256 +
  257 ++ `id` (required) - The ID of a project
  258 +
247 259
248 ## Team members 260 ## Team members
249 261
doc/install/installation.md
@@ -63,7 +63,7 @@ Make sure you have the right version of Python installed. @@ -63,7 +63,7 @@ Make sure you have the right version of Python installed.
63 python --version 63 python --version
64 64
65 # If it's Python 3 you might need to install Python 2 separately 65 # If it's Python 3 you might need to install Python 2 separately
66 - sudo apt-get install python2.7 66 + sudo apt-get install -y python2.7
67 67
68 # Make sure you can access Python via python2 68 # Make sure you can access Python via python2
69 python2 --version 69 python2 --version
@@ -72,7 +72,7 @@ Make sure you have the right version of Python installed. @@ -72,7 +72,7 @@ Make sure you have the right version of Python installed.
72 sudo ln -s /usr/bin/python /usr/bin/python2 72 sudo ln -s /usr/bin/python /usr/bin/python2
73 73
74 # For reStructuredText markup language support install required package: 74 # For reStructuredText markup language support install required package:
75 - sudo apt-get install python-docutils 75 + sudo apt-get install -y python-docutils
76 76
77 **Note:** In order to receive mail notifications, make sure to install a 77 **Note:** In order to receive mail notifications, make sure to install a
78 mail server. By default, Debian is shipped with exim4 whereas Ubuntu 78 mail server. By default, Debian is shipped with exim4 whereas Ubuntu
features/profile/profile.feature
@@ -12,26 +12,31 @@ Feature: Profile @@ -12,26 +12,31 @@ Feature: Profile
12 And I should see new contact info 12 And I should see new contact info
13 13
14 Scenario: I change my password without old one 14 Scenario: I change my password without old one
15 - Given I visit profile account page 15 + Given I visit profile password page
16 When I try change my password w/o old one 16 When I try change my password w/o old one
17 Then I should see a missing password error message 17 Then I should see a missing password error message
18 - And I should be redirected to account page 18 + And I should be redirected to password page
19 19
20 Scenario: I change my password 20 Scenario: I change my password
21 - Given I visit profile account page 21 + Given I visit profile password page
22 Then I change my password 22 Then I change my password
23 And I should be redirected to sign in page 23 And I should be redirected to sign in page
24 24
  25 + Scenario: I edit my avatar
  26 + Given I visit profile page
  27 + Then I change my avatar
  28 + And I should see new avatar
  29 +
25 Scenario: My password is expired 30 Scenario: My password is expired
26 Given my password is expired 31 Given my password is expired
27 And I am not an ldap user 32 And I am not an ldap user
28 - And I visit profile account page 33 + Given I visit profile password page
29 Then I redirected to expired password page 34 Then I redirected to expired password page
30 And I submit new password 35 And I submit new password
31 And I redirected to sign in page 36 And I redirected to sign in page
32 37
33 Scenario: I unsuccessfully change my password 38 Scenario: I unsuccessfully change my password
34 - Given I visit profile account page 39 + Given I visit profile password page
35 When I unsuccessfully change my password 40 When I unsuccessfully change my password
36 Then I should see a password error message 41 Then I should see a password error message
37 42
features/steps/profile/profile.rb
@@ -3,9 +3,7 @@ class Profile &lt; Spinach::FeatureSteps @@ -3,9 +3,7 @@ class Profile &lt; Spinach::FeatureSteps
3 include SharedPaths 3 include SharedPaths
4 4
5 step 'I should see my profile info' do 5 step 'I should see my profile info' do
6 - page.should have_content "Profile"  
7 - page.should have_content @user.name  
8 - page.should have_content @user.email 6 + page.should have_content "Profile settings"
9 end 7 end
10 8
11 step 'I change my contact info' do 9 step 'I change my contact info' do
@@ -22,6 +20,17 @@ class Profile &lt; Spinach::FeatureSteps @@ -22,6 +20,17 @@ class Profile &lt; Spinach::FeatureSteps
22 @user.twitter.should == 'testtwitter' 20 @user.twitter.should == 'testtwitter'
23 end 21 end
24 22
  23 + step 'I change my avatar' do
  24 + attach_file(:user_avatar, File.join(Rails.root, 'public', 'gitlab_logo.png'))
  25 + click_button "Save changes"
  26 + @user.reload
  27 + end
  28 +
  29 + step 'I should see new avatar' do
  30 + @user.avatar.should be_instance_of AttachmentUploader
  31 + @user.avatar.url.should == "/uploads/user/avatar/#{ @user.id }/gitlab_logo.png"
  32 + end
  33 +
25 step 'I try change my password w/o old one' do 34 step 'I try change my password w/o old one' do
26 within '.update-password' do 35 within '.update-password' do
27 fill_in "user_password", with: "222333" 36 fill_in "user_password", with: "222333"
@@ -124,8 +133,12 @@ class Profile &lt; Spinach::FeatureSteps @@ -124,8 +133,12 @@ class Profile &lt; Spinach::FeatureSteps
124 current_path.should == new_user_session_path 133 current_path.should == new_user_session_path
125 end 134 end
126 135
  136 + step 'I should be redirected to password page' do
  137 + current_path.should == edit_profile_password_path
  138 + end
  139 +
127 step 'I should be redirected to account page' do 140 step 'I should be redirected to account page' do
128 - current_path.should == account_profile_path 141 + current_path.should == profile_account_path
129 end 142 end
130 143
131 step 'I click on my profile picture' do 144 step 'I click on my profile picture' do
features/steps/shared/paths.rb
@@ -65,8 +65,12 @@ module SharedPaths @@ -65,8 +65,12 @@ module SharedPaths
65 visit profile_path 65 visit profile_path
66 end 66 end
67 67
  68 + step 'I visit profile password page' do
  69 + visit edit_profile_password_path
  70 + end
  71 +
68 step 'I visit profile account page' do 72 step 'I visit profile account page' do
69 - visit account_profile_path 73 + visit profile_account_path
70 end 74 end
71 75
72 step 'I visit profile SSH keys page' do 76 step 'I visit profile SSH keys page' do
lib/api/groups.rb
@@ -66,7 +66,6 @@ module API @@ -66,7 +66,6 @@ module API
66 present group, with: Entities::GroupDetail 66 present group, with: Entities::GroupDetail
67 end 67 end
68 68
69 -  
70 # Remove group 69 # Remove group
71 # 70 #
72 # Parameters: 71 # Parameters:
lib/api/projects.rb
@@ -129,6 +129,16 @@ module API @@ -129,6 +129,16 @@ module API
129 end 129 end
130 end 130 end
131 131
  132 + # Remove project
  133 + #
  134 + # Parameters:
  135 + # id (required) - The ID of a project
  136 + # Example Request:
  137 + # DELETE /projects/:id
  138 + delete ":id" do
  139 + authorize! :remove_project, user_project
  140 + user_project.destroy
  141 + end
132 142
133 # Mark this project as forked from another 143 # Mark this project as forked from another
134 # 144 #
spec/features/notes_on_merge_requests_spec.rb
@@ -216,12 +216,6 @@ describe &quot;On a merge request diff&quot;, js: true, focus: true do @@ -216,12 +216,6 @@ describe &quot;On a merge request diff&quot;, js: true, focus: true do
216 end 216 end
217 end 217 end
218 218
219 - it do  
220 - within("tr[id='342e16cbbd482ac2047dc679b2749d248cc1428f_18_17'] + .js-temp-notes-holder") do  
221 - should have_no_css(".js-temp-notes-holder")  
222 - end  
223 - end  
224 -  
225 it 'should be added as discussion' do 219 it 'should be added as discussion' do
226 should have_content("Another comment on line 17") 220 should have_content("Another comment on line 17")
227 should have_css(".notes_holder") 221 should have_css(".notes_holder")
spec/features/profile_spec.rb
@@ -12,7 +12,7 @@ describe &quot;Profile account page&quot; do @@ -12,7 +12,7 @@ describe &quot;Profile account page&quot; do
12 describe "when signup is enabled" do 12 describe "when signup is enabled" do
13 before do 13 before do
14 Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) 14 Gitlab.config.gitlab.stub(:signup_enabled).and_return(true)
15 - visit account_profile_path 15 + visit profile_account_path
16 end 16 end
17 17
18 it { page.should have_content("Remove account") } 18 it { page.should have_content("Remove account") }
@@ -26,12 +26,12 @@ describe &quot;Profile account page&quot; do @@ -26,12 +26,12 @@ describe &quot;Profile account page&quot; do
26 describe "when signup is disabled" do 26 describe "when signup is disabled" do
27 before do 27 before do
28 Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) 28 Gitlab.config.gitlab.stub(:signup_enabled).and_return(false)
29 - visit account_profile_path 29 + visit profile_account_path
30 end 30 end
31 31
32 it "should not have option to remove account" do 32 it "should not have option to remove account" do
33 page.should_not have_content("Remove account") 33 page.should_not have_content("Remove account")
34 - current_path.should == account_profile_path 34 + current_path.should == profile_account_path
35 end 35 end
36 end 36 end
37 end 37 end
spec/features/security/profile_access_spec.rb
@@ -29,7 +29,7 @@ describe &quot;Users Security&quot; do @@ -29,7 +29,7 @@ describe &quot;Users Security&quot; do
29 end 29 end
30 30
31 describe "GET /profile/account" do 31 describe "GET /profile/account" do
32 - subject { account_profile_path } 32 + subject { profile_account_path }
33 33
34 it { should be_allowed_for @u1 } 34 it { should be_allowed_for @u1 }
35 it { should be_allowed_for :admin } 35 it { should be_allowed_for :admin }
spec/helpers/application_helper_spec.rb
@@ -38,6 +38,24 @@ describe ApplicationHelper do @@ -38,6 +38,24 @@ describe ApplicationHelper do
38 current_action?(:baz, :bar, :foo).should be_true 38 current_action?(:baz, :bar, :foo).should be_true
39 end 39 end
40 end 40 end
  41 +
  42 + describe "avatar_icon" do
  43 + avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png')
  44 +
  45 + it "should return an url for the avatar" do
  46 + user = create(:user)
  47 + user.avatar = File.open(avatar_file_path)
  48 + user.save!
  49 + avatar_icon(user.email).to_s.should == "/uploads/user/avatar/#{ user.id }/gitlab_logo.png"
  50 + end
  51 +
  52 + it "should call gravatar_icon when no avatar is present" do
  53 + user = create(:user)
  54 + user.save!
  55 + stub!(:gravatar_icon).and_return('gravatar_method_called')
  56 + avatar_icon(user.email).to_s.should == "gravatar_method_called"
  57 + end
  58 + end
41 59
42 describe "gravatar_icon" do 60 describe "gravatar_icon" do
43 let(:user_email) { 'user@email.com' } 61 let(:user_email) { 'user@email.com' }
spec/helpers/projects_helper_spec.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +require 'spec_helper'
  2 +
  3 +describe ProjectsHelper do
  4 + describe '#project_issues_trackers' do
  5 + it "returns the correct issues trackers available" do
  6 + project_issues_trackers.should ==
  7 + "<option value=\"redmine\">Redmine</option>\n" \
  8 + "<option value=\"gitlab\">GitLab</option>"
  9 + end
  10 + end
  11 +end
spec/requests/api/projects_spec.rb
@@ -730,4 +730,42 @@ describe API::API do @@ -730,4 +730,42 @@ describe API::API do
730 end 730 end
731 end 731 end
732 end 732 end
  733 +
  734 + describe "DELETE /projects/:id" do
  735 + context "when authenticated as user" do
  736 + it "should remove project" do
  737 + delete api("/projects/#{project.id}", user)
  738 + response.status.should == 200
  739 + end
  740 +
  741 + it "should not remove a project if not an owner" do
  742 + user3 = create(:user)
  743 + project.team << [user3, :developer]
  744 + delete api("/projects/#{project.id}", user3)
  745 + response.status.should == 403
  746 + end
  747 +
  748 + it "should not remove a non existing project" do
  749 + delete api("/projects/1328", user)
  750 + response.status.should == 404
  751 + end
  752 +
  753 + it "should not remove a project not attached to user" do
  754 + delete api("/projects/#{project.id}", user2)
  755 + response.status.should == 404
  756 + end
  757 + end
  758 +
  759 + context "when authenticated as admin" do
  760 + it "should remove any existing project" do
  761 + delete api("/projects/#{project.id}", admin)
  762 + response.status.should == 200
  763 + end
  764 +
  765 + it "should not remove a non existing project" do
  766 + delete api("/projects/1328", admin)
  767 + response.status.should == 404
  768 + end
  769 + end
  770 + end
733 end 771 end
spec/routing/routing_spec.rb
@@ -128,7 +128,7 @@ end @@ -128,7 +128,7 @@ end
128 # profile_update PUT /profile/update(.:format) profile#update 128 # profile_update PUT /profile/update(.:format) profile#update
129 describe ProfilesController, "routing" do 129 describe ProfilesController, "routing" do
130 it "to #account" do 130 it "to #account" do
131 - get("/profile/account").should route_to('profiles#account') 131 + get("/profile/account").should route_to('profiles/accounts#show')
132 end 132 end
133 133
134 it "to #history" do 134 it "to #history" do