From 7023dda7e04380f0249b0569a2f73731d8707eef Mon Sep 17 00:00:00 2001 From: George Vinogradov Date: Wed, 30 Nov 2011 16:58:14 +0400 Subject: [PATCH 01/12] First iteration of groups refactoring. --- app/controllers/application_controller.rb | 9 ++- app/controllers/projects_controller.rb | 29 +++++-- config/routes.rb | 2 +- db/schema.rb | 7 +- vendor/plugins/related_models/MIT-LICENSE | 20 +++++ vendor/plugins/related_models/README | 13 +++ vendor/plugins/related_models/Rakefile | 23 ++++++ .../app/controllers/related_models/base.rb | 23 ++++++ vendor/plugins/related_models/init.rb | 2 + vendor/plugins/related_models/install.rb | 1 + .../related_models/lib/related_models.rb | 14 ++++ .../lib/related_models/belongs_to_helpers.rb | 39 +++++++++ .../lib/related_models/class_methods.rb | 68 ++++++++++++++++ .../lib/related_models/polymorphic_helpers.rb | 80 +++++++++++++++++++ .../lib/related_models/url_helpers.rb | 28 +++++++ .../test/related_models_test.rb | 8 ++ .../related_models/test/test_helper.rb | 3 + vendor/plugins/related_models/uninstall.rb | 1 + 18 files changed, 356 insertions(+), 14 deletions(-) create mode 100644 vendor/plugins/related_models/MIT-LICENSE create mode 100644 vendor/plugins/related_models/README create mode 100644 vendor/plugins/related_models/Rakefile create mode 100644 vendor/plugins/related_models/app/controllers/related_models/base.rb create mode 100644 vendor/plugins/related_models/init.rb create mode 100644 vendor/plugins/related_models/install.rb create mode 100644 vendor/plugins/related_models/lib/related_models.rb create mode 100644 vendor/plugins/related_models/lib/related_models/belongs_to_helpers.rb create mode 100644 vendor/plugins/related_models/lib/related_models/class_methods.rb create mode 100644 vendor/plugins/related_models/lib/related_models/polymorphic_helpers.rb create mode 100644 vendor/plugins/related_models/lib/related_models/url_helpers.rb create mode 100644 vendor/plugins/related_models/test/related_models_test.rb create mode 100644 vendor/plugins/related_models/test/test_helper.rb create mode 100644 vendor/plugins/related_models/uninstall.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1bca7a425..9f81d8af6 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -15,8 +15,13 @@ class ApplicationController < ActionController::Base protected def get_owner - params['user_id'] && User.find_by_id(params['user_id']) || - params['group_id'] && Group.find_by_id(params['group_id']) || current_user +# params['user_id'] && User.find_by_id(params['user_id']) || +# params['group_id'] && Group.find_by_id(params['group_id']) || current_user + if parent and (parent.is_a? User or parent.is_a? Group) + parent + else + current_user + end end def layout_by_resource diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 95495c37e..4c3f044a6 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,4 +1,8 @@ class ProjectsController < ApplicationController + is_related_controller! + + belongs_to :user, :group, :polymorphic => true, :optional => true + before_filter :authenticate_user!, :except => :auto_build before_filter :find_project, :only => [:show, :edit, :update, :destroy, :fork, :build, :process_build] before_filter :get_paths, :only => [:new, :create, :edit, :update] @@ -6,12 +10,20 @@ class ProjectsController < ApplicationController load_and_authorize_resource def index - if params[:query] - @projects = Project.accessible_by(current_ability).where(:name => params[:query]).paginate(:page => params[:project_page]) - else - @projects = Project.accessible_by(current_ability).paginate(:page => params[:project_page]) - end - +# puts parent.inspect +# puts parent.is_a? User + @projects = if parent? and !parent.nil? + parent.projects + else + Project + end.accessible_by(current_ability) + + @projects = if params[:query] + @projects.where(["name LIKE ?", "%#{params[:query]}%"]) + else + @projects + end.paginate(:page => params[:project_page]) + @own_projects = current_user.own_projects @part_projects = current_user.projects - @own_projects end @@ -30,8 +42,9 @@ class ProjectsController < ApplicationController def create @project = Project.new params[:project] @project.owner = get_owner +# puts @project.owner.inspect - if @project.save! + if @project.save flash[:notice] = t('flash.project.saved') redirect_to @project else @@ -46,7 +59,7 @@ class ProjectsController < ApplicationController flash[:notice] = t('flash.project.saved') redirect_to @project else - @project.save! + @project.save flash[:error] = t('flash.project.save_error') render :action => :edit end diff --git a/config/routes.rb b/config/routes.rb index 959f53c70..104464420 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -106,7 +106,7 @@ Rosa::Application.routes.draw do resources :users, :groups do resources :platforms, :only => [:new, :create] - resources :projects, :only => [:new, :create] + resources :projects, :only => [:new, :create, :index] resources :repositories, :only => [:new, :create] end diff --git a/db/schema.rb b/db/schema.rb index 1e6684487..33ea2eeda 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -249,10 +249,11 @@ ActiveRecord::Schema.define(:version => 20111128140341) do create_table "users", :force => true do |t| t.string "name" - t.string "email", :default => "", :null => false - t.string "encrypted_password", :limit => 128, :default => "", :null => false + t.string "email", :default => "", :null => false + t.string "encrypted_password", :limit => 128, :default => "", :null => false + t.string "password_salt", :default => "", :null => false t.string "reset_password_token" - t.datetime "reset_password_sent_at" + t.string "remember_token" t.datetime "remember_created_at" t.datetime "created_at" t.datetime "updated_at" diff --git a/vendor/plugins/related_models/MIT-LICENSE b/vendor/plugins/related_models/MIT-LICENSE new file mode 100644 index 000000000..bfe93818e --- /dev/null +++ b/vendor/plugins/related_models/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2011 [name of plugin creator] + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/plugins/related_models/README b/vendor/plugins/related_models/README new file mode 100644 index 000000000..66273bc62 --- /dev/null +++ b/vendor/plugins/related_models/README @@ -0,0 +1,13 @@ +RelatedModels +============= + +Introduction goes here. + + +Example +======= + +Example goes here. + + +Copyright (c) 2011 [name of plugin creator], released under the MIT license diff --git a/vendor/plugins/related_models/Rakefile b/vendor/plugins/related_models/Rakefile new file mode 100644 index 000000000..7e2cd366e --- /dev/null +++ b/vendor/plugins/related_models/Rakefile @@ -0,0 +1,23 @@ +require 'rake' +require 'rake/testtask' +require 'rdoc/task' + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the related_models plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.libs << 'test' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the related_models plugin.' +RDoc::Task.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'RelatedModels' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('lib/**/*.rb') +end diff --git a/vendor/plugins/related_models/app/controllers/related_models/base.rb b/vendor/plugins/related_models/app/controllers/related_models/base.rb new file mode 100644 index 000000000..b8a2d83b3 --- /dev/null +++ b/vendor/plugins/related_models/app/controllers/related_models/base.rb @@ -0,0 +1,23 @@ +module RelatedModels + class Base < ::ApplicationController + def self.is_child!(base) + base.class_eval do +# include InheritedResources::Actions +# include InheritedResources::BaseHelpers + extend RelatedModels::ClassMethods + extend RelatedModels::UrlHelpers + + helper_method :parent_url, :parent_path + + self.class_attribute :parents_symbols, :resources_configuration, :instance_writer => false + + self.parents_symbols ||= [] + self.resources_configuration ||= {} + + protected :parents_symbols, :resources_configuration, :parents_symbols?, :resources_configuration? + end + end + + is_child!(self) + end +end diff --git a/vendor/plugins/related_models/init.rb b/vendor/plugins/related_models/init.rb new file mode 100644 index 000000000..28b3e9d14 --- /dev/null +++ b/vendor/plugins/related_models/init.rb @@ -0,0 +1,2 @@ +# Include hook code here +require 'related_models' diff --git a/vendor/plugins/related_models/install.rb b/vendor/plugins/related_models/install.rb new file mode 100644 index 000000000..f7732d379 --- /dev/null +++ b/vendor/plugins/related_models/install.rb @@ -0,0 +1 @@ +# Install hook code here diff --git a/vendor/plugins/related_models/lib/related_models.rb b/vendor/plugins/related_models/lib/related_models.rb new file mode 100644 index 000000000..2a5323623 --- /dev/null +++ b/vendor/plugins/related_models/lib/related_models.rb @@ -0,0 +1,14 @@ +# RelatedModels +module RelatedModels + autoload :ClassMethods, 'related_models/class_methods' + autoload :BelongsToHelpers, 'related_models/belongs_to_helpers' + autoload :PolymorphicHelpers, 'related_models/polymorphic_helpers' + autoload :UrlHelpers, 'related_models/url_helpers' +end + +class ActionController::Base + #include ClassMethods + def self.is_related_controller! + RelatedModels::Base.is_child!(self) + end +end diff --git a/vendor/plugins/related_models/lib/related_models/belongs_to_helpers.rb b/vendor/plugins/related_models/lib/related_models/belongs_to_helpers.rb new file mode 100644 index 000000000..713306353 --- /dev/null +++ b/vendor/plugins/related_models/lib/related_models/belongs_to_helpers.rb @@ -0,0 +1,39 @@ +module RelatedModels + module BelongsToHelpers + protected + def parent? + true + end + + def parent + @parent ||= find_parent + end + + def parent_type + parent.class.name.underscore.to_sym + end + + private + + def symbols_for_association_chain + parents_symbols.compact + end + + def find_parent + k = params.symbolize_keys.keys + res = nil + + symbols_for_association_chain.reverse.each do |sym| + if k.include? resources_configuration[sym][:param] + parent_config = resources_configuration[sym] + res = parent_config[:parent_class].send(parent_config[:finder], params[parent_config[:param]]) + break + end + end + unless res + raise "Couldn't find parent" + end + return res + end + end +end diff --git a/vendor/plugins/related_models/lib/related_models/class_methods.rb b/vendor/plugins/related_models/lib/related_models/class_methods.rb new file mode 100644 index 000000000..0a912a597 --- /dev/null +++ b/vendor/plugins/related_models/lib/related_models/class_methods.rb @@ -0,0 +1,68 @@ +module RelatedModels + module ClassMethods + protected + def belongs_to(*symbols) + options = symbols.extract_options! + + options.symbolize_keys! + options.assert_valid_keys(:polymorphic, :optional, :finder) + + optional = options.delete(:optional) + polymorphic = options.delete(:polymorphic) + finder = options.delete(:finder) + + include BelongsToHelpers if self.parents_symbols.empty? + + acts_as_polymorphic! if polymorphic || optional + + raise ArgumentError, 'You have to give me at least one association name.' if symbols.empty? + raise ArgumentError, 'You cannot define multiple associations with options: #{options.keys.inspect} to belongs to.' unless symbols.size == 1 || options.empty? + + symbols.each do |symbol| + symbol = symbol.to_sym + + if polymorphic || optional + self.parents_symbols << :polymorphic unless self.parents_symbols.include?(:polymorphic) + self.resources_configuration[:polymorphic] ||= {} + self.resources_configuration[:polymorphic][:symbols] ||= [] + + self.resources_configuration[:polymorphic][:symbols] << symbol + self.resources_configuration[:polymorphic][:optional] ||= optional + else + self.parents_symbols << symbol + end + + config = self.resources_configuration[symbol] = {} + + config[:parent_class] = begin + class_name = symbol.to_s.pluralize.classify + class_name.constantize + rescue NameError => e + raise unless e.message.include?(class_name) + nil + end + + config[:collection_name] = symbol.to_s.pluralize.to_sym + config[:instance_name] = symbol + config[:param] = :"#{symbol}_id" + config[:route_name] = symbol + config[:finder] = finder || :find + end + + create_resources_url_helpers! + helper_method :parent, :parent? + end + + private + def acts_as_polymorphic! #:nodoc: + unless self.parents_symbols.include?(:polymorphic) + include PolymorphicHelpers + helper_method :parent_type, :parent_class + end + end + + def inherited(base) + super(base) + end + end +end diff --git a/vendor/plugins/related_models/lib/related_models/polymorphic_helpers.rb b/vendor/plugins/related_models/lib/related_models/polymorphic_helpers.rb new file mode 100644 index 000000000..dd604b6c4 --- /dev/null +++ b/vendor/plugins/related_models/lib/related_models/polymorphic_helpers.rb @@ -0,0 +1,80 @@ +module RelatedModels + module PolymorphicHelpers + + protected + + # Returns the parent type. A Comments class can have :task, :file, :note + # as parent types. + # + def parent_type + @parent_type + end + + def parent_class + parent.class if @parent_type + end + + # Returns the parent object. They are also available with the instance + # variable name: @task, @file, @note... + # + def parent + k = params.symbolize_keys.keys + res = nil + + symbols_for_association_chain.reverse.each do |sym| + if k.include? resources_configuration[sym][:param] + parent_config = resources_configuration[sym] + res = parent_config[:parent_class].send(parent_config[:finder], params[parent_config[:param]]) + break + end + end + return res + end + + # If the polymorphic association is optional, we might not have a parent. + # + def parent? + if resources_configuration[:polymorphic][:optional] + parents_symbols.size > 1 || !@parent_type.nil? + else + true + end + end + + private + + # Maps parents_symbols to build association chain. + # + # If the parents_symbols find :polymorphic, it goes through the + # params keys to see which polymorphic parent matches the given params. + # + # When optional is given, it does not raise errors if the polymorphic + # params are missing. + # + def symbols_for_association_chain #:nodoc: + polymorphic_config = resources_configuration[:polymorphic] + parents_symbols.map do |symbol| + if symbol == :polymorphic + params_keys = params.keys + + keys = polymorphic_config[:symbols].map do |poly| + params_keys.include?(resources_configuration[poly][:param].to_s) ? poly : nil + end.compact + + if keys.empty? + raise ScriptError, "Could not find param for polymorphic association. The request" << + "parameters are #{params.keys.inspect} and the polymorphic " << + "associations are #{polymorphic_config[:symbols].inspect}." unless polymorphic_config[:optional] + + nil + else + @parent_type = keys[-1].to_sym + @parent_types = keys.map(&:to_sym) + end + else + symbol + end + end.flatten.compact + end + end +end diff --git a/vendor/plugins/related_models/lib/related_models/url_helpers.rb b/vendor/plugins/related_models/lib/related_models/url_helpers.rb new file mode 100644 index 000000000..031e2068e --- /dev/null +++ b/vendor/plugins/related_models/lib/related_models/url_helpers.rb @@ -0,0 +1,28 @@ +module RelatedModels + module UrlHelpers + protected + + def create_resources_url_helpers! + segment = if parents_symbols.include? :polymorphic + :polymorphic + else + resources_configuration[symbols_for_association_chain.first][:route_name] + end + + unless parent.nil? + class_eval <<-URL_HELPERS, __FILE__, __LINE__ + protected + def parent_path(*given_args) + given_options = given_args.extract_options! + #{segment}_path(parent, given_options) + end + + def parent_url(*given_args) + given_options = given_args.extract_options! + #{segment}_url(parent, given_options) + end + URL_HELPERS + end + end + end +end diff --git a/vendor/plugins/related_models/test/related_models_test.rb b/vendor/plugins/related_models/test/related_models_test.rb new file mode 100644 index 000000000..f0a232310 --- /dev/null +++ b/vendor/plugins/related_models/test/related_models_test.rb @@ -0,0 +1,8 @@ +require 'test_helper' + +class RelatedModelsTest < ActiveSupport::TestCase + # Replace this with your real tests. + test "the truth" do + assert true + end +end diff --git a/vendor/plugins/related_models/test/test_helper.rb b/vendor/plugins/related_models/test/test_helper.rb new file mode 100644 index 000000000..2ca36a1e4 --- /dev/null +++ b/vendor/plugins/related_models/test/test_helper.rb @@ -0,0 +1,3 @@ +require 'rubygems' +require 'test/unit' +require 'active_support' diff --git a/vendor/plugins/related_models/uninstall.rb b/vendor/plugins/related_models/uninstall.rb new file mode 100644 index 000000000..973833346 --- /dev/null +++ b/vendor/plugins/related_models/uninstall.rb @@ -0,0 +1 @@ +# Uninstall hook code here From 7f8091e83e420996ddfedbe6618e867e515fded1 Mon Sep 17 00:00:00 2001 From: "konstantin.grabar" Date: Tue, 29 Nov 2011 21:45:03 +0400 Subject: [PATCH 02/12] [refs #2249] Add repositories specs. Fixes perosonal repo factory --- .../repositories_controller_spec.rb | 133 ++++++++++++++++++ spec/factories/repository_factory.rb | 1 + .../repositories_controller.rb | 68 +++++++++ 3 files changed, 202 insertions(+) create mode 100644 spec/controllers/repositories_controller_spec.rb create mode 100644 spec/shared_examples/repositories_controller.rb diff --git a/spec/controllers/repositories_controller_spec.rb b/spec/controllers/repositories_controller_spec.rb new file mode 100644 index 000000000..4c526adfc --- /dev/null +++ b/spec/controllers/repositories_controller_spec.rb @@ -0,0 +1,133 @@ +require 'spec_helper' +require 'shared_examples/repositories_controller' + +describe RepositoriesController do + before(:each) do + @repository = Factory(:repository) + @personal_repository = Factory(:personal_repository) + @platform = Factory(:platform) + @project = Factory(:project) + @another_user = Factory(:user) + @create_params = {:repository => {:name => 'pro', :description => 'pro2'}, :platform_id => @platform.id} + end + + context 'for guest' do + [:index, :create].each do |action| + it "should not be able to perform #{ action } action" do + get action + response.should redirect_to(new_user_session_path) + end + end + + [:show, :new, :add_project, :remove_project, :destroy].each do |action| + it "should not be able to perform #{ action } action" do + get action, :id => @repository.id + response.should redirect_to(new_user_session_path) + end + end + end + + context 'for admin' do + before(:each) do + @admin = Factory(:admin) + set_session_for(@admin) + end + + it_should_behave_like 'be_able_to_perform_index_action' + it_should_behave_like 'be_able_to_perform_show_action' + + it 'should be able to perform new action' do + get :new + response.should render_template(:new) + end + + it 'should be able to perform create action' do + post :create, @create_params + response.should redirect_to(platform_repositories_path(@platform.id)) + end + + it 'should change objects count after create action' do + lambda { post :create, @create_params }.should change{ Repository.count }.by(1) + end + + it_should_behave_like 'be_able_to_perform_destroy_action' + it_should_behave_like 'change_repositories_count_after_destroy' + it_should_behave_like 'be_able_to_perform_add_project_action' + it_should_behave_like 'be_able_to_perform_add_project_action_with_project_id_param' + it_should_behave_like 'add_project_to_repository' + it_should_behave_like 'be_able_to_perform_remove_project' + it_should_behave_like 'remove_project_from_repository' + it_should_behave_like 'not_be_able_to_destroy_personal_repository' + end + + context 'for anyone except admin' do + before(:each) do + @user = Factory(:user) + set_session_for(@user) + end + + it 'should not be able to perform new action' do + get :new + response.should redirect_to(forbidden_path) + end + + it 'should not be able to perform create action' do + post :create, @create_params + response.should redirect_to(forbidden_path) + end + + it 'should not change objects count after create action' do + lambda { post :create, @create_params }.should change{ Repository.count }.by(0) + end + + it_should_behave_like 'not_be_able_to_destroy_personal_repository' + end + + context 'for owner user' do + before(:each) do + @user = Factory(:user) + set_session_for(@user) + @repository.update_attribute(:owner, @user) + r = @repository.relations.build(:object_type => 'User', :object_id => @user.id, :role => 'admin') + r.save! + end + + it_should_behave_like 'be_able_to_perform_index_action' + it_should_behave_like 'be_able_to_perform_show_action' + it_should_behave_like 'be_able_to_perform_add_project_action' + it_should_behave_like 'be_able_to_perform_add_project_action_with_project_id_param' + it_should_behave_like 'add_project_to_repository' + it_should_behave_like 'be_able_to_perform_remove_project' + it_should_behave_like 'remove_project_from_repository' + it_should_behave_like 'be_able_to_perform_destroy_action' + it_should_behave_like 'change_repositories_count_after_destroy' + end + + context 'for reader user' do + before(:each) do + @user = Factory(:user) + set_session_for(@user) + r = @repository.relations.build(:object_type => 'User', :object_id => @user.id, :role => 'reader') + r.save! + end + + it_should_behave_like 'be_able_to_perform_index_action' + it_should_behave_like 'be_able_to_perform_show_action' + + it 'should not be able to perform add_project action' do + get :add_project, :id => @repository.id + response.should redirect_to(forbidden_path) + end + + it 'should not be able to perform add_project action with project_id param' do + get :add_project, :id => @repository.id, :project_id => @project.id + response.should redirect_to(forbidden_path) + end + + it 'should not be able to perform destroy action' do + delete :destroy, :id => @repository.id + response.should redirect_to(forbidden_path) + end + end +end + diff --git a/spec/factories/repository_factory.rb b/spec/factories/repository_factory.rb index a730f7f4b..4590b321b 100644 --- a/spec/factories/repository_factory.rb +++ b/spec/factories/repository_factory.rb @@ -13,5 +13,6 @@ Factory.define(:personal_repository, :class => Repository) do |p| p.after_create { |rep| rep.platform.platform_type = 'personal' + rep.platform.save! } end diff --git a/spec/shared_examples/repositories_controller.rb b/spec/shared_examples/repositories_controller.rb new file mode 100644 index 000000000..78d6cf3fa --- /dev/null +++ b/spec/shared_examples/repositories_controller.rb @@ -0,0 +1,68 @@ +shared_examples_for 'be_able_to_perform_index_action' do + it 'should be able to perform index action' do + get :index + response.should render_template(:index) + end +end + +shared_examples_for 'be_able_to_perform_show_action' do + it 'should be able to perform show action' do + get :show, :id => @repository.id + response.should render_template(:show) + end +end + +shared_examples_for 'be_able_to_perform_add_project_action' do + it 'should be able to perform add_project action' do + get :add_project, :id => @repository.id + response.should render_template(:projects_list) + end +end + +shared_examples_for 'be_able_to_perform_add_project_action_with_project_id_param' do + it 'should be able to perform add_project action with project_id param' do + get :add_project, :id => @repository.id, :project_id => @project.id + response.should redirect_to(repository_path(@repository)) + end +end + +shared_examples_for 'add_project_to_repository' do + it 'should be able to add project to repository' do + get :add_project, :id => @repository.id, :project_id => @project.id + @repository.projects.exists? :id => @project.id + end +end + +shared_examples_for 'be_able_to_perform_remove_project' do + it 'should be able to perform remove_project action' do + get :remove_project, :id => @repository.id, :project_id => @project.id + response.should redirect_to(repository_path(@repository)) + end +end + +shared_examples_for 'remove_project_from_repository' do + it 'should be able to remove project from repository' do + get :remove_project, :id => @repository.id, :project_id => @project.id + !@repository.projects.exists? :id => @project.id + end +end + +shared_examples_for 'be_able_to_perform_destroy_action' do + it 'should be able to perform destroy action' do + delete :destroy, :id => @repository.id + response.should redirect_to(platform_path(@repository.platform.id)) + end +end + +shared_examples_for 'change_repositories_count_after_destroy' do + it 'should change objects count after destroy action' do + lambda { delete :destroy, :id => @repository.id }.should change{ Repository.count }.by(-1) + end +end + +shared_examples_for 'not_be_able_to_destroy_personal_repository' do + it 'should not be able to destroy personal repository' do + delete :destroy, :id => @personal_repository.id + response.should redirect_to(forbidden_path) + end +end From 3bc2ff894c21b686f1ffcbff525be803017a91b6 Mon Sep 17 00:00:00 2001 From: Pavel Chipiga Date: Tue, 29 Nov 2011 23:42:58 +0200 Subject: [PATCH 03/12] Improve and fix project fork functionality. Fix project create and validation. Add user role display. Add user role at user edit form. Refs #2261 --- app/controllers/projects_controller.rb | 8 +++++++- app/models/project.rb | 1 - app/views/users/_form.html.haml | 2 +- app/views/users/index.html.haml | 11 +++++------ config/environments/production.rb | 15 +++++++++++++++ config/locales/ru.yml | 1 + 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 4c3f044a6..aa98dbca9 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -72,7 +72,13 @@ class ProjectsController < ApplicationController end def fork - redirect_to @project.fork(current_user), :notice => t("flash.project.forked") + if forked = @project.fork(current_user) and forked.valid? + redirect_to forked, :notice => t("flash.project.forked") + else + flash[:warning] = t("flash.project.fork_error") + flash[:error] = forked.errors.full_messages + redirect_to @project + end end # TODO remove this? diff --git a/app/models/project.rb b/app/models/project.rb index cc46d9c71..61228f5c8 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -14,7 +14,6 @@ class Project < ActiveRecord::Base has_many :collaborators, :through => :relations, :source => :object, :source_type => 'User' has_many :groups, :through => :relations, :source => :object, :source_type => 'Group' - validates :description, :uniqueness => {:scope => [:owner_id, :owner_type]}, :presence => true validates :name, :uniqueness => {:scope => [:owner_id, :owner_type]}, :presence => true, :format => { :with => /^[a-zA-Z0-9_\-\+\.]+$/ } validates :owner, :presence => true # validate {errors.add(:base, I18n.t('flash.project.save_warning_ssh_key')) if owner.ssh_key.blank?} diff --git a/app/views/users/_form.html.haml b/app/views/users/_form.html.haml index 509b68d05..77047fc67 100644 --- a/app/views/users/_form.html.haml +++ b/app/views/users/_form.html.haml @@ -9,7 +9,7 @@ = f.text_field :email, :class => 'text_field' .group = f.label :role, t("activerecord.attributes.user.role"), :class => :label - = f.select :role, User::ROLES, :include_blank => true + = f.select :role, User::ROLES, :include_blank => 'user' .group = f.label :ssh_key, t("activerecord.attributes.user.ssh_key"), :class => :label = f.text_area :ssh_key, :class => 'text_area' diff --git a/app/views/users/index.html.haml b/app/views/users/index.html.haml index ec7471852..fd94929b6 100644 --- a/app/views/users/index.html.haml +++ b/app/views/users/index.html.haml @@ -12,15 +12,14 @@ %th.first ID %th= t("activerecord.attributes.user.name") %th= t("activerecord.attributes.user.email") + %th= t("activerecord.attributes.user.role") %th.last   - @users.each do |user| %tr{:class => cycle("odd", "even")} - %td - = user.id - %td - = link_to user.name, user_path(user) - %td - = user.email + %td= user.id + %td= link_to user.name, user_path(user) + %td= user.email + %td= user.role %td.last - if can? :read, user = link_to t("layout.show"), user_path(user) diff --git a/config/environments/production.rb b/config/environments/production.rb index aaa0ff1c2..c0a995f50 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -48,3 +48,18 @@ Rosa::Application.configure do # Send deprecation notices to registered listeners config.active_support.deprecation = :notify end + +# Uncomment this to stub XML RPC calls +# require 'xmlrpc/client' +# module XMLRPC +# class Client +# def call(*args) +# # raise args.inspect +# case +# when args.first == 'get_status' +# {:client_count => '1', :count_new_task => '2', :count_build_task => 3} +# else; 0 +# end +# end +# end +# end diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 62a205daf..0ce1daf02 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -336,6 +336,7 @@ ru: save_warning_ssh_key: Владельцу проекта необходимо указать в профиле свой SSH ключ destroyed: Проект успешно удален forked: Проект успешно форкнут + fork_error: Ошибка форка user: saved: Пользователь успешно сохранен From 20e0757adf36c04abc479f8ab9b688031b6fd354 Mon Sep 17 00:00:00 2001 From: Pavel Chipiga Date: Wed, 30 Nov 2011 00:16:20 +0200 Subject: [PATCH 04/12] Try to fix strange production error with project fork. Refs #2261 --- app/models/project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 61228f5c8..37fd3ecf7 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -80,7 +80,7 @@ class Project < ActiveRecord::Base def fork(new_owner) clone.tap do |c| - c.parent_id = id + c.parent = self c.owner = new_owner c.updated_at = nil; c.created_at = nil # :id = nil c.save From 6a3c0cec6cf60ddc9848576f88ddd3584b02ad4d Mon Sep 17 00:00:00 2001 From: Pavel Chipiga Date: Wed, 30 Nov 2011 00:23:09 +0200 Subject: [PATCH 05/12] Rollback last changes and fix deploy script. Refs #2261 --- app/models/project.rb | 2 +- config/deploy.rb | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 37fd3ecf7..61228f5c8 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -80,7 +80,7 @@ class Project < ActiveRecord::Base def fork(new_owner) clone.tap do |c| - c.parent = self + c.parent_id = id c.owner = new_owner c.updated_at = nil; c.created_at = nil # :id = nil c.save diff --git a/config/deploy.rb b/config/deploy.rb index 2f6af60c6..0cff59cac 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -64,3 +64,5 @@ namespace :deploy do symlink_downloads_dir end end + +after "deploy:update_code", "deploy:migrate" From 4f46b82914bf9fafe070a1121b73616e83e44543 Mon Sep 17 00:00:00 2001 From: Pavel Chipiga Date: Wed, 30 Nov 2011 01:41:12 +0200 Subject: [PATCH 06/12] Fix bugs after renaming unixname to name. Refs #2261 --- config/locales/ru.yml | 5 ++--- db/schema.rb | 4 +--- lib/product_builder.rb | 2 +- spec/controllers/projects_controller_spec.rb | 4 ++-- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 0ce1daf02..eee59670e 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -436,9 +436,9 @@ ru: repository: name: Название + description: Описание platform_id: Платформа platform: Платформа - unixname: Unixname created_at: Создан updated_at: Обновлен owner: Владелец @@ -476,7 +476,7 @@ ru: platform: name: Название - unixname: Unixname + description: Описание parent_platform_id: Родительская платформа parent: Родительская платформа released: Released @@ -499,7 +499,6 @@ ru: project: category_id: Категория name: Название - unixname: Unixname description: Описание owner: Владелец visibility: Видимость diff --git a/db/schema.rb b/db/schema.rb index 33ea2eeda..74e364bc6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -220,7 +220,6 @@ ActiveRecord::Schema.define(:version => 20111128140341) do t.string "object_type" t.integer "target_id" t.string "target_type" - t.integer "role_id" t.datetime "created_at" t.datetime "updated_at" t.string "role" @@ -257,9 +256,8 @@ ActiveRecord::Schema.define(:version => 20111128140341) do t.datetime "remember_created_at" t.datetime "created_at" t.datetime "updated_at" - t.string "uname" t.text "ssh_key" - t.integer "role_id" + t.string "uname" t.string "role" end diff --git a/lib/product_builder.rb b/lib/product_builder.rb index 0a3447445..10a6212c1 100644 --- a/lib/product_builder.rb +++ b/lib/product_builder.rb @@ -10,7 +10,7 @@ class ProductBuilder def self.create_product pbl # product_build_list self.client(pbl.product.platform.distrib_type). - call('create_product', pbl.id.to_s, pbl.product.platform.unixname, pbl.product.ks, pbl.product.menu, + call('create_product', pbl.id.to_s, pbl.product.platform.name, pbl.product.ks, pbl.product.menu, pbl.product.build_script, pbl.product.counter, [], "#{pbl.base_url}#{pbl.product.tar.url}") end end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index acd3260e7..3e45b88bb 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -5,8 +5,8 @@ describe ProjectsController do before(:each) do @project = Factory(:project) @another_user = Factory(:user) - @create_params = {:project => {:name => 'pro', :unixname => 'pro2'}} - @update_params = {:project => {:name => 'pro2', :unixname => 'pro2'}} + @create_params = {:project => {:name => 'pro'}} + @update_params = {:project => {:name => 'pro2'}} platform = Factory(:platform) any_instance_of(Project, :collected_project_versions => ['v1.0', 'v2.0']) From 3a2215d0ee8efe0ad6424b1eb393772bd67be772 Mon Sep 17 00:00:00 2001 From: Pavel Chipiga Date: Wed, 30 Nov 2011 02:22:26 +0200 Subject: [PATCH 07/12] Redo project versions to use tags and branches for build. Refs #2261 --- app/controllers/build_lists_controller.rb | 2 +- app/controllers/projects_controller.rb | 4 ++-- app/models/project.rb | 14 +++++++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/controllers/build_lists_controller.rb b/app/controllers/build_lists_controller.rb index b0fb4ebe6..147b6abf8 100644 --- a/app/controllers/build_lists_controller.rb +++ b/app/controllers/build_lists_controller.rb @@ -126,7 +126,7 @@ class BuildListsController < ApplicationController def find_project_versions @git_repository = @project.git_repository - @project_versions = @project.collected_project_versions + @project_versions = @project.versions end def find_build_list_by_bs diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index aa98dbca9..91e8aca9a 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -99,7 +99,7 @@ class ProjectsController < ApplicationController @arches = Arch.recent @bpls = Platform.main @pls = @project.repositories.collect { |rep| ["#{rep.platform.name}/#{rep.name}", rep.platform.id] } - @project_versions = @project.collected_project_versions + @project_versions = @project.versions end def process_build @@ -115,7 +115,7 @@ class ProjectsController < ApplicationController update_type = params[:build][:update_type] build_requires = params[:build][:build_requires] - @project_versions = @project.collected_project_versions + @project_versions = @project.versions if !check_arches || !check_project_versions @arches = Arch.recent diff --git a/app/models/project.rb b/app/models/project.rb index 61228f5c8..6ab460bee 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -48,18 +48,26 @@ class Project < ActiveRecord::Base end end + # TODO deprecate and remove project_versions and collected_project_versions ? def project_versions res = tags.select{|tag| tag.name =~ /^v\./} return res if res and res.size > 0 tags - end - + end def collected_project_versions project_versions.collect{|tag| tag.name.gsub(/^\w+\./, "")} end def tags - self.git_repository.tags.sort_by{|t| t.name.gsub(/[a-zA-Z.]+/, '').to_i} + self.git_repository.tags #.sort_by{|t| t.name.gsub(/[a-zA-Z.]+/, '').to_i} + end + + def branches + self.git_repository.branches + end + + def versions + tags.map(&:name) + branches.map{|b| "latest_#{b.name}"} end def members From 19076c805e8ceaa5fec12392e556e52ac160483d Mon Sep 17 00:00:00 2001 From: Pavel Chipiga Date: Wed, 30 Nov 2011 02:56:57 +0200 Subject: [PATCH 08/12] Skip authorization for callback actions during project build. Refactor. Refs #2261 --- app/controllers/build_lists_controller.rb | 16 +++++++++------- app/models/ability.rb | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/app/controllers/build_lists_controller.rb b/app/controllers/build_lists_controller.rb index 147b6abf8..56703ebbd 100644 --- a/app/controllers/build_lists_controller.rb +++ b/app/controllers/build_lists_controller.rb @@ -1,12 +1,14 @@ class BuildListsController < ApplicationController - before_filter :authenticate_user!, :except => [:status_build, :pre_build, :post_build, :circle_build, :new_bbdt] - before_filter :authenticate_build_service!, :only => [:status_build, :pre_build, :post_build, :circle_build, :new_bbdt] - before_filter :find_project, :only => [:index, :filter, :show, :publish] - before_filter :find_arches, :only => [:index, :filter, :all] - before_filter :find_project_versions, :only => [:index, :filter] - before_filter :find_build_list_by_bs, :only => [:status_build, :pre_build, :post_build] + CALLBACK_ACTIONS = [:status_build, :pre_build, :post_build, :circle_build, :new_bbdt] - load_and_authorize_resource + before_filter :authenticate_user!, :except => CALLBACK_ACTIONS + before_filter :authenticate_build_service!, :only => CALLBACK_ACTIONS + before_filter :find_project, :only => [:index, :filter, :show, :publish] + before_filter :find_arches, :only => [:index, :filter, :all] + before_filter :find_project_versions, :only => [:index, :filter] + before_filter :find_build_list_by_bs, :only => [:status_build, :pre_build, :post_build] + + load_and_authorize_resource :except => CALLBACK_ACTIONS def all if params[:filter] diff --git a/app/models/ability.rb b/app/models/ability.rb index 3a89b9c1f..0f1bc65ec 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -14,7 +14,8 @@ class Ability can :forbidden, Platform can :read, [Repository, Platform], :visibility => 'open' - can :auto_build, Project # TODO: This needs to be checked! + # TODO remove because auth callbacks skipped + can :auto_build, Project can [:status_build, :pre_build, :post_build, :circle_build, :new_bbdt], BuildList # Guest rights From bb1ca5644b7bcdfec2dc1c9f40b38836639445f7 Mon Sep 17 00:00:00 2001 From: "konstantin.grabar" Date: Wed, 30 Nov 2011 13:53:53 +0400 Subject: [PATCH 09/12] [refs #2249] Add personal repositories specs. Correct perosnal repository factory --- .../personal_repositories_controller_spec.rb | 103 ++++++++++++++++++ spec/factories/repository_factory.rb | 1 + .../personal_repositories_controller.rb | 82 ++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 spec/shared_examples/personal_repositories_controller.rb diff --git a/spec/controllers/personal_repositories_controller_spec.rb b/spec/controllers/personal_repositories_controller_spec.rb index 1ca1fa29c..d1ebee784 100644 --- a/spec/controllers/personal_repositories_controller_spec.rb +++ b/spec/controllers/personal_repositories_controller_spec.rb @@ -1,5 +1,108 @@ require 'spec_helper' +require 'shared_examples/personal_repositories_controller' describe PersonalRepositoriesController do + before(:each) do + @repository = Factory(:personal_repository) + @platform = Factory(:platform) + @project = Factory(:project) + @another_user = Factory(:user) + @create_params = {:repository => {:name => 'pro', :description => 'pro2'}, :platform_id => @platform.id} + end + + context 'for guest' do + [:show, :add_project, :remove_project, :settings, :change_visibility].each do |action| + it "should not be able to perform #{ action } action" do + get action, :id => @repository.id + response.should redirect_to(new_user_session_path) + end + end + end + + context 'for admin' do + before(:each) do + @admin = Factory(:admin) + set_session_for(@admin) + end + + it_should_behave_like 'be_able_to_perform_show_action' + it_should_behave_like 'be_able_to_perform_add_project_action' + it_should_behave_like 'be_able_to_perform_add_project_action_with_project_id_param' + it_should_behave_like 'add_project_to_repository' + it_should_behave_like 'be_able_to_perform_remove_project' + it_should_behave_like 'remove_project_from_repository' + it_should_behave_like 'be_able_to_perform_settings_action' + it_should_behave_like 'be_able_to_perform_change_visibility' + it_should_behave_like 'be_able_to_change_visibility' + end + + context 'for anyone except admin' do + before(:each) do + @user = Factory(:user) + set_session_for(@user) + end + + end + + context 'for owner user' do + before(:each) do + @user = Factory(:user) + set_session_for(@user) + + @repository.update_attribute(:owner, @user) + r = @repository.relations.build(:object_type => 'User', :object_id => @user.id, :role => 'admin') + r.save! + + @repository.platform.update_attribute(:owner, @user) + p = @repository.platform.relations.build(:object_type => 'User', :object_id => @user.id, :role => 'admin') + p.save! + end + + it_should_behave_like 'be_able_to_perform_settings_action' + it_should_behave_like 'be_able_to_perform_change_visibility' + it_should_behave_like 'be_able_to_change_visibility' + it_should_behave_like 'be_able_to_perform_show_action' + it_should_behave_like 'be_able_to_perform_add_project_action' + it_should_behave_like 'be_able_to_perform_add_project_action_with_project_id_param' + it_should_behave_like 'add_project_to_repository' + it_should_behave_like 'be_able_to_perform_remove_project' + it_should_behave_like 'remove_project_from_repository' + end + + context 'for reader user' do + before(:each) do + @user = Factory(:user) + set_session_for(@user) + r = @repository.relations.build(:object_type => 'User', :object_id => @user.id, :role => 'reader') + r.save! + end + + it_should_behave_like 'be_able_to_perform_show_action' + + it 'should not be able to perform add_project action' do + get :add_project, :id => @repository.id + response.should redirect_to(forbidden_path) + end + + it 'should not be able to perform add_project action with project_id param' do + get :add_project, :id => @repository.id, :project_id => @project.id + response.should redirect_to(forbidden_path) + end + + it 'should not be able to perform settings action' do + get :settings, :id => @repository.id + response.should redirect_to(forbidden_path) + end + + it 'should not be able to perform change_visibility action' do + get :change_visibility, :id => @repository.id + response.should redirect_to(forbidden_path) + end + + it 'should not change visibility of repository' do + get :change_visibility, :id => @repository.id + @repository.platform.reload.visibility.should == 'hidden' + end + end end diff --git a/spec/factories/repository_factory.rb b/spec/factories/repository_factory.rb index 4590b321b..1b643ae35 100644 --- a/spec/factories/repository_factory.rb +++ b/spec/factories/repository_factory.rb @@ -13,6 +13,7 @@ Factory.define(:personal_repository, :class => Repository) do |p| p.after_create { |rep| rep.platform.platform_type = 'personal' + rep.platform.visibility = 'hidden' rep.platform.save! } end diff --git a/spec/shared_examples/personal_repositories_controller.rb b/spec/shared_examples/personal_repositories_controller.rb new file mode 100644 index 000000000..6b93b6ca7 --- /dev/null +++ b/spec/shared_examples/personal_repositories_controller.rb @@ -0,0 +1,82 @@ +shared_examples_for 'be_able_to_perform_show_action' do + it 'should be able to perform show action' do + get :show, :id => @repository.id + response.should render_template(:show) + end +end + +shared_examples_for 'be_able_to_perform_add_project_action' do + it 'should be able to perform add_project action' do + get :add_project, :id => @repository.id + response.should render_template(:projects_list) + end +end + +shared_examples_for 'be_able_to_perform_add_project_action_with_project_id_param' do + it 'should be able to perform add_project action with project_id param' do + get :add_project, :id => @repository.id, :project_id => @project.id + response.should redirect_to(personal_repository_path(@repository)) + end +end + +shared_examples_for 'add_project_to_repository' do + it 'should be able to add project to repository' do + get :add_project, :id => @repository.id, :project_id => @project.id + @repository.projects.exists? :id => @project.id + end +end + +shared_examples_for 'be_able_to_perform_remove_project' do + it 'should be able to perform remove_project action' do + get :remove_project, :id => @repository.id, :project_id => @project.id + response.should redirect_to(personal_repository_path(@repository)) + end +end + +shared_examples_for 'remove_project_from_repository' do + it 'should be able to remove project from repository' do + get :remove_project, :id => @repository.id, :project_id => @project.id + !@repository.projects.exists? :id => @project.id + end +end + +shared_examples_for 'be_able_to_perform_destroy_action' do + it 'should be able to perform destroy action' do + delete :destroy, :id => @repository.id + response.should redirect_to(platform_path(@repository.platform.id)) + end +end + +shared_examples_for 'change_repositories_count_after_destroy' do + it 'should change objects count after destroy action' do + lambda { delete :destroy, :id => @repository.id }.should change{ Repository.count }.by(-1) + end +end + +shared_examples_for 'not_be_able_to_destroy_personal_repository' do + it 'should not be able to destroy personal repository' do + delete :destroy, :id => @personal_repository.id + response.should redirect_to(forbidden_path) + end +end + +shared_examples_for 'be_able_to_perform_settings_action' do + it 'should be able to perform settings action' do + get :settings, :id => @repository.id + response.should render_template(:settings) + end +end + +shared_examples_for 'be_able_to_perform_change_visibility' do + it 'should be able to perform change_visibility action' do + get :change_visibility, :id => @repository.id + response.should redirect_to(settings_personal_repository_path(@repository)) + end +end + +shared_examples_for 'be_able_to_change_visibility' do + it 'should change visibility of repository' do + get :change_visibility, :id => @repository.id + @repository.platform.reload.visibility.should == 'open' + end +end From 5f5fe8c8bebf4370f97e11770f486936de816e42 Mon Sep 17 00:00:00 2001 From: Pavel Chipiga Date: Wed, 30 Nov 2011 13:57:48 +0200 Subject: [PATCH 10/12] Send blank string when no product tar attached. Refs #2261 --- lib/product_builder.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/product_builder.rb b/lib/product_builder.rb index 10a6212c1..e37f79f74 100644 --- a/lib/product_builder.rb +++ b/lib/product_builder.rb @@ -10,7 +10,7 @@ class ProductBuilder def self.create_product pbl # product_build_list self.client(pbl.product.platform.distrib_type). - call('create_product', pbl.id.to_s, pbl.product.platform.name, pbl.product.ks, pbl.product.menu, - pbl.product.build_script, pbl.product.counter, [], "#{pbl.base_url}#{pbl.product.tar.url}") + call('create_product', pbl.id.to_s, pbl.product.platform.name, pbl.product.ks, pbl.product.menu, pbl.product.build_script, + pbl.product.counter, [], pbl.product.tar.exists? ? "#{pbl.base_url}#{pbl.product.tar.url}" : '') end end From f154ccc132a1a7c2f75cb91dc9c6cb174d300824 Mon Sep 17 00:00:00 2001 From: George Vinogradov Date: Wed, 30 Nov 2011 19:27:19 +0400 Subject: [PATCH 11/12] Fixed groups creation. --- app/controllers/groups_controller.rb | 28 ++++++++++++++++++++++++---- app/models/group.rb | 8 ++++++++ app/models/relation.rb | 15 +++++++++++++++ config/routes.rb | 4 +++- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index ec116fb6a..1f6a74084 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -1,12 +1,27 @@ # coding: UTF-8 class GroupsController < ApplicationController + is_related_controller! + + belongs_to :user, :optional => true + before_filter :authenticate_user! before_filter :find_group, :only => [:show, :edit, :update, :destroy] load_and_authorize_resource def index - @groups = Group.paginate(:page => params[:group_page]) + puts parent.inspect + @groups = if parent? and !parent.nil? + parent.groups + else + Group + end.accessible_by(current_ability) + + @groups = if params[:query] + @groups.where(["name LIKE ?", "%#{params[:query]}%"]) + else + @groups + end.paginate(:page => params[:group_page]) end def show @@ -24,13 +39,18 @@ class GroupsController < ApplicationController def create @group = Group.new params[:group] - @group.owner = current_user - @group.members << current_user - if @group.save + @group.owner = if parent? and parent.is_a? User + parent + else + current_user + end + + if @group.save! flash[:notice] = t('flash.group.saved') redirect_to edit_group_path(@group) else flash[:error] = t('flash.group.save_error') + flash[:warning] = @project.errors[:base] render :action => :new end end diff --git a/app/models/group.rb b/app/models/group.rb index e56a0709a..5b1a7c387 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -20,6 +20,14 @@ class Group < ActiveRecord::Base delegate :ssh_key, :to => :owner + after_create :add_owner_to_members + include Modules::Models::PersonalRepository include Modules::Models::Owner + + protected + def add_owner_to_members + Relation.create_with_role(self.owner, self, 'admin') +# members << self.owner if !members.exists?(:id => self.owner.id) + end end diff --git a/app/models/relation.rb b/app/models/relation.rb index dd2d4a173..2a6709926 100644 --- a/app/models/relation.rb +++ b/app/models/relation.rb @@ -5,6 +5,21 @@ class Relation < ActiveRecord::Base ROLES = %w[reader writer admin] validates :role, :inclusion => {:in => ROLES} + before_validation :add_default_role + scope :by_object, lambda {|obj| {:conditions => ['object_id = ? AND object_type = ?', obj.id, obj.class.to_s]}} scope :by_target, lambda {|tar| {:conditions => ['target_id = ? AND target_type = ?', tar.id, tar.class.to_s]}} + + def self.create_with_role(object, target, role) + r = new + r.object = object + r.target = target + r.role = role + r.save + end + + protected + def add_default_role + self.role = ROLES.first if role.nil? || role.empty? + end end diff --git a/config/routes.rb b/config/routes.rb index 104464420..6652cc68e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,7 +6,9 @@ Rosa::Application.routes.draw do get '/users/auth/:provider' => 'users/omniauth_callbacks#passthru' end - resources :users + resources :users do + resources :groups, :only => [:new, :create, :index] + end resources :event_logs, :only => :index From 9cc820080b0513becdee5abdd72d03f4579f12be Mon Sep 17 00:00:00 2001 From: George Vinogradov Date: Mon, 5 Dec 2011 16:32:18 +0400 Subject: [PATCH 12/12] Groups base functional. --- app/controllers/collaborators_controller.rb | 25 ++++++- app/controllers/members_controller.rb | 76 +++++++++++++++++++++ app/models/ability.rb | 15 +++- app/views/collaborators/edit.html.haml | 41 +++++------ app/views/groups/_sidebar.html.haml | 14 +++- app/views/layouts/application.html.haml | 3 + app/views/members/edit.html.haml | 35 ++++++++++ app/views/projects/_sidebar.html.haml | 12 +++- config/locales/ru.yml | 9 +++ config/routes.rb | 12 ++++ 10 files changed, 214 insertions(+), 28 deletions(-) create mode 100644 app/controllers/members_controller.rb create mode 100644 app/views/members/edit.html.haml diff --git a/app/controllers/collaborators_controller.rb b/app/controllers/collaborators_controller.rb index 72d45bc61..2eb1cf4fd 100644 --- a/app/controllers/collaborators_controller.rb +++ b/app/controllers/collaborators_controller.rb @@ -29,8 +29,11 @@ class CollaboratorsController < ApplicationController def update all_user_ids = [] + all_groups_ids = [] + puts params.inspect Relation::ROLES.each { |r| - all_user_ids = all_user_ids | params[r.to_sym].keys if params[r.to_sym] + all_user_ids = all_user_ids | params['user'][r.to_sym].keys if params['user'][r.to_sym] + all_groups_ids = all_groups_ids | params['group'][r.to_sym].keys if params['group'][r.to_sym] } # Remove relations @@ -40,11 +43,17 @@ class CollaboratorsController < ApplicationController users_for_removing.each do |u| Relation.by_object(u).by_target(@project).each {|r| r.destroy} end + groups_for_removing = @project.groups.select do |u| + !all_groups_ids.map{|k| k.to_i}.include? u.id and @project.owner != u + end + groups_for_removing.each do |u| + Relation.by_object(u).by_target(@project).each {|r| r.destroy} + end # Create relations Relation::ROLES.each { |r| #users_for_creating = users_for_creating params[:user].keys.map{|p| p.to_i} - @project.collaborators.map(&:id) - params[r.to_sym].keys.each { |u| + params['user'][r.to_sym].keys.each { |u| if relation = @project.relations.find_by_object_id_and_object_type(u, 'User') relation.update_attribute(:role, r) else @@ -53,7 +62,17 @@ class CollaboratorsController < ApplicationController puts r relation.save! end - } if params[r.to_sym] + } if params['user'][r.to_sym] + params['group'][r.to_sym].keys.each { |u| + if relation = @project.relations.find_by_object_id_and_object_type(u, 'Group') + relation.update_attribute(:role, r) + else + relation = @project.relations.build(:object_id => u, :object_type => 'Group', :role => r) + puts relation.inspect + puts r + relation.save! + end + } if params['group'][r.to_sym] } if @project.save diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb new file mode 100644 index 000000000..2a4fbdf3e --- /dev/null +++ b/app/controllers/members_controller.rb @@ -0,0 +1,76 @@ +class MembersController < ApplicationController + before_filter :authenticate_user! + is_related_controller! + + belongs_to :group, :optional => true + +# before_filter :find_target + before_filter :find_users + + def index + redirect_to edit_group_members_path(parent) + end + + def show + end + + def new + end + + def edit + if params[:id] + @user = User.find params[:id] + render :edit_rights and return + end + end + + def create + end + + def update + all_user_ids = [] + Relation::ROLES.each { |r| + all_user_ids = all_user_ids | params[r.to_sym].keys if params[r.to_sym] + } + + # Remove relations + users_for_removing = parent.members.select do |u| + !all_user_ids.map{|k| k.to_i}.include? u.id and parent.owner != u + end + users_for_removing.each do |u| + Relation.by_object(u).by_target(parent).each {|r| r.destroy} + end + + # Create relations + Relation::ROLES.each { |r| + #users_for_creating = users_for_creating params[:user].keys.map{|p| p.to_i} - @project.collaborators.map(&:id) + params[r.to_sym].keys.each { |u| + if relation = parent.objects.find_by_object_id_and_object_type(u, 'User') + relation.update_attribute(:role, r) + else + relation = parent.objects.build(:object_id => u, :object_type => 'User', :role => r) + puts relation.inspect + puts r + relation.save! + end + } if params[r.to_sym] + } + + if parent.save + flash[:notice] = t("flash.members.successfully_changed") + else + flash[:error] = t("flash.members.error_in_changing") + end + redirect_to parent_path + end + + def destroy + end + + protected + + def find_users + @users = User.all + end + +end diff --git a/app/models/ability.rb b/app/models/ability.rb index 0f1bc65ec..247b64817 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -29,12 +29,19 @@ class Ability can [:index, :destroy], AutoBuildList, :project_id => user.own_project_ids # If rules goes one by one CanCan joins them by 'OR' sql operator can :read, Project, :visibility => 'open' + can :read, Group can :read, User can :manage_collaborators, Project do |project| project.relations.exists? :object_id => user.id, :object_type => 'User', :role => 'admin' end + + can :manage_members, Group do |group| + group.objects.exists? :object_id => user.id, :object_type => 'User', :role => 'admin' + end + # Put here model names which objects can user create can :create, Project + can :create, Group can :publish, BuildList do |build_list| build_list.can_published? && build_list.project.relations.exists?(:object_type => 'User', :object_id => user.id) end @@ -51,6 +58,10 @@ class Ability can [:read, :update, :process_build, :build], Project, projects_in_relations_with(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id) do |project| project.relations.exists?(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id) end + + can [:read, :update], Group, groups_in_relations_with(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id) do |group| + group.objects.exists?(:role => ['writer', 'admin'], :object_type => 'User', :object_id => user.id) + end can :manage, Platform, :owner_type => 'User', :owner_id => user.id #can :read, Platform, :members => {:id => user.id} @@ -110,7 +121,7 @@ class Ability # Sub query for platforms, projects relations # TODO: Replace table names list by method_missing way - %w[platforms projects repositories].each do |table_name| + %w[platforms projects repositories groups].each do |table_name| define_method table_name + "_in_relations_with" do |opts| query = "#{ table_name }.id IN (SELECT target_id FROM relations WHERE relations.target_type = '#{ table_name.singularize.camelize }'" opts.each do |key, value| @@ -126,4 +137,4 @@ class Ability #def projects_in_relations_with(opts={}) # ["projects.id IN (SELECT target_id FROM relations WHERE relations.object_id #{ opts[:object_id].class == Array ? 'IN (?)' : '= ?' } AND relations.object_type = '#{ opts[:object_type] }' AND relations.target_type = 'Platform') AND relations.role", opts[:object_id]] #end -end \ No newline at end of file +end diff --git a/app/views/collaborators/edit.html.haml b/app/views/collaborators/edit.html.haml index a34d97092..1edcff67c 100644 --- a/app/views/collaborators/edit.html.haml +++ b/app/views/collaborators/edit.html.haml @@ -22,28 +22,29 @@ = link_to user.name, user_path(user) %td - Relation::ROLES.each do |role| - = check_box_tag "#{ role }[#{user.id}]", '1', ((@project.relations.exists? :object_id => user.id, :object_type => 'User', :role => role) ? :checked : nil), {:class => "user_role_chbx"} - = label_tag "#{ role }[#{user.id}]", t("layout.collaborators.roles.#{ role }") + = check_box_tag "user[#{ role }][#{user.id}]", '1', ((@project.relations.exists? :object_id => user.id, :object_type => 'User', :role => role) ? :checked : nil), {:class => "user_role_chbx"} + = label_tag "user[#{ role }][#{user.id}]", t("layout.collaborators.roles.#{ role }") %td = user.uname - /%h2.title= t("layout.groups.list_header") - /%table.table - / %tr - / %th.first ID - / %th= t("activerecord.attributes.group.name") - / %th= t("activerecord.attributes.group.uname") - / %th.last= t("layout.collaborators.add") - / - @groups.each do |group| - / %tr{:class => cycle("odd", "even")} - / %td - / = group.id - / %td - / = link_to group.name, group_path(group) - / %td - / = group.uname - / %td.last - / = check_box_tag "group[#{group.id}]", '1', (@project.groups.include? group) ? :checked : nil - / = label_tag "group[#{group.id}]", t("layout.collaborators.add") + %h2.title= t("layout.groups.list_header") + %table.table + %tr + %th.first ID + %th= t("activerecord.attributes.group.name") + %th= t("activerecord.attributes.group.uname") + %th.last= t("layout.collaborators.add") + - @groups.each do |group| + %tr{:class => cycle("odd", "even")} + %td + = group.id + %td + = link_to group.name, group_path(group) + %td + - Relation::ROLES.each do |role| + = check_box_tag "group[#{role}][#{group.id}]", '1', ((@project.relations.exists? :object_id => group.id, :object_type => 'Group', :role => role) ? :checked : nil), {:class => "user_role_chbx"} + = label_tag "group[#{role}][#{group.id}]", t("layout.collaborators.roles.#{role}") + %td + = group.uname .group.navform.wat-cf %button.button{:type => "submit"} = image_tag("web-app-theme/icons/tick.png", :alt => t("layout.save")) diff --git a/app/views/groups/_sidebar.html.haml b/app/views/groups/_sidebar.html.haml index 754d588f1..6ee1d6923 100644 --- a/app/views/groups/_sidebar.html.haml +++ b/app/views/groups/_sidebar.html.haml @@ -1,5 +1,15 @@ .block.notice %h3= t("layout.groups.members") .content - - @group.members.each do |member| - %p= link_to member.name, member + %p + %ul + - @group.members.each do |user| + %li + - if can? :read, user + = link_to user.name, user_path(user) + - else + = user.name + - if (@group.owner == user) + = '(' + t("layout.owner") + ')' + %br + = link_to t("layout.groups.edit_members"), edit_group_members_path(@group) if can? :manage_members, @group diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 9e1e43f6b..068431143 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -25,6 +25,9 @@ -if can? :index, Project %li{:class => controller.controller_path == 'projects' ? 'active' : '' } %a{:href => projects_path}= t("layout.menu.projects") + -if can? :index, Group + %li{:class => controller.controller_path == 'groups' ? 'active' : '' } + %a{:href => groups_path}= t("layout.menu.groups") -if can? :index, Download %li{:class => controller.controller_path == 'downloads' ? 'active' : '' } %a{:href => downloads_path}= t("layout.menu.downloads") diff --git a/app/views/members/edit.html.haml b/app/views/members/edit.html.haml new file mode 100644 index 000000000..8ea7bfaa6 --- /dev/null +++ b/app/views/members/edit.html.haml @@ -0,0 +1,35 @@ +.block + .secondary-navigation + %ul.wat-cf + %li.first= link_to t("layout.members.back_to_group"), parent_path + %li.active= link_to t("layout.members.edit"), edit_group_members_path(@group) + .content + .inner + = form_tag group_members_path(parent) do + %h2.title= t("layout.users.list_header") + %table.table + %tr + %th.first ID + %th= t("activerecord.attributes.user.name") + %th= t("activerecord.attributes.user.roles") + %th= t("activerecord.attributes.user.uname") + - #TODO: Replace this Chelyabinsk add/remove collaborators method by more human method + - @users.each do |user| + %tr{:class => cycle("odd", "even")} + %td + = user.id + %td + = link_to user.name, user_path(user) + %td + - Relation::ROLES.each do |role| + = check_box_tag "#{ role }[#{user.id}]", '1', ((parent.relations.exists? :object_id => user.id, :object_type => 'User', :role => role) ? :checked : nil), {:class => "user_role_chbx"} + = label_tag "#{ role }[#{user.id}]", t("layout.members.roles.#{ role }") + %td + = user.uname + .group.navform.wat-cf + %button.button{:type => "submit"} + = image_tag("web-app-theme/icons/tick.png", :alt => t("layout.save")) + = t("layout.save") + %span.text_button_padding= t("layout.or") + = link_to t("layout.cancel"), group_path(parent), :class => "text_button_padding link_button" + diff --git a/app/views/projects/_sidebar.html.haml b/app/views/projects/_sidebar.html.haml index f5ab2217c..04aced964 100644 --- a/app/views/projects/_sidebar.html.haml +++ b/app/views/projects/_sidebar.html.haml @@ -13,8 +13,18 @@ = user.name - if (@project.owner == user) = '(' + t("layout.owner") + ')' - %br + /%br -# if can? :update, @project + %p + %b + = "#{t("layout.projects.groups")}:" + %ul + - @project.groups.each do |group| + %li + = link_to group.name, group_path(group) + - if (@project.owner == group) + = '(' + t("layout.owner") + ')' + %br = link_to t("layout.projects.edit_collaborators"), edit_project_collaborators_path(@project) if can? :manage_collaborators, @project / %p diff --git a/config/locales/ru.yml b/config/locales/ru.yml index eee59670e..c6e745193 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -221,6 +221,10 @@ ru: roles_header: Роли для add_role: Добавить/Удалить роль + members: + back_to_group: Вернуться к группе + edit: Редактировать список + roles: Роли groups: list: Список @@ -233,6 +237,7 @@ ru: show: Группа back_to_the_list: ⇐ К списку групп confirm_delete: Вы уверены, что хотите удалить эту группу? + edit_members: Изменить список участников users: list: Список @@ -319,6 +324,10 @@ ru: successfully_changed: Список коллабораторов успешно изменен error_in_changing: Ошибка изменения списка коллабораторов + members: + successfully_changed: Список участников успешно изменен + error_in_changing: Ошибка изменения списка участников + auto_build_list: success: Сборка проекта автоматизорована! failed: Не удалось автоматизировать сборку! diff --git a/config/routes.rb b/config/routes.rb index 6652cc68e..6b5514d6b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -105,6 +105,18 @@ Rosa::Application.routes.draw do end end + resources :groups do + resources :members, :only => [:index, :edit, :update] do + collection do + get :edit + post :update + end + member do + post :update + end + end + end + resources :users, :groups do resources :platforms, :only => [:new, :create]