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