From 2b683b0d0bf90c84b33ec4ed5c70e3bc787094e2 Mon Sep 17 00:00:00 2001
From: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Date: Fri, 23 Nov 2012 07:11:09 +0300
Subject: [PATCH] Ability to create project with namespace

---
 app/helpers/application_helper.rb      | 12 ++++++++++++
 app/models/group.rb                    |  4 ++++
 app/models/namespace.rb                |  4 ++++
 app/models/project.rb                  |  3 +++
 app/models/user.rb                     | 12 +++++++++++-
 app/views/profile/account.html.haml    | 21 ++++++++++++++++++---
 app/views/projects/_new_form.html.haml |  6 ++++++
 config/routes.rb                       |  2 +-
 db/schema.rb                           |  3 ++-
 spec/models/user_spec.rb               |  1 +
 10 files changed, 62 insertions(+), 6 deletions(-)

diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index cba34c963a0..8f206609a2f 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -74,6 +74,18 @@ module ApplicationHelper
     grouped_options_for_select(options, @ref || @project.default_branch)
   end
 
+  def namespaces_options
+    groups = current_user.namespaces.select {|n| n.type == 'Group'}
+    users = current_user.namespaces.reject {|n| n.type == 'Group'}
+
+    options = [
+      ["Groups", groups.map {|g| [g.human_name, g.id]} ],
+      [ "Users", users.map {|u| [u.human_name, u.id]} ]
+    ]
+
+    grouped_options_for_select(options, current_user.namespace.id)
+  end
+
   def search_autocomplete_source
     projects = current_user.projects.map{ |p| { label: p.name, url: project_path(p) } }
 
diff --git a/app/models/group.rb b/app/models/group.rb
index 683606fa706..ab7b1b8983f 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -14,4 +14,8 @@ class Group < Namespace
   def users
     User.joins(:users_projects).where(users_projects: {project_id: project_ids}).uniq
   end
+
+  def human_name
+    name
+  end
 end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index bdf624efffc..2fa8b06d924 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -17,4 +17,8 @@ class Namespace < ActiveRecord::Base
   def to_param
     code
   end
+
+  def human_name
+    owner_name
+  end
 end
diff --git a/app/models/project.rb b/app/models/project.rb
index 479a2ac863a..eb3b1b3d113 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -81,10 +81,13 @@ class Project < ActiveRecord::Base
     end
 
     def create_by_user(params, user)
+      namespace_id = params.delete(:namespace_id) || namespace.try(:id)
+
       project = Project.new params
 
       Project.transaction do
         project.owner = user
+        project.namespace_id = namespace_id
         project.save!
 
         # Add user as project master
diff --git a/app/models/user.rb b/app/models/user.rb
index 6d539c1f498..cd1dd205569 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -38,13 +38,16 @@ class User < ActiveRecord::Base
   devise :database_authenticatable, :token_authenticatable, :lockable,
          :recoverable, :rememberable, :trackable, :validatable, :omniauthable
 
-  attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name,
+  attr_accessible :email, :password, :password_confirmation, :remember_me, :bio, :name, :username,
                   :skype, :linkedin, :twitter, :dark_scheme, :theme_id, :force_random_password,
                   :extern_uid, :provider, :as => [:default, :admin]
   attr_accessible :projects_limit, :as => :admin
 
   attr_accessor :force_random_password
 
+  # Namespace for personal projects
+  has_one :namespace, class_name: "Namespace", foreign_key: :owner_id, conditions: 'type IS NULL', dependent: :destroy
+
   has_many :keys, dependent: :destroy
   has_many :projects, through: :users_projects
   has_many :users_projects, dependent: :destroy
@@ -112,4 +115,11 @@ class User < ActiveRecord::Base
       self.password = self.password_confirmation = Devise.friendly_token.first(8)
     end
   end
+
+  def namespaces
+    namespaces = []
+    namespaces << self.namespace
+    namespaces = namespaces + Group.all if admin
+    namespaces
+  end
 end
diff --git a/app/views/profile/account.html.haml b/app/views/profile/account.html.haml
index 1e3a8b1a0d4..21a5f5a24be 100644
--- a/app/views/profile/account.html.haml
+++ b/app/views/profile/account.html.haml
@@ -8,6 +8,7 @@
           = link_to authbutton(provider, 32), omniauth_authorize_path(User, provider)
 
 
+
 %fieldset
   %legend
     Private token
@@ -44,11 +45,25 @@
         .input= f.password_field :password
       .clearfix
         = f.label :password_confirmation
-        .input= f.password_field :password_confirmation
-    .actions
-      = f.submit 'Save', class: "btn save-btn"
+        .input
+          = f.password_field :password_confirmation
+      .clearfix
+        .input
+          = f.submit 'Save password', class: "btn save-btn"
 
 
 
+%fieldset
+  %legend
+    Username
+    %small.right
+      Changing your username can have unintended side effects!
+  = form_for @user, url: profile_update_path,  method: :put do |f|
+    .padded
+      = f.label :username
+      .input
+        = f.text_field :username
+      .input
+        = f.submit 'Save username', class: "btn save-btn"
 
 
diff --git a/app/views/projects/_new_form.html.haml b/app/views/projects/_new_form.html.haml
index e6d5e93fca7..978352e7da2 100644
--- a/app/views/projects/_new_form.html.haml
+++ b/app/views/projects/_new_form.html.haml
@@ -12,6 +12,12 @@
   %hr
   %div.adv_settings
     %h6 Advanced settings:
+    - if current_user.namespaces.size > 1
+      .clearfix
+        = f.label :namespace_id do
+          Namespace
+        .input
+          = f.select :namespace_id, namespaces_options, {}, {class: 'chosen'}
     .clearfix
       = f.label :path do
         Git Clone
diff --git a/config/routes.rb b/config/routes.rb
index 42de89dd1df..192f48828b2 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -49,7 +49,7 @@ Gitlab::Application.routes.draw do
         delete :remove_project
       end
     end
-    resources :projects, constraints: { id: /[^\/]+/ } do
+    resources :projects, constraints: { id: /[a-zA-Z.\/0-9_\-]+/ } do
       member do
         get :team
         put :team_update
diff --git a/db/schema.rb b/db/schema.rb
index 90b027d412b..8ce3df0d65a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
 #
 # It's strongly recommended to check this file into your version control system.
 
-ActiveRecord::Schema.define(:version => 20121122150932) do
+ActiveRecord::Schema.define(:version => 20121123104937) do
 
   create_table "events", :force => true do |t|
     t.string   "target_type"
@@ -195,6 +195,7 @@ ActiveRecord::Schema.define(:version => 20121122150932) do
     t.datetime "locked_at"
     t.string   "extern_uid"
     t.string   "provider"
+    t.string   "username"
   end
 
   add_index "users", ["email"], :name => "index_users_on_email", :unique => true
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 4ac699b1c45..3a87499ba22 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -36,6 +36,7 @@ require 'spec_helper'
 
 describe User do
   describe "Associations" do
+    it { should have_one(:namespace) }
     it { should have_many(:users_projects).dependent(:destroy) }
     it { should have_many(:projects) }
     it { should have_many(:my_own_projects).class_name('Project') }
-- 
GitLab