Commit 76f2e065ea51f6364b1ca3dc0b1d29d6f52a4b04
Exists in
master
and in
4 other branches
Merge branch 'master' into install-guide-improvements
Conflicts: doc/install/installation.md
Showing
64 changed files
with
661 additions
and
384 deletions
Show diff stats
CHANGELOG
| @@ -24,6 +24,7 @@ v 5.3.0 | @@ -24,6 +24,7 @@ v 5.3.0 | ||
| 24 | - init.d: Ensure socket is removed before starting service | 24 | - init.d: Ensure socket is removed before starting service |
| 25 | - Admin area: Style teams:index, group:show pages | 25 | - Admin area: Style teams:index, group:show pages |
| 26 | - Own page for failed forking | 26 | - Own page for failed forking |
| 27 | + - Scrum view for milestone | ||
| 27 | 28 | ||
| 28 | v 5.2.0 | 29 | v 5.2.0 |
| 29 | - Turbolinks | 30 | - Turbolinks |
Gemfile
| @@ -29,7 +29,7 @@ gem 'gitlab_git', '~> 1.3.0' | @@ -29,7 +29,7 @@ gem 'gitlab_git', '~> 1.3.0' | ||
| 29 | gem 'gitlab-grack', '~> 1.0.1', require: 'grack' | 29 | gem 'gitlab-grack', '~> 1.0.1', require: 'grack' |
| 30 | 30 | ||
| 31 | # LDAP Auth | 31 | # LDAP Auth |
| 32 | -gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap" | 32 | +gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap" |
| 33 | 33 | ||
| 34 | # Syntax highlighter | 34 | # Syntax highlighter |
| 35 | gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb' | 35 | gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb' |
| @@ -72,6 +72,9 @@ gem "seed-fu" | @@ -72,6 +72,9 @@ gem "seed-fu" | ||
| 72 | gem "redcarpet", "~> 2.2.2" | 72 | gem "redcarpet", "~> 2.2.2" |
| 73 | gem "github-markup", "~> 0.7.4", require: 'github/markup' | 73 | gem "github-markup", "~> 0.7.4", require: 'github/markup' |
| 74 | 74 | ||
| 75 | +# Asciidoc to HTML | ||
| 76 | +gem "asciidoctor" | ||
| 77 | + | ||
| 75 | # Servers | 78 | # Servers |
| 76 | gem "puma", '~> 2.0.1' | 79 | gem "puma", '~> 2.0.1' |
| 77 | 80 |
Gemfile.lock
| @@ -46,6 +46,7 @@ GEM | @@ -46,6 +46,7 @@ GEM | ||
| 46 | rails (~> 3.0) | 46 | rails (~> 3.0) |
| 47 | addressable (2.3.4) | 47 | addressable (2.3.4) |
| 48 | arel (3.0.2) | 48 | arel (3.0.2) |
| 49 | + asciidoctor (0.1.3) | ||
| 49 | awesome_print (1.1.0) | 50 | awesome_print (1.1.0) |
| 50 | backports (2.6.7) | 51 | backports (2.6.7) |
| 51 | bcrypt-ruby (3.0.1) | 52 | bcrypt-ruby (3.0.1) |
| @@ -168,8 +169,8 @@ GEM | @@ -168,8 +169,8 @@ GEM | ||
| 168 | github-linguist (~> 2.3.4) | 169 | github-linguist (~> 2.3.4) |
| 169 | gitlab-grit (~> 2.5.1) | 170 | gitlab-grit (~> 2.5.1) |
| 170 | gitlab_meta (5.0) | 171 | gitlab_meta (5.0) |
| 171 | - gitlab_omniauth-ldap (1.0.2) | ||
| 172 | - net-ldap (~> 0.2.2) | 172 | + gitlab_omniauth-ldap (1.0.3) |
| 173 | + net-ldap (~> 0.3.1) | ||
| 173 | omniauth (~> 1.0) | 174 | omniauth (~> 1.0) |
| 174 | pyu-ruby-sasl (~> 0.0.3.1) | 175 | pyu-ruby-sasl (~> 0.0.3.1) |
| 175 | rubyntlm (~> 0.1.1) | 176 | rubyntlm (~> 0.1.1) |
| @@ -265,7 +266,7 @@ GEM | @@ -265,7 +266,7 @@ GEM | ||
| 265 | multi_xml (0.5.3) | 266 | multi_xml (0.5.3) |
| 266 | multipart-post (1.2.0) | 267 | multipart-post (1.2.0) |
| 267 | mysql2 (0.3.11) | 268 | mysql2 (0.3.11) |
| 268 | - net-ldap (0.2.2) | 269 | + net-ldap (0.3.1) |
| 269 | nokogiri (1.5.9) | 270 | nokogiri (1.5.9) |
| 270 | oauth (0.4.7) | 271 | oauth (0.4.7) |
| 271 | oauth2 (0.8.1) | 272 | oauth2 (0.8.1) |
| @@ -517,6 +518,7 @@ PLATFORMS | @@ -517,6 +518,7 @@ PLATFORMS | ||
| 517 | DEPENDENCIES | 518 | DEPENDENCIES |
| 518 | acts-as-taggable-on | 519 | acts-as-taggable-on |
| 519 | annotate! | 520 | annotate! |
| 521 | + asciidoctor | ||
| 520 | awesome_print | 522 | awesome_print |
| 521 | better_errors | 523 | better_errors |
| 522 | binding_of_caller | 524 | binding_of_caller |
| @@ -544,7 +546,7 @@ DEPENDENCIES | @@ -544,7 +546,7 @@ DEPENDENCIES | ||
| 544 | gitlab-pygments.rb (~> 0.3.2) | 546 | gitlab-pygments.rb (~> 0.3.2) |
| 545 | gitlab_git (~> 1.3.0) | 547 | gitlab_git (~> 1.3.0) |
| 546 | gitlab_meta (= 5.0) | 548 | gitlab_meta (= 5.0) |
| 547 | - gitlab_omniauth-ldap (= 1.0.2) | 549 | + gitlab_omniauth-ldap (= 1.0.3) |
| 548 | gon | 550 | gon |
| 549 | grape (~> 0.4.1) | 551 | grape (~> 0.4.1) |
| 550 | grape-entity (~> 0.3.0) | 552 | grape-entity (~> 0.3.0) |
VERSION
app/assets/javascripts/milestones.js.coffee
| @@ -1,14 +0,0 @@ | @@ -1,14 +0,0 @@ | ||
| 1 | -$ -> | ||
| 2 | - $('.milestone-issue-filter li[data-closed]').addClass('hide') | ||
| 3 | - | ||
| 4 | - $('.milestone-issue-filter ul.nav li a').click -> | ||
| 5 | - $('.milestone-issue-filter li').toggleClass('active') | ||
| 6 | - $('.milestone-issue-filter li[data-closed]').toggleClass('hide') | ||
| 7 | - false | ||
| 8 | - | ||
| 9 | - $('.milestone-merge-requests-filter li[data-closed]').addClass('hide') | ||
| 10 | - | ||
| 11 | - $('.milestone-merge-requests-filter ul.nav li a').click -> | ||
| 12 | - $('.milestone-merge-requests-filter li').toggleClass('active') | ||
| 13 | - $('.milestone-merge-requests-filter li[data-closed]').toggleClass('hide') | ||
| 14 | - false |
app/assets/stylesheets/gitlab_bootstrap/nav.scss
app/assets/stylesheets/sections/events.scss
app/assets/stylesheets/sections/notes.scss
| @@ -92,6 +92,10 @@ ul.notes { | @@ -92,6 +92,10 @@ ul.notes { | ||
| 92 | .note-body { | 92 | .note-body { |
| 93 | @include md-typography; | 93 | @include md-typography; |
| 94 | margin-left: 45px; | 94 | margin-left: 45px; |
| 95 | + | ||
| 96 | + .highlight { | ||
| 97 | + @include border-radius(4px); | ||
| 98 | + } | ||
| 95 | } | 99 | } |
| 96 | .note-header { | 100 | .note-header { |
| 97 | padding-bottom: 5px; | 101 | padding-bottom: 5px; |
app/contexts/issues/list_context.rb
| @@ -8,7 +8,7 @@ module Issues | @@ -8,7 +8,7 @@ module Issues | ||
| 8 | @issues = case params[:status] | 8 | @issues = case params[:status] |
| 9 | when issues_filter[:all] then @project.issues | 9 | when issues_filter[:all] then @project.issues |
| 10 | when issues_filter[:closed] then @project.issues.closed | 10 | when issues_filter[:closed] then @project.issues.closed |
| 11 | - when issues_filter[:to_me] then @project.issues.assigned(current_user) | 11 | + when issues_filter[:to_me] then @project.issues.assigned_to(current_user) |
| 12 | when issues_filter[:by_me] then @project.issues.authored(current_user) | 12 | when issues_filter[:by_me] then @project.issues.authored(current_user) |
| 13 | else @project.issues.opened | 13 | else @project.issues.opened |
| 14 | end | 14 | end |
app/contexts/projects/create_context.rb
| @@ -51,6 +51,7 @@ module Projects | @@ -51,6 +51,7 @@ module Projects | ||
| 51 | if shell.import_repository(@project.path_with_namespace, @project.import_url) | 51 | if shell.import_repository(@project.path_with_namespace, @project.import_url) |
| 52 | # We should create satellite for imported repo | 52 | # We should create satellite for imported repo |
| 53 | @project.satellite.create unless @project.satellite.exists? | 53 | @project.satellite.create unless @project.satellite.exists? |
| 54 | + @project.imported = true | ||
| 54 | true | 55 | true |
| 55 | else | 56 | else |
| 56 | @project.errors.add(:import_url, 'cannot clone repo') | 57 | @project.errors.add(:import_url, 'cannot clone repo') |
app/controllers/admin/groups_controller.rb
| @@ -8,10 +8,6 @@ class Admin::GroupsController < Admin::ApplicationController | @@ -8,10 +8,6 @@ class Admin::GroupsController < Admin::ApplicationController | ||
| 8 | end | 8 | end |
| 9 | 9 | ||
| 10 | def show | 10 | def show |
| 11 | - @projects = Project.scoped | ||
| 12 | - @projects = @projects.not_in_group(@group) if @group.projects.present? | ||
| 13 | - @projects = @projects.all | ||
| 14 | - @projects.reject!(&:empty_repo?) | ||
| 15 | end | 11 | end |
| 16 | 12 | ||
| 17 | def new | 13 | def new |
app/controllers/admin/users_controller.rb
| @@ -55,8 +55,14 @@ class Admin::UsersController < Admin::ApplicationController | @@ -55,8 +55,14 @@ class Admin::UsersController < Admin::ApplicationController | ||
| 55 | def create | 55 | def create |
| 56 | admin = params[:user].delete("admin") | 56 | admin = params[:user].delete("admin") |
| 57 | 57 | ||
| 58 | - @admin_user = User.new(params[:user], as: :admin) | 58 | + opts = { |
| 59 | + force_random_password: true, | ||
| 60 | + password_expires_at: Time.now | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + @admin_user = User.new(params[:user].merge(opts), as: :admin) | ||
| 59 | @admin_user.admin = (admin && admin.to_i > 0) | 64 | @admin_user.admin = (admin && admin.to_i > 0) |
| 65 | + @admin_user.created_by_id = current_user.id | ||
| 60 | 66 | ||
| 61 | respond_to do |format| | 67 | respond_to do |format| |
| 62 | if @admin_user.save | 68 | if @admin_user.save |
app/controllers/application_controller.rb
| 1 | class ApplicationController < ActionController::Base | 1 | class ApplicationController < ActionController::Base |
| 2 | before_filter :authenticate_user! | 2 | before_filter :authenticate_user! |
| 3 | before_filter :reject_blocked! | 3 | before_filter :reject_blocked! |
| 4 | + before_filter :check_password_expiration | ||
| 4 | before_filter :set_current_user_for_thread | 5 | before_filter :set_current_user_for_thread |
| 5 | before_filter :add_abilities | 6 | before_filter :add_abilities |
| 6 | before_filter :dev_tools if Rails.env == 'development' | 7 | before_filter :dev_tools if Rails.env == 'development' |
| @@ -156,4 +157,10 @@ class ApplicationController < ActionController::Base | @@ -156,4 +157,10 @@ class ApplicationController < ActionController::Base | ||
| 156 | gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url | 157 | gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url |
| 157 | gon.relative_url_root = Gitlab.config.gitlab.relative_url_root | 158 | gon.relative_url_root = Gitlab.config.gitlab.relative_url_root |
| 158 | end | 159 | end |
| 160 | + | ||
| 161 | + def check_password_expiration | ||
| 162 | + if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now | ||
| 163 | + redirect_to new_profile_password_path and return | ||
| 164 | + end | ||
| 165 | + end | ||
| 159 | end | 166 | end |
| @@ -0,0 +1,38 @@ | @@ -0,0 +1,38 @@ | ||
| 1 | +class PasswordsController < ApplicationController | ||
| 2 | + layout 'navless' | ||
| 3 | + | ||
| 4 | + skip_before_filter :check_password_expiration | ||
| 5 | + | ||
| 6 | + before_filter :set_user | ||
| 7 | + before_filter :set_title | ||
| 8 | + | ||
| 9 | + def new | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + def create | ||
| 13 | + new_password = params[:user][:password] | ||
| 14 | + new_password_confirmation = params[:user][:password_confirmation] | ||
| 15 | + | ||
| 16 | + result = @user.update_attributes( | ||
| 17 | + password: new_password, | ||
| 18 | + password_confirmation: new_password_confirmation | ||
| 19 | + ) | ||
| 20 | + | ||
| 21 | + if result | ||
| 22 | + @user.update_attributes(password_expires_at: nil) | ||
| 23 | + redirect_to root_path, notice: 'Password successfully changed' | ||
| 24 | + else | ||
| 25 | + render :new | ||
| 26 | + end | ||
| 27 | + end | ||
| 28 | + | ||
| 29 | + private | ||
| 30 | + | ||
| 31 | + def set_user | ||
| 32 | + @user = current_user | ||
| 33 | + end | ||
| 34 | + | ||
| 35 | + def set_title | ||
| 36 | + @title = "New password" | ||
| 37 | + end | ||
| 38 | +end |
app/controllers/snippets_controller.rb
| @@ -7,8 +7,12 @@ class SnippetsController < ApplicationController | @@ -7,8 +7,12 @@ class SnippetsController < ApplicationController | ||
| 7 | # Allow destroy snippet | 7 | # Allow destroy snippet |
| 8 | before_filter :authorize_admin_snippet!, only: [:destroy] | 8 | before_filter :authorize_admin_snippet!, only: [:destroy] |
| 9 | 9 | ||
| 10 | + before_filter :set_title | ||
| 11 | + | ||
| 10 | respond_to :html | 12 | respond_to :html |
| 11 | 13 | ||
| 14 | + layout 'navless' | ||
| 15 | + | ||
| 12 | def index | 16 | def index |
| 13 | @snippets = Snippet.public.fresh.non_expired.page(params[:page]).per(20) | 17 | @snippets = Snippet.public.fresh.non_expired.page(params[:page]).per(20) |
| 14 | end | 18 | end |
| @@ -98,4 +102,8 @@ class SnippetsController < ApplicationController | @@ -98,4 +102,8 @@ class SnippetsController < ApplicationController | ||
| 98 | def authorize_admin_snippet! | 102 | def authorize_admin_snippet! |
| 99 | return render_404 unless can?(current_user, :admin_personal_snippet, @snippet) | 103 | return render_404 unless can?(current_user, :admin_personal_snippet, @snippet) |
| 100 | end | 104 | end |
| 105 | + | ||
| 106 | + def set_title | ||
| 107 | + @title = 'Snippets' | ||
| 108 | + end | ||
| 101 | end | 109 | end |
app/helpers/application_helper.rb
| @@ -142,7 +142,7 @@ module ApplicationHelper | @@ -142,7 +142,7 @@ module ApplicationHelper | ||
| 142 | end | 142 | end |
| 143 | 143 | ||
| 144 | def user_color_scheme_class | 144 | def user_color_scheme_class |
| 145 | - COLOR_SCHEMES[current_user.try(:color_scheme_id)] | 145 | + COLOR_SCHEMES[current_user.try(:color_scheme_id)] if defined?(current_user) |
| 146 | end | 146 | end |
| 147 | 147 | ||
| 148 | # Define whenever show last push event | 148 | # Define whenever show last push event |
app/helpers/projects_helper.rb
| @@ -48,4 +48,36 @@ module ProjectsHelper | @@ -48,4 +48,36 @@ module ProjectsHelper | ||
| 48 | def remove_project_message(project) | 48 | def remove_project_message(project) |
| 49 | "You are going to remove #{project.name_with_namespace}.\n Removed project CANNOT be restored!\n Are you ABSOLUTELY sure?" | 49 | "You are going to remove #{project.name_with_namespace}.\n Removed project CANNOT be restored!\n Are you ABSOLUTELY sure?" |
| 50 | end | 50 | end |
| 51 | + | ||
| 52 | + def project_nav_tabs | ||
| 53 | + @nav_tabs ||= get_project_nav_tabs(@project, current_user) | ||
| 54 | + end | ||
| 55 | + | ||
| 56 | + def project_nav_tab?(name) | ||
| 57 | + project_nav_tabs.include? name | ||
| 58 | + end | ||
| 59 | + | ||
| 60 | + private | ||
| 61 | + | ||
| 62 | + def get_project_nav_tabs(project, current_user) | ||
| 63 | + nav_tabs = [:home] | ||
| 64 | + | ||
| 65 | + if project.repo_exists? && can?(current_user, :download_code, project) | ||
| 66 | + nav_tabs << [:files, :commits, :network, :graphs] | ||
| 67 | + end | ||
| 68 | + | ||
| 69 | + if project.repo_exists? && project.merge_requests_enabled | ||
| 70 | + nav_tabs << :merge_requests | ||
| 71 | + end | ||
| 72 | + | ||
| 73 | + if can?(current_user, :admin_project, project) | ||
| 74 | + nav_tabs << :settings | ||
| 75 | + end | ||
| 76 | + | ||
| 77 | + [:issues, :wiki, :wall, :snippets].each do |feature| | ||
| 78 | + nav_tabs << feature if project.send :"#{feature}_enabled" | ||
| 79 | + end | ||
| 80 | + | ||
| 81 | + nav_tabs.flatten | ||
| 82 | + end | ||
| 51 | end | 83 | end |
app/models/concerns/issuable.rb
| @@ -22,8 +22,10 @@ module Issuable | @@ -22,8 +22,10 @@ module Issuable | ||
| 22 | scope :closed, -> { with_state(:closed) } | 22 | scope :closed, -> { with_state(:closed) } |
| 23 | scope :of_group, ->(group) { where(project_id: group.project_ids) } | 23 | scope :of_group, ->(group) { where(project_id: group.project_ids) } |
| 24 | scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } | 24 | scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } |
| 25 | - scope :assigned, ->(u) { where(assignee_id: u.id)} | 25 | + scope :assigned_to, ->(u) { where(assignee_id: u.id)} |
| 26 | scope :recent, -> { order("created_at DESC") } | 26 | scope :recent, -> { order("created_at DESC") } |
| 27 | + scope :assigned, -> { where("assignee_id IS NOT NULL") } | ||
| 28 | + scope :unassigned, -> { where("assignee_id IS NULL") } | ||
| 27 | 29 | ||
| 28 | delegate :name, | 30 | delegate :name, |
| 29 | :email, | 31 | :email, |
app/models/issue.rb
| @@ -27,7 +27,7 @@ class Issue < ActiveRecord::Base | @@ -27,7 +27,7 @@ class Issue < ActiveRecord::Base | ||
| 27 | 27 | ||
| 28 | scope :cared, ->(user) { where(assignee_id: user) } | 28 | scope :cared, ->(user) { where(assignee_id: user) } |
| 29 | scope :authored, ->(user) { where(author_id: user) } | 29 | scope :authored, ->(user) { where(author_id: user) } |
| 30 | - scope :open_for, ->(user) { opened.assigned(user) } | 30 | + scope :open_for, ->(user) { opened.assigned_to(user) } |
| 31 | 31 | ||
| 32 | state_machine :state, initial: :opened do | 32 | state_machine :state, initial: :opened do |
| 33 | event :close do | 33 | event :close do |
app/models/merge_request.rb
| @@ -91,6 +91,15 @@ class MergeRequest < ActiveRecord::Base | @@ -91,6 +91,15 @@ class MergeRequest < ActiveRecord::Base | ||
| 91 | if target_branch == source_branch | 91 | if target_branch == source_branch |
| 92 | errors.add :branch_conflict, "You can not use same branch for source and target branches" | 92 | errors.add :branch_conflict, "You can not use same branch for source and target branches" |
| 93 | end | 93 | end |
| 94 | + | ||
| 95 | + if opened? || reopened? | ||
| 96 | + similar_mrs = self.project.merge_requests.where(source_branch: source_branch, target_branch: target_branch).opened | ||
| 97 | + similar_mrs = similar_mrs.where('id not in (?)', self.id) if self.id | ||
| 98 | + | ||
| 99 | + if similar_mrs.any? | ||
| 100 | + errors.add :base, "There is already an open merge request for this branches" | ||
| 101 | + end | ||
| 102 | + end | ||
| 94 | end | 103 | end |
| 95 | 104 | ||
| 96 | def reload_code | 105 | def reload_code |
app/models/namespace.rb
| @@ -27,6 +27,7 @@ class Namespace < ActiveRecord::Base | @@ -27,6 +27,7 @@ class Namespace < ActiveRecord::Base | ||
| 27 | message: "only letters, digits, spaces & '_' '-' '.' allowed." } | 27 | message: "only letters, digits, spaces & '_' '-' '.' allowed." } |
| 28 | validates :description, length: { within: 0..255 } | 28 | validates :description, length: { within: 0..255 } |
| 29 | validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, | 29 | validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, |
| 30 | + exclusion: { in: Gitlab::Blacklist.path }, | ||
| 30 | format: { with: Gitlab::Regex.path_regex, | 31 | format: { with: Gitlab::Regex.path_regex, |
| 31 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } | 32 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } |
| 32 | 33 |
app/models/project.rb
| @@ -79,6 +79,7 @@ class Project < ActiveRecord::Base | @@ -79,6 +79,7 @@ class Project < ActiveRecord::Base | ||
| 79 | format: { with: Gitlab::Regex.project_name_regex, | 79 | format: { with: Gitlab::Regex.project_name_regex, |
| 80 | message: "only letters, digits, spaces & '_' '-' '.' allowed. Letter should be first" } | 80 | message: "only letters, digits, spaces & '_' '-' '.' allowed. Letter should be first" } |
| 81 | validates :path, presence: true, length: { within: 0..255 }, | 81 | validates :path, presence: true, length: { within: 0..255 }, |
| 82 | + exclusion: { in: Gitlab::Blacklist.path }, | ||
| 82 | format: { with: Gitlab::Regex.path_regex, | 83 | format: { with: Gitlab::Regex.path_regex, |
| 83 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } | 84 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } |
| 84 | validates :issues_enabled, :wall_enabled, :merge_requests_enabled, | 85 | validates :issues_enabled, :wall_enabled, :merge_requests_enabled, |
| @@ -92,7 +93,7 @@ class Project < ActiveRecord::Base | @@ -92,7 +93,7 @@ class Project < ActiveRecord::Base | ||
| 92 | format: { with: URI::regexp(%w(http https)), message: "should be a valid url" }, | 93 | format: { with: URI::regexp(%w(http https)), message: "should be a valid url" }, |
| 93 | if: :import? | 94 | if: :import? |
| 94 | 95 | ||
| 95 | - validate :check_limit, :repo_name | 96 | + validate :check_limit |
| 96 | 97 | ||
| 97 | # Scopes | 98 | # Scopes |
| 98 | scope :without_user, ->(user) { where("projects.id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) } | 99 | scope :without_user, ->(user) { where("projects.id NOT IN (:ids)", ids: user.authorized_projects.map(&:id) ) } |
| @@ -166,14 +167,6 @@ class Project < ActiveRecord::Base | @@ -166,14 +167,6 @@ class Project < ActiveRecord::Base | ||
| 166 | errors[:base] << ("Can't check your ability to create project") | 167 | errors[:base] << ("Can't check your ability to create project") |
| 167 | end | 168 | end |
| 168 | 169 | ||
| 169 | - def repo_name | ||
| 170 | - denied_paths = %w(admin dashboard groups help profile projects search) | ||
| 171 | - | ||
| 172 | - if denied_paths.include?(path) | ||
| 173 | - errors.add(:path, "like #{path} is not allowed") | ||
| 174 | - end | ||
| 175 | - end | ||
| 176 | - | ||
| 177 | def to_param | 170 | def to_param |
| 178 | if namespace | 171 | if namespace |
| 179 | namespace.path + "/" + path | 172 | namespace.path + "/" + path |
| @@ -420,6 +413,10 @@ class Project < ActiveRecord::Base | @@ -420,6 +413,10 @@ class Project < ActiveRecord::Base | ||
| 420 | !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?) | 413 | !(forked_project_link.nil? || forked_project_link.forked_from_project.nil?) |
| 421 | end | 414 | end |
| 422 | 415 | ||
| 416 | + def imported? | ||
| 417 | + imported | ||
| 418 | + end | ||
| 419 | + | ||
| 423 | def rename_repo | 420 | def rename_repo |
| 424 | old_path_with_namespace = File.join(namespace_dir, path_was) | 421 | old_path_with_namespace = File.join(namespace_dir, path_was) |
| 425 | new_path_with_namespace = File.join(namespace_dir, path) | 422 | new_path_with_namespace = File.join(namespace_dir, path) |
app/models/user.rb
| @@ -42,8 +42,11 @@ class User < ActiveRecord::Base | @@ -42,8 +42,11 @@ class User < ActiveRecord::Base | ||
| 42 | 42 | ||
| 43 | attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username, | 43 | attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username, |
| 44 | :skype, :linkedin, :twitter, :color_scheme_id, :theme_id, :force_random_password, | 44 | :skype, :linkedin, :twitter, :color_scheme_id, :theme_id, :force_random_password, |
| 45 | - :extern_uid, :provider, as: [:default, :admin] | ||
| 46 | - attr_accessible :projects_limit, :can_create_team, :can_create_group, as: :admin | 45 | + :extern_uid, :provider, :password_expires_at, |
| 46 | + as: [:default, :admin] | ||
| 47 | + | ||
| 48 | + attr_accessible :projects_limit, :can_create_team, :can_create_group, | ||
| 49 | + as: :admin | ||
| 47 | 50 | ||
| 48 | attr_accessor :force_random_password | 51 | attr_accessor :force_random_password |
| 49 | 52 | ||
| @@ -104,6 +107,7 @@ class User < ActiveRecord::Base | @@ -104,6 +107,7 @@ class User < ActiveRecord::Base | ||
| 104 | validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} | 107 | validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} |
| 105 | validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} | 108 | validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} |
| 106 | validates :username, presence: true, uniqueness: true, | 109 | validates :username, presence: true, uniqueness: true, |
| 110 | + exclusion: { in: Gitlab::Blacklist.path }, | ||
| 107 | format: { with: Gitlab::Regex.username_regex, | 111 | format: { with: Gitlab::Regex.username_regex, |
| 108 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } | 112 | message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } |
| 109 | 113 | ||
| @@ -363,4 +367,8 @@ class User < ActiveRecord::Base | @@ -363,4 +367,8 @@ class User < ActiveRecord::Base | ||
| 363 | def accessible_deploy_keys | 367 | def accessible_deploy_keys |
| 364 | DeployKey.in_projects(self.master_projects).uniq | 368 | DeployKey.in_projects(self.master_projects).uniq |
| 365 | end | 369 | end |
| 370 | + | ||
| 371 | + def created_by | ||
| 372 | + User.find_by_id(created_by_id) if created_by_id | ||
| 373 | + end | ||
| 366 | end | 374 | end |
app/observers/project_observer.rb
| 1 | class ProjectObserver < BaseObserver | 1 | class ProjectObserver < BaseObserver |
| 2 | def after_create(project) | 2 | def after_create(project) |
| 3 | - unless project.forked? | ||
| 4 | - GitlabShellWorker.perform_async( | ||
| 5 | - :add_repository, | ||
| 6 | - project.path_with_namespace | ||
| 7 | - ) | ||
| 8 | - | ||
| 9 | - log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"") | ||
| 10 | - end | 3 | + return true if project.forked? || project.imported? |
| 4 | + | ||
| 5 | + GitlabShellWorker.perform_async( | ||
| 6 | + :add_repository, | ||
| 7 | + project.path_with_namespace | ||
| 8 | + ) | ||
| 9 | + | ||
| 10 | + log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"") | ||
| 11 | end | 11 | end |
| 12 | 12 | ||
| 13 | def after_update(project) | 13 | def after_update(project) |
app/views/admin/teams/members/new.html.haml
| 1 | %h3.page_title | 1 | %h3.page_title |
| 2 | - Team: #{@team.name} | ||
| 3 | - | ||
| 4 | -%fieldset | ||
| 5 | - %legend Members (#{@team.members.count}) | ||
| 6 | - = form_tag admin_team_members_path(@team), id: "team_members", class: "bulk_import", method: :post do | ||
| 7 | - %table#members_list | ||
| 8 | - %thead | ||
| 9 | - %tr | ||
| 10 | - %th User name | ||
| 11 | - %th Default project access | ||
| 12 | - %th Team access | ||
| 13 | - %th | ||
| 14 | - - @team.members.each do |member| | ||
| 15 | - %tr.member | ||
| 16 | - %td | ||
| 17 | - = link_to [:admin, member] do | ||
| 18 | - = member.name | ||
| 19 | - %small= "(#{member.email})" | ||
| 20 | - %td= @team.human_default_projects_access(member) | ||
| 21 | - %td= @team.admin?(member) ? "Admin" : "Member" | ||
| 22 | - %td | ||
| 23 | - %tr | ||
| 24 | - %td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_username), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' | ||
| 25 | - %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } | ||
| 26 | - %td | ||
| 27 | - %span= check_box_tag :group_admin | ||
| 28 | - %span Admin? | ||
| 29 | - %td= submit_tag 'Add', class: "btn btn-primary", id: :add_members_to_team | 2 | + New members for |
| 3 | + = link_to @team.name, admin_team_path(@team) | ||
| 4 | + team | ||
| 5 | +%hr | ||
| 6 | += form_tag admin_team_members_path(@team), id: "team_members", class: "bulk_import", method: :post do | ||
| 7 | + - if @team.errors.any? | ||
| 8 | + .alert.alert-error | ||
| 9 | + %span= @team.errors.full_messages.first | ||
| 10 | + .clearfix | ||
| 11 | + = label_tag :user_ids do | ||
| 12 | + Users to add | ||
| 13 | + .input | ||
| 14 | + = select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_username), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' | ||
| 15 | + .clearfix.group-description-holder | ||
| 16 | + = label_tag :default_project_access do | ||
| 17 | + Default permission in projects | ||
| 18 | + .input | ||
| 19 | + = select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } | ||
| 20 | + .clearfix | ||
| 21 | + = label_tag :group_admin do | ||
| 22 | + Is team admin | ||
| 23 | + .input | ||
| 24 | + = check_box_tag :group_admin | ||
| 25 | + .clearfix.form-actions | ||
| 26 | + = submit_tag 'Add users into team', class: "btn btn-primary", id: :add_members_to_team | ||
| 27 | + = link_to 'Cancel', :back, class: "btn" |
app/views/admin/users/_form.html.haml
| @@ -24,19 +24,25 @@ | @@ -24,19 +24,25 @@ | ||
| 24 | = f.text_field :email, required: true, autocomplete: "off" | 24 | = f.text_field :email, required: true, autocomplete: "off" |
| 25 | %span.help-inline * required | 25 | %span.help-inline * required |
| 26 | 26 | ||
| 27 | - %fieldset | ||
| 28 | - %legend Password | ||
| 29 | - .clearfix | ||
| 30 | - = f.label :password | ||
| 31 | - .input= f.password_field :password, disabled: f.object.force_random_password | ||
| 32 | - .clearfix | ||
| 33 | - = f.label :password_confirmation | ||
| 34 | - .input= f.password_field :password_confirmation, disabled: f.object.force_random_password | ||
| 35 | - -if f.object.new_record? | 27 | + - if @admin_user.new_record? |
| 28 | + %fieldset | ||
| 29 | + %legend Password | ||
| 30 | + .clearfix | ||
| 31 | + = f.label :password | ||
| 32 | + .input | ||
| 33 | + %strong | ||
| 34 | + A temporary password will be generated and sent to user. | ||
| 35 | + %br | ||
| 36 | + User will be forced to change it after first sign in | ||
| 37 | + - else | ||
| 38 | + %fieldset | ||
| 39 | + %legend Password | ||
| 40 | + .clearfix | ||
| 41 | + = f.label :password | ||
| 42 | + .input= f.password_field :password, disabled: f.object.force_random_password | ||
| 36 | .clearfix | 43 | .clearfix |
| 37 | - = f.label :force_random_password do | ||
| 38 | - %span Generate random password | ||
| 39 | - .input= f.check_box :force_random_password, {}, true, nil | 44 | + = f.label :password_confirmation |
| 45 | + .input= f.password_field :password_confirmation, disabled: f.object.force_random_password | ||
| 40 | 46 | ||
| 41 | %fieldset | 47 | %fieldset |
| 42 | %legend Access | 48 | %legend Access |
app/views/admin/users/show.html.haml
| 1 | +%h3.page_title | ||
| 2 | + User: | ||
| 3 | + = @admin_user.name | ||
| 4 | + - if @admin_user.blocked? | ||
| 5 | + %span.cred (Blocked) | ||
| 6 | + - if @admin_user.admin | ||
| 7 | + %span.cred (Admin) | ||
| 8 | + | ||
| 9 | + .pull-right | ||
| 10 | + = link_to edit_admin_user_path(@admin_user), class: "btn grouped btn-small" do | ||
| 11 | + %i.icon-edit | ||
| 12 | + Edit | ||
| 13 | + - unless @admin_user == current_user | ||
| 14 | + - if @admin_user.blocked? | ||
| 15 | + = link_to 'Unblock', unblock_admin_user_path(@admin_user), method: :put, class: "btn grouped btn-small success" | ||
| 16 | + - else | ||
| 17 | + = link_to 'Block', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn grouped btn-small btn-remove" | ||
| 18 | + = link_to 'Destroy', [:admin, @admin_user], confirm: "USER #{@admin_user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn grouped btn-small btn-remove" | ||
| 19 | +%hr | ||
| 20 | + | ||
| 1 | .row | 21 | .row |
| 2 | .span6 | 22 | .span6 |
| 3 | - %h3.page_title | ||
| 4 | - = image_tag gravatar_icon(@admin_user.email, 90), class: "avatar s90" | ||
| 5 | - = @admin_user.name | ||
| 6 | - - if @admin_user.blocked? | ||
| 7 | - %span.cred (Blocked) | ||
| 8 | - - if @admin_user.admin | ||
| 9 | - %span.cred (Admin) | ||
| 10 | - .pull-right | ||
| 11 | - = link_to edit_admin_user_path(@admin_user), class: "btn pull-right" do | ||
| 12 | - %i.icon-edit | ||
| 13 | - Edit | ||
| 14 | - %br | ||
| 15 | - %small @#{@admin_user.username} | ||
| 16 | - %br | ||
| 17 | - %small member since #{@admin_user.created_at.stamp("Nov 12, 2031")} | ||
| 18 | - .clearfix | ||
| 19 | - %hr | ||
| 20 | - %p | ||
| 21 | - %span.btn.btn-small | ||
| 22 | - %i.icon-envelope | ||
| 23 | - = mail_to @admin_user.email | ||
| 24 | - - unless @admin_user == current_user | ||
| 25 | - - if @admin_user.blocked? | ||
| 26 | - = link_to 'Unblock', unblock_admin_user_path(@admin_user), method: :put, class: "btn btn-small success" | ||
| 27 | - - else | ||
| 28 | - = link_to 'Block', block_admin_user_path(@admin_user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove" | ||
| 29 | - = link_to 'Destroy', [:admin, @admin_user], confirm: "USER #{@admin_user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn btn-small btn-remove" | 23 | + .ui-box |
| 24 | + %h5.title | ||
| 25 | + Account: | ||
| 26 | + .pull-right | ||
| 27 | + = image_tag gravatar_icon(@admin_user.email, 32), class: "avatar s32" | ||
| 28 | + %ul.well-list | ||
| 29 | + %li | ||
| 30 | + %span.light Name: | ||
| 31 | + %strong= @admin_user.name | ||
| 32 | + %li | ||
| 33 | + %span.light Username: | ||
| 34 | + %strong | ||
| 35 | + = @admin_user.username | ||
| 36 | + %li | ||
| 37 | + %span.light Email: | ||
| 38 | + %strong | ||
| 39 | + = mail_to @admin_user.email | ||
| 40 | + | ||
| 41 | + %li | ||
| 42 | + %span.light Member since: | ||
| 43 | + %strong | ||
| 44 | + = @admin_user.created_at.stamp("Nov 12, 2031") | ||
| 45 | + | ||
| 46 | + %li | ||
| 47 | + %span.light Last sign-in at: | ||
| 48 | + %strong | ||
| 49 | + - if @admin_user.last_sign_in_at | ||
| 50 | + = @admin_user.last_sign_in_at.stamp("Nov 12, 2031") | ||
| 51 | + - else | ||
| 52 | + never | ||
| 53 | + | ||
| 54 | + - if @admin_user.ldap_user? | ||
| 55 | + %li | ||
| 56 | + %span.light LDAP uid: | ||
| 57 | + %strong | ||
| 58 | + = @admin_user.extern_uid | ||
| 59 | + | ||
| 60 | + - if @admin_user.created_by | ||
| 61 | + %li | ||
| 62 | + %span.light Created by: | ||
| 63 | + %strong | ||
| 64 | + = link_to @admin_user.created_by.name, [:admin, @admin_user.created_by] | ||
| 65 | + | ||
| 30 | %hr | 66 | %hr |
| 31 | %h5 | 67 | %h5 |
| 32 | Add User to Projects | 68 | Add User to Projects |
| @@ -67,11 +103,11 @@ | @@ -67,11 +103,11 @@ | ||
| 67 | 103 | ||
| 68 | 104 | ||
| 69 | .span6 | 105 | .span6 |
| 70 | - = render 'users/profile', user: @admin_user | ||
| 71 | .ui-box | 106 | .ui-box |
| 72 | %h5.title Projects (#{@projects.count}) | 107 | %h5.title Projects (#{@projects.count}) |
| 73 | %ul.well-list | 108 | %ul.well-list |
| 74 | - @projects.sort_by(&:name_with_namespace).each do |project| | 109 | - @projects.sort_by(&:name_with_namespace).each do |project| |
| 110 | + - tm = project.team.get_tm(@admin_user.id) | ||
| 75 | %li | 111 | %li |
| 76 | = link_to admin_project_path(project), class: dom_class(project) do | 112 | = link_to admin_project_path(project), class: dom_class(project) do |
| 77 | - if project.namespace | 113 | - if project.namespace |
| @@ -79,16 +115,17 @@ | @@ -79,16 +115,17 @@ | ||
| 79 | \/ | 115 | \/ |
| 80 | %strong.well-title | 116 | %strong.well-title |
| 81 | = truncate(project.name, length: 45) | 117 | = truncate(project.name, length: 45) |
| 82 | - %span.pull-right.light | ||
| 83 | - - if project.owner == @admin_user | ||
| 84 | - %i.icon-wrench | ||
| 85 | - - tm = project.team.get_tm(@admin_user.id) | ||
| 86 | - - if tm | ||
| 87 | - = tm.project_access_human | ||
| 88 | - = link_to edit_admin_project_member_path(project, tm.user), class: "btn btn-small" do | 118 | + |
| 119 | + - if project.owner == @admin_user | ||
| 120 | + %span.label.label-info owner | ||
| 121 | + | ||
| 122 | + - if tm | ||
| 123 | + .pull-right | ||
| 124 | + = link_to edit_admin_project_member_path(project, tm.user), class: "btn grouped btn-small" do | ||
| 89 | %i.icon-edit | 125 | %i.icon-edit |
| 90 | - = link_to admin_project_member_path(project, tm.user), confirm: remove_from_project_team_message(project, @admin_user), method: :delete, class: "btn btn-small btn-remove" do | 126 | + = link_to admin_project_member_path(project, tm.user), confirm: remove_from_project_team_message(project, @admin_user), method: :delete, class: "btn grouped btn-small btn-remove" do |
| 91 | %i.icon-remove | 127 | %i.icon-remove |
| 92 | - %p.light | ||
| 93 | - %i.icon-wrench | ||
| 94 | - – user is a project owner | 128 | + |
| 129 | + .pull-right.light | ||
| 130 | + = tm.project_access_human | ||
| 131 | + |
app/views/devise/sessions/_oauth_providers.html.haml
| 1 | -- if enabled_oauth_providers.present? | 1 | +- providers = (enabled_oauth_providers - [:ldap]) |
| 2 | +- if providers.present? | ||
| 2 | %hr | 3 | %hr |
| 3 | %div{:'data-no-turbolink' => 'data-no-turbolink'} | 4 | %div{:'data-no-turbolink' => 'data-no-turbolink'} |
| 4 | %span Sign in with: | 5 | %span Sign in with: |
| 5 | - - (enabled_oauth_providers - [:ldap]).each do |provider| | 6 | + - providers.each do |provider| |
| 6 | %span | 7 | %span |
| 7 | - if default_providers.include?(provider) | 8 | - if default_providers.include?(provider) |
| 8 | = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) | 9 | = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) |
app/views/edit_tree/show.html.haml
| @@ -23,7 +23,7 @@ | @@ -23,7 +23,7 @@ | ||
| 23 | = hidden_field_tag 'last_commit', @last_commit | 23 | = hidden_field_tag 'last_commit', @last_commit |
| 24 | = hidden_field_tag 'content', '', id: :file_content | 24 | = hidden_field_tag 'content', '', id: :file_content |
| 25 | .commit-button-annotation | 25 | .commit-button-annotation |
| 26 | - = button_tag "Commit", class: 'btn commit-btn js-commit-button' | 26 | + = button_tag "Commit changes", class: 'btn commit-btn js-commit-button btn-primary' |
| 27 | .message | 27 | .message |
| 28 | to branch | 28 | to branch |
| 29 | %strong= @ref | 29 | %strong= @ref |
app/views/layouts/nav/_project.html.haml
| @@ -3,43 +3,48 @@ | @@ -3,43 +3,48 @@ | ||
| 3 | = link_to project_path(@project), title: "Project" do | 3 | = link_to project_path(@project), title: "Project" do |
| 4 | %i.icon-home | 4 | %i.icon-home |
| 5 | 5 | ||
| 6 | - - unless @project.empty_repo? | ||
| 7 | - - if can? current_user, :download_code, @project | ||
| 8 | - = nav_link(controller: %w(tree blob blame)) do | ||
| 9 | - = link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref) | ||
| 10 | - = nav_link(controller: %w(commit commits compare repositories protected_branches)) do | ||
| 11 | - = link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref) | ||
| 12 | - = nav_link(controller: %w(network)) do | ||
| 13 | - = link_to "Network", project_network_path(@project, @ref || @repository.root_ref) | ||
| 14 | - = nav_link(controller: %w(graphs)) do | ||
| 15 | - = link_to "Graphs", project_graph_path(@project, @ref || @repository.root_ref) | ||
| 16 | - | ||
| 17 | - - if @project.issues_enabled | 6 | + - if project_nav_tab? :files |
| 7 | + = nav_link(controller: %w(tree blob blame)) do | ||
| 8 | + = link_to 'Files', project_tree_path(@project, @ref || @repository.root_ref) | ||
| 9 | + | ||
| 10 | + - if project_nav_tab? :commits | ||
| 11 | + = nav_link(controller: %w(commit commits compare repositories protected_branches)) do | ||
| 12 | + = link_to "Commits", project_commits_path(@project, @ref || @repository.root_ref) | ||
| 13 | + | ||
| 14 | + - if project_nav_tab? :network | ||
| 15 | + = nav_link(controller: %w(network)) do | ||
| 16 | + = link_to "Network", project_network_path(@project, @ref || @repository.root_ref) | ||
| 17 | + | ||
| 18 | + - if project_nav_tab? :graphs | ||
| 19 | + = nav_link(controller: %w(graphs)) do | ||
| 20 | + = link_to "Graphs", project_graph_path(@project, @ref || @repository.root_ref) | ||
| 21 | + | ||
| 22 | + - if project_nav_tab? :issues | ||
| 18 | = nav_link(controller: %w(issues milestones labels)) do | 23 | = nav_link(controller: %w(issues milestones labels)) do |
| 19 | = link_to url_for_project_issues do | 24 | = link_to url_for_project_issues do |
| 20 | Issues | 25 | Issues |
| 21 | - if @project.used_default_issues_tracker? | 26 | - if @project.used_default_issues_tracker? |
| 22 | %span.count.issue_counter= @project.issues.opened.count | 27 | %span.count.issue_counter= @project.issues.opened.count |
| 23 | 28 | ||
| 24 | - - if @project.repo_exists? && @project.merge_requests_enabled | 29 | + - if project_nav_tab? :merge_requests |
| 25 | = nav_link(controller: :merge_requests) do | 30 | = nav_link(controller: :merge_requests) do |
| 26 | = link_to project_merge_requests_path(@project) do | 31 | = link_to project_merge_requests_path(@project) do |
| 27 | Merge Requests | 32 | Merge Requests |
| 28 | %span.count.merge_counter= @project.merge_requests.opened.count | 33 | %span.count.merge_counter= @project.merge_requests.opened.count |
| 29 | 34 | ||
| 30 | - - if @project.wiki_enabled | 35 | + - if project_nav_tab? :wiki |
| 31 | = nav_link(controller: :wikis) do | 36 | = nav_link(controller: :wikis) do |
| 32 | = link_to 'Wiki', project_wiki_path(@project, :home) | 37 | = link_to 'Wiki', project_wiki_path(@project, :home) |
| 33 | 38 | ||
| 34 | - - if @project.wall_enabled | 39 | + - if project_nav_tab? :wall |
| 35 | = nav_link(controller: :walls) do | 40 | = nav_link(controller: :walls) do |
| 36 | = link_to 'Wall', project_wall_path(@project) | 41 | = link_to 'Wall', project_wall_path(@project) |
| 37 | 42 | ||
| 38 | - - if @project.snippets_enabled | 43 | + - if project_nav_tab? :snippets |
| 39 | = nav_link(controller: :snippets) do | 44 | = nav_link(controller: :snippets) do |
| 40 | = link_to 'Snippets', project_snippets_path(@project) | 45 | = link_to 'Snippets', project_snippets_path(@project) |
| 41 | 46 | ||
| 42 | - - if can? current_user, :admin_project, @project | 47 | + - if project_nav_tab? :settings |
| 43 | = nav_link(html_options: {class: "#{project_tab_class}"}) do | 48 | = nav_link(html_options: {class: "#{project_tab_class}"}) do |
| 44 | = link_to edit_project_path(@project), class: "stat-tab tab " do | 49 | = link_to edit_project_path(@project), class: "stat-tab tab " do |
| 45 | Settings | 50 | Settings |
app/views/layouts/nav/_team.html.haml
| @@ -18,7 +18,7 @@ | @@ -18,7 +18,7 @@ | ||
| 18 | Members | 18 | Members |
| 19 | %span.count= @team.members.count | 19 | %span.count= @team.members.count |
| 20 | 20 | ||
| 21 | - - if can? current_user, :admin_user_team, @team | 21 | + - if can? current_user, :manage_user_team, @team |
| 22 | = nav_link(path: 'teams#edit') do | 22 | = nav_link(path: 'teams#edit') do |
| 23 | = link_to edit_team_path(@team), class: "stat-tab tab " do | 23 | = link_to edit_team_path(@team), class: "stat-tab tab " do |
| 24 | Settings | 24 | Settings |
app/views/layouts/snippets.html.haml
| @@ -1,20 +0,0 @@ | @@ -1,20 +0,0 @@ | ||
| 1 | -!!! 5 | ||
| 2 | -%html{ lang: "en"} | ||
| 3 | - = render "layouts/head", title: "Snipepts" | ||
| 4 | - %body{class: "#{app_theme} application", :'data-page' => body_data_page} | ||
| 5 | - = render "layouts/head_panel", title: "Snippets" | ||
| 6 | - = render "layouts/flash" | ||
| 7 | - %nav.main-nav | ||
| 8 | - .container | ||
| 9 | - %ul | ||
| 10 | - = nav_link(path: 'snippets#user_index', html_options: {class: 'home'}) do | ||
| 11 | - = link_to user_snippets_path(current_user), title: "My Snippets" do | ||
| 12 | - %i.icon-home | ||
| 13 | - = nav_link(path: 'snippets#new') do | ||
| 14 | - = link_to new_snippet_path do | ||
| 15 | - New snippet | ||
| 16 | - = nav_link(path: 'snippets#index') do | ||
| 17 | - = link_to snippets_path do | ||
| 18 | - Discover snippets | ||
| 19 | - .container | ||
| 20 | - .content= yield |
| @@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
| 1 | +.ui-box | ||
| 2 | + %h5.title= title | ||
| 3 | + %ul.well-list | ||
| 4 | + - issues.each do |issue| | ||
| 5 | + %li | ||
| 6 | + = link_to [@project, issue] do | ||
| 7 | + %span.badge{class: issue.closed? ? 'badge-important' : 'badge-info'} ##{issue.id} | ||
| 8 | + = link_to_gfm truncate(issue.title, length: 60), [@project, issue] | ||
| 9 | + - if issue.assignee | ||
| 10 | + .pull-right | ||
| 11 | + = image_tag gravatar_icon(issue.assignee.email, 16), class: "avatar s16" |
app/views/milestones/show.html.haml
| @@ -55,39 +55,52 @@ | @@ -55,39 +55,52 @@ | ||
| 55 | = markdown @milestone.description | 55 | = markdown @milestone.description |
| 56 | 56 | ||
| 57 | 57 | ||
| 58 | -.row | ||
| 59 | - .span6 | ||
| 60 | - .ui-box.milestone-issue-filter | ||
| 61 | - .title | ||
| 62 | - %ul.nav.nav-pills | ||
| 63 | - %li.active= link_to('Open Issues', '#') | ||
| 64 | - %li=link_to('All Issues', '#') | ||
| 65 | - %ul.well-list | ||
| 66 | - - @issues.each do |issue| | ||
| 67 | - %li{data: {closed: issue.closed?}} | ||
| 68 | - = link_to [@project, issue] do | ||
| 69 | - %span.badge.badge-info ##{issue.id} | ||
| 70 | - – | ||
| 71 | - = link_to_gfm truncate(issue.title, length: 60), [@project, issue] | 58 | +%ul.nav.nav-tabs |
| 59 | + %li.active | ||
| 60 | + = link_to '#tab-issues', 'data-toggle' => 'tab' do | ||
| 61 | + Issues | ||
| 62 | + %span.badge= @issues.count | ||
| 63 | + %li | ||
| 64 | + = link_to '#tab-merge-requests', 'data-toggle' => 'tab' do | ||
| 65 | + Merge Requests | ||
| 66 | + %span.badge= @merge_requests.count | ||
| 67 | + %li | ||
| 68 | + = link_to '#tab-participants', 'data-toggle' => 'tab' do | ||
| 69 | + Participants | ||
| 70 | + %span.badge= @users.count | ||
| 72 | 71 | ||
| 73 | - .span6 | ||
| 74 | - .ui-box.milestone-merge-requests-filter | ||
| 75 | - .title | ||
| 76 | - %ul.nav.nav-pills | ||
| 77 | - %li.active= link_to('Open Merge Requests', '#') | ||
| 78 | - %li=link_to('All Merge Requests', '#') | ||
| 79 | - %ul.well-list | ||
| 80 | - - @merge_requests.each do |merge_request| | ||
| 81 | - %li{data: {closed: merge_request.closed? || merge_request.merged?}} | ||
| 82 | - = link_to [@project, merge_request] do | ||
| 83 | - %span.badge.badge-info ##{merge_request.id} | ||
| 84 | - – | ||
| 85 | - = link_to_gfm truncate(merge_request.title, length: 60), [@project, merge_request] | ||
| 86 | 72 | ||
| 87 | -%hr | ||
| 88 | -%h6 Participants: | ||
| 89 | -%div | ||
| 90 | - - @users.each do |user| | ||
| 91 | - = link_to_member(@project, user) | 73 | +.tab-content |
| 74 | + .tab-pane.active#tab-issues | ||
| 75 | + .row | ||
| 76 | + .span4 | ||
| 77 | + = render('issues', title: 'Unstarted Issues (open and unassigned)', issues: @issues.opened.unassigned) | ||
| 78 | + .span4 | ||
| 79 | + = render('issues', title: 'Ongoing Issues (open and assigned)', issues: @issues.opened.assigned) | ||
| 80 | + .span4 | ||
| 81 | + = render('issues', title: 'Completed Issues (closed)', issues: @issues.closed) | ||
| 82 | + | ||
| 83 | + .tab-pane#tab-merge-requests | ||
| 84 | + .row | ||
| 85 | + .span6 | ||
| 86 | + .ui-box | ||
| 87 | + %h5.title Open | ||
| 88 | + %ul.well-list | ||
| 89 | + - @merge_requests.opened.each do |merge_request| | ||
| 90 | + = render 'merge_request', merge_request: merge_request | ||
| 91 | + .span6 | ||
| 92 | + .ui-box | ||
| 93 | + %h5.title Closed | ||
| 94 | + %ul.well-list | ||
| 95 | + - @merge_requests.closed.each do |merge_request| | ||
| 96 | + = render 'merge_request', merge_request: merge_request | ||
| 92 | 97 | ||
| 93 | -.clearfix | 98 | + .tab-pane#tab-participants |
| 99 | + %ul.bordered-list | ||
| 100 | + - @users.each do |user| | ||
| 101 | + %li | ||
| 102 | + = link_to user, title: user.name, class: "dark" do | ||
| 103 | + = image_tag gravatar_icon(user.email, 32), class: "avatar s32" | ||
| 104 | + %strong= truncate(user.name, lenght: 40) | ||
| 105 | + %br | ||
| 106 | + %small.cgray= user.username |
app/views/notify/new_user_email.html.haml
| @@ -8,13 +8,14 @@ | @@ -8,13 +8,14 @@ | ||
| 8 | %p | 8 | %p |
| 9 | login.......................................... | 9 | login.......................................... |
| 10 | %code= @user['email'] | 10 | %code= @user['email'] |
| 11 | -%p | ||
| 12 | - - unless Gitlab.config.gitlab.signup_enabled | 11 | + |
| 12 | +- if @user.created_by_id | ||
| 13 | + %p | ||
| 13 | password.................................. | 14 | password.................................. |
| 14 | %code= @password | 15 | %code= @password |
| 15 | 16 | ||
| 16 | -%p | ||
| 17 | - Please change your password immediately after login. | 17 | + %p |
| 18 | + You will be forced to change this password immediately after login. | ||
| 18 | 19 | ||
| 19 | %p | 20 | %p |
| 20 | = link_to "Click here to login", root_url | 21 | = link_to "Click here to login", root_url |
app/views/notify/new_user_email.text.erb
| @@ -3,10 +3,11 @@ Hi <%= @user.name %>! | @@ -3,10 +3,11 @@ Hi <%= @user.name %>! | ||
| 3 | The Administrator created an account for you. Now you are a member of company GitLab application. | 3 | The Administrator created an account for you. Now you are a member of company GitLab application. |
| 4 | 4 | ||
| 5 | login.................. <%= @user.email %> | 5 | login.................. <%= @user.email %> |
| 6 | -<% unless Gitlab.config.gitlab.signup_enabled %> | 6 | +<% if @user.created_by_id %> |
| 7 | password............... <%= @password %> | 7 | password............... <%= @password %> |
| 8 | + | ||
| 9 | + You will be forced to change this password immediately after login. | ||
| 8 | <% end %> | 10 | <% end %> |
| 9 | 11 | ||
| 10 | -Please change your password immediately after login. | ||
| 11 | 12 | ||
| 12 | Click here to login: <%= url_for(root_url) %> | 13 | Click here to login: <%= url_for(root_url) %> |
| @@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
| 1 | += form_for @user, url: profile_password_path, method: :post do |f| | ||
| 2 | + .light-well.padded | ||
| 3 | + %p.slead | ||
| 4 | + Please set new password before proceed. | ||
| 5 | + %br | ||
| 6 | + After successful password update you will be redirected to login screen | ||
| 7 | + -if @user.errors.any? | ||
| 8 | + .alert.alert-error | ||
| 9 | + %ul | ||
| 10 | + - @user.errors.full_messages.each do |msg| | ||
| 11 | + %li= msg | ||
| 12 | + | ||
| 13 | + .clearfix | ||
| 14 | + = f.label :password | ||
| 15 | + .input= f.password_field :password, required: true | ||
| 16 | + .clearfix | ||
| 17 | + = f.label :password_confirmation | ||
| 18 | + .input | ||
| 19 | + = f.password_field :password_confirmation, required: true | ||
| 20 | + .clearfix | ||
| 21 | + .input | ||
| 22 | + = f.submit 'Set new password', class: "btn btn-create" |
app/views/projects/_settings_nav.html.haml
| @@ -5,8 +5,8 @@ | @@ -5,8 +5,8 @@ | ||
| 5 | Edit | 5 | Edit |
| 6 | = nav_link(controller: [:team_members, :teams]) do | 6 | = nav_link(controller: [:team_members, :teams]) do |
| 7 | = link_to project_team_index_path(@project), class: "team-tab tab" do | 7 | = link_to project_team_index_path(@project), class: "team-tab tab" do |
| 8 | - %i.icon-user | ||
| 9 | - Team | 8 | + %i.icon-group |
| 9 | + Project Members | ||
| 10 | = nav_link(controller: :deploy_keys) do | 10 | = nav_link(controller: :deploy_keys) do |
| 11 | = link_to project_deploy_keys_path(@project) do | 11 | = link_to project_deploy_keys_path(@project) do |
| 12 | %span | 12 | %span |
| @@ -14,7 +14,7 @@ | @@ -14,7 +14,7 @@ | ||
| 14 | = nav_link(controller: :hooks) do | 14 | = nav_link(controller: :hooks) do |
| 15 | = link_to project_hooks_path(@project) do | 15 | = link_to project_hooks_path(@project) do |
| 16 | %span | 16 | %span |
| 17 | - Hooks | 17 | + Web Hooks |
| 18 | = nav_link(controller: :services) do | 18 | = nav_link(controller: :services) do |
| 19 | = link_to project_services_path(@project) do | 19 | = link_to project_services_path(@project) do |
| 20 | %span | 20 | %span |
app/views/snippets/current_user_index.html.haml
| 1 | %h3.page_title | 1 | %h3.page_title |
| 2 | My Snippets | 2 | My Snippets |
| 3 | %small share code pastes with others out of git repository | 3 | %small share code pastes with others out of git repository |
| 4 | - = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do | ||
| 5 | - Add new snippet | 4 | + .pull-right |
| 5 | + = link_to new_snippet_path, class: "btn btn-small add_new grouped btn-primary", title: "New Snippet" do | ||
| 6 | + Add new snippet | ||
| 7 | + = link_to snippets_path, class: "btn btn-small grouped" do | ||
| 8 | + Discover snippets | ||
| 6 | 9 | ||
| 7 | %hr | 10 | %hr |
| 8 | 11 |
app/views/snippets/index.html.haml
| 1 | %h3.page_title | 1 | %h3.page_title |
| 2 | Public snippets | 2 | Public snippets |
| 3 | %small share code pastes with others out of git repository | 3 | %small share code pastes with others out of git repository |
| 4 | - = link_to new_snippet_path, class: "btn btn-small add_new pull-right", title: "New Snippet" do | ||
| 5 | - Add new snippet | 4 | + |
| 5 | + .pull-right | ||
| 6 | + = link_to new_snippet_path, class: "btn btn-small add_new grouped btn-primary", title: "New Snippet" do | ||
| 7 | + Add new snippet | ||
| 8 | + = link_to user_snippets_path(current_user), class: "btn btn-small grouped" do | ||
| 9 | + My snippets | ||
| 6 | 10 | ||
| 7 | %hr | 11 | %hr |
| 8 | .row | 12 | .row |
app/views/team_members/index.html.haml
app/views/teams/edit.html.haml
| @@ -5,8 +5,9 @@ | @@ -5,8 +5,9 @@ | ||
| 5 | = link_to 'Projects', '#tab-projects', 'data-toggle' => 'tab' | 5 | = link_to 'Projects', '#tab-projects', 'data-toggle' => 'tab' |
| 6 | %li | 6 | %li |
| 7 | = link_to 'Edit Team', '#tab-edit', 'data-toggle' => 'tab' | 7 | = link_to 'Edit Team', '#tab-edit', 'data-toggle' => 'tab' |
| 8 | - %li | ||
| 9 | - = link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab' | 8 | + - if can? current_user, :admin_user_team, @team |
| 9 | + %li | ||
| 10 | + = link_to 'Remove', '#tab-remove', 'data-toggle' => 'tab' | ||
| 10 | 11 | ||
| 11 | .span9 | 12 | .span9 |
| 12 | .tab-content | 13 | .tab-content |
config/environments/production.rb
| @@ -52,7 +52,7 @@ Gitlab::Application.configure do | @@ -52,7 +52,7 @@ Gitlab::Application.configure do | ||
| 52 | # config.action_mailer.raise_delivery_errors = false | 52 | # config.action_mailer.raise_delivery_errors = false |
| 53 | 53 | ||
| 54 | # Enable threaded mode | 54 | # Enable threaded mode |
| 55 | - config.threadsafe! | 55 | + config.threadsafe! unless $rails_rake_task |
| 56 | 56 | ||
| 57 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to | 57 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to |
| 58 | # the I18n.default_locale when a translation can not be found) | 58 | # the I18n.default_locale when a translation can not be found) |
config/routes.rb
db/fixtures/production/001_admin.rb
| @@ -3,7 +3,8 @@ admin = User.create( | @@ -3,7 +3,8 @@ admin = User.create( | ||
| 3 | name: "Administrator", | 3 | name: "Administrator", |
| 4 | username: 'root', | 4 | username: 'root', |
| 5 | password: "5iveL!fe", | 5 | password: "5iveL!fe", |
| 6 | - password_confirmation: "5iveL!fe" | 6 | + password_confirmation: "5iveL!fe", |
| 7 | + password_expires_at: Time.now | ||
| 7 | ) | 8 | ) |
| 8 | 9 | ||
| 9 | admin.projects_limit = 10000 | 10 | admin.projects_limit = 10000 |
db/migrate/20130613165816_add_password_expires_at_to_users.rb
0 → 100644
db/schema.rb
| @@ -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 => 20130522141856) do | 14 | +ActiveRecord::Schema.define(:version => 20130614132337) 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 |
| @@ -172,6 +172,7 @@ ActiveRecord::Schema.define(:version => 20130522141856) do | @@ -172,6 +172,7 @@ ActiveRecord::Schema.define(:version => 20130522141856) do | ||
| 172 | t.string "issues_tracker_id" | 172 | t.string "issues_tracker_id" |
| 173 | t.boolean "snippets_enabled", :default => true, :null => false | 173 | t.boolean "snippets_enabled", :default => true, :null => false |
| 174 | t.datetime "last_activity_at" | 174 | t.datetime "last_activity_at" |
| 175 | + t.boolean "imported", :default => false, :null => false | ||
| 175 | end | 176 | end |
| 176 | 177 | ||
| 177 | add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" | 178 | add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" |
| @@ -292,6 +293,8 @@ ActiveRecord::Schema.define(:version => 20130522141856) do | @@ -292,6 +293,8 @@ ActiveRecord::Schema.define(:version => 20130522141856) do | ||
| 292 | t.string "state" | 293 | t.string "state" |
| 293 | t.integer "color_scheme_id", :default => 1, :null => false | 294 | t.integer "color_scheme_id", :default => 1, :null => false |
| 294 | t.integer "notification_level", :default => 1, :null => false | 295 | t.integer "notification_level", :default => 1, :null => false |
| 296 | + t.datetime "password_expires_at" | ||
| 297 | + t.integer "created_by_id" | ||
| 295 | end | 298 | end |
| 296 | 299 | ||
| 297 | add_index "users", ["admin"], :name => "index_users_on_admin" | 300 | add_index "users", ["admin"], :name => "index_users_on_admin" |
doc/api/README.md
| @@ -69,15 +69,15 @@ When listing resources you can pass the following parameters: | @@ -69,15 +69,15 @@ When listing resources you can pass the following parameters: | ||
| 69 | 69 | ||
| 70 | ## Contents | 70 | ## Contents |
| 71 | 71 | ||
| 72 | -+ [Users](doc/api/users.md) | ||
| 73 | -+ [Session](doc/api/session.md) | ||
| 74 | -+ [Projects](doc/api/projects.md) | ||
| 75 | -+ [Project Snippets](doc/api/project_snippets.md) | ||
| 76 | -+ [Repositories](doc/api/repositories.md) | ||
| 77 | -+ [Issues](doc/api/issues.md) | ||
| 78 | -+ [Milestones](doc/api/milestones.md) | ||
| 79 | -+ [Notes](doc/api/notes.md) | ||
| 80 | -+ [Deploy Keys](doc/api/deploy_keys.md) | ||
| 81 | -+ [System Hooks](doc/api/system_hooks.md) | ||
| 82 | -+ [Groups](doc/api/groups.md) | ||
| 83 | -+ [User Teams](doc/api/user_teams.md) | 72 | ++ [Users](users.md) |
| 73 | ++ [Session](session.md) | ||
| 74 | ++ [Projects](projects.md) | ||
| 75 | ++ [Project Snippets](project_snippets.md) | ||
| 76 | ++ [Repositories](repositories.md) | ||
| 77 | ++ [Issues](issues.md) | ||
| 78 | ++ [Milestones](milestones.md) | ||
| 79 | ++ [Notes](notes.md) | ||
| 80 | ++ [Deploy Keys](deploy_keys.md) | ||
| 81 | ++ [System Hooks](system_hooks.md) | ||
| 82 | ++ [Groups](groups.md) | ||
| 83 | ++ [User Teams](user_teams.md) |
doc/install/installation.md
| @@ -148,10 +148,10 @@ To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install | @@ -148,10 +148,10 @@ To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install | ||
| 148 | cd /home/git/gitlab | 148 | cd /home/git/gitlab |
| 149 | 149 | ||
| 150 | # Checkout to stable release | 150 | # Checkout to stable release |
| 151 | - sudo -u git -H git checkout 5-2-stable | 151 | + sudo -u git -H git checkout 5-3-stable |
| 152 | 152 | ||
| 153 | **Note:** | 153 | **Note:** |
| 154 | -You can change `5-2-stable` to `master` if you want the *bleeding edge* version, but do so with caution! | 154 | +You can change `5-3-stable` to `master` if you want the *bleeding edge* version, but do so with caution! |
| 155 | 155 | ||
| 156 | ## Configure it | 156 | ## Configure it |
| 157 | 157 | ||
| @@ -352,10 +352,10 @@ GitLab uses [Omniauth](http://www.omniauth.org/) for authentication and already | @@ -352,10 +352,10 @@ GitLab uses [Omniauth](http://www.omniauth.org/) for authentication and already | ||
| 352 | 352 | ||
| 353 | These steps are fairly general and you will need to figure out the exact details from the Omniauth provider's documentation. | 353 | These steps are fairly general and you will need to figure out the exact details from the Omniauth provider's documentation. |
| 354 | 354 | ||
| 355 | -* Add `gem "omniauth-your-auth-provider"` to the [Gemfile](https://github.com/gitlabhq/gitlabhq/blob/5-2-stable/Gemfile#L18) | 355 | +* Add `gem "omniauth-your-auth-provider"` to the [Gemfile](https://github.com/gitlabhq/gitlabhq/blob/5-3-stable/Gemfile#L18) |
| 356 | * Run `sudo -u git -H bundle install` to install the new gem(s) | 356 | * Run `sudo -u git -H bundle install` to install the new gem(s) |
| 357 | -* Add provider specific configuration options to your `config/gitlab.yml` (you can use the [auth providers section of the example config](https://github.com/gitlabhq/gitlabhq/blob/5-2-stable/config/gitlab.yml.example#L53) as a reference) | ||
| 358 | -* Add icons for the new provider into the [vendor/assets/images/authbuttons](https://github.com/gitlabhq/gitlabhq/tree/5-2-stable/vendor/assets/images/authbuttons) directory (you can find some more popular ones over at https://github.com/intridea/authbuttons) | 357 | +* Add provider specific configuration options to your `config/gitlab.yml` (you can use the [auth providers section of the example config](https://github.com/gitlabhq/gitlabhq/blob/5-3-stable/config/gitlab.yml.example#L53) as a reference) |
| 358 | +* Add icons for the new provider into the [vendor/assets/images/authbuttons](https://github.com/gitlabhq/gitlabhq/tree/5-3-stable/vendor/assets/images/authbuttons) directory (you can find some more popular ones over at https://github.com/intridea/authbuttons) | ||
| 359 | * Restart GitLab | 359 | * Restart GitLab |
| 360 | 360 | ||
| 361 | ### Examples | 361 | ### Examples |
| @@ -0,0 +1,80 @@ | @@ -0,0 +1,80 @@ | ||
| 1 | +# From 5.2 to 5.3 | ||
| 2 | + | ||
| 3 | +### 0. Backup | ||
| 4 | + | ||
| 5 | +It's useful to make a backup just in case things go south: | ||
| 6 | +(With MySQL, this may require granting "LOCK TABLES" privileges to the GitLab user on the database version) | ||
| 7 | + | ||
| 8 | +```bash | ||
| 9 | +cd /home/git/gitlab | ||
| 10 | +sudo -u git -H RAILS_ENV=production bundle exec rake gitlab:backup:create | ||
| 11 | +``` | ||
| 12 | + | ||
| 13 | +### 1. Stop server | ||
| 14 | + | ||
| 15 | + sudo service gitlab stop | ||
| 16 | + | ||
| 17 | +### 2. Get latest code | ||
| 18 | + | ||
| 19 | +```bash | ||
| 20 | +cd /home/git/gitlab | ||
| 21 | +sudo -u git -H git fetch | ||
| 22 | +sudo -u git -H git checkout 5-3-stable | ||
| 23 | +``` | ||
| 24 | + | ||
| 25 | +### 3. Install libs, migrations, etc. | ||
| 26 | + | ||
| 27 | +```bash | ||
| 28 | +cd /home/git/gitlab | ||
| 29 | + | ||
| 30 | +# MySQL | ||
| 31 | +sudo -u git -H bundle install --without development test postgres --deployment | ||
| 32 | + | ||
| 33 | +#PostgreSQL | ||
| 34 | +sudo -u git -H bundle install --without development test mysql --deployment | ||
| 35 | + | ||
| 36 | +sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production | ||
| 37 | +``` | ||
| 38 | + | ||
| 39 | +### 4. Update config files | ||
| 40 | + | ||
| 41 | +* Make `/home/git/gitlab/config/gitlab.yml` same as https://github.com/gitlabhq/gitlabhq/blob/5-2-stable/config/gitlab.yml.example but with your settings. | ||
| 42 | +* Make `/home/git/gitlab/config/puma.rb` same as https://github.com/gitlabhq/gitlabhq/blob/5-2-stable/config/puma.rb.example but with your settings. | ||
| 43 | + | ||
| 44 | +### 5. Update Init script | ||
| 45 | + | ||
| 46 | +```bash | ||
| 47 | +sudo rm /etc/init.d/gitlab | ||
| 48 | +sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/5-3-stable/lib/support/init.d/gitlab | ||
| 49 | +sudo chmod +x /etc/init.d/gitlab | ||
| 50 | +``` | ||
| 51 | + | ||
| 52 | +### 6. Start application | ||
| 53 | + | ||
| 54 | + sudo service gitlab start | ||
| 55 | + sudo service nginx restart | ||
| 56 | + | ||
| 57 | +### 7. Check application status | ||
| 58 | + | ||
| 59 | +Check if GitLab and its environment are configured correctly: | ||
| 60 | + | ||
| 61 | + sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production | ||
| 62 | + | ||
| 63 | +To make sure you didn't miss anything run a more thorough check with: | ||
| 64 | + | ||
| 65 | + sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production | ||
| 66 | + | ||
| 67 | +If all items are green, then congratulations upgrade complete! | ||
| 68 | + | ||
| 69 | +## Things went south? Revert to previous version (5.2) | ||
| 70 | + | ||
| 71 | +### 1. Revert the code to the previous version | ||
| 72 | +Follow the [`upgrade guide from 5.1 to 5.2`](5.1-to-5.2.md), except for the database migration | ||
| 73 | +(The backup is already migrated to the previous version) | ||
| 74 | + | ||
| 75 | +### 2. Restore from the backup: | ||
| 76 | + | ||
| 77 | +```bash | ||
| 78 | +cd /home/git/gitlab | ||
| 79 | +sudo -u git -H RAILS_ENV=production bundle exec rake gitlab:backup:restore | ||
| 80 | +``` |
features/project/issues/milestones.feature
| @@ -22,5 +22,3 @@ Feature: Project Milestones | @@ -22,5 +22,3 @@ Feature: Project Milestones | ||
| 22 | Given the milestone has open and closed issues | 22 | Given the milestone has open and closed issues |
| 23 | And I click link "v2.2" | 23 | And I click link "v2.2" |
| 24 | Then I should see 3 issues | 24 | Then I should see 3 issues |
| 25 | - When I click link "All Issues" | ||
| 26 | - Then I should see 4 issues |
features/steps/project/project_active_tab.rb
| @@ -45,7 +45,7 @@ class ProjectActiveTab < Spinach::FeatureSteps | @@ -45,7 +45,7 @@ class ProjectActiveTab < Spinach::FeatureSteps | ||
| 45 | # Sub Tabs: Home | 45 | # Sub Tabs: Home |
| 46 | 46 | ||
| 47 | Given 'I click the "Team" tab' do | 47 | Given 'I click the "Team" tab' do |
| 48 | - click_link('Team') | 48 | + click_link('Project Members') |
| 49 | end | 49 | end |
| 50 | 50 | ||
| 51 | Given 'I click the "Attachments" tab' do | 51 | Given 'I click the "Attachments" tab' do |
| @@ -61,7 +61,7 @@ class ProjectActiveTab < Spinach::FeatureSteps | @@ -61,7 +61,7 @@ class ProjectActiveTab < Spinach::FeatureSteps | ||
| 61 | end | 61 | end |
| 62 | 62 | ||
| 63 | Given 'I click the "Hooks" tab' do | 63 | Given 'I click the "Hooks" tab' do |
| 64 | - click_link('Hooks') | 64 | + click_link('Web Hooks') |
| 65 | end | 65 | end |
| 66 | 66 | ||
| 67 | Given 'I click the "Deploy Keys" tab' do | 67 | Given 'I click the "Deploy Keys" tab' do |
| @@ -73,7 +73,7 @@ class ProjectActiveTab < Spinach::FeatureSteps | @@ -73,7 +73,7 @@ class ProjectActiveTab < Spinach::FeatureSteps | ||
| 73 | end | 73 | end |
| 74 | 74 | ||
| 75 | Then 'the active sub tab should be Team' do | 75 | Then 'the active sub tab should be Team' do |
| 76 | - ensure_active_sub_tab('Team') | 76 | + ensure_active_sub_tab('Project Members') |
| 77 | end | 77 | end |
| 78 | 78 | ||
| 79 | Then 'the active sub tab should be Attachments' do | 79 | Then 'the active sub tab should be Attachments' do |
| @@ -89,7 +89,7 @@ class ProjectActiveTab < Spinach::FeatureSteps | @@ -89,7 +89,7 @@ class ProjectActiveTab < Spinach::FeatureSteps | ||
| 89 | end | 89 | end |
| 90 | 90 | ||
| 91 | Then 'the active sub tab should be Hooks' do | 91 | Then 'the active sub tab should be Hooks' do |
| 92 | - ensure_active_sub_tab('Hooks') | 92 | + ensure_active_sub_tab('Web Hooks') |
| 93 | end | 93 | end |
| 94 | 94 | ||
| 95 | Then 'the active sub tab should be Deploy Keys' do | 95 | Then 'the active sub tab should be Deploy Keys' do |
features/steps/project/project_merge_requests.rb
| @@ -57,8 +57,8 @@ class ProjectMergeRequests < Spinach::FeatureSteps | @@ -57,8 +57,8 @@ class ProjectMergeRequests < Spinach::FeatureSteps | ||
| 57 | 57 | ||
| 58 | And 'I submit new merge request "Wiki Feature"' do | 58 | And 'I submit new merge request "Wiki Feature"' do |
| 59 | fill_in "merge_request_title", with: "Wiki Feature" | 59 | fill_in "merge_request_title", with: "Wiki Feature" |
| 60 | - select "master", from: "merge_request_source_branch" | ||
| 61 | - select "stable", from: "merge_request_target_branch" | 60 | + select "bootstrap", from: "merge_request_source_branch" |
| 61 | + select "master", from: "merge_request_target_branch" | ||
| 62 | click_button "Submit merge request" | 62 | click_button "Submit merge request" |
| 63 | end | 63 | end |
| 64 | 64 |
features/steps/project/project_milestones.rb
| @@ -50,12 +50,6 @@ class ProjectMilestones < Spinach::FeatureSteps | @@ -50,12 +50,6 @@ class ProjectMilestones < Spinach::FeatureSteps | ||
| 50 | end | 50 | end |
| 51 | 51 | ||
| 52 | Then "I should see 3 issues" do | 52 | Then "I should see 3 issues" do |
| 53 | - page.should have_selector('.milestone-issue-filter .well-list li', count: 4) | ||
| 54 | - page.should have_selector('.milestone-issue-filter .well-list li.hide', count: 1) | ||
| 55 | - end | ||
| 56 | - | ||
| 57 | - Then "I should see 4 issues" do | ||
| 58 | - page.should have_selector('.milestone-issue-filter .well-list li', count: 4) | ||
| 59 | - page.should_not have_selector('.milestone-issue-filter .well-list li.hide') | 53 | + page.should have_selector('#tab-issues li', count: 4) |
| 60 | end | 54 | end |
| 61 | end | 55 | end |
features/steps/userteams/userteams.rb
| @@ -93,7 +93,7 @@ class Userteams < Spinach::FeatureSteps | @@ -93,7 +93,7 @@ class Userteams < Spinach::FeatureSteps | ||
| 93 | Then 'I should see issues from this team assigned to me' do | 93 | Then 'I should see issues from this team assigned to me' do |
| 94 | team = UserTeam.last | 94 | team = UserTeam.last |
| 95 | team.projects.each do |project| | 95 | team.projects.each do |project| |
| 96 | - project.issues.assigned(current_user).each do |issue| | 96 | + project.issues.assigned_to(current_user).each do |issue| |
| 97 | page.should have_content issue.title | 97 | page.should have_content issue.title |
| 98 | end | 98 | end |
| 99 | end | 99 | end |
| @@ -121,7 +121,7 @@ class Userteams < Spinach::FeatureSteps | @@ -121,7 +121,7 @@ class Userteams < Spinach::FeatureSteps | ||
| 121 | team = UserTeam.last | 121 | team = UserTeam.last |
| 122 | team.projects.each do |project| | 122 | team.projects.each do |project| |
| 123 | team.members.each do |member| | 123 | team.members.each do |member| |
| 124 | - project.issues.assigned(member).each do |issue| | 124 | + project.issues.assigned_to(member).each do |issue| |
| 125 | page.should have_content issue.title | 125 | page.should have_content issue.title |
| 126 | end | 126 | end |
| 127 | end | 127 | end |
| @@ -131,9 +131,7 @@ class Userteams < Spinach::FeatureSteps | @@ -131,9 +131,7 @@ class Userteams < Spinach::FeatureSteps | ||
| 131 | Given 'project from team has merge requests assigned to me' do | 131 | Given 'project from team has merge requests assigned to me' do |
| 132 | team = UserTeam.last | 132 | team = UserTeam.last |
| 133 | team.projects.each do |project| | 133 | team.projects.each do |project| |
| 134 | - team.members.each do |member| | ||
| 135 | - 3.times { create(:merge_request, assignee: member, project: project) } | ||
| 136 | - end | 134 | + create(:merge_request, assignee: current_user, project: project) |
| 137 | end | 135 | end |
| 138 | end | 136 | end |
| 139 | 137 | ||
| @@ -145,10 +143,8 @@ class Userteams < Spinach::FeatureSteps | @@ -145,10 +143,8 @@ class Userteams < Spinach::FeatureSteps | ||
| 145 | Then 'I should see merge requests from this team assigned to me' do | 143 | Then 'I should see merge requests from this team assigned to me' do |
| 146 | team = UserTeam.last | 144 | team = UserTeam.last |
| 147 | team.projects.each do |project| | 145 | team.projects.each do |project| |
| 148 | - team.members.each do |member| | ||
| 149 | - project.issues.assigned(member).each do |merge_request| | ||
| 150 | - page.should have_content merge_request.title | ||
| 151 | - end | 146 | + project.merge_requests.each do |merge_request| |
| 147 | + page.should have_content merge_request.title | ||
| 152 | end | 148 | end |
| 153 | end | 149 | end |
| 154 | end | 150 | end |
| @@ -156,20 +152,8 @@ class Userteams < Spinach::FeatureSteps | @@ -156,20 +152,8 @@ class Userteams < Spinach::FeatureSteps | ||
| 156 | Given 'project from team has merge requests assigned to team members' do | 152 | Given 'project from team has merge requests assigned to team members' do |
| 157 | team = UserTeam.last | 153 | team = UserTeam.last |
| 158 | team.projects.each do |project| | 154 | team.projects.each do |project| |
| 159 | - team.members.each do |member| | ||
| 160 | - 3.times { create(:merge_request, assignee: member, project: project) } | ||
| 161 | - end | ||
| 162 | - end | ||
| 163 | - end | ||
| 164 | - | ||
| 165 | - Then 'I should see merge requests from this team assigned to me' do | ||
| 166 | - team = UserTeam.last | ||
| 167 | - team.projects.each do |project| | ||
| 168 | - team.members.each do |member| | ||
| 169 | - project.issues.assigned(member).each do |merge_request| | ||
| 170 | - page.should have_content merge_request.title | ||
| 171 | - end | ||
| 172 | - end | 155 | + member = team.members.sample |
| 156 | + create(:merge_request, assignee: member, project: project) | ||
| 173 | end | 157 | end |
| 174 | end | 158 | end |
| 175 | 159 |
lib/gitlab/backend/grack_auth.rb
| 1 | require_relative 'shell_env' | 1 | require_relative 'shell_env' |
| 2 | -require 'omniauth-ldap' | 2 | +require_relative 'grack_ldap' |
| 3 | +require_relative 'grack_helpers' | ||
| 3 | 4 | ||
| 4 | module Grack | 5 | module Grack |
| 5 | class Auth < Rack::Auth::Basic | 6 | class Auth < Rack::Auth::Basic |
| 6 | - attr_accessor :user, :project | 7 | + include LDAP |
| 8 | + include Helpers | ||
| 9 | + | ||
| 10 | + attr_accessor :user, :project, :ref, :env | ||
| 7 | 11 | ||
| 8 | def call(env) | 12 | def call(env) |
| 9 | @env = env | 13 | @env = env |
| @@ -14,42 +18,52 @@ module Grack | @@ -14,42 +18,52 @@ module Grack | ||
| 14 | @env['PATH_INFO'] = @request.path | 18 | @env['PATH_INFO'] = @request.path |
| 15 | @env['SCRIPT_NAME'] = "" | 19 | @env['SCRIPT_NAME'] = "" |
| 16 | 20 | ||
| 17 | - return render_not_found unless project | ||
| 18 | - return unauthorized unless project.public || @auth.provided? | ||
| 19 | - return bad_request if @auth.provided? && !@auth.basic? | ||
| 20 | - | ||
| 21 | - if valid? | ||
| 22 | - if @auth.provided? | ||
| 23 | - @env['REMOTE_USER'] = @auth.username | ||
| 24 | - end | ||
| 25 | - return @app.call(env) | ||
| 26 | - else | ||
| 27 | - unauthorized | ||
| 28 | - end | 21 | + auth! |
| 29 | end | 22 | end |
| 30 | 23 | ||
| 31 | - def valid? | 24 | + private |
| 25 | + | ||
| 26 | + def auth! | ||
| 27 | + return render_not_found unless project | ||
| 28 | + | ||
| 32 | if @auth.provided? | 29 | if @auth.provided? |
| 30 | + return bad_request unless @auth.basic? | ||
| 31 | + | ||
| 33 | # Authentication with username and password | 32 | # Authentication with username and password |
| 34 | login, password = @auth.credentials | 33 | login, password = @auth.credentials |
| 35 | 34 | ||
| 36 | - @user = authenticate(login, password) | ||
| 37 | - return false unless @user | 35 | + @user = authenticate_user(login, password) |
| 38 | 36 | ||
| 39 | - Gitlab::ShellEnv.set_env(@user) | 37 | + if @user |
| 38 | + Gitlab::ShellEnv.set_env(@user) | ||
| 39 | + @env['REMOTE_USER'] = @auth.username | ||
| 40 | + else | ||
| 41 | + return unauthorized | ||
| 42 | + end | ||
| 43 | + | ||
| 44 | + else | ||
| 45 | + return unauthorized unless project.public | ||
| 40 | end | 46 | end |
| 41 | 47 | ||
| 48 | + if authorized_git_request? | ||
| 49 | + @app.call(env) | ||
| 50 | + else | ||
| 51 | + unauthorized | ||
| 52 | + end | ||
| 53 | + end | ||
| 54 | + | ||
| 55 | + def authorized_git_request? | ||
| 42 | # Git upload and receive | 56 | # Git upload and receive |
| 43 | if @request.get? | 57 | if @request.get? |
| 44 | - validate_get_request | 58 | + authorize_request(@request.params['service']) |
| 45 | elsif @request.post? | 59 | elsif @request.post? |
| 46 | - validate_post_request | 60 | + authorize_request(File.basename(@request.path)) |
| 47 | else | 61 | else |
| 48 | false | 62 | false |
| 49 | end | 63 | end |
| 50 | end | 64 | end |
| 51 | 65 | ||
| 52 | - def authenticate(login, password) | 66 | + def authenticate_user(login, password) |
| 53 | user = User.find_by_email(login) || User.find_by_username(login) | 67 | user = User.find_by_email(login) || User.find_by_username(login) |
| 54 | 68 | ||
| 55 | # If the provided login was not a known email or username | 69 | # If the provided login was not a known email or username |
| @@ -65,34 +79,12 @@ module Grack | @@ -65,34 +79,12 @@ module Grack | ||
| 65 | end | 79 | end |
| 66 | end | 80 | end |
| 67 | 81 | ||
| 68 | - def ldap_auth(login, password) | ||
| 69 | - # Check user against LDAP backend if user is not authenticated | ||
| 70 | - # Only check with valid login and password to prevent anonymous bind results | ||
| 71 | - return nil unless ldap_conf.enabled && !login.blank? && !password.blank? | ||
| 72 | - | ||
| 73 | - ldap = OmniAuth::LDAP::Adaptor.new(ldap_conf) | ||
| 74 | - ldap_user = ldap.bind_as( | ||
| 75 | - filter: Net::LDAP::Filter.eq(ldap.uid, login), | ||
| 76 | - size: 1, | ||
| 77 | - password: password | ||
| 78 | - ) | ||
| 79 | - | ||
| 80 | - User.find_by_extern_uid_and_provider(ldap_user.dn, 'ldap') if ldap_user | ||
| 81 | - end | ||
| 82 | - | ||
| 83 | - def validate_get_request | ||
| 84 | - validate_request(@request.params['service']) | ||
| 85 | - end | ||
| 86 | - | ||
| 87 | - def validate_post_request | ||
| 88 | - validate_request(File.basename(@request.path)) | ||
| 89 | - end | ||
| 90 | - | ||
| 91 | - def validate_request(service) | ||
| 92 | - if service == 'git-upload-pack' | 82 | + def authorize_request(service) |
| 83 | + case service | ||
| 84 | + when 'git-upload-pack' | ||
| 93 | project.public || can?(user, :download_code, project) | 85 | project.public || can?(user, :download_code, project) |
| 94 | - elsif service == 'git-receive-pack' | ||
| 95 | - action = if project.protected_branch?(current_ref) | 86 | + when'git-receive-pack' |
| 87 | + action = if project.protected_branch?(ref) | ||
| 96 | :push_code_to_protected_branches | 88 | :push_code_to_protected_branches |
| 97 | else | 89 | else |
| 98 | :push_code | 90 | :push_code |
| @@ -104,49 +96,24 @@ module Grack | @@ -104,49 +96,24 @@ module Grack | ||
| 104 | end | 96 | end |
| 105 | end | 97 | end |
| 106 | 98 | ||
| 107 | - def can?(object, action, subject) | ||
| 108 | - abilities.allowed?(object, action, subject) | ||
| 109 | - end | ||
| 110 | - | ||
| 111 | - def current_ref | ||
| 112 | - if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/ | ||
| 113 | - input = Zlib::GzipReader.new(@request.body).read | ||
| 114 | - else | ||
| 115 | - input = @request.body.read | ||
| 116 | - end | ||
| 117 | - # Need to reset seek point | ||
| 118 | - @request.body.rewind | ||
| 119 | - /refs\/heads\/([\w\.-]+)/n.match(input.force_encoding('ascii-8bit')).to_a.last | ||
| 120 | - end | ||
| 121 | - | ||
| 122 | def project | 99 | def project |
| 123 | - unless instance_variable_defined? :@project | ||
| 124 | - # Find project by PATH_INFO from env | ||
| 125 | - if m = /^\/([\w\.\/-]+)\.git/.match(@request.path_info).to_a | ||
| 126 | - @project = Project.find_with_namespace(m.last) | ||
| 127 | - end | ||
| 128 | - end | ||
| 129 | - return @project | 100 | + @project ||= project_by_path(@request.path_info) |
| 130 | end | 101 | end |
| 131 | 102 | ||
| 132 | - PLAIN_TYPE = {"Content-Type" => "text/plain"} | ||
| 133 | - | ||
| 134 | - def render_not_found | ||
| 135 | - [404, PLAIN_TYPE, ["Not Found"]] | 103 | + def ref |
| 104 | + @ref ||= parse_ref | ||
| 136 | end | 105 | end |
| 137 | 106 | ||
| 138 | - protected | 107 | + def parse_ref |
| 108 | + input = if @env["HTTP_CONTENT_ENCODING"] =~ /gzip/ | ||
| 109 | + Zlib::GzipReader.new(@request.body).read | ||
| 110 | + else | ||
| 111 | + @request.body.read | ||
| 112 | + end | ||
| 139 | 113 | ||
| 140 | - def abilities | ||
| 141 | - @abilities ||= begin | ||
| 142 | - abilities = Six.new | ||
| 143 | - abilities << Ability | ||
| 144 | - abilities | ||
| 145 | - end | ||
| 146 | - end | ||
| 147 | - | ||
| 148 | - def ldap_conf | ||
| 149 | - @ldap_conf ||= Gitlab.config.ldap | 114 | + # Need to reset seek point |
| 115 | + @request.body.rewind | ||
| 116 | + /refs\/heads\/([\w\.-]+)/n.match(input.force_encoding('ascii-8bit')).to_a.last | ||
| 150 | end | 117 | end |
| 151 | - end# Auth | ||
| 152 | -end# Grack | 118 | + end |
| 119 | +end |
| @@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
| 1 | +module Grack | ||
| 2 | + module Helpers | ||
| 3 | + def project_by_path(path) | ||
| 4 | + if m = /^\/([\w\.\/-]+)\.git/.match(path).to_a | ||
| 5 | + path_with_namespace = m.last | ||
| 6 | + path_with_namespace.gsub!(/.wiki$/, '') | ||
| 7 | + | ||
| 8 | + Project.find_with_namespace(path_with_namespace) | ||
| 9 | + end | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + def render_not_found | ||
| 13 | + [404, {"Content-Type" => "text/plain"}, ["Not Found"]] | ||
| 14 | + end | ||
| 15 | + | ||
| 16 | + def can?(object, action, subject) | ||
| 17 | + abilities.allowed?(object, action, subject) | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | + def abilities | ||
| 21 | + @abilities ||= begin | ||
| 22 | + abilities = Six.new | ||
| 23 | + abilities << Ability | ||
| 24 | + abilities | ||
| 25 | + end | ||
| 26 | + end | ||
| 27 | + end | ||
| 28 | +end |
| @@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
| 1 | +require 'omniauth-ldap' | ||
| 2 | + | ||
| 3 | +module Grack | ||
| 4 | + module LDAP | ||
| 5 | + def ldap_auth(login, password) | ||
| 6 | + # Check user against LDAP backend if user is not authenticated | ||
| 7 | + # Only check with valid login and password to prevent anonymous bind results | ||
| 8 | + return nil unless ldap_conf.enabled && !login.blank? && !password.blank? | ||
| 9 | + | ||
| 10 | + ldap = OmniAuth::LDAP::Adaptor.new(ldap_conf) | ||
| 11 | + ldap_user = ldap.bind_as( | ||
| 12 | + filter: Net::LDAP::Filter.eq(ldap.uid, login), | ||
| 13 | + size: 1, | ||
| 14 | + password: password | ||
| 15 | + ) | ||
| 16 | + | ||
| 17 | + User.find_by_extern_uid_and_provider(ldap_user.dn, 'ldap') if ldap_user | ||
| 18 | + end | ||
| 19 | + | ||
| 20 | + def ldap_conf | ||
| 21 | + @ldap_conf ||= Gitlab.config.ldap | ||
| 22 | + end | ||
| 23 | + end | ||
| 24 | +end |
spec/features/admin/admin_users_spec.rb
| @@ -20,13 +20,10 @@ describe "Admin::Users" do | @@ -20,13 +20,10 @@ describe "Admin::Users" do | ||
| 20 | 20 | ||
| 21 | describe "GET /admin/users/new" do | 21 | describe "GET /admin/users/new" do |
| 22 | before do | 22 | before do |
| 23 | - @password = "123ABC" | ||
| 24 | visit new_admin_user_path | 23 | visit new_admin_user_path |
| 25 | fill_in "user_name", with: "Big Bang" | 24 | fill_in "user_name", with: "Big Bang" |
| 26 | fill_in "user_username", with: "bang" | 25 | fill_in "user_username", with: "bang" |
| 27 | fill_in "user_email", with: "bigbang@mail.com" | 26 | fill_in "user_email", with: "bigbang@mail.com" |
| 28 | - fill_in "user_password", with: @password | ||
| 29 | - fill_in "user_password_confirmation", with: @password | ||
| 30 | end | 27 | end |
| 31 | 28 | ||
| 32 | it "should create new user" do | 29 | it "should create new user" do |
| @@ -57,26 +54,13 @@ describe "Admin::Users" do | @@ -57,26 +54,13 @@ describe "Admin::Users" do | ||
| 57 | end | 54 | end |
| 58 | 55 | ||
| 59 | it "should send valid email to user with email & password" do | 56 | it "should send valid email to user with email & password" do |
| 60 | - Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) | ||
| 61 | User.observers.enable :user_observer do | 57 | User.observers.enable :user_observer do |
| 62 | click_button "Create user" | 58 | click_button "Create user" |
| 63 | user = User.last | 59 | user = User.last |
| 64 | email = ActionMailer::Base.deliveries.last | 60 | email = ActionMailer::Base.deliveries.last |
| 65 | email.subject.should have_content("Account was created") | 61 | email.subject.should have_content("Account was created") |
| 66 | email.text_part.body.should have_content(user.email) | 62 | email.text_part.body.should have_content(user.email) |
| 67 | - email.text_part.body.should have_content(@password) | ||
| 68 | - end | ||
| 69 | - end | ||
| 70 | - | ||
| 71 | - it "should send valid email to user with email without password when signup is enabled" do | ||
| 72 | - Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) | ||
| 73 | - User.observers.enable :user_observer do | ||
| 74 | - click_button "Create user" | ||
| 75 | - user = User.last | ||
| 76 | - email = ActionMailer::Base.deliveries.last | ||
| 77 | - email.subject.should have_content("Account was created") | ||
| 78 | - email.text_part.body.should have_content(user.email) | ||
| 79 | - email.text_part.body.should_not have_content(@password) | 63 | + email.text_part.body.should have_content('password') |
| 80 | end | 64 | end |
| 81 | end | 65 | end |
| 82 | end | 66 | end |
spec/mailers/notify_spec.rb
| @@ -15,7 +15,7 @@ describe Notify do | @@ -15,7 +15,7 @@ describe Notify do | ||
| 15 | 15 | ||
| 16 | describe 'for new users, the email' do | 16 | describe 'for new users, the email' do |
| 17 | let(:example_site_path) { root_path } | 17 | let(:example_site_path) { root_path } |
| 18 | - let(:new_user) { create(:user, email: 'newguy@example.com') } | 18 | + let(:new_user) { create(:user, email: 'newguy@example.com', created_by_id: 1) } |
| 19 | 19 | ||
| 20 | subject { Notify.new_user_email(new_user.id, new_user.password) } | 20 | subject { Notify.new_user_email(new_user.id, new_user.password) } |
| 21 | 21 | ||
| @@ -32,8 +32,7 @@ describe Notify do | @@ -32,8 +32,7 @@ describe Notify do | ||
| 32 | end | 32 | end |
| 33 | 33 | ||
| 34 | it 'contains the new user\'s password' do | 34 | it 'contains the new user\'s password' do |
| 35 | - Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) | ||
| 36 | - should have_body_text /#{new_user.password}/ | 35 | + should have_body_text /password/ |
| 37 | end | 36 | end |
| 38 | 37 | ||
| 39 | it 'includes a link to the site' do | 38 | it 'includes a link to the site' do |
| @@ -61,8 +60,7 @@ describe Notify do | @@ -61,8 +60,7 @@ describe Notify do | ||
| 61 | end | 60 | end |
| 62 | 61 | ||
| 63 | it 'should not contain the new user\'s password' do | 62 | it 'should not contain the new user\'s password' do |
| 64 | - Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) | ||
| 65 | - should_not have_body_text /#{new_user.password}/ | 63 | + should_not have_body_text /password/ |
| 66 | end | 64 | end |
| 67 | 65 | ||
| 68 | it 'includes a link to the site' do | 66 | it 'includes a link to the site' do |