Commit b01f8b63c2c13f8d6b9111771fb4f1422214d91c

Authored by Dmitriy Zaporozhets
1 parent 44209861

added NamespacedProject role. Extended project info displayed for admin. Fixed project limit

app/controllers/groups_controller.rb
... ... @@ -49,6 +49,7 @@ class GroupsController < ApplicationController
49 49 def people
50 50 @project = group.projects.find(params[:project_id]) if params[:project_id]
51 51 @users = @project ? @project.users : group.users
  52 + @users.sort_by!(&:name)
52 53  
53 54 if @project
54 55 @team_member = @project.users_projects.new
... ...
app/controllers/snippets_controller.rb
... ... @@ -16,7 +16,7 @@ class SnippetsController < ProjectResourceController
16 16 respond_to :html
17 17  
18 18 def index
19   - @snippets = @project.snippets
  19 + @snippets = @project.snippets.fresh
20 20 end
21 21  
22 22 def new
... ... @@ -60,7 +60,7 @@ class SnippetsController < ProjectResourceController
60 60 redirect_to project_snippets_path(@project)
61 61 end
62 62  
63   - def raw
  63 + def raw
64 64 send_data(
65 65 @snippet.content,
66 66 type: "text/plain",
... ...
app/models/project.rb
... ... @@ -25,6 +25,7 @@ class Project < ActiveRecord::Base
25 25 include PushObserver
26 26 include Authority
27 27 include Team
  28 + include NamespacedProject
28 29  
29 30 class TransferError < StandardError; end
30 31  
... ... @@ -178,7 +179,7 @@ class Project &lt; ActiveRecord::Base
178 179 end
179 180  
180 181 def repo_name
181   - denied_paths = %w(gitolite-admin groups projects dashboard)
  182 + denied_paths = %w(gitolite-admin groups projects dashboard help )
182 183  
183 184 if denied_paths.include?(path)
184 185 errors.add(:path, "like #{path} is not allowed")
... ... @@ -245,57 +246,11 @@ class Project &lt; ActiveRecord::Base
245 246 gitlab_ci_service && gitlab_ci_service.active
246 247 end
247 248  
248   - def path_with_namespace
249   - if namespace
250   - namespace.path + '/' + path
251   - else
252   - path
253   - end
254   - end
255   -
256 249 # For compatibility with old code
257 250 def code
258 251 path
259 252 end
260 253  
261   - def transfer(new_namespace)
262   - Project.transaction do
263   - old_namespace = namespace
264   - self.namespace = new_namespace
265   -
266   - old_dir = old_namespace.try(:path) || ''
267   - new_dir = new_namespace.try(:path) || ''
268   -
269   - old_repo = if old_dir.present?
270   - File.join(old_dir, self.path)
271   - else
272   - self.path
273   - end
274   -
275   - if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present?
276   - raise TransferError.new("Project with same path in target namespace already exists")
277   - end
278   -
279   - Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
280   -
281   - git_host.move_repository(old_repo, self)
282   -
283   - save!
284   - end
285   - rescue Gitlab::ProjectMover::ProjectMoveError => ex
286   - raise TransferError.new(ex.message)
287   - end
288   -
289   - def name_with_namespace
290   - @name_with_namespace ||= begin
291   - if namespace
292   - namespace.human_name + " / " + name
293   - else
294   - name
295   - end
296   - end
297   - end
298   -
299 254 def items_for entity
300 255 case entity
301 256 when 'issue' then
... ... @@ -304,16 +259,4 @@ class Project &lt; ActiveRecord::Base
304 259 merge_requests
305 260 end
306 261 end
307   -
308   - def namespace_owner
309   - namespace.try(:owner)
310   - end
311   -
312   - def chief
313   - if namespace
314   - namespace_owner
315   - else
316   - owner
317   - end
318   - end
319 262 end
... ...
app/models/user.rb
... ... @@ -56,7 +56,6 @@ class User &lt; ActiveRecord::Base
56 56 has_many :issues, foreign_key: :author_id, dependent: :destroy
57 57 has_many :notes, foreign_key: :author_id, dependent: :destroy
58 58 has_many :merge_requests, foreign_key: :author_id, dependent: :destroy
59   - has_many :my_own_projects, class_name: "Project", foreign_key: :owner_id
60 59 has_many :events, class_name: "Event", foreign_key: :author_id, dependent: :destroy
61 60 has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC"
62 61 has_many :assigned_issues, class_name: "Issue", foreign_key: :assignee_id, dependent: :destroy
... ... @@ -124,16 +123,4 @@ class User &lt; ActiveRecord::Base
124 123 self.password = self.password_confirmation = Devise.friendly_token.first(8)
125 124 end
126 125 end
127   -
128   - def authorized_groups
129   - @authorized_groups ||= begin
130   - groups = Group.where(id: self.projects.pluck(:namespace_id)).all
131   - groups = groups + self.groups
132   - groups.uniq
133   - end
134   - end
135   -
136   - def authorized_projects
137   - Project.authorized_for(self)
138   - end
139 126 end
... ...
app/roles/account.rb
... ... @@ -105,4 +105,20 @@ module Account
105 105 def namespace_id
106 106 namespace.try :id
107 107 end
  108 +
  109 + def authorized_groups
  110 + @authorized_groups ||= begin
  111 + groups = Group.where(id: self.projects.pluck(:namespace_id)).all
  112 + groups = groups + self.groups
  113 + groups.uniq
  114 + end
  115 + end
  116 +
  117 + def authorized_projects
  118 + Project.authorized_for(self)
  119 + end
  120 +
  121 + def my_own_projects
  122 + Project.personal(self)
  123 + end
108 124 end
... ...
app/roles/namespaced_project.rb 0 → 100644
... ... @@ -0,0 +1,59 @@
  1 +module NamespacedProject
  2 + def transfer(new_namespace)
  3 + Project.transaction do
  4 + old_namespace = namespace
  5 + self.namespace = new_namespace
  6 +
  7 + old_dir = old_namespace.try(:path) || ''
  8 + new_dir = new_namespace.try(:path) || ''
  9 +
  10 + old_repo = if old_dir.present?
  11 + File.join(old_dir, self.path)
  12 + else
  13 + self.path
  14 + end
  15 +
  16 + if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present?
  17 + raise TransferError.new("Project with same path in target namespace already exists")
  18 + end
  19 +
  20 + Gitlab::ProjectMover.new(self, old_dir, new_dir).execute
  21 +
  22 + git_host.move_repository(old_repo, self)
  23 +
  24 + save!
  25 + end
  26 + rescue Gitlab::ProjectMover::ProjectMoveError => ex
  27 + raise TransferError.new(ex.message)
  28 + end
  29 +
  30 + def name_with_namespace
  31 + @name_with_namespace ||= begin
  32 + if namespace
  33 + namespace.human_name + " / " + name
  34 + else
  35 + name
  36 + end
  37 + end
  38 + end
  39 +
  40 + def namespace_owner
  41 + namespace.try(:owner)
  42 + end
  43 +
  44 + def chief
  45 + if namespace
  46 + namespace_owner
  47 + else
  48 + owner
  49 + end
  50 + end
  51 +
  52 + def path_with_namespace
  53 + if namespace
  54 + namespace.path + '/' + path
  55 + else
  56 + path
  57 + end
  58 + end
  59 +end
... ...
app/views/admin/projects/_form.html.haml
... ... @@ -19,43 +19,47 @@
19 19 .input
20 20 = text_field_tag :ppath, @project.path_to_repo, class: "xlarge", disabled: true
21 21  
22   - - unless project.new_record?
  22 + - if project.repo_exists?
23 23 .clearfix
24   - = f.label :namespace_id
25   - .input
26   - = f.select :namespace_id, namespaces_options(@project.namespace_id, :all), {}, {class: 'chosen'}
27   - &nbsp;
28   - %span.cred Be careful. Changing project namespace can have unintended side effects
  24 + = f.label :default_branch, "Default Branch"
  25 + .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
29 26  
30   - - if project.repo_exists?
31   - .clearfix
32   - = f.label :default_branch, "Default Branch"
33   - .input= f.select(:default_branch, project.heads.map(&:name), {}, style: "width:210px;")
  27 + %fieldset.adv_settings
  28 + %legend Features:
34 29  
35   - - unless project.new_record?
36   - %fieldset.adv_settings
37   - %legend Features:
  30 + .clearfix
  31 + = f.label :issues_enabled, "Issues"
  32 + .input= f.check_box :issues_enabled
38 33  
39   - .clearfix
40   - = f.label :issues_enabled, "Issues"
41   - .input= f.check_box :issues_enabled
  34 + .clearfix
  35 + = f.label :merge_requests_enabled, "Merge Requests"
  36 + .input= f.check_box :merge_requests_enabled
42 37  
43   - .clearfix
44   - = f.label :merge_requests_enabled, "Merge Requests"
45   - .input= f.check_box :merge_requests_enabled
  38 + .clearfix
  39 + = f.label :wall_enabled, "Wall"
  40 + .input= f.check_box :wall_enabled
46 41  
47   - .clearfix
48   - = f.label :wall_enabled, "Wall"
49   - .input= f.check_box :wall_enabled
  42 + .clearfix
  43 + = f.label :wiki_enabled, "Wiki"
  44 + .input= f.check_box :wiki_enabled
  45 +
  46 + %fieldset.features
  47 + %legend Transfer:
  48 + .control-group
  49 + = f.label :namespace_id do
  50 + %span Namespace
  51 + .controls
  52 + = f.select :namespace_id, namespaces_options(@project.namespace_id, :all), {}, {class: 'chosen'}
  53 + %br
  54 + %ul.prepend-top-10.cred
  55 + %li Be careful. Changing project namespace can have unintended side effects
  56 + %li You can transfer project only to namespaces you can manage
  57 + %li You will need to update your local repositories to point to the new location.
50 58  
51   - .clearfix
52   - = f.label :wiki_enabled, "Wiki"
53   - .input= f.check_box :wiki_enabled
54 59  
55   - - unless project.new_record?
56   - .actions
57   - = f.submit 'Save Project', class: "btn save-btn"
58   - = link_to 'Cancel', admin_projects_path, class: "btn cancel-btn"
  60 + .actions
  61 + = f.submit 'Save Project', class: "btn save-btn"
  62 + = link_to 'Cancel', admin_projects_path, class: "btn cancel-btn"
59 63  
60 64  
61 65  
... ...
app/views/admin/projects/index.html.haml
1 1 %h3.page_title
2   - Projects
  2 + Projects (#{@projects.count})
3 3 = link_to 'New Project', new_project_path, class: "btn small right"
4 4 %br
5 5 = form_tag admin_projects_path, method: :get, class: 'form-inline' do
... ...
app/views/admin/projects/show.html.haml
... ... @@ -47,9 +47,12 @@
47 47 %tr
48 48 %td
49 49 %b
50   - Path:
  50 + Owned by:
51 51 %td
52   - %code= @project.path_to_repo
  52 + - if @project.chief
  53 + = link_to @project.chief.name, admin_user_path(@project.chief)
  54 + - else
  55 + (deleted)
53 56 %tr
54 57 %td
55 58 %b
... ... @@ -59,9 +62,46 @@
59 62 %tr
60 63 %td
61 64 %b
  65 + Created at:
  66 + %td
  67 + = @project.created_at.stamp("March 1, 1999")
  68 +
  69 +%table.zebra-striped
  70 + %thead
  71 + %tr
  72 + %th Repository
  73 + %th
  74 + %tr
  75 + %td
  76 + %b
  77 + FS Path:
  78 + %td
  79 + %code= @project.path_to_repo
  80 + %tr
  81 + %td
  82 + %b
  83 + Smart HTTP:
  84 + %td
  85 + = link_to @project.http_url_to_repo
  86 + %tr
  87 + %td
  88 + %b
  89 + SSH:
  90 + %td
  91 + = link_to @project.ssh_url_to_repo
  92 + %tr
  93 + %td
  94 + %b
  95 + Last commit at:
  96 + %td
  97 + = last_commit(@project)
  98 + %tr
  99 + %td
  100 + %b
62 101 Post Receive File:
63 102 %td
64 103 = check_box_tag :post_receive_file, 1, @project.has_post_receive_file?, disabled: true
  104 +
65 105 %br
66 106 %h5
67 107 Team
... ...
app/views/admin/users/index.html.haml
1 1 %h3.page_title
2   - Users
  2 + Users (#{@admin_users.count})
3 3 = link_to 'New User', new_admin_user_path, class: "btn small right"
4 4 %br
5 5  
... ... @@ -40,10 +40,13 @@
40 40 %td= user.users_projects.count
41 41 %td= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn small"
42 42 %td.bgred
43   - - if user.blocked
44   - = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success"
  43 + - if user == current_user
  44 + %span.cred It's you!
45 45 - else
46   - = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger"
47   - = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger"
  46 + - if user.blocked
  47 + = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn small success"
  48 + - else
  49 + = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn small danger"
  50 + = link_to 'Destroy', [:admin, user], confirm: "USER #{user.name} WILL BE REMOVED! Are you sure?", method: :delete, class: "btn small danger"
48 51  
49 52 = paginate @admin_users, theme: "admin"
... ...
app/views/admin/users/show.html.haml
... ... @@ -40,6 +40,12 @@
40 40 %tr
41 41 %td
42 42 %b
  43 + Created at:
  44 + %td
  45 + = @admin_user.created_at.stamp("March 1, 1999")
  46 + %tr
  47 + %td
  48 + %b
43 49 Projects limit:
44 50 %td
45 51 = @admin_user.projects_limit
... ...
app/views/hooks/index.html.haml
... ... @@ -22,22 +22,21 @@
22 22 %hr
23 23  
24 24 -if @hooks.any?
25   - %h3
26   - Hooks
27   - %small (#{@hooks.count})
  25 + %h3.page_title
  26 + Hooks (#{@hooks.count})
28 27 %br
29 28 %table
30 29 %thead
31 30 %tr
32 31 %th URL
33   - %th Method
34 32 %th
35 33 - @hooks.each do |hook|
36 34 %tr
37 35 %td
  36 + %span.badge.badge-info POST
38 37 = link_to project_hook_path(@project, hook) do
39 38 %strong= hook.url
40   - = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn small right"
41   - %td POST
42 39 %td
43   - = link_to 'Remove', project_hook_path(@project, hook), confirm: 'Are you sure?', method: :delete, class: "danger btn small right"
  40 + .right
  41 + = link_to 'Test Hook', test_project_hook_path(@project, hook), class: "btn small grouped"
  42 + = link_to 'Remove', project_hook_path(@project, hook), confirm: 'Are you sure?', method: :delete, class: "danger btn small grouped"
... ...
app/views/projects/create.js.haml
... ... @@ -9,3 +9,4 @@
9 9 $('.project_new_holder').show();
10 10 $("#new_project").replaceWith("#{escape_javascript(render('new_form'))}");
11 11 $('.save-project-loader').hide();
  12 + new Projects();
... ...
app/views/projects/files.html.haml
... ... @@ -17,7 +17,6 @@
17 17 = time_ago_in_words(note.created_at)
18 18 ago
19 19 - else
20   - .alert-message.block-message
21   - %span All files attached to project wall, issues etc will be displayed here
  20 + %p.slead All files attached to project wall, issues etc will be displayed here
22 21  
23 22  
... ...
app/views/snippets/_snippet.html.haml
1 1 %tr
2 2 %td
  3 + = image_tag gravatar_icon(snippet.author_email), class: "avatar s24"
3 4 %a{href: project_snippet_path(snippet.project, snippet)}
4 5 %strong= truncate(snippet.title, length: 60)
5 6 %td
6 7 = snippet.file_name
7 8 %td
8 9 %span.cgray
9   - - if snippet.expires_at
  10 + - if snippet.expires_at
10 11 = snippet.expires_at.to_date.to_s(:short)
11 12 - else
12 13 Never
... ...
app/views/snippets/index.html.haml
1 1 = render "projects/project_head"
2 2  
3   -- if can? current_user, :write_snippet, @project
4   - .alert-message.block-message
  3 +%h3.page_title
  4 + Snippets
  5 + %small share code pastes with others out of git repository
  6 +
  7 + - if can? current_user, :write_snippet, @project
5 8 = link_to new_project_snippet_path(@project), class: "btn small add_new right", title: "New Snippet" do
6 9 Add new snippet
7   - Share code pastes with others if it can't be in a git repository
8   - %br
9   - To add new snippet - click on button.
10   -
  10 +%br
11 11 %table
12 12 %thead
13 13 %tr
14 14 %th Title
15 15 %th File Name
16 16 %th Expires At
17   - = render @snippets.fresh
18   - - if @snippets.fresh.empty?
  17 + = render @snippets
  18 + - if @snippets.empty?
19 19 %tr
20 20 %td{colspan: 3}
21 21 %h3.nothing_here_message Nothing here.
... ...
app/views/team_members/_team.html.haml
... ... @@ -4,7 +4,7 @@
4 4 = Project.access_options.key(access).pluralize
5 5 %small= members.size
6 6 %ul.unstyled
7   - - members.each do |up|
  7 + - members.sort_by(&:user_name).each do |up|
8 8 = render(partial: 'team_members/show', locals: {member: up})
9 9  
10 10  
... ...
spec/models/user_spec.rb
... ... @@ -41,7 +41,6 @@ describe User do
41 41 it { should have_many(:users_projects).dependent(:destroy) }
42 42 it { should have_many(:projects) }
43 43 it { should have_many(:groups) }
44   - it { should have_many(:my_own_projects).class_name('Project') }
45 44 it { should have_many(:keys).dependent(:destroy) }
46 45 it { should have_many(:events).class_name('Event').dependent(:destroy) }
47 46 it { should have_many(:recent_events).class_name('Event') }
... ... @@ -116,4 +115,16 @@ describe User do
116 115 user.authentication_token.should_not be_blank
117 116 end
118 117 end
  118 +
  119 + describe 'projects and namespaces' do
  120 + before do
  121 + ActiveRecord::Base.observers.enable(:user_observer)
  122 + @user = create :user
  123 + @project = create :project, namespace: @user.namespace
  124 + end
  125 +
  126 + it { @user.authorized_projects.should include(@project) }
  127 + it { @user.my_own_projects.should include(@project) }
  128 + it { @user.several_namespaces?.should be_false }
  129 + end
119 130 end
... ...