added NamespacedProject role. Extended project info displayed for admin. Fixed project limit
This commit is contained in:
parent
44209861e8
commit
b01f8b63c2
|
@ -49,6 +49,7 @@ class GroupsController < ApplicationController
|
||||||
def people
|
def people
|
||||||
@project = group.projects.find(params[:project_id]) if params[:project_id]
|
@project = group.projects.find(params[:project_id]) if params[:project_id]
|
||||||
@users = @project ? @project.users : group.users
|
@users = @project ? @project.users : group.users
|
||||||
|
@users.sort_by!(&:name)
|
||||||
|
|
||||||
if @project
|
if @project
|
||||||
@team_member = @project.users_projects.new
|
@team_member = @project.users_projects.new
|
||||||
|
|
|
@ -16,7 +16,7 @@ class SnippetsController < ProjectResourceController
|
||||||
respond_to :html
|
respond_to :html
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@snippets = @project.snippets
|
@snippets = @project.snippets.fresh
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
|
|
@ -25,6 +25,7 @@ class Project < ActiveRecord::Base
|
||||||
include PushObserver
|
include PushObserver
|
||||||
include Authority
|
include Authority
|
||||||
include Team
|
include Team
|
||||||
|
include NamespacedProject
|
||||||
|
|
||||||
class TransferError < StandardError; end
|
class TransferError < StandardError; end
|
||||||
|
|
||||||
|
@ -178,7 +179,7 @@ class Project < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def repo_name
|
def repo_name
|
||||||
denied_paths = %w(gitolite-admin groups projects dashboard)
|
denied_paths = %w(gitolite-admin groups projects dashboard help )
|
||||||
|
|
||||||
if denied_paths.include?(path)
|
if denied_paths.include?(path)
|
||||||
errors.add(:path, "like #{path} is not allowed")
|
errors.add(:path, "like #{path} is not allowed")
|
||||||
|
@ -245,57 +246,11 @@ class Project < ActiveRecord::Base
|
||||||
gitlab_ci_service && gitlab_ci_service.active
|
gitlab_ci_service && gitlab_ci_service.active
|
||||||
end
|
end
|
||||||
|
|
||||||
def path_with_namespace
|
|
||||||
if namespace
|
|
||||||
namespace.path + '/' + path
|
|
||||||
else
|
|
||||||
path
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# For compatibility with old code
|
# For compatibility with old code
|
||||||
def code
|
def code
|
||||||
path
|
path
|
||||||
end
|
end
|
||||||
|
|
||||||
def transfer(new_namespace)
|
|
||||||
Project.transaction do
|
|
||||||
old_namespace = namespace
|
|
||||||
self.namespace = new_namespace
|
|
||||||
|
|
||||||
old_dir = old_namespace.try(:path) || ''
|
|
||||||
new_dir = new_namespace.try(:path) || ''
|
|
||||||
|
|
||||||
old_repo = if old_dir.present?
|
|
||||||
File.join(old_dir, self.path)
|
|
||||||
else
|
|
||||||
self.path
|
|
||||||
end
|
|
||||||
|
|
||||||
if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present?
|
|
||||||
raise TransferError.new("Project with same path in target namespace already exists")
|
|
||||||
end
|
|
||||||
|
|
||||||
Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
|
|
||||||
|
|
||||||
git_host.move_repository(old_repo, self)
|
|
||||||
|
|
||||||
save!
|
|
||||||
end
|
|
||||||
rescue Gitlab::ProjectMover::ProjectMoveError => ex
|
|
||||||
raise TransferError.new(ex.message)
|
|
||||||
end
|
|
||||||
|
|
||||||
def name_with_namespace
|
|
||||||
@name_with_namespace ||= begin
|
|
||||||
if namespace
|
|
||||||
namespace.human_name + " / " + name
|
|
||||||
else
|
|
||||||
name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def items_for entity
|
def items_for entity
|
||||||
case entity
|
case entity
|
||||||
when 'issue' then
|
when 'issue' then
|
||||||
|
@ -304,16 +259,4 @@ class Project < ActiveRecord::Base
|
||||||
merge_requests
|
merge_requests
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def namespace_owner
|
|
||||||
namespace.try(:owner)
|
|
||||||
end
|
|
||||||
|
|
||||||
def chief
|
|
||||||
if namespace
|
|
||||||
namespace_owner
|
|
||||||
else
|
|
||||||
owner
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -56,7 +56,6 @@ class User < ActiveRecord::Base
|
||||||
has_many :issues, foreign_key: :author_id, dependent: :destroy
|
has_many :issues, foreign_key: :author_id, dependent: :destroy
|
||||||
has_many :notes, foreign_key: :author_id, dependent: :destroy
|
has_many :notes, foreign_key: :author_id, dependent: :destroy
|
||||||
has_many :merge_requests, foreign_key: :author_id, dependent: :destroy
|
has_many :merge_requests, foreign_key: :author_id, dependent: :destroy
|
||||||
has_many :my_own_projects, class_name: "Project", foreign_key: :owner_id
|
|
||||||
has_many :events, class_name: "Event", foreign_key: :author_id, dependent: :destroy
|
has_many :events, class_name: "Event", foreign_key: :author_id, dependent: :destroy
|
||||||
has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC"
|
has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC"
|
||||||
has_many :assigned_issues, class_name: "Issue", foreign_key: :assignee_id, dependent: :destroy
|
has_many :assigned_issues, class_name: "Issue", foreign_key: :assignee_id, dependent: :destroy
|
||||||
|
@ -124,16 +123,4 @@ class User < ActiveRecord::Base
|
||||||
self.password = self.password_confirmation = Devise.friendly_token.first(8)
|
self.password = self.password_confirmation = Devise.friendly_token.first(8)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def authorized_groups
|
|
||||||
@authorized_groups ||= begin
|
|
||||||
groups = Group.where(id: self.projects.pluck(:namespace_id)).all
|
|
||||||
groups = groups + self.groups
|
|
||||||
groups.uniq
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def authorized_projects
|
|
||||||
Project.authorized_for(self)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -105,4 +105,20 @@ module Account
|
||||||
def namespace_id
|
def namespace_id
|
||||||
namespace.try :id
|
namespace.try :id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def authorized_groups
|
||||||
|
@authorized_groups ||= begin
|
||||||
|
groups = Group.where(id: self.projects.pluck(:namespace_id)).all
|
||||||
|
groups = groups + self.groups
|
||||||
|
groups.uniq
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def authorized_projects
|
||||||
|
Project.authorized_for(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def my_own_projects
|
||||||
|
Project.personal(self)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
59
app/roles/namespaced_project.rb
Normal file
59
app/roles/namespaced_project.rb
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
module NamespacedProject
|
||||||
|
def transfer(new_namespace)
|
||||||
|
Project.transaction do
|
||||||
|
old_namespace = namespace
|
||||||
|
self.namespace = new_namespace
|
||||||
|
|
||||||
|
old_dir = old_namespace.try(:path) || ''
|
||||||
|
new_dir = new_namespace.try(:path) || ''
|
||||||
|
|
||||||
|
old_repo = if old_dir.present?
|
||||||
|
File.join(old_dir, self.path)
|
||||||
|
else
|
||||||
|
self.path
|
||||||
|
end
|
||||||
|
|
||||||
|
if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present?
|
||||||
|
raise TransferError.new("Project with same path in target namespace already exists")
|
||||||
|
end
|
||||||
|
|
||||||
|
Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
|
||||||
|
|
||||||
|
git_host.move_repository(old_repo, self)
|
||||||
|
|
||||||
|
save!
|
||||||
|
end
|
||||||
|
rescue Gitlab::ProjectMover::ProjectMoveError => ex
|
||||||
|
raise TransferError.new(ex.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
def name_with_namespace
|
||||||
|
@name_with_namespace ||= begin
|
||||||
|
if namespace
|
||||||
|
namespace.human_name + " / " + name
|
||||||
|
else
|
||||||
|
name
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def namespace_owner
|
||||||
|
namespace.try(:owner)
|
||||||
|
end
|
||||||
|
|
||||||
|
def chief
|
||||||
|
if namespace
|
||||||
|
namespace_owner
|
||||||
|
else
|
||||||
|
owner
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def path_with_namespace
|
||||||
|
if namespace
|
||||||
|
namespace.path + '/' + path
|
||||||
|
else
|
||||||
|
path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -19,20 +19,11 @@
|
||||||
.input
|
.input
|
||||||
= text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true
|
= text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true
|
||||||
|
|
||||||
- unless project.new_record?
|
|
||||||
.clearfix
|
|
||||||
= f.label :namespace_id
|
|
||||||
.input
|
|
||||||
= f.select :namespace_id, namespaces_options(@project.namespace_id, :all), {}, {class: 'chosen'}
|
|
||||||
|
|
||||||
%span.cred Be careful. Changing project namespace can have unintended side effects
|
|
||||||
|
|
||||||
- if project.repo_exists?
|
- if project.repo_exists?
|
||||||
.clearfix
|
.clearfix
|
||||||
= f.label :default_branch, "Default Branch"
|
= f.label :default_branch, "Default Branch"
|
||||||
.input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
|
.input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
|
||||||
|
|
||||||
- unless project.new_record?
|
|
||||||
%fieldset.adv_settings
|
%fieldset.adv_settings
|
||||||
%legend Features:
|
%legend Features:
|
||||||
|
|
||||||
|
@ -52,7 +43,20 @@
|
||||||
= f.label :wiki_enabled, "Wiki"
|
= f.label :wiki_enabled, "Wiki"
|
||||||
.input= f.check_box :wiki_enabled
|
.input= f.check_box :wiki_enabled
|
||||||
|
|
||||||
- unless project.new_record?
|
%fieldset.features
|
||||||
|
%legend Transfer:
|
||||||
|
.control-group
|
||||||
|
= f.label :namespace_id do
|
||||||
|
%span Namespace
|
||||||
|
.controls
|
||||||
|
= f.select :namespace_id, namespaces_options(@project.namespace_id, :all), {}, {class: 'chosen'}
|
||||||
|
%br
|
||||||
|
%ul.prepend-top-10.cred
|
||||||
|
%li Be careful. Changing project namespace can have unintended side effects
|
||||||
|
%li You can transfer project only to namespaces you can manage
|
||||||
|
%li You will need to update your local repositories to point to the new location.
|
||||||
|
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
= f.submit 'Save Project', class: "btn save-btn"
|
= f.submit 'Save Project', class: "btn save-btn"
|
||||||
= link_to 'Cancel', admin_projects_path, class: "btn cancel-btn"
|
= link_to 'Cancel', admin_projects_path, class: "btn cancel-btn"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
%h3.page_title
|
%h3.page_title
|
||||||
Projects
|
Projects (#{@projects.count})
|
||||||
= link_to 'New Project', new_project_path, class: "btn small right"
|
= link_to 'New Project', new_project_path, class: "btn small right"
|
||||||
%br
|
%br
|
||||||
= form_tag admin_projects_path, method: :get, class: 'form-inline' do
|
= form_tag admin_projects_path, method: :get, class: 'form-inline' do
|
||||||
|
|
|
@ -47,21 +47,61 @@
|
||||||
%tr
|
%tr
|
||||||
%td
|
%td
|
||||||
%b
|
%b
|
||||||
Path:
|
Owned by:
|
||||||
%td
|
%td
|
||||||
%code= @project.path_to_repo
|
- if @project.chief
|
||||||
|
= link_to @project.chief.name, admin_user_path(@project.chief)
|
||||||
|
- else
|
||||||
|
(deleted)
|
||||||
%tr
|
%tr
|
||||||
%td
|
%td
|
||||||
%b
|
%b
|
||||||
Created by:
|
Created by:
|
||||||
%td
|
%td
|
||||||
= @project.owner_name || '(deleted)'
|
= @project.owner_name || '(deleted)'
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
%b
|
||||||
|
Created at:
|
||||||
|
%td
|
||||||
|
= @project.created_at.stamp("March 1, 1999")
|
||||||
|
|
||||||
|
%table.zebra-striped
|
||||||
|
%thead
|
||||||
|
%tr
|
||||||
|
%th Repository
|
||||||
|
%th
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
%b
|
||||||
|
FS Path:
|
||||||
|
%td
|
||||||
|
%code= @project.path_to_repo
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
%b
|
||||||
|
Smart HTTP:
|
||||||
|
%td
|
||||||
|
= link_to @project.http_url_to_repo
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
%b
|
||||||
|
SSH:
|
||||||
|
%td
|
||||||
|
= link_to @project.ssh_url_to_repo
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
%b
|
||||||
|
Last commit at:
|
||||||
|
%td
|
||||||
|
= last_commit(@project)
|
||||||
%tr
|
%tr
|
||||||
%td
|
%td
|
||||||
%b
|
%b
|
||||||
Post Receive File:
|
Post Receive File:
|
||||||
%td
|
%td
|
||||||
= check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true
|
= check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true
|
||||||
|
|
||||||
%br
|
%br
|
||||||
%h5
|
%h5
|
||||||
Team
|
Team
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
%h3.page_title
|
%h3.page_title
|
||||||
Users
|
Users (#{@admin_users.count})
|
||||||
= link_to 'New User', new_admin_user_path, class: "btn small right"
|
= link_to 'New User', new_admin_user_path, class: "btn small right"
|
||||||
%br
|
%br
|
||||||
|
|
||||||
|
@ -40,6 +40,9 @@
|
||||||
%td= user.users_projects.count
|
%td= user.users_projects.count
|
||||||
%td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small"
|
%td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small"
|
||||||
%td.bgred
|
%td.bgred
|
||||||
|
- if user == current_user
|
||||||
|
%span.cred It's you!
|
||||||
|
- else
|
||||||
- if user.blocked
|
- if user.blocked
|
||||||
= link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success"
|
= link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success"
|
||||||
- else
|
- else
|
||||||
|
|
|
@ -37,6 +37,12 @@
|
||||||
%b
|
%b
|
||||||
Blocked:
|
Blocked:
|
||||||
%td= check_box_tag "blocked", 1, @admin_user.blocked, disabled: :disabled
|
%td= check_box_tag "blocked", 1, @admin_user.blocked, disabled: :disabled
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
%b
|
||||||
|
Created at:
|
||||||
|
%td
|
||||||
|
= @admin_user.created_at.stamp("March 1, 1999")
|
||||||
%tr
|
%tr
|
||||||
%td
|
%td
|
||||||
%b
|
%b
|
||||||
|
|
|
@ -22,22 +22,21 @@
|
||||||
%hr
|
%hr
|
||||||
|
|
||||||
-if @hooks.any?
|
-if @hooks.any?
|
||||||
%h3
|
%h3.page_title
|
||||||
Hooks
|
Hooks (#{@hooks.count})
|
||||||
%small (#{@hooks.count})
|
|
||||||
%br
|
%br
|
||||||
%table
|
%table
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%th URL
|
%th URL
|
||||||
%th Method
|
|
||||||
%th
|
%th
|
||||||
- @hooks.each do |hook|
|
- @hooks.each do |hook|
|
||||||
%tr
|
%tr
|
||||||
%td
|
%td
|
||||||
|
%span.badge.badge-info POST
|
||||||
= link_to project_hook_path(@project, hook) do
|
= link_to project_hook_path(@project, hook) do
|
||||||
%strong= hook.url
|
%strong= hook.url
|
||||||
= link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn small right"
|
|
||||||
%td POST
|
|
||||||
%td
|
%td
|
||||||
= link_to 'Remove', project_hook_path(@project, hook), confirm: 'Are you sure?', method: :delete, class: "danger btn small right"
|
.right
|
||||||
|
= link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn small grouped"
|
||||||
|
= link_to 'Remove', project_hook_path(@project, hook), confirm: 'Are you sure?', method: :delete, class: "danger btn small grouped"
|
||||||
|
|
|
@ -9,3 +9,4 @@
|
||||||
$('.project_new_holder').show();
|
$('.project_new_holder').show();
|
||||||
$("#new_project").replaceWith("#{escape_javascript(render('new_form'))}");
|
$("#new_project").replaceWith("#{escape_javascript(render('new_form'))}");
|
||||||
$('.save-project-loader').hide();
|
$('.save-project-loader').hide();
|
||||||
|
new Projects();
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
= time_ago_in_words(note.created_at)
|
= time_ago_in_words(note.created_at)
|
||||||
ago
|
ago
|
||||||
- else
|
- else
|
||||||
.alert-message.block-message
|
%p.slead All files attached to project wall, issues etc will be displayed here
|
||||||
%span All files attached to project wall, issues etc will be displayed here
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
%tr
|
%tr
|
||||||
%td
|
%td
|
||||||
|
= image_tag gravatar_icon(snippet.author_email), class: "avatar s24"
|
||||||
%a{href: project_snippet_path(snippet.project, snippet)}
|
%a{href: project_snippet_path(snippet.project, snippet)}
|
||||||
%strong= truncate(snippet.title, length: 60)
|
%strong= truncate(snippet.title, length: 60)
|
||||||
%td
|
%td
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
= render "projects/project_head"
|
= render "projects/project_head"
|
||||||
|
|
||||||
- if can? current_user, :write_snippet, @project
|
%h3.page_title
|
||||||
.alert-message.block-message
|
Snippets
|
||||||
|
%small share code pastes with others out of git repository
|
||||||
|
|
||||||
|
- if can? current_user, :write_snippet, @project
|
||||||
= link_to new_project_snippet_path(@project), class: "btn small add_new right", title: "New Snippet" do
|
= link_to new_project_snippet_path(@project), class: "btn small add_new right", title: "New Snippet" do
|
||||||
Add new snippet
|
Add new snippet
|
||||||
Share code pastes with others if it can't be in a git repository
|
%br
|
||||||
%br
|
|
||||||
To add new snippet - click on button.
|
|
||||||
|
|
||||||
%table
|
%table
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%th Title
|
%th Title
|
||||||
%th File Name
|
%th File Name
|
||||||
%th Expires At
|
%th Expires At
|
||||||
= render @snippets.fresh
|
= render @snippets
|
||||||
- if @snippets.fresh.empty?
|
- if @snippets.empty?
|
||||||
%tr
|
%tr
|
||||||
%td{colspan: 3}
|
%td{colspan: 3}
|
||||||
%h3.nothing_here_message Nothing here.
|
%h3.nothing_here_message Nothing here.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
= Project.access_options.key(access).pluralize
|
= Project.access_options.key(access).pluralize
|
||||||
%small= members.size
|
%small= members.size
|
||||||
%ul.unstyled
|
%ul.unstyled
|
||||||
- members.each do |up|
|
- members.sort_by(&:user_name).each do |up|
|
||||||
= render(partial: 'team_members/show', locals: {member: up})
|
= render(partial: 'team_members/show', locals: {member: up})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,6 @@ describe User do
|
||||||
it { should have_many(:users_projects).dependent(:destroy) }
|
it { should have_many(:users_projects).dependent(:destroy) }
|
||||||
it { should have_many(:projects) }
|
it { should have_many(:projects) }
|
||||||
it { should have_many(:groups) }
|
it { should have_many(:groups) }
|
||||||
it { should have_many(:my_own_projects).class_name('Project') }
|
|
||||||
it { should have_many(:keys).dependent(:destroy) }
|
it { should have_many(:keys).dependent(:destroy) }
|
||||||
it { should have_many(:events).class_name('Event').dependent(:destroy) }
|
it { should have_many(:events).class_name('Event').dependent(:destroy) }
|
||||||
it { should have_many(:recent_events).class_name('Event') }
|
it { should have_many(:recent_events).class_name('Event') }
|
||||||
|
@ -116,4 +115,16 @@ describe User do
|
||||||
user.authentication_token.should_not be_blank
|
user.authentication_token.should_not be_blank
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'projects and namespaces' do
|
||||||
|
before do
|
||||||
|
ActiveRecord::Base.observers.enable(:user_observer)
|
||||||
|
@user = create :user
|
||||||
|
@project = create :project, namespace: @user.namespace
|
||||||
|
end
|
||||||
|
|
||||||
|
it { @user.authorized_projects.should include(@project) }
|
||||||
|
it { @user.my_own_projects.should include(@project) }
|
||||||
|
it { @user.several_namespaces?.should be_false }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue