diff --git a/Gemfile b/Gemfile index 7ed9a93a3..0ace218c6 100644 --- a/Gemfile +++ b/Gemfile @@ -2,19 +2,19 @@ source 'http://rubygems.org' gem 'rails', '3.2.6' #, :git => 'git://github.com/rails/rails.git' -gem 'pg', '~> 0.13.2' +gem 'pg', '~> 0.14.0' # gem 'silent-postgres', :git => 'git://github.com/dolzenko/silent-postgres.git' #'~> 0.1.1' gem 'redhillonrails_core', :git => 'git://github.com/chipiga/redhillonrails_core.git', :branch => 'rails31' # '~> 2.0.0.pre' # deprecated # gem 'schema_plus', '~> 0.2.1' # buggy shit! -gem 'devise', '~> 2.0.4' -gem 'omniauth', '~> 1.0.3' +gem 'devise', '~> 2.1.2' +gem 'omniauth', '~> 1.1.0' gem 'omniauth-openid', '~> 1.0.1' -gem 'cancan', '~> 1.6.7' +gem 'cancan', '1.6.7' # 1.6.8 fail specs with strange error gem 'ancestry', '~> 1.3.0' -gem 'paperclip', '~> 3.0.4' -gem 'resque', '~> 1.20.0' +gem 'paperclip', '~> 3.1.4' +gem 'resque', '~> 1.21.0' gem 'resque-status', '~> 0.3.3' gem 'resque_mailer', '~> 2.1.0' gem 'perform_later', '~> 1.3.0' # should be after resque_mailer @@ -26,6 +26,8 @@ gem 'state_machine' gem 'grack', :git => 'git://github.com/rdblue/grack.git', :require => 'git_http' gem "grit", :git => 'git://github.com/warpc/grit.git' #, :path => '~/Sites/code/grit' gem 'charlock_holmes', '~> 0.6.8' #, :git => 'git://github.com/brianmario/charlock_holmes.git', :branch => 'bundle-icu' +# gem 'ruby-filemagic', '~> 0.4.2', :require => 'filemagic/ext' +gem 'github-linguist', '~> 2.1.2', :require => 'linguist' gem 'diff-display', '~> 0.0.1' # Wiki @@ -39,7 +41,7 @@ gem 'wikicloth' gem 'unicorn', '~> 4.3.1', :platforms => [:mri, :rbx] gem 'trinidad', '~> 1.0.2', :platforms => :jruby -gem 'newrelic_rpm', '~> 3.3.5', :platforms => [:mri, :rbx] +gem 'newrelic_rpm', '~> 3.4.0.1', :platforms => [:mri, :rbx] gem 'whenever', '~> 0.7.3', :require => false gem 'jbuilder', '~> 0.4.0' @@ -54,14 +56,14 @@ gem 'rails-backbone', '~> 0.7.2' group :assets do gem 'sass-rails', '~> 3.2.5' gem 'coffee-rails', '~> 3.2.2' - gem 'compass-rails', '~> 1.0.2' + gem 'compass-rails', '~> 1.0.3' gem 'uglifier', '~> 1.2.4' gem 'therubyracer', '~> 0.10.1', :platforms => [:mri, :rbx] gem 'therubyrhino', '~> 1.73.1', :platforms => :jruby end group :production do - gem "airbrake", '~> 3.1.1' + gem "airbrake", '~> 3.1.2' gem 'bluepill', '~> 0.0.60', :require => false end @@ -78,8 +80,8 @@ group :development do end group :test do - gem 'rspec-rails', '~> 2.10.1', :group => 'development' - gem 'factory_girl_rails', '~> 3.4.0' + gem 'rspec-rails', '~> 2.11.0', :group => 'development' + gem 'factory_girl_rails', '~> 3.5.0' gem 'rr', '~> 1.0.4' gem 'shoulda' end diff --git a/Gemfile.lock b/Gemfile.lock index 15dc97662..1ff9bd23d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -52,7 +52,7 @@ GEM activesupport (3.2.6) i18n (~> 0.6) multi_json (~> 1.0) - airbrake (3.1.1) + airbrake (3.1.2) activesupport builder albino (1.3.3) @@ -88,34 +88,41 @@ GEM coffee-script-source execjs coffee-script-source (1.3.3) - compass (0.12.1) + compass (0.12.2) chunky_png (~> 1.2) fssm (>= 0.2.7) sass (~> 3.1) - compass-rails (1.0.2) - compass (>= 0.12.0, < 0.14) + compass-rails (1.0.3) + compass (>= 0.12.2, < 0.14) creole (0.4.2) daemons (1.1.6) - devise (2.0.4) + devise (2.1.2) bcrypt-ruby (~> 3.0) - orm_adapter (~> 0.0.3) + orm_adapter (~> 0.1) railties (~> 3.1) - warden (~> 1.1.1) + warden (~> 1.2.1) diff-display (0.0.1) diff-lcs (1.1.3) ejs (1.0.0) erubis (2.7.0) + escape_utils (0.2.4) eventmachine (0.12.10) execjs (1.4.0) multi_json (~> 1.0) expression_parser (0.9.0) - factory_girl (3.4.0) + factory_girl (3.5.0) activesupport (>= 3.0.0) - factory_girl_rails (3.4.0) - factory_girl (~> 3.4.0) + factory_girl_rails (3.5.0) + factory_girl (~> 3.5.0) railties (>= 3.0.0) + ffi (1.0.11) fssm (0.2.9) - github-markup (0.7.2) + github-linguist (2.1.2) + charlock_holmes (~> 0.6.6) + escape_utils (~> 0.2.3) + mime-types (~> 1.18) + pygments.rb (>= 0.2.13) + github-markup (0.7.4) gollum (1.3.1) albino (~> 1.3.2) github-markup (>= 0.4.0, < 1.0.0) @@ -132,18 +139,18 @@ GEM haml (~> 3.0) railties (~> 3.0) hashie (1.2.0) - highline (1.6.12) + highline (1.6.13) hike (1.2.1) - hirb (0.6.2) + hirb (0.7.0) i18n (0.6.0) jbuilder (0.4.0) activesupport (>= 3.0.0) blankslate (>= 2.1.2.4) - journey (1.0.3) + journey (1.0.4) jquery-rails (2.0.2) railties (>= 3.2.0, < 5.0) thor (~> 0.14) - json (1.7.3) + json (1.7.4) kgio (2.7.4) libv8 (3.3.10.4) macaddr (1.6.1) @@ -152,18 +159,18 @@ GEM i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) - mailcatcher (0.5.6) + mailcatcher (0.5.8) activesupport (~> 3.0) eventmachine (~> 0.12) haml (~> 3.1) mail (~> 2.3) sinatra (~> 1.2) - skinny (~> 0.2) + skinny (~> 0.2, >= 0.2.1) sqlite3 (~> 1.3) thin (~> 1.2) meta-tags (1.2.6) actionpack - mime-types (1.18) + mime-types (1.19) multi_json (1.3.6) mustache (0.99.4) net-scp (1.0.4) @@ -173,16 +180,16 @@ GEM net-ssh (2.5.2) net-ssh-gateway (1.1.0) net-ssh (>= 1.99.1) - newrelic_rpm (3.3.5) - nokogiri (1.5.4) - omniauth (1.0.3) + newrelic_rpm (3.4.0.1) + nokogiri (1.5.5) + omniauth (1.1.0) hashie (~> 1.2) rack omniauth-openid (1.0.1) omniauth (~> 1.0) rack-openid (~> 1.3.1) - orm_adapter (0.0.7) - paperclip (3.0.4) + orm_adapter (0.4.0) + paperclip (3.1.4) activemodel (>= 3.0.0) activerecord (>= 3.0.0) activesupport (>= 3.0.0) @@ -192,9 +199,11 @@ GEM rails (~> 3.0) redis resque - pg (0.13.2) + pg (0.14.0) polyglot (0.3.3) posix-spawn (0.3.6) + pygments.rb (0.2.13) + rubypython (~> 0.5.3) rack (1.4.1) rack-cache (1.2) rack (>= 0.4) @@ -230,21 +239,21 @@ GEM rake (>= 0.8.7) rdoc (~> 3.4) thor (>= 0.14.6, < 2.0) - raindrops (0.9.0) + raindrops (0.10.0) rake (0.9.2.2) rdiscount (1.6.8) rdoc (3.12) json (~> 1.4) redcarpet (1.17.2) - redis (2.2.2) - redis-namespace (1.0.3) - redis (< 3.0.0) + redis (3.0.1) + redis-namespace (1.2.0) + redis (~> 3.0.0) redisk (0.2.2) redis (>= 0.1.1) redis-namespace (>= 0.1.0) - resque (1.20.0) + resque (1.21.0) multi_json (~> 1.0) - redis-namespace (~> 1.0.2) + redis-namespace (~> 1.0) sinatra (>= 0.9.2) vegas (~> 0.1.2) resque-status (0.3.3) @@ -254,46 +263,50 @@ GEM resque_mailer (2.1.0) actionmailer (~> 3.0) rr (1.0.4) - rspec (2.10.0) - rspec-core (~> 2.10.0) - rspec-expectations (~> 2.10.0) - rspec-mocks (~> 2.10.0) - rspec-core (2.10.1) - rspec-expectations (2.10.0) + rspec (2.11.0) + rspec-core (~> 2.11.0) + rspec-expectations (~> 2.11.0) + rspec-mocks (~> 2.11.0) + rspec-core (2.11.1) + rspec-expectations (2.11.2) diff-lcs (~> 1.1.3) - rspec-mocks (2.10.1) - rspec-rails (2.10.1) + rspec-mocks (2.11.1) + rspec-rails (2.11.0) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec (~> 2.10.0) + rspec (~> 2.11.0) ruby-haml-js (0.0.3) execjs sprockets (>= 2.0.0) - ruby-openid (2.1.8) + ruby-openid (2.2.0) + rubypython (0.5.3) + blankslate (>= 2.1.2.3) + ffi (~> 1.0.7) russian (0.6.0) i18n (>= 0.5.0) - rvm-capistrano (1.2.2) + rvm-capistrano (1.2.5) capistrano (>= 2.0.0) sanitize (2.0.3) nokogiri (>= 1.4.4, < 1.6) - sass (3.1.19) + sass (3.1.20) sass-rails (3.2.5) railties (~> 3.2.0) sass (>= 3.1.10) tilt (~> 1.3) shotgun (0.9) rack (>= 1.0) - shoulda (3.0.1) - shoulda-context (~> 1.0.0) - shoulda-matchers (~> 1.0.0) + shoulda (3.1.1) + shoulda-context (~> 1.0) + shoulda-matchers (~> 1.2) shoulda-context (1.0.0) - shoulda-matchers (1.0.0) + shoulda-matchers (1.2.0) + activesupport (>= 3.0.0) sinatra (1.3.2) rack (~> 1.3, >= 1.3.6) rack-protection (~> 1.2) tilt (~> 1.3, >= 1.3.3) - skinny (0.2.0) + skinny (0.2.1) eventmachine (~> 0.12) thin (~> 1.2) sprockets (2.1.3) @@ -302,22 +315,22 @@ GEM tilt (~> 1.1, != 1.3.0) sqlite3 (1.3.6) state_machine (1.1.2) - systemu (2.5.1) + systemu (2.5.2) therubyracer (0.10.1) libv8 (~> 3.3.10) - thin (1.3.1) + thin (1.4.1) daemons (>= 1.0.9) eventmachine (>= 0.12.6) rack (>= 1.0.0) - thor (0.15.2) + thor (0.15.4) tilt (1.3.3) treetop (1.4.10) polyglot polyglot (>= 0.3.1) tzinfo (0.3.33) - uglifier (1.2.4) + uglifier (1.2.6) execjs (>= 0.3.0) - multi_json (>= 1.0.2) + multi_json (~> 1.3) unicorn (4.3.1) kgio (~> 2.6) rack @@ -326,7 +339,7 @@ GEM macaddr (~> 1.0) vegas (0.1.11) rack (>= 1.0.0) - warden (1.1.1) + warden (1.2.1) rack (>= 1.0) whenever (0.7.3) activesupport (>= 2.3.4) @@ -341,20 +354,21 @@ PLATFORMS DEPENDENCIES RedCloth - airbrake (~> 3.1.1) + airbrake (~> 3.1.2) ancestry (~> 1.3.0) bluepill (~> 0.0.60) - cancan (~> 1.6.7) + cancan (= 1.6.7) cape capistrano capistrano_colors charlock_holmes (~> 0.6.8) coffee-rails (~> 3.2.2) - compass-rails (~> 1.0.2) + compass-rails (~> 1.0.3) creole - devise (~> 2.0.4) + devise (~> 2.1.2) diff-display (~> 0.0.1) - factory_girl_rails (~> 3.4.0) + factory_girl_rails (~> 3.5.0) + github-linguist (~> 2.1.2) gollum (= 1.3.1) grack! grit! @@ -365,12 +379,12 @@ DEPENDENCIES jquery-rails (~> 2.0.2) mailcatcher meta-tags (~> 1.2.5) - newrelic_rpm (~> 3.3.5) - omniauth (~> 1.0.3) + newrelic_rpm (~> 3.4.0.1) + omniauth (~> 1.1.0) omniauth-openid (~> 1.0.1) - paperclip (~> 3.0.4) + paperclip (~> 3.1.4) perform_later (~> 1.3.0) - pg (~> 0.13.2) + pg (~> 0.14.0) rails (= 3.2.6) rails-backbone (~> 0.7.2) rails3-generators @@ -378,11 +392,11 @@ DEPENDENCIES rdiscount redcarpet (= 1.17.2) redhillonrails_core! - resque (~> 1.20.0) + resque (~> 1.21.0) resque-status (~> 0.3.3) resque_mailer (~> 2.1.0) rr (~> 1.0.4) - rspec-rails (~> 2.10.1) + rspec-rails (~> 2.11.0) ruby-haml-js (~> 0.0.3) russian (~> 0.6.0) rvm-capistrano diff --git a/app/assets/javascripts/extra/flash_notifies.js b/app/assets/javascripts/extra/flash_notifies.js new file mode 100644 index 000000000..52c9fbf53 --- /dev/null +++ b/app/assets/javascripts/extra/flash_notifies.js @@ -0,0 +1,18 @@ +function setCookie (name, value, expires, path, domain, secure) { + document.cookie = name + "=" + escape(value) + + ((expires) ? "; expires=" + expires : "") + + ((path) ? "; path=" + path : "") + + ((domain) ? "; domain=" + domain : "") + + ((secure) ? "; secure" : ""); +} + +$(document).ready(function() { + if ($(".alert").size()) { + $(".alert").alert() + } + + $('#close-alert').click(function () { + setCookie("flash_notify_hash", FLASH_HASH_ID, FLASH_EXPIRES_AT); + }); +}); + diff --git a/app/assets/stylesheets/design/custom.scss b/app/assets/stylesheets/design/custom.scss index 58c4a5414..9c9dcb0e0 100644 --- a/app/assets/stylesheets/design/custom.scss +++ b/app/assets/stylesheets/design/custom.scss @@ -1201,4 +1201,64 @@ hr.bootstrap { .line_numbers a { color: #999999; -} \ No newline at end of file +} + +/* Flash Notifies */ + +.flash_notify { + .alert-success { + color: #468847; + background-color: #DFF0D8; + border-color: #D6E9C6; + } + + .alert { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + color: #C09853; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #FCF8E3; + border: 1px solid #FBEED5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + } + + .alert-danger, .alert-error { + color: #B94A48; + background-color: #F2DEDE; + border-color: #EED3D7; + } + + .alert-info { + color: #3A87AD; + background-color: #D9EDF7; + border-color: #BCE8F1; + } + + .alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 18px; + } + + button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; + } + + .close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 18px; + color: black; + text-shadow: 0 1px 0 white; + opacity: 0.2; + filter: alpha(opacity=20); + } +} diff --git a/app/controllers/admin/flash_notifies_controller.rb b/app/controllers/admin/flash_notifies_controller.rb new file mode 100644 index 000000000..5946427bf --- /dev/null +++ b/app/controllers/admin/flash_notifies_controller.rb @@ -0,0 +1,41 @@ +class Admin::FlashNotifiesController < Admin::BaseController + def index + @flash_notifies = FlashNotify.paginate(:page => params[:page], :per_page => 20) + end + + def new + @flash_notify = FlashNotify.new(:published => true) + end + + def create + @flash_notify = FlashNotify.new(params[:flash_notify]) + if @flash_notify.save + flash[:notice] = t("flash.flash_notify.saved") + redirect_to admin_flash_notifies_path + else + flash[:error] = t("flash.flash_notify.save_error") + flash[:warning] = @flash_notify.errors.full_messages.join('. ') + render :new + end + end + + def update + if @flash_notify.update_attributes(params[:flash_notify]) + flash[:notice] = t("flash.flash_notify.saved") + redirect_to admin_flash_notifies_path + else + flash[:error] = t("flash.flash_notify.save_error") + flash[:warning] = @flash_notify.errors.full_messages.join('. ') + render :edit + end + end + + def destroy + if @flash_notify.destroy + flash[:notice] = t("flash.flash_notify.destroyed") + else + flash[:error] = t("flash.flash_notify.destroy_error") + end + redirect_to admin_flash_notifies_path + end +end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 91d5076b8..9e042ab3b 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -12,7 +12,7 @@ class Admin::UsersController < Admin::BaseController def create @user.role = params[:role] @user.confirmed_at = Time.now.utc - if @user.save + if (@user.save rescue false) flash[:notice] = t('flash.user.saved') redirect_to admin_users_path else diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 642ee629b..b191227aa 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -17,6 +17,7 @@ class ApplicationController < ActionController::Base rescue_from CanCan::AccessDenied do |exception| redirect_to forbidden_url, :alert => t("flash.exception_message") end + rescue_from Grit::NoSuchPathError, :with => :not_found protected @@ -53,4 +54,8 @@ class ApplicationController < ActionController::Base "application" end end + + def not_found + raise ActionController::RoutingError.new('Not Found') + end end diff --git a/app/controllers/projects/build_lists_controller.rb b/app/controllers/projects/build_lists_controller.rb index cb5115741..ce7364d52 100644 --- a/app/controllers/projects/build_lists_controller.rb +++ b/app/controllers/projects/build_lists_controller.rb @@ -46,7 +46,8 @@ class Projects::BuildListsController < Projects::BaseController Arch.where(:id => params[:arches]).each do |arch| Platform.main.where(:id => params[:build_for_platforms]).each do |build_for_platform| @build_list = @project.build_lists.build(params[:build_list]) - @build_list.commit_hash = @project.git_repository.commits(@build_list.project_version.match(/^latest_(.+)/).to_a.last || @build_list.project_version).first.id if @build_list.project_version + @build_list.commit_hash = @project.repo.commits(@build_list.project_version.match(/^latest_(.+)/).to_a.last || + @build_list.project_version).first.id if @build_list.project_version @build_list.build_for_platform = build_for_platform; @build_list.arch = arch; @build_list.user = current_user @build_list.include_repos = @build_list.include_repos.select {|ir| @build_list.build_for_platform.repository_ids.include? ir.to_i} @build_list.priority = current_user.build_priority # User builds more priority than mass rebuild with zero priority @@ -98,7 +99,6 @@ class Projects::BuildListsController < Projects::BaseController else @build_list.fail_publish end - render :nothing => true, :status => 200 end diff --git a/app/controllers/projects/comments_controller.rb b/app/controllers/projects/comments_controller.rb index 371365eb9..3b36c3456 100644 --- a/app/controllers/projects/comments_controller.rb +++ b/app/controllers/projects/comments_controller.rb @@ -41,7 +41,7 @@ class Projects::CommentsController < Projects::BaseController def find_commentable @commentable = params[:issue_id].present? && @project.issues.find_by_serial_id(params[:issue_id]) || - params[:commit_id].present? && @project.git_repository.commit(params[:commit_id]) + params[:commit_id].present? && @project.repo.commit(params[:commit_id]) end def find_or_build_comment diff --git a/app/controllers/projects/commit_subscribes_controller.rb b/app/controllers/projects/commit_subscribes_controller.rb index de5b2ac6e..b7dbc31c7 100644 --- a/app/controllers/projects/commit_subscribes_controller.rb +++ b/app/controllers/projects/commit_subscribes_controller.rb @@ -25,7 +25,7 @@ class Projects::CommitSubscribesController < Projects::BaseController protected def find_commit - @commit = @project.git_repository.commit(params[:commit_id]) + @commit = @project.repo.commit(params[:commit_id]) @options = {:project_id => @project.id, :subscribeable_id => @commit.id.hex, :subscribeable_type => @commit.class.name, :user_id => current_user.id} end end diff --git a/app/controllers/projects/git/base_controller.rb b/app/controllers/projects/git/base_controller.rb index 37168d764..a77c39ffd 100644 --- a/app/controllers/projects/git/base_controller.rb +++ b/app/controllers/projects/git/base_controller.rb @@ -4,36 +4,19 @@ class Projects::Git::BaseController < Projects::BaseController skip_before_filter :authenticate_user!, :only => [:show, :index, :blame, :raw, :archive] if APP_CONFIG['anonymous_access'] load_and_authorize_resource :project - before_filter :find_git_repository - before_filter :find_tags - before_filter :find_branches - before_filter :set_treeish - before_filter :set_current_tag - before_filter :set_current_branch + before_filter :set_treeish_and_path + before_filter :set_branch_and_tree protected - def find_git_repository - @git_repository = @project.git_repository - end - - def find_tags - @tags = @git_repository.tags - end - - def find_branches - @branches = @git_repository.branches - end - - def set_treeish + def set_treeish_and_path @treeish = params[:treeish].presence || @project.default_branch + @path = params[:path] end - def set_current_tag - @current_tag = @tags.select{|t| t.name == @treeish }.first - end - - def set_current_branch - @current_branch = @branches.select{|b| b.name == @treeish }.first + def set_branch_and_tree + @branch = @project.repo.branches.detect{|b| b.name == @treeish} + @tree = @project.repo.tree(@treeish) + # raise Grit::NoSuchPathError if @tree.blobs.blank? end end diff --git a/app/controllers/projects/git/blobs_controller.rb b/app/controllers/projects/git/blobs_controller.rb index b8abb0799..96dc586dc 100644 --- a/app/controllers/projects/git/blobs_controller.rb +++ b/app/controllers/projects/git/blobs_controller.rb @@ -1,34 +1,17 @@ # -*- encoding : utf-8 -*- class Projects::Git::BlobsController < Projects::Git::BaseController - before_filter :find_tree - before_filter :find_branch - before_filter :set_path_blob + before_filter :set_blob + before_filter lambda {authorize! :write, @project}, :only => [:edit, :update] def show - redirect_to project_path(@project) and return unless @blob.present? - if params[:raw] - response.headers['Cache-Control'] = "public, max-age=#{12.hours.to_i}" - response.headers['Content-Type'] = @blob.mime_type - response.headers['Content-Disposition'] = 'inline' - render(:text => @blob.data) and return - end end def edit - redirect_to project_path(@project) and return unless @blob.present? - authorize! :write, @project end def update - redirect_to project_path(@project) and return unless @blob.present? - authorize! :write, @project - # Here might be callbacks for notification purposes: - # @git_repository.after_update_file do |repo, sha| - # end - - res = @git_repository.update_file(params[:path], params[:content].gsub("\r", ''), - :message => params[:message].gsub("\r", ''), :actor => current_user, :head => @treeish) - if res + if @project.update_file(params[:path], params[:content].gsub("\r", ''), + :message => params[:message].gsub("\r", ''), :actor => current_user, :head => @treeish) flash[:notice] = t("flash.blob.successfully_updated", :name => params[:path]) else flash[:notice] = t("flash.blob.updating_error", :name => params[:path]) @@ -37,28 +20,17 @@ class Projects::Git::BlobsController < Projects::Git::BaseController end def blame - @blame = Grit::Blob.blame(@git_repository.repo, @commit.id, @path) + @blame = Grit::Blob.blame(@project.repo, @commit.id, @path) end def raw - redirect_to project_path(@project) and return unless @blob.present? - headers["Content-Disposition"] = %[attachment;filename="#{@blob.name}"] - render :text => @blob.data, :content_type => @blob.mime_type + send_data @blob.data, :type => @blob.content_type, :disposition => @blob.disposition end protected - def find_branch - @branch = @project.branch(@treeish) - end - - def set_path_blob - @path = params[:path] - @blob = @tree / @path - @commit = @git_repository.log(@treeish, @path, :max_count => 1).first - end - - def find_tree - @tree = @git_repository.tree(@treeish) + def set_blob + @blob = @tree / @path or raise Grit::NoSuchPathError + @commit = @project.repo.log(@treeish, @path, :max_count => 1).first end end diff --git a/app/controllers/projects/git/commits_controller.rb b/app/controllers/projects/git/commits_controller.rb index 7279a9065..31816996c 100644 --- a/app/controllers/projects/git/commits_controller.rb +++ b/app/controllers/projects/git/commits_controller.rb @@ -1,23 +1,15 @@ # -*- encoding : utf-8 -*- class Projects::Git::CommitsController < Projects::Git::BaseController - def index - @branch_name = params[:treeish] || @project.default_branch - @branch = @project.branch(@branch_name) - @path = params[:path] - if @path.present? - @commits = @git_repository.repo.log(@branch_name, @path) - @render_paginate = false + @commits = @project.repo.log(@treeish, @path) else - @commits, @page, @last_page = @git_repository.paginate_commits(@branch_name, :page => params[:page]) - @render_paginate = true + @commits, @page, @last_page = @project.paginate_commits(@treeish, :page => params[:page]) end end def show - @commit = @git_repository.commit(params[:id]) # @git_repository.commits(params[:id]).first - + @commit = @project.repo.commit(params[:id]) respond_to do |format| format.html format.diff { render :text => (@commit.diffs.map(&:diff).join("\n") rescue ''), :content_type => "text/plain" } diff --git a/app/controllers/projects/git/trees_controller.rb b/app/controllers/projects/git/trees_controller.rb index 9655ffd4b..45dae2aa1 100644 --- a/app/controllers/projects/git/trees_controller.rb +++ b/app/controllers/projects/git/trees_controller.rb @@ -1,32 +1,21 @@ # -*- encoding : utf-8 -*- class Projects::Git::TreesController < Projects::Git::BaseController + before_filter lambda{redirect_to @project if params[:treeish] == @project.default_branch and params[:path].blank?}, :only => 'show' + def show - redirect_to project_path(@project) and return if params[:treeish] == @project.default_branch and params[:path].blank? - - @path = params[:path] - @tree = @git_repository.tree(@treeish) - @branch = @project.branch(@treeish) - -# @commit = @git_repository.commits(@treeish, 1).first -# Raises Grit::Git::GitTimeout - @commit = @branch.present? ? @branch.commit() : @git_repository.log(@treeish, @path, :max_count => 1).first - render "empty" and return unless @commit - - @tree = @tree / @path if @path + @tree = @tree / @path if @path.present? + @commit = @branch.present? ? @branch.commit() : @project.repo.log(@treeish, @path, :max_count => 1).first + render 'empty' unless @commit end def archive - treeish = params[:treeish].presence || @project.default_branch - format = params[:format] || 'tar' - commit = @project.git_repository.log(treeish, nil, :max_count => 1).first - if !commit or !['tar', 'zip'].include?(format) - raise ActiveRecord::RecordNotFound#("Couldn't send Project archive with id=#{@project.id}, treeish=#{treeish} and format=#{format}") - end - name = "#{@project.owner.uname}-#{@project.name}#{@project.tags.include?(treeish) ? "-#{treeish}" : ''}-#{commit.id[0..19]}" - fullname = "#{name}.#{format == 'tar' ? 'tar.gz' : 'zip'}" + @commit = @project.repo.log(@treeish, nil, :max_count => 1).first + raise Grit::NoSuchPathError unless @commit + name = "#{@project.owner.uname}-#{@project.name}#{@project.repo.tags.include?(@treeish) ? "-#{@treeish}" : ''}-#{@commit.id[0..19]}" + fullname = "#{name}.#{params[:format] == 'tar' ? 'tar.gz' : 'zip'}" file = Tempfile.new fullname, 'tmp' - system("cd #{@project.path}; git archive --format=#{format} --prefix=#{name}/ #{treeish} #{format == 'tar' ? ' | gzip -9' : ''} > #{file.path}") + system("cd #{@project.path}; git archive --format=#{params[:format]} --prefix=#{name}/ #{@treeish} #{params[:format] == 'tar' ? ' | gzip -9' : ''} > #{file.path}") file.close - send_file file.path, :disposition => 'attachment', :type => "application/#{format == 'tar' ? 'x-tar-gz' : 'zip'}", :filename => fullname + send_file file.path, :disposition => 'attachment', :type => "application/#{params[:format] == 'tar' ? 'x-tar-gz' : 'zip'}", :filename => fullname end end diff --git a/app/controllers/projects/projects_controller.rb b/app/controllers/projects/projects_controller.rb index b948f5d7c..845d89ccb 100644 --- a/app/controllers/projects/projects_controller.rb +++ b/app/controllers/projects/projects_controller.rb @@ -1,11 +1,7 @@ # -*- encoding : utf-8 -*- class Projects::ProjectsController < Projects::BaseController before_filter :authenticate_user! - load_and_authorize_resource - # TODO WTF ? fork, update, sections not authorize - before_filter do |controller| - authorize! params[:action].to_sym, @project if params[:action] != 'index' - end + load_and_authorize_resource :id_param => :project_name # to force member actions load def index @projects = Project.accessible_by(current_ability, :membered) diff --git a/app/controllers/projects/pull_requests_controller.rb b/app/controllers/projects/pull_requests_controller.rb index f2f38bc4b..8f1ebdbb9 100644 --- a/app/controllers/projects/pull_requests_controller.rb +++ b/app/controllers/projects/pull_requests_controller.rb @@ -94,8 +94,7 @@ class Projects::PullRequestsController < Projects::BaseController #Maybe slow? ILIKE? items = Project.accessible_by(current_ability, :membered) items << PullRequest.default_base_project(@project) - logger.debug "items.count is #{items.count}" - items.select! {|e| Regexp.new(params[:term].downcase).match(e.name.downcase) && e.branches.count > 0} + items.select! {|e| Regexp.new(params[:term].downcase).match(e.name.downcase) && e.repo.branches.count > 0} items.uniq! render :json => json_for_autocomplete_base(items)#, :full_name, [:branches]) @@ -110,7 +109,7 @@ class Projects::PullRequestsController < Projects::BaseController def json_for_autocomplete_base items items.collect do |project| hash = {"id" => project.id.to_s, "label" => project.full_name, "value" => project.full_name} - hash[:refs] = project.branches_and_tags.map &:name + hash[:refs] = project.repo.branches_and_tags.map &:name hash end end diff --git a/app/helpers/git_helper.rb b/app/helpers/git_helper.rb index 0443fd232..039ac7716 100644 --- a/app/helpers/git_helper.rb +++ b/app/helpers/git_helper.rb @@ -4,7 +4,7 @@ module GitHelper def render_path # TODO: Looks ugly, rewrite with clear mind. if @path.present? - if @treeish == "master" + if @treeish == @project.default_branch res = "#{link_to @project.name, tree_path(@project)} / " else res = "#{link_to @project.name, tree_path(@project, @treeish)} / " @@ -36,22 +36,6 @@ module GitHelper res.html_safe end - def render_blob(blob) - blob.data.split("\n").collect do |line| - content_tag :div, line.present? ? h(line) : tag(:br) - end.join.html_safe - end - - def choose_render_way(blob) - case - when blob.mime_type.match(/image/); :image - when blob.binary?; :binary - else - @text = @blob.data.split("\n") - :text - end - end - def iterate_path(path, &block) path.split(File::SEPARATOR).inject('') do |a, e| if e != '.' and e != '..' @@ -63,7 +47,6 @@ module GitHelper end end - # TODO This is very dirty hack. Maybe need to be changed. def branch_selector_options(project) p = params.dup p.delete(:path) if p[:path].present? # to root path @@ -71,15 +54,21 @@ module GitHelper current = url_for(p).split('?', 2).first res = [] - res << [I18n.t('layout.git.repositories.commits'), [truncate(params[:treeish], :length => 20)]] unless (project.branches + project.tags).map(&:name).include?(params[:treeish] || project.default_branch) - res << [I18n.t('layout.git.repositories.branches'), project.branches.map{|b| [truncate(b.name, :length => 20), url_for(p.merge :treeish => b.name).split('?', 2).first]}] - res << [I18n.t('layout.git.repositories.tags'), project.tags.map{|t| [truncate(t.name, :length => 20), url_for(p.merge :treeish => t.name).split('?', 2).first]}] + res << [I18n.t('layout.git.repositories.commits'), [params[:treeish].truncate(20)]] unless project.repo.branches_and_tags.map(&:name).include?(params[:treeish] || project.default_branch) + linking = Proc.new {|t| [t.name.truncate(20), url_for(p.merge :treeish => t.name).split('?', 2).first]} + res << [I18n.t('layout.git.repositories.branches'), project.repo.branches.map(&linking)] + res << [I18n.t('layout.git.repositories.tags'), project.repo.tags.map(&linking)] grouped_options_for_select(res, current) end + def versions_for_group_select(project) + [ ['Branches', project.repo.branches.map{|b| "latest_#{b.name}"}], + ['Tags', project.repo.tags.map(&:name)] ] + end + def split_commits_by_date(commits) - res = commits.sort{|x, y| y.authored_date <=> x.authored_date}.inject({}) do |h, commit| + commits.sort{|x, y| y.authored_date <=> x.authored_date}.inject({}) do |h, commit| dt = commit.authored_date h[dt.year] ||= {} h[dt.year][dt.month] ||= {} @@ -87,7 +76,5 @@ module GitHelper h[dt.year][dt.month][dt.day] << commit h end - return res end - end diff --git a/app/helpers/pull_request_helper.rb b/app/helpers/pull_request_helper.rb index 670b774f1..7601e71a3 100644 --- a/app/helpers/pull_request_helper.rb +++ b/app/helpers/pull_request_helper.rb @@ -37,7 +37,7 @@ module PullRequestHelper end def ref_path project, ref - return tree_path(project, ref) if project.branches_and_tags.map(&:name).include? ref + return tree_path(project, ref) if project.repo.branches_and_tags.map(&:name).include? ref return commit_path(project, ref) if project.git_repository.commit ref '#' end diff --git a/app/models/activity_feed_observer.rb b/app/models/activity_feed_observer.rb index ca752aa57..829f28889 100644 --- a/app/models/activity_feed_observer.rb +++ b/app/models/activity_feed_observer.rb @@ -74,7 +74,7 @@ class ActivityFeedObserver < ActiveRecord::Observer change_type = record.change_type branch_name = record.refname.split('/').last - last_commits = record.project.git_repository.repo.log(branch_name, nil).first(3) + last_commits = record.project.repo.log(branch_name, nil).first(3) first_commiter = User.find_by_email(last_commits[0].author.email) unless last_commits.blank? last_commits = last_commits.collect do |commit| #:author => 'author' [commit.sha, commit.message] @@ -87,7 +87,7 @@ class ActivityFeedObserver < ActiveRecord::Observer else kind = 'git_new_push_notification' options = {:project_id => record.project.id, :project_name => record.project.name, :last_commits => last_commits, :branch_name => branch_name, - :change_type => change_type, :user_email => record.project.git_repository.repo.log(branch_name, nil).first.author.email, + :change_type => change_type, :user_email => record.project.repo.repo.log(branch_name, nil).first.author.email, :project_owner => record.project.owner.uname} options.merge!({:user_id => first_commiter.id, :user_name => first_commiter.name}) if first_commiter end diff --git a/app/models/build_list.rb b/app/models/build_list.rb index a3f0b416b..3df87673d 100644 --- a/app/models/build_list.rb +++ b/app/models/build_list.rb @@ -189,7 +189,7 @@ class BuildList < ActiveRecord::Base # TODO: remove 'return' after deployment ABF kernel 2.0 return if pkg.nil? # For old client that does not sends data about packages self.package_version = "#{pkg.platform.name}-#{pkg.version}-#{pkg.release}" - system("cd #{self.project.git_repository.path} && git tag #{self.package_version} #{self.commit_hash}") # TODO REDO through grit + system("cd #{self.project.repo.path} && git tag #{self.package_version} #{self.commit_hash}") # TODO REDO through grit save end diff --git a/app/models/build_list/filter.rb b/app/models/build_list/filter.rb index b6095fc71..48f0b59cc 100644 --- a/app/models/build_list/filter.rb +++ b/app/models/build_list/filter.rb @@ -20,15 +20,7 @@ class BuildList::Filter build_lists = build_lists.scoped_to_is_circle(@options[:is_circle]) if @options[:is_circle].present? build_lists = build_lists.scoped_to_project_name(@options[:project_name]) if @options[:project_name] build_lists = build_lists.by_mass_build(@options[:mass_build_id]) if @options[:mass_build_id] - -# TODO [BuildList#created_at filters] Uncomment here and in build_lists/_filter.html.haml to return filters -# -# if @options[:created_at_start] || @options[:created_at_end] -# build_lists = build_lists.for_creation_date_period(@options[:created_at_start], @options[:created_at_end]) -# end - if @options[:updated_at_start] || @options[:updated_at_end] - build_lists = build_lists.for_notified_date_period(@options[:updated_at_start], @options[:updated_at_end]) - end + build_lists = build_lists.for_notified_date_period(@options[:updated_at_start], @options[:updated_at_end]) if @options[:updated_at_start] || @options[:updated_at_end] end build_lists @@ -49,8 +41,6 @@ class BuildList::Filter @options = HashWithIndifferentAccess.new(options.reverse_merge({ :ownership => nil, :status => nil, - :created_at_start => nil, - :created_at_end => nil, :updated_at_start => nil, :updated_at_end => nil, :arch_id => nil, @@ -63,14 +53,12 @@ class BuildList::Filter })) @options[:ownership] = @options[:ownership].presence || (@project || !@user ? 'index' : 'owned') - @options[:status] = @options[:status].present? ? @options[:status].to_i : nil - @options[:created_at_start] = build_date_from_params(:created_at_start, @options) - @options[:created_at_end] = build_date_from_params(:created_at_end, @options) + @options[:status] = @options[:status].try(:to_i) @options[:updated_at_start] = build_date_from_params(:updated_at_start, @options) @options[:updated_at_end] = build_date_from_params(:updated_at_end, @options) @options[:project_version] = @options[:project_version].presence - @options[:arch_id] = @options[:arch_id].present? ? @options[:arch_id].to_i : nil - @options[:platform_id] = @options[:platform_id].present? ? @options[:platform_id].to_i : nil + @options[:arch_id] = @options[:arch_id].try(:to_i) + @options[:platform_id] = @options[:platform_id].try(:to_i) @options[:is_circle] = @options[:is_circle].present? ? @options[:is_circle] == "1" : nil @options[:bs_id] = @options[:bs_id].presence @options[:project_name] = @options[:project_name].presence diff --git a/app/models/comment.rb b/app/models/comment.rb index e5c22c36f..6960860cc 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -15,7 +15,9 @@ class Comment < ActiveRecord::Base attr_accessible :body def commentable - commit_comment? ? project.git_repository.commit(commentable_id.to_s(16)) : super + # raise commentable_id.inspect + # raise commentable_id.to_s(16).inspect + commit_comment? ? project.repo.commit(commentable_id.to_s(16)) : super # TODO leading zero problem end def commentable=(c) diff --git a/app/models/flash_notify.rb b/app/models/flash_notify.rb new file mode 100644 index 000000000..601b197b2 --- /dev/null +++ b/app/models/flash_notify.rb @@ -0,0 +1,24 @@ +require 'digest/md5' + +class FlashNotify < ActiveRecord::Base + # attr_accessible :title, :body + + STATUSES = %w[error success info] + + validates :status, :inclusion => {:in => STATUSES} + validates :body_ru, :body_en, :status, :presence => true + + scope :published, where(:published => true) + + def hash_id + @digest ||= Digest::MD5.hexdigest("#{self.id}-#{self.updated_at}") + end + + def body(language) + read_attribute("body_#{language}") + end + + def should_show?(cookie_hash_id) + cookie_hash_id != hash_id && published + end +end diff --git a/app/models/git/repository.rb b/app/models/git/repository.rb deleted file mode 100644 index 057ba4968..000000000 --- a/app/models/git/repository.rb +++ /dev/null @@ -1,130 +0,0 @@ -# -*- encoding : utf-8 -*- -class Git::Repository - delegate :commits, :commit, :tree, :tags, :heads, :commit_count, :log, :branches, :to => :repo - - attr_accessor :path, :name, :repo, :last_actor - - def initialize(path) - @path = path - @update_callbacks = [] - end - - def master - commits('master', 1).first - end - - def to_s - name - end - - def repo - @repo ||= Grit::Repo.new(path) rescue Grit::Repo.new(GAP_REPO_PATH) - end - - # Adds a callback to be fired after update file. - # - # block - A block that expects this Git::Repository instance and the created - # commit's SHA1 as the arguments. - # - # For example: - # - # after_update_file do |repo, sha| - # # callback body - # end - # - # Returns nothing. - def after_update_file(&block) - @update_callbacks << block - end - - # Writes file to repo and runs 'after_update_file' callbacks - # - # path - path to file in repository - # data - new content of file - # options - an optional Hash of options - # :head - branch name to write this commit to - # (Default: 'master') - # :actor - author of this commit. (See Git::Repository#get_actor) - # (Default: nil) - # :message - commit message - # (Default: "Updated file ") - # - # Returns commits sha if committing was successful and false otherwise - def update_file(path, data, options = {}) - head = options[:head].to_s || 'master' - actor = get_actor(options[:actor]) - filename = File.split(path).last - message = options[:message] - message = "Updated file #{filename}" if message.nil? or message.empty? - - # can not write to unexisted branch - return false if branches.select{|b| b.name == head}.size != 1 - - parent = commits(head).first - - index = repo.index - index.read_tree(parent.tree.id) - - # can not create new file - return false if (index.current_tree / path).nil? - - index.add(path, data) - sha = index.commit(message, :parents => [parent], :actor => actor, - :last_tree => parent.tree.id, :head => head) - # call all defined callbacks - @update_callbacks.each do |cb| - cb.call(self, sha) - end - sha - end - - def self.create(path) - repo = Grit::Repo.init_bare(path) - repo.enable_daemon_serve - end - - def paginate_commits(treeish, options = {}) - options[:page] = 1 unless options[:page].present? - options[:page] = options[:page].to_i - - options[:per_page] = 20 unless options[:per_page].present? - options[:per_page] = options[:per_page].to_i - - skip = options[:per_page] * (options[:page] - 1) - last_page = (skip + options[:per_page]) >= commit_count(treeish) - - [commits(treeish, options[:per_page], skip), options[:page], last_page] - end - - # Pretty object inspection - def inspect - %Q{#} - end - - protected - - # Creates new Grit::Actor instance - # - # Might be: - # * A Hash containing :name and :email - # * An instance of Grit::Actor - # * A String like "John Doe - # * Any object that responds to `name` and `email` methods - def get_actor(actor = nil) - @last_actor = case actor.class.to_s - when 'Grit::Actor' then options[:actor] - when 'Hash' then Grit::Actor.new(actor[:name], actor[:email]) - when 'String' then Grit::Actor.from_stirng(actor) - else begin - if actor.respond_to?(:name) and actor.respond_to?(:email) - Grit::Actor.new(actor.name, actor.email) - else - config = Grit::Config.new(repo) - Grit::Actor.new(config['user.name'], config['user.email']) - end - end - end - @last_actor - end - -end diff --git a/app/models/project.rb b/app/models/project.rb index 13f071fae..dd2c62f92 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -26,9 +26,6 @@ class Project < ActiveRecord::Base validates :owner, :presence => true validate { errors.add(:base, :can_have_less_or_equal, :count => MAX_OWN_PROJECTS) if owner.projects.size >= MAX_OWN_PROJECTS } - validates_attachment_size :srpm, :less_than => 500.megabytes - validates_attachment_content_type :srpm, :content_type => ['application/octet-stream', "application/x-rpm", "application/x-redhat-package-manager"], :message => I18n.t('layout.invalid_content_type') - attr_accessible :name, :description, :visibility, :srpm, :is_package, :default_branch, :has_issues, :has_wiki attr_readonly :name @@ -41,34 +38,50 @@ class Project < ActiveRecord::Base scope :addable_to_repository, lambda { |repository_id| where("projects.id NOT IN (SELECT project_to_repositories.project_id FROM project_to_repositories WHERE (project_to_repositories.repository_id = #{ repository_id }))") } after_create :attach_to_personal_repository - after_create :create_git_repo - after_save :create_wiki - after_commit(:on => :create) {|p| p.fork_git_repo unless p.is_root?} # later with resque - after_destroy :destroy_git_repo - after_destroy :destroy_wiki - after_commit(:on => :create) {|p| p.import_attached_srpm if p.srpm?}# later with resque # should be after create_git_repo - # after_rollback lambda { destroy_git_repo rescue true if new_record? } - - has_ancestry - - has_attached_file :srpm + has_ancestry :orphan_strategy => :rootify #:adopt not available yet include Modules::Models::Owner + include Modules::Models::Git + include Modules::Models::Wiki + + class << self + def find_by_owner_and_name(owner_name, project_name) + owner = User.find_by_uname(owner_name) || Group.find_by_uname(owner_name) || User.by_uname(owner_name).first || Group.by_uname(owner_name).first and + scoped = where(:owner_id => owner.id, :owner_type => owner.class) and + scoped.find_by_name(project_name) || scoped.by_name(project_name).first + # owner.projects.find_by_name(project_name) || owner.projects.by_name(project_name).first # TODO force this work? + end + + def find_by_owner_and_name!(owner_name, project_name) + find_by_owner_and_name(owner_name, project_name) or raise ActiveRecord::RecordNotFound + end + end def to_param name end - def self.find_by_owner_and_name(owner_name, project_name) - owner = User.find_by_uname(owner_name) || Group.find_by_uname(owner_name) || User.by_uname(owner_name).first || Group.by_uname(owner_name).first and - scoped = where(:owner_id => owner.id, :owner_type => owner.class) and - scoped.find_by_name(project_name) || scoped.by_name(project_name).first - # owner.projects.find_by_name(project_name) || owner.projects.by_name(project_name).first # TODO force this work? + def members + collaborators + groups.map(&:members).flatten end - def self.find_by_owner_and_name!(owner_name, project_name) - find_by_owner_and_name(owner_name, project_name) or raise ActiveRecord::RecordNotFound + def platforms + @platforms ||= repositories.map(&:platform).uniq + end + + def owner_and_admin_ids + recipients = self.relations.by_role('admin').where(:actor_type => 'User').map { |rel| rel.read_attribute(:actor_id) } + recipients = recipients | [self.owner_id] if self.owner_type == 'User' + recipients + end + + def public? + visibility == 'open' + end + + def owner?(user) + owner == user end def build_for(platform, user, arch = 'i586', auto_publish = false, mass_build_id = nil, priority = 0) @@ -94,90 +107,6 @@ class Project < ActiveRecord::Base end end - def tags - self.git_repository.tags #.sort_by{|t| t.name.gsub(/[a-zA-Z.]+/, '').to_i} - end - - def branches - self.git_repository.branches - end - - def branches_and_tags - #@branches_and_tags ||= branches + tags # ??? - branches + tags - end - - def last_active_branch - @last_active_branch ||= branches.inject do |r, c| - r_last = r.commit.committed_date || r.commit.authored_date unless r.nil? - c_last = c.commit.committed_date || c.commit.authored_date - if r.nil? or r_last < c_last - r = c - end - r - end - @last_active_branch - end - - def branch(name = nil) - name = default_branch if name.blank? - branches.select{|b| b.name == name}.first - end - - def tree_info(tree, treeish = nil, path = nil) - treeish = tree.id unless treeish.present? - # initialize result as hash of => nil - res = (tree.trees.sort + tree.blobs.sort).inject({}){|h, e| h.merge!({e => nil})} - # fills result vith commits that describes this file - res = res.inject(res) do |h, (entry, commit)| - # only if commit == nil ... - if commit.nil? and entry.respond_to? :name - # ... find last commit corresponds to this file ... - c = git_repository.log(treeish, File.join([path, entry.name].compact), :max_count => 1).first - # ... and add it to result. - h[entry] = c - # find another files, that linked to this commit and set them their commit - # c.diffs.map{|diff| diff.b_path.split(File::SEPARATOR, 2).first}.each do |name| - # h.each_pair do |k, v| - # h[k] = c if k.name == name and v.nil? - # end - # end - end - h - end - end - - def versions - tags.map(&:name) + branches.map{|b| "latest_#{b.name}"} - end - - def versions_for_group_select - [ - ['Branches', branches.map{|b| "latest_#{b.name}"}], - ['Tags', tags.map(&:name)] - ] - end - - def members - collaborators + groups.map(&:members).flatten - end - - def git_repository - @git_repository ||= Git::Repository.new(path) - end - - def git_repo_name - File.join owner.uname, name - end - - def wiki_repo_name - File.join owner.uname, "#{name}.wiki" - end - - def public? - visibility == 'open' - end - def fork(new_owner) dup.tap do |c| c.parent_id = id @@ -187,12 +116,8 @@ class Project < ActiveRecord::Base end end - def path - build_path(git_repo_name) - end - - def wiki_path - build_wiki_path(git_repo_name) + def human_average_build_time + I18n.t("layout.projects.human_average_build_time", {:hours => (average_build_time/3600).to_i, :minutes => (average_build_time%3600/60).to_i}) end def xml_rpc_create(repository) @@ -213,101 +138,9 @@ class Project < ActiveRecord::Base end end - def platforms - @platforms ||= repositories.map(&:platform).uniq - end - - def import_srpm(srpm_path = srpm.path, branch_name = 'import') - system("#{Rails.root.join('bin', 'import_srpm.sh')} #{srpm_path} #{path} #{branch_name} >> /dev/null 2>&1") - end - - def owner?(user) - owner == user - end - - def owner_and_admin_ids - recipients = self.relations.by_role('admin').where(:actor_type => 'User').map { |rel| rel.read_attribute(:actor_id) } - recipients = recipients | [self.owner_id] if self.owner_type == 'User' - recipients - end - - def human_average_build_time - time = average_build_time - I18n.t("layout.projects.human_average_build_time", {:hours => (time/3600).to_i, :minutes => (time%3600/60).to_i}) - end - - def full_name - @full_name ||= "#{owner.uname}/#{name}" - end - protected - def build_path(dir) - File.join(APP_CONFIG['root_path'], 'git_projects', "#{dir}.git") - end - - def build_wiki_path(dir) - File.join(APP_CONFIG['root_path'], 'git_projects', "#{dir}.wiki.git") - end - def attach_to_personal_repository repositories << self.owner.personal_repository if !repositories.exists?(:id => self.owner.personal_repository) end - - def create_git_repo - if is_root? - Grit::Repo.init_bare(path) - write_hook - end - end - - def fork_git_repo - dummy = Grit::Repo.new(path) rescue parent.git_repository.repo.fork_bare(path) - write_hook - end - later :fork_git_repo, :queue => :fork_import - - def destroy_git_repo - FileUtils.rm_rf path - end - - def import_attached_srpm - if srpm? - import_srpm # srpm.path - self.srpm = nil; save # clear srpm - end - end - later :import_attached_srpm, :queue => :fork_import - - def create_wiki - if has_wiki && !FileTest.exist?(wiki_path) - Grit::Repo.init_bare(wiki_path) - wiki = Gollum::Wiki.new(wiki_path, {:base_path => Rails.application.routes.url_helpers.project_wiki_index_path(owner, self)}) - wiki.write_page('Home', :markdown, I18n.t("wiki.seed.welcome_content"), - {:name => owner.name, :email => owner.email, :message => 'Initial commit'}) - end - end - - def destroy_wiki - FileUtils.rm_rf wiki_path - end - - def write_hook - is_production = Rails.env == "production" - hook = File.join(::Rails.root.to_s, 'tmp', "post-receive-hook") - FileUtils.cp(File.join(::Rails.root.to_s, 'bin', "post-receive-hook.partial"), hook) - File.open(hook, 'a') do |f| - s = "\n /bin/bash -l -c \"cd #{is_production ? '/srv/rosa_build/current' : Rails.root.to_s} && #{is_production ? 'RAILS_ENV=production' : ''} bundle exec rake hook:enqueue[$owner,$reponame,$newrev,$oldrev,$ref,$newrev_type,$oldrev_type]\"" - s << " > /dev/null 2>&1" if is_production - s << "\ndone\n" - f.write(s) - f.chmod(0755) - end - - hook_file = File.join(path, 'hooks', 'post-receive') - FileUtils.cp(hook, hook_file) - FileUtils.rm_rf(hook) - - rescue Exception # FIXME - end end diff --git a/app/models/pull_request.rb b/app/models/pull_request.rb index 59b1a61d8..d14daca0b 100644 --- a/app/models/pull_request.rb +++ b/app/models/pull_request.rb @@ -9,7 +9,7 @@ class PullRequest < ActiveRecord::Base validate :uniq_merge validates_each :head_ref, :base_ref do |record, attr, value| project = attr == :head_ref ? record.head_project : record.base_project - if !((project.branches + project.tags).map(&:name).include?(value) || project.git_repository.commits.map(&:id).include?(value)) + if !((project.repo.branches_and_tags).map(&:name).include?(value) || project.git_repository.commits.map(&:id).include?(value)) record.errors.add attr, I18n.t('projects.pull_requests.wrong_ref') end end @@ -194,13 +194,13 @@ class PullRequest < ActiveRecord::Base def clean Dir.chdir(path) do - base_project.branches.each {|branch| system 'git', 'checkout', branch.name} + base_project.repo.branches.each {|branch| system 'git', 'checkout', branch.name} system 'git', 'checkout', base_ref - base_project.branches.each do |branch| + base_project.repo.branches.each do |branch| system 'git', 'branch', '-D', branch.name unless [base_ref, head_branch].include? branch.name end - base_project.tags.each do |tag| + base_project.repo.tags.each do |tag| system 'git', 'tag', '-d', tag.name unless [base_ref, head_branch].include? tag.name end end diff --git a/app/views/admin/flash_notifies/_form.html.haml b/app/views/admin/flash_notifies/_form.html.haml new file mode 100644 index 000000000..c609dd20b --- /dev/null +++ b/app/views/admin/flash_notifies/_form.html.haml @@ -0,0 +1,21 @@ +.leftlist= f.label :body_ru, t("activerecord.attributes.flash_notify.body_ru"), :class => :label +.rightlist= f.text_area :body_ru, :class => 'text_field' +.both + +.leftlist= f.label :body_en, t("activerecord.attributes.flash_notify.body_en"), :class => :label +.rightlist= f.text_area :body_en, :class => 'text_field' +.both + +.leftlist= f.label :status, t("activerecord.attributes.flash_notify.status"), :class => :label +.rightlist= f.select :status, FlashNotify::STATUSES +.both + +.leftlist= f.label :published, t("activerecord.attributes.flash_notify.published"), :class => :label +.rightlist= f.check_box :published +.both + +.button_block + = submit_tag t("layout.save") + %span.text_button_padding= t("layout.or") + = link_to t("layout.cancel"), admin_flash_notifies_path, :class => "button" + diff --git a/app/views/admin/flash_notifies/edit.html.haml b/app/views/admin/flash_notifies/edit.html.haml new file mode 100644 index 000000000..a1f10e1cd --- /dev/null +++ b/app/views/admin/flash_notifies/edit.html.haml @@ -0,0 +1,6 @@ +%h3= t("layout.flash_notifies.edit_header") + += form_for @flash_notify, :url => admin_flash_notify_path(@flash_notify), :html => { :class => :form } do |f| + = render "form", :f => f + += render 'submenu' diff --git a/app/views/admin/flash_notifies/index.html.haml b/app/views/admin/flash_notifies/index.html.haml new file mode 100644 index 000000000..9578d1a0e --- /dev/null +++ b/app/views/admin/flash_notifies/index.html.haml @@ -0,0 +1,22 @@ += link_to t("layout.flash_notifies.new"), new_admin_flash_notify_path, :class => 'button' if can? :create, FlashNotify + +%table#myTable.tablesorter.flash_notifys{:cellspacing => "0", :cellpadding => "0"} + %thead + %tr + %th.th1= t("activerecord.attributes.flash_notify.body_en") + %th.th2= t("activerecord.attributes.flash_notify.body_ru") + %th.th3= t("activerecord.attributes.flash_notify.published") + %th.th3= t("layout.flash_notifies.actions") + %tbody + - @flash_notifies.each do |flash_notify| + %tr{:class => cycle("odd", "even")} + %td= flash_notify.body_en.truncate 18 + %td= flash_notify.body_ru.truncate 18 + %td= flash_notify.published + %td + = link_to t("layout.flash_notifies.edit"), edit_admin_flash_notify_path(flash_notify) + = link_to t("layout.flash_notifies.delete"), admin_flash_notify_path(flash_notify), :method => :delete, :confirm => t("layout.mass_builds.cancel_confirm") if can?(:delete, flash_notify) + += will_paginate @flash_notifies + += render 'submenu' diff --git a/app/views/admin/flash_notifies/new.html.haml b/app/views/admin/flash_notifies/new.html.haml new file mode 100644 index 000000000..0177e384e --- /dev/null +++ b/app/views/admin/flash_notifies/new.html.haml @@ -0,0 +1,6 @@ +%h3= t("layout.flash_notifies.new_header") + += form_for @flash_notify, :url => admin_flash_notifies_path, :html => { :class => :form } do |f| + = render "form", :f => f + += render 'submenu' diff --git a/app/views/layouts/_notifies.html.haml b/app/views/layouts/_notifies.html.haml new file mode 100644 index 000000000..82ca70300 --- /dev/null +++ b/app/views/layouts/_notifies.html.haml @@ -0,0 +1,10 @@ +- if current_user || APP_CONFIG['anonymous_access'] + .flash_notify + - if (flash_notify = FlashNotify.published.first) && flash_notify.should_show?(cookies[:flash_notify_hash]) + .alert{:class => "alert-#{flash_notify.status}"} + = flash_notify.body I18n.locale + %a.close#close-alert{:'data-dismiss'=>"alert", :href=>"#"} × + + :javascript + var FLASH_HASH_ID = "#{flash_notify.hash_id}"; + var FLASH_EXPIRES_AT = "#{Date.today + 1.year}"; diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 9bce9bc2b..9f62ca9a2 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -47,6 +47,7 @@ = yield :feed_tabs .both = render "layouts/flashes" + = render "layouts/notifies" %article - if content_for?(:sidebar) %aside= yield :sidebar diff --git a/app/views/projects/base/_repo_block.html.haml b/app/views/projects/base/_repo_block.html.haml index 0870762d5..f301d63b3 100644 --- a/app/views/projects/base/_repo_block.html.haml +++ b/app/views/projects/base/_repo_block.html.haml @@ -6,8 +6,8 @@ =image_tag 'zip.png', :alt => 'ZIP' %b.caret %ul.dropdown-menu - %li=link_to "tar.gz", archive_path(project, 'tar', @treeish) - %li=link_to "zip", archive_path(project, 'zip', @treeish) + %li=link_to "tar.gz", archive_path(project, @treeish, 'tar') + %li=link_to "zip", archive_path(project, @treeish, 'zip') = text_field_tag :url, git_repo_url(project.git_repo_name), :class => 'name', :spellcheck => 'false', :readonly => true .git_help ? diff --git a/app/views/projects/base/_submenu.html.haml b/app/views/projects/base/_submenu.html.haml index fa0c0580f..e98955ad1 100644 --- a/app/views/projects/base/_submenu.html.haml +++ b/app/views/projects/base/_submenu.html.haml @@ -1,12 +1,12 @@ - content_for :submenu do - - act = action_name.to_sym; contr = controller_name.to_sym + - act = action_name.to_sym; contr = controller_name.to_sym; treeish = params[:treeish].presence || @project.default_branch .left .table-sort-left=image_tag visibility_icon(@project.visibility) .table-sort-right=@project.name %nav %ul - %li= link_to t("project_menu.project"), project_path(@project), :class => (act.in?([:show, :edit]) && contr.in?([:trees, :blobs]) ? 'active' : nil) - %li= link_to t("project_menu.commits"), commits_path(@project), :class => (act.in?([:index, :show]) && contr == :commits ? 'active' : nil) + %li= link_to t("project_menu.project"), tree_path(@project, treeish), :class => (act.in?([:show, :edit]) && contr.in?([:trees, :blobs]) ? 'active' : nil) + %li= link_to t("project_menu.commits"), commits_path(@project, treeish), :class => (act.in?([:index, :show]) && contr == :commits ? 'active' : nil) - if @project.is_package and can?(:read, @project => BuildList) %li= link_to t("project_menu.builds"), project_build_lists_path(@project), :class => (contr == :build_lists ? 'active' : nil) - if @project.has_issues diff --git a/app/views/projects/build_lists/new.html.haml b/app/views/projects/build_lists/new.html.haml index 10024025a..ccda36113 100644 --- a/app/views/projects/build_lists/new.html.haml +++ b/app/views/projects/build_lists/new.html.haml @@ -13,10 +13,7 @@ %h3= t("activerecord.attributes.build_list.save_to_platform") .lineForm= f.select :save_to_platform_id, @project.repositories.collect{|r| ["#{r.platform.name}/#{r.name}", r.platform.id]} %h3= t("activerecord.attributes.build_list.project_version") - - if controller.action_name == 'new' - .lineForm= f.select :project_version, @project.versions_for_group_select, :selected => "latest_" + @project.default_branch - - else - .lineForm= f.select :project_version, @project.versions_for_group_select + .lineForm= f.select :project_version, versions_for_group_select(@project), :selected => params[:build_list].try(:fetch, :project_version) || "latest_" + @project.default_branch %h3= t("activerecord.attributes.build_list.arch") - Arch.recent.each do |arch| .both diff --git a/app/views/projects/build_lists/show.html.haml b/app/views/projects/build_lists/show.html.haml index f061efcf3..f0f3f1d19 100644 --- a/app/views/projects/build_lists/show.html.haml +++ b/app/views/projects/build_lists/show.html.haml @@ -35,7 +35,7 @@ .both .leftlist= t("activerecord.attributes.build_list.update_type") .rightlist - - if @build_list.can_publish? and can?(:publish, @build_list) + - if @build_list.can_publish? && can?(:publish, @build_list) = f.select :update_type, options_for_select(build_list_classified_update_types, @build_list.update_type) - else = @build_list.update_type @@ -81,11 +81,11 @@ = "#{@build_list.human_current_duration} / #{@build_list.project.human_average_build_time}" .both - - if @build_list.can_cancel? and can?(:cancel, @build_list) + - if @build_list.can_cancel? && can?(:cancel, @build_list) = link_to t("layout.build_lists.cancel"), cancel_build_list_path(@build_list), :method => :put, :confirm => t("layout.confirm"), :class => 'button' - - if @build_list.can_publish? and @build_list.save_to_platform.released and @build_list.advisory.nil? + - if @build_list.can_publish? && @build_list.save_to_platform.released && @build_list.advisory.nil? && can?(:publish, @build_list) #advisory_block .leftlist= label_tag :attach_advisory, t("layout.build_lists.attached_advisory") .rightlist @@ -123,8 +123,8 @@ var r = new Rosa.Routers.BuildListsAdvisoriesRouter(); }); - = submit_tag t("layout.publish"), :confirm => t("layout.confirm"), :name => 'publish' if @build_list.can_publish? and can?(:publish, @build_list) - = submit_tag t("layout.reject_publish"), :confirm => t("layout.confirm"), :name => 'reject_publish' if @build_list.can_reject_publish? and can?(:reject_publish, @build_list) + = submit_tag t("layout.publish"), :confirm => t("layout.confirm"), :name => 'publish' if @build_list.can_publish? && can?(:publish, @build_list) + = submit_tag t("layout.reject_publish"), :confirm => t("layout.confirm"), :name => 'reject_publish' if @build_list.can_reject_publish? && can?(:reject_publish, @build_list) .hr %h3= t("layout.build_lists.items_header") diff --git a/app/views/projects/git/blobs/_editor.html.haml b/app/views/projects/git/blobs/_editor.html.haml index 874945aee..1298ff0c0 100644 --- a/app/views/projects/git/blobs/_editor.html.haml +++ b/app/views/projects/git/blobs/_editor.html.haml @@ -4,7 +4,7 @@ = render 'fork' .both -= form_tag blob_path(@project, @treeish, @path), :name => 'blob-editor', :method => :put do += form_tag edit_blob_path(@project, @treeish, @path), :name => 'blob-editor', :method => :put do .file= text_area_tag :content, @blob.data, :id => 'code' .both diff --git a/app/views/projects/git/blobs/_render_as_binary.html.haml b/app/views/projects/git/blobs/_render_as_binary.html.haml new file mode 100644 index 000000000..bd7379a10 --- /dev/null +++ b/app/views/projects/git/blobs/_render_as_binary.html.haml @@ -0,0 +1,8 @@ +%table.table.blob + %tr + %td.lines + %td.blob + :plain +
+
#{link_to @blob.basename, raw_path(@project, @treeish, @path)}
+
\ No newline at end of file diff --git a/app/views/projects/git/blobs/_render_as_image.html.haml b/app/views/projects/git/blobs/_render_as_image.html.haml new file mode 100644 index 000000000..ae1ef4884 --- /dev/null +++ b/app/views/projects/git/blobs/_render_as_image.html.haml @@ -0,0 +1,8 @@ +%table.table.blob + %tr + %td.lines + %td.blob + :plain +
+
+
\ No newline at end of file diff --git a/app/views/projects/git/blobs/_render_as_text.html.haml b/app/views/projects/git/blobs/_render_as_text.html.haml new file mode 100644 index 000000000..3105d704e --- /dev/null +++ b/app/views/projects/git/blobs/_render_as_text.html.haml @@ -0,0 +1,6 @@ +.gutter= render_line_numbers(@blob.loc) +#output.formatted.cm-s-default + %pre#code + :preserve + #{h(@blob.data).html_safe} +.both diff --git a/app/views/projects/git/blobs/_show.html.haml b/app/views/projects/git/blobs/_show.html.haml index f867189fd..b808cefc1 100644 --- a/app/views/projects/git/blobs/_show.html.haml +++ b/app/views/projects/git/blobs/_show.html.haml @@ -4,37 +4,10 @@ = render 'fork' .both -- render_way = choose_render_way(@blob) .file - .top= render 'top', :render_way => render_way - .data - - case render_way - - when :image - %table.table.blob - %tr - %td.lines - %td.blob - :plain -
-
-
- - when :text - .gutter= render_line_numbers(@text.length) - #output.formatted.cm-s-default - %pre#code - =#{render_blob(@blob)} - :preserve - #{h(@blob.data).html_safe} - .both - - when :binary - %table.table.blob - %tr - %td.lines - %td.blob - :plain -
-
#{ link_to @blob.basename, raw_path(@project, @treeish, @path) }
-
+ .top= render 'top' + .data= render "render_as_#{@blob.render_as}" + :javascript $(document).ready(function() { var text = $('#code').text().replace(/&/gi, '&'); diff --git a/app/views/projects/git/blobs/_top.html.haml b/app/views/projects/git/blobs/_top.html.haml index 8073aa9db..3fa62790b 100644 --- a/app/views/projects/git/blobs/_top.html.haml +++ b/app/views/projects/git/blobs/_top.html.haml @@ -1,20 +1,20 @@ .l = @blob.mode \| - - if render_way == :text - #{@text.length} lines (#{@text.select{|s| s.strip.length > 0}.length} sloc) + - if @blob.render_as == :text + #{@blob.loc} lines (#{@blob.sloc} sloc) \| = number_to_human_size @blob.size .r - - if render_way == :text and can? :write, @project and @treeish.in? @project.branches.map(&:name) + - if @blob.render_as == :text && can?(:write, @project) && @branch.present? = link_to "Edit", edit_blob_path(@project, @treeish, @path) \| - - if render_way == :text and params[:action] != 'show' + - if @blob.render_as == :text && params[:action] != 'show' = link_to "Normal", blob_path(@project, @treeish, @path) \| = link_to "Raw", raw_path(@project, @treeish, @path) \| - - if render_way == :text and params[:action] != 'blame' + - if @blob.render_as == :text && params[:action] != 'blame' = link_to "Blame", blame_path(@project, @treeish, @path) \| = link_to "History", commits_path(@project, @treeish, @path) diff --git a/app/views/projects/git/blobs/blame.html.haml b/app/views/projects/git/blobs/blame.html.haml index 81fef4b00..9f19328e8 100644 --- a/app/views/projects/git/blobs/blame.html.haml +++ b/app/views/projects/git/blobs/blame.html.haml @@ -20,7 +20,6 @@ .l= render 'whereami' .both - - render_way = choose_render_way(@blob) .file - .top= render 'top', :render_way => render_way + .top= render 'top' .blame_data= render 'blame_table' if @blame.first.first.present? diff --git a/app/views/projects/git/commits/_commit_diff.html.haml b/app/views/projects/git/commits/_commit_diff.html.haml index f95850f84..8537ff1a7 100644 --- a/app/views/projects/git/commits/_commit_diff.html.haml +++ b/app/views/projects/git/commits/_commit_diff.html.haml @@ -7,4 +7,4 @@ .r= link_to "view file @ #{short_hash_id(commit_id)}", blob_path(@project, commit_id, commit_diff.b_path) .clear - .diff_data= render_diff(commit_diff, commit_diff_counter) unless (@git_repository.tree(commit_id) / commit_diff.b_path).binary? \ No newline at end of file + .diff_data= render_diff(commit_diff, commit_diff_counter) unless (@project.repo.tree(commit_id) / commit_diff.b_path).binary? diff --git a/app/views/projects/git/commits/_show.html.haml b/app/views/projects/git/commits/_show.html.haml index 9e6e6a30c..9815b5e2d 100644 --- a/app/views/projects/git/commits/_show.html.haml +++ b/app/views/projects/git/commits/_show.html.haml @@ -13,7 +13,6 @@ -begin = render_commit_stats(stats) - = render :partial => 'commit_diff', :collection => @commit.diffs - rescue Grit::Git::GitTimeout %p= t 'layout.git.repositories.commit_diff_too_big' diff --git a/app/views/projects/git/commits/index.html.haml b/app/views/projects/git/commits/index.html.haml index f3f9cca11..e8221fb1e 100644 --- a/app/views/projects/git/commits/index.html.haml +++ b/app/views/projects/git/commits/index.html.haml @@ -3,4 +3,4 @@ = render 'repo_block', :project => @project = render :partial => 'commits', :object => @commits -= render 'paginate' if @render_paginate += render 'paginate' if @path.blank? diff --git a/app/views/projects/git/trees/_show.html.haml b/app/views/projects/git/trees/_show.html.haml index 2bf2868aa..35bae8bea 100644 --- a/app/views/projects/git/trees/_show.html.haml +++ b/app/views/projects/git/trees/_show.html.haml @@ -31,7 +31,7 @@ .pic= image_tag 'folder.png' .name= link_to(entry.name, tree_path(@project, @treeish, entry_path), :class => 'files-see') %td - %span{:style => "display: none;"}= commit.committed_date || commit.authored_date - = l(commit.committed_date || commit.authored_date, :format => :short) + %span{:style => "display: none;"}= date = commit.committed_date || commit.authored_date + = l(date, :format => :short) %td= commit.short_message %td= (commit.committer || commit.author).name \ No newline at end of file diff --git a/app/views/projects/projects/_form.html.haml b/app/views/projects/projects/_form.html.haml index ffede9552..9a7b90ba2 100644 --- a/app/views/projects/projects/_form.html.haml +++ b/app/views/projects/projects/_form.html.haml @@ -35,7 +35,7 @@ .both - if [:edit, :update].include? act .leftlist= t("activerecord.attributes.project.default_branch") - .rightlist= f.select :default_branch, options_from_collection_for_select(@project.branches, :name, :name, @project.default_branch), :class => 'sel80', :id => 'branch_selector' + .rightlist= f.select :default_branch, options_from_collection_for_select(@project.repo.branches, :name, :name, @project.default_branch), :class => 'sel80', :id => 'branch_selector' .both - if [:edit, :update].include? act .leftlist diff --git a/app/views/projects/pull_requests/new.html.haml b/app/views/projects/pull_requests/new.html.haml index 67d789c00..9045c6562 100644 --- a/app/views/projects/pull_requests/new.html.haml +++ b/app/views/projects/pull_requests/new.html.haml @@ -51,10 +51,10 @@ :javascript $(function() { $('input#base_refs').autocomplete({ - source: #{@pull.base_project.branches_and_tags.map &:name} + source: #{@pull.base_project.repo.branches_and_tags.map &:name} }); $('input#head_refs').autocomplete({ - source: #{@project.branches_and_tags.map &:name} + source: #{@project.repo.branches_and_tags.map &:name} }); }); diff --git a/app/views/users/base/_form.html.haml b/app/views/users/base/_form.html.haml index d88807a92..4baa5218e 100644 --- a/app/views/users/base/_form.html.haml +++ b/app/views/users/base/_form.html.haml @@ -43,5 +43,5 @@ .both .leftlist \  -.rightlist= submit_tag t("layout.save") +.rightlist= submit_tag t("layout.save"), :data => {:"disable-with" => t("layout.saving")} .both diff --git a/config/locales/en.yml b/config/locales/en.yml index bd6cea0e7..155b48e71 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -26,6 +26,7 @@ en: delete: Erase delete_selected: Remove selected save: Save + saving: Saving clone: Clone search_by_name: Filter by name are_you_sure: "Sure?" diff --git a/config/locales/menu.en.yml b/config/locales/menu.en.yml index 76bc4dac8..ef0afde9e 100644 --- a/config/locales/menu.en.yml +++ b/config/locales/menu.en.yml @@ -38,5 +38,6 @@ en: admins_menu: users: Users register_requests: Invites + flash_notifies: Notifies event_logs: Event log resque_server: Resque diff --git a/config/locales/menu.ru.yml b/config/locales/menu.ru.yml index 928a8783f..2d8dd42d0 100644 --- a/config/locales/menu.ru.yml +++ b/config/locales/menu.ru.yml @@ -38,5 +38,6 @@ ru: admins_menu: users: Пользователи register_requests: Инвайты + flash_notifies: Оповещения event_logs: Лог событий resque_server: Resque diff --git a/config/locales/models/flash_notify.en.yml b/config/locales/models/flash_notify.en.yml new file mode 100644 index 000000000..50f5ac06c --- /dev/null +++ b/config/locales/models/flash_notify.en.yml @@ -0,0 +1,28 @@ +en: + layout: + flash_notifies: + list_header: Notifies + new: New notify + new_header: New notify + actions: Actions + edit: Edit + edit_header: Edit notify + delete: Delete + + flash: + flash_notify: + saved: Notify added + save_error: Unable to add notify + destroyed: Notify deleted + + activerecord: + models: + flash_notify: Notify + attributes: + flash_notify: + body_ru: Body Ru + body_en: Body En + published: Published + status: Status + created_at: Created + updated_at: Updated diff --git a/config/locales/models/flash_notify.ru.yml b/config/locales/models/flash_notify.ru.yml new file mode 100644 index 000000000..b2be708c1 --- /dev/null +++ b/config/locales/models/flash_notify.ru.yml @@ -0,0 +1,28 @@ +ru: + layout: + flash_notifies: + list_header: Оповещения + new: Новое оповещение + new_header: Новое оповещение + actions: Действия + edit: Редактирование + edit_header: Редактировать оповещение + delete: Удалить + + flash: + flash_notify: + saved: Оповещение сохранено + save_error: Не получилось сохранить оповещение + destroyed: Оповещение удалено + + activerecord: + models: + flash_notify: Оповещение + attributes: + flash_notify: + body_ru: Текст Ru + body_en: Текст En + published: Опубликовано + status: Статус + created_at: Создано + updated_at: Обновлено diff --git a/config/locales/ru.yml b/config/locales/ru.yml index ebb485db3..240ef889f 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -26,6 +26,7 @@ ru: delete: Удалить delete_selected: Удалить выбранное save: Сохранить + saving: Сохранение... clone: Клонировать search_by_name: Фильтр по имени are_you_sure: "Вы уверены?" diff --git a/config/routes.rb b/config/routes.rb index a35d9e419..27b36851d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -32,8 +32,9 @@ Rosa::Application.routes.draw do get :reject end end + resources :flash_notifies resources :event_logs, :only => :index - constraints AdminAccess do + constraints Rosa::Constraints::AdminAccess do mount Resque::Server => 'resque' end end @@ -133,7 +134,6 @@ Rosa::Application.routes.draw do end resources :projects, :only => [:index, :new, :create] - scope ':owner_name/:project_name', :constraints => {:project_name => Project::NAME_REGEXP} do # project scope :as => 'project' do resources :wiki do @@ -188,7 +188,7 @@ Rosa::Application.routes.draw do end # Resource - get '/edit' => 'projects#edit', :as => :edit_project + get '/modify' => 'projects#edit', :as => :edit_project put '/' => 'projects#update' delete '/' => 'projects#destroy' # Member @@ -196,41 +196,43 @@ Rosa::Application.routes.draw do get '/sections' => 'projects#sections', :as => :sections_project post '/sections' => 'projects#sections' delete '/remove_user' => 'projects#remove_user', :as => :remove_user_project - constraints :treeish => /[^\/]+/ do - # Tree - get '/' => "git/trees#show", :as => :project - get '/tree/:treeish(/*path)' => "git/trees#show", :defaults => {:treeish => :master}, :as => :tree, :format => false - # Commits - get '/commits/:treeish(/*path)' => "git/commits#index", :defaults => {:treeish => :master}, :as => :commits, :format => false - get '/commit/:id(.:format)' => "git/commits#show", :as => :commit - # Commit comments - post '/commit/:commit_id/comments(.:format)' => "comments#create", :as => :project_commit_comments - get '/commit/:commit_id/comments/:id(.:format)' => "comments#edit", :as => :edit_project_commit_comment - put '/commit/:commit_id/comments/:id(.:format)' => "comments#update", :as => :project_commit_comment - delete '/commit/:commit_id/comments/:id(.:format)' => "comments#destroy" - # Commit subscribes - post '/commit/:commit_id/subscribe' => "commit_subscribes#create", :as => :subscribe_commit - delete '/commit/:commit_id/unsubscribe' => "commit_subscribes#destroy", :as => :unsubscribe_commit - # Editing files - get '/blob/:treeish/*path/edit' => "git/blobs#edit", :defaults => {:treeish => :master}, :as => :edit_blob - put '/blob/:treeish/*path' => "git/blobs#update", :defaults => {:treeish => :master}, :format => false - # Blobs - get '/blob/:treeish/*path' => "git/blobs#show", :defaults => {:treeish => :master}, :as => :blob, :format => false - # Blame - get '/blame/:treeish/*path' => "git/blobs#blame", :defaults => {:treeish => :master}, :as => :blame, :format => false - # Raw - get '/raw/:treeish/*path' => "git/blobs#raw", :defaults => {:treeish => :master}, :as => :raw, :format => false - # Archive - get '/archive/:format/tree/:treeish' => "git/trees#archive", :defaults => {:treeish => :master}, :as => :archive, :format => /zip|tar/ + constraints :treeish => /.+/ do + constraints Rosa::Constraints::Treeish do + # Tree + get '/' => "git/trees#show", :as => :project + get '/tree/:treeish(/*path)' => "git/trees#show", :as => :tree, :format => false + # Commits + get '/commits/:treeish(/*path)' => "git/commits#index", :as => :commits, :format => false + get '/commit/:id(.:format)' => "git/commits#show", :as => :commit + # Commit comments + post '/commit/:commit_id/comments(.:format)' => "comments#create", :as => :project_commit_comments + get '/commit/:commit_id/comments/:id(.:format)' => "comments#edit", :as => :edit_project_commit_comment + put '/commit/:commit_id/comments/:id(.:format)' => "comments#update", :as => :project_commit_comment + delete '/commit/:commit_id/comments/:id(.:format)' => "comments#destroy" + # Commit subscribes + post '/commit/:commit_id/subscribe' => "commit_subscribes#create", :as => :subscribe_commit + delete '/commit/:commit_id/unsubscribe' => "commit_subscribes#destroy", :as => :unsubscribe_commit + # Editing files + get '/edit/:treeish/*path' => "git/blobs#edit", :as => :edit_blob, :format => false + put '/edit/:treeish/*path' => "git/blobs#update", :format => false + # Blobs + get '/blob/:treeish/*path' => "git/blobs#show", :as => :blob, :format => false + # Blame + get '/blame/:treeish/*path' => "git/blobs#blame", :as => :blame, :format => false + # Raw + get '/raw/:treeish/*path' => "git/blobs#raw", :as => :raw, :format => false + # Archive + get '/archive/:treeish.:format' => "git/trees#archive", :as => :archive, :format => /zip|tar/ + end end end end scope ':uname' do # project owner profile - constraints OwnerConstraint.new(User) do + constraints Rosa::Constraints::Owner.new(User) do get '/' => 'users/profile#show', :as => :user end - constraints OwnerConstraint.new(Group, true) do + constraints Rosa::Constraints::Owner.new(Group, true) do get '/' => 'groups/profile#show', :as => :group end end diff --git a/db/migrate/20120719045806_create_flash_notifies.rb b/db/migrate/20120719045806_create_flash_notifies.rb new file mode 100644 index 000000000..2a9f16a29 --- /dev/null +++ b/db/migrate/20120719045806_create_flash_notifies.rb @@ -0,0 +1,11 @@ +class CreateFlashNotifies < ActiveRecord::Migration + def change + create_table :flash_notifies do |t| + t.text :body_ru, :null => false + t.text :body_en, :null => false + t.string :status, :null => false + t.boolean :published, :null => false, :default => true + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index cafd05648..a4126a632 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 => 20120703101719) do +ActiveRecord::Schema.define(:version => 20120719045806) do create_table "activity_feeds", :force => true do |t| t.integer "user_id", :null => false @@ -159,6 +159,15 @@ ActiveRecord::Schema.define(:version => 20120703101719) do t.datetime "updated_at", :null => false end + create_table "flash_notifies", :force => true do |t| + t.text "body_ru", :null => false + t.text "body_en", :null => false + t.string "status", :null => false + t.boolean "published", :default => true, :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + create_table "groups", :force => true do |t| t.integer "owner_id" t.datetime "created_at", :null => false diff --git a/doc/README_FOR_APP b/doc/README_FOR_APP index 8458ee4f1..cca71ab75 100644 --- a/doc/README_FOR_APP +++ b/doc/README_FOR_APP @@ -21,4 +21,8 @@ Add to /etc/rc.d/rc.sysinit sudo urpmi lib64icu-devel # mandriva gem install charlock_holmes -- --with-icu-dir=/opt/local # macports +sudo urpmi lib64magic-devel # mandriva +brew install libmagic; brew link libmagic # brew +gem install ruby-filemagic + git config --global core.quotepath false diff --git a/lib/ext/core/string.rb b/lib/ext/core/string.rb index fa8ad17a0..162210a9f 100644 --- a/lib/ext/core/string.rb +++ b/lib/ext/core/string.rb @@ -1,30 +1,26 @@ # -*- encoding : utf-8 -*- require 'charlock_holmes/string' -# require 'iconv' class String def default_encoding! - if ascii_only? - force_encoding(Encoding.default_internal || Encoding::UTF_8) - else - force_encoding((detected = detect_encoding and detected[:encoding]) || Encoding.default_internal || Encoding::UTF_8).encode! + default_encoding = Encoding.default_internal || Encoding::UTF_8 + if ascii_only? # no need to encode if ascii + force_encoding(default_encoding) + else # should encode + options = {:invalid => :replace, :undef => :replace, :replace => ''} + if (detected = detect_encoding) && detected[:encoding] + force_encoding(detected[:encoding]).encode!(default_encoding, detected[:encoding], options) + end + # re-encode through UTF-16 to filter incorrect symbols + encode!(Encoding::UTF_16, default_encoding, options).encode!(default_encoding, Encoding::UTF_16) + raise unless valid_encoding? # check result end + rescue + replace "--broken encoding: #{detect_encoding[:encoding] || 'unknown'}" + ensure + self end - # def enforce_utf8(from = nil) - # begin - # is_utf8? ? self : ::Iconv.iconv('utf8', from, self).first - # rescue - # converter = ::Iconv.new('UTF-8//IGNORE//TRANSLIT', 'ASCII//IGNORE//TRANSLIT') - # # If Ruby 1.9, else another RubyEngine (ree, Ruby 1.8) - # begin - # converter.iconv(self).unpack('U*').select{|cp| cp < 127}.pack('U*').force_encoding('utf-8') - # rescue - # converter.iconv(self).unpack('U*').select{|cp| cp < 127}.pack('U*') - # end - # end - # end - # same as reverse.truncate.reverse def rtruncate(length, options = {}) text = self.dup diff --git a/lib/ext/git/grit.rb b/lib/ext/git/grit.rb index 1fbc50109..4fa2f11f3 100644 --- a/lib/ext/git/grit.rb +++ b/lib/ext/git/grit.rb @@ -1,11 +1,49 @@ # -*- encoding : utf-8 -*- module Grit class Blob + include Linguist::BlobHelper + + MAX_VIEW_SIZE = 2.megabytes + MAX_DATA_SIZE = 50.megabytes + + def data_with_limit + size <= MAX_DATA_SIZE ? data_without_limit : nil # 'Error: blob is too big' + end + alias_method_chain :data, :limit + + def large? + size.to_i > MAX_VIEW_SIZE + end + + def render_as + @render_as ||= case + when large?; :binary + when image?; :image + when text?; :text + else + :binary + end + end + + # def file_mime_type + # @file_mime_type ||= data.file_type(:mime_type) + # end + # + # def text? + # file_mime_type =~ /^text\// # not binary? + # end + # + # def binary? + # not text? # file_mime_type !~ /^text\// + # # s = data.split(//); ((s.size - s.grep(" ".."~").size) / s.size.to_f) > 0.30 # works only for latin chars + # end + # + # def image? + # mime_type.match(/image/) + # end DEFAULT_RAW_MIME_TYPE = MIME::Types[DEFAULT_MIME_TYPE].first - delegate :binary?, :ascii?, :encoding, :to => :raw_mime_type - def mime_type_with_class_store set_associated_mimes @associated_mimes.first.simplified @@ -25,29 +63,35 @@ module Grit protected - # store all associated MIME::Types inside class - def set_associated_mimes - @associated_mimes ||= [] - if @associated_mimes.empty? - guesses = MIME::Types.type_for(self.name) rescue [DEFAULT_RAW_MIME_TYPE] - guesses = [DEFAULT_RAW_MIME_TYPE] if guesses.empty? + # store all associated MIME::Types inside class + def set_associated_mimes + @associated_mimes ||= [] + if @associated_mimes.empty? + guesses = MIME::Types.type_for(self.name) rescue [DEFAULT_RAW_MIME_TYPE] + guesses = [DEFAULT_RAW_MIME_TYPE] if guesses.empty? - @associated_mimes = guesses.sort{|a,b| mime_sort(a, b)} - end - @associated_mimes + @associated_mimes = guesses.sort{|a,b| mime_sort(a, b)} end + @associated_mimes + end - # TODO make more clever function - def mime_sort(a,b) - return 0 if a.media_type == b.media_type and a.registered? == b.registered? - return -1 if a.media_type == 'text' and !a.registered? - return 1 - end + # TODO make more clever function + def mime_sort(a,b) + return 0 if a.media_type == b.media_type and a.registered? == b.registered? + return -1 if a.media_type == 'text' and !a.registered? + return 1 + end + end + class Repo + def branches_and_tags + branches + tags # @branches_and_tags ||= # ??? + end end end Grit::Git.git_timeout = 60 +# Grit::Git.git_max_size = 5.megabytes # Grit.debug = true GAP_REPO_PATH = '/tmp/gap_repo.git' unless File.directory? GAP_REPO_PATH diff --git a/lib/ext/rails/constraints.rb b/lib/ext/rails/constraints.rb deleted file mode 100644 index 2ec8ef342..000000000 --- a/lib/ext/rails/constraints.rb +++ /dev/null @@ -1,18 +0,0 @@ -# -*- encoding : utf-8 -*- -class OwnerConstraint - def initialize(class_name, bang = false) - @class_name = class_name - @finder = 'find_by_insensitive_uname' - @finder << '!' if bang - end - - def matches?(request) - @class_name.send(@finder, request.params[:uname]).present? - end -end - -class AdminAccess - def self.matches?(request) - !!request.env['warden'].user.try(:admin?) - end -end diff --git a/lib/ext/rosa/constraints.rb b/lib/ext/rosa/constraints.rb new file mode 100644 index 000000000..54e9e6191 --- /dev/null +++ b/lib/ext/rosa/constraints.rb @@ -0,0 +1,40 @@ +# -*- encoding : utf-8 -*- +module Rosa + module Constraints + class Owner + def initialize(class_name, bang = false) + @class_name = class_name + @finder = 'find_by_insensitive_uname' + @finder << '!' if bang + end + + def matches?(request) + @class_name.send(@finder, request.params[:uname]).present? + end + end + + class AdminAccess + def self.matches?(request) + !!request.env['warden'].user.try(:admin?) + end + end + + class Treeish + def self.matches?(request) + params = request.path_parameters + if params[:treeish] # parse existing branch (tag) and path + branch_or_tag = begin + (p = Project.find_by_owner_and_name params[:owner_name], params[:project_name]) && + p.repo.branches_and_tags.detect{|t| params[:treeish].start_with?(t.name)}.try(:name) || + params[:treeish].split('/').first + end + if path = params[:treeish].sub(branch_or_tag, '')[1..-1] and path.present? + params[:path] = File.join([path, params[:path]].compact) + end + params[:treeish] = branch_or_tag + end + true + end + end + end +end diff --git a/lib/modules/models/git.rb b/lib/modules/models/git.rb new file mode 100644 index 000000000..4cf2baafc --- /dev/null +++ b/lib/modules/models/git.rb @@ -0,0 +1,171 @@ +# -*- encoding : utf-8 -*- +module Modules + module Models + module Git + extend ActiveSupport::Concern + + included do + validates_attachment_size :srpm, :less_than => 500.megabytes + validates_attachment_content_type :srpm, :content_type => ['application/octet-stream', "application/x-rpm", "application/x-redhat-package-manager"], :message => I18n.t('layout.invalid_content_type') + + has_attached_file :srpm + # attr_accessible :srpm + + after_create :create_git_repo + after_commit(:on => :create) {|p| p.fork_git_repo unless p.is_root?} # later with resque + after_commit(:on => :create) {|p| p.import_attached_srpm if p.srpm?} # later with resque # should be after create_git_repo + after_destroy :destroy_git_repo + # after_rollback lambda { destroy_git_repo rescue true if new_record? } + + later :import_attached_srpm, :queue => :fork_import + later :fork_git_repo, :queue => :fork_import + end + + def repo + @repo ||= Grit::Repo.new(path) rescue Grit::Repo.new(GAP_REPO_PATH) + end + + def path + build_path(git_repo_name) + end + + def git_repo_name + File.join owner.uname, name + end + + def versions + repo.tags.map(&:name) + repo.branches.map{|b| "latest_#{b.name}"} + end + + def update_file(path, data, options = {}) + head = options[:head].to_s || default_branch + actor = get_actor(options[:actor]) + filename = File.split(path).last + message = options[:message] + message = "Updated file #{filename}" if message.nil? or message.empty? + + # can not write to unexisted branch + return false if repo.branches.select{|b| b.name == head}.size != 1 + + parent = repo.commits(head).first + + index = repo.index + index.read_tree(parent.tree.id) + + # can not create new file + return false if (index.current_tree / path).nil? + + index.add(path, data) + index.commit(message, :parents => [parent], :actor => actor, :last_tree => parent.tree.id, :head => head) + end + + def paginate_commits(treeish, options = {}) + options[:page] = options[:page].try(:to_i) || 1 + options[:per_page] = options[:per_page].try(:to_i) || 20 + + skip = options[:per_page] * (options[:page] - 1) + last_page = (skip + options[:per_page]) >= repo.commit_count(treeish) + + [repo.commits(treeish, options[:per_page], skip), options[:page], last_page] + end + + def tree_info(tree, treeish = nil, path = nil) + treeish ||= tree.id + # initialize result as hash of => nil + res = (tree.trees.sort + tree.blobs.sort).inject({}){|h, e| h.merge!({e => nil})} + # fills result vith commits that describes this file + res = res.inject(res) do |h, (entry, commit)| + if commit.nil? and entry.respond_to?(:name) # only if commit == nil + # ... find last commit corresponds to this file ... + c = repo.log(treeish, File.join([path, entry.name].compact), :max_count => 1).first + # ... and add it to result. + h[entry] = c + # find another files, that linked to this commit and set them their commit + # c.diffs.map{|diff| diff.b_path.split(File::SEPARATOR, 2).first}.each do |name| + # h.each_pair do |k, v| + # h[k] = c if k.name == name and v.nil? + # end + # end + end + h + end + end + + def import_srpm(srpm_path = srpm.path, branch_name = 'import') + system("#{Rails.root.join('bin', 'import_srpm.sh')} #{srpm_path} #{path} #{branch_name} >> /dev/null 2>&1") + end + + protected + + def build_path(dir) + File.join(APP_CONFIG['root_path'], 'git_projects', "#{dir}.git") + end + + def import_attached_srpm + if srpm? + import_srpm # srpm.path + self.srpm = nil; save # clear srpm + end + end + + def create_git_repo + if is_root? + Grit::Repo.init_bare(path) + write_hook + end + end + + def fork_git_repo + dummy = Grit::Repo.new(path) rescue parent.repo.fork_bare(path) + write_hook + end + + def destroy_git_repo + FileUtils.rm_rf path + end + + def write_hook + is_production = Rails.env == "production" + hook = File.join(::Rails.root.to_s, 'tmp', "post-receive-hook") + FileUtils.cp(File.join(::Rails.root.to_s, 'bin', "post-receive-hook.partial"), hook) + File.open(hook, 'a') do |f| + s = "\n /bin/bash -l -c \"cd #{is_production ? '/srv/rosa_build/current' : Rails.root.to_s} && #{is_production ? 'RAILS_ENV=production' : ''} bundle exec rake hook:enqueue[$owner,$reponame,$newrev,$oldrev,$ref,$newrev_type,$oldrev_type]\"" + s << " > /dev/null 2>&1" if is_production + s << "\ndone\n" + f.write(s) + f.chmod(0755) + end + + hook_file = File.join(path, 'hooks', 'post-receive') + FileUtils.cp(hook, hook_file) + FileUtils.rm_rf(hook) + + rescue Exception # FIXME + end + + def get_actor(actor = nil) + @last_actor = case actor.class.to_s + when 'Grit::Actor' then options[:actor] + when 'Hash' then Grit::Actor.new(actor[:name], actor[:email]) + when 'String' then Grit::Actor.from_stirng(actor) + else begin + if actor.respond_to?(:name) and actor.respond_to?(:email) + Grit::Actor.new(actor.name, actor.email) + else + config = Grit::Config.new(repo) + Grit::Actor.new(config['user.name'], config['user.email']) + end + end + end + @last_actor + end + + module ClassMethods + def process_hook(owner_uname, repo, newrev, oldrev, ref, newrev_type, oldrev_type) + rec = GitHook.new(owner_uname, repo, newrev, oldrev, ref, newrev_type, oldrev_type) + ActivityFeedObserver.instance.after_create rec + end + end + end + end +end diff --git a/lib/modules/models/owner.rb b/lib/modules/models/owner.rb index 182682e18..e88ac3f5f 100644 --- a/lib/modules/models/owner.rb +++ b/lib/modules/models/owner.rb @@ -8,15 +8,8 @@ module Modules after_create lambda { relations.create :actor_id => owner.id, :actor_type => owner.class.to_s, :role => 'admin' } end - module ClassMethods - end - - module InstanceMethods - - def name_with_owner - "#{owner.respond_to?(:uname) ? owner.uname : owner.name}/#{self.name}" - end - + def name_with_owner + "#{owner.respond_to?(:uname) ? owner.uname : owner.name}/#{self.name}" end end end diff --git a/lib/modules/models/personal_repository.rb b/lib/modules/models/personal_repository.rb index b821ce750..b5ca7bdb2 100644 --- a/lib/modules/models/personal_repository.rb +++ b/lib/modules/models/personal_repository.rb @@ -9,19 +9,25 @@ module Modules end def create_personal_repository - pl = own_platforms.build - pl.owner = self - pl.name = "#{self.uname}_personal" - pl.description = "#{self.uname}_personal" - pl.platform_type = 'personal' - pl.distrib_type = APP_CONFIG['distr_types'].first - pl.visibility = 'open' - pl.save! + begin + pl = own_platforms.build + pl.owner = self + pl.name = "#{self.uname}_personal" + pl.description = "#{self.uname}_personal" + pl.platform_type = 'personal' + pl.distrib_type = APP_CONFIG['distr_types'].first + pl.visibility = 'open' + pl.save! - rep = pl.repositories.build - rep.name = 'main' - rep.description = 'main' - rep.save! + rep = pl.repositories.build + rep.name = 'main' + rep.description = 'main' + rep.save! + rescue Exception => e + pl.now_destroy rescue false + raise e + end + return true end def personal_platform diff --git a/lib/modules/models/wiki.rb b/lib/modules/models/wiki.rb new file mode 100644 index 000000000..1f13446b9 --- /dev/null +++ b/lib/modules/models/wiki.rb @@ -0,0 +1,39 @@ +# -*- encoding : utf-8 -*- +module Modules + module Models + module Wiki + extend ActiveSupport::Concern + + included do + after_create :create_wiki + after_destroy :destroy_wiki + end + + def wiki_path + build_path(wiki_repo_name) + end + + def wiki_repo_name + File.join owner.uname, "#{name}.wiki" + end + + protected + + def create_wiki + if has_wiki && !FileTest.exist?(wiki_path) + Grit::Repo.init_bare(wiki_path) + wiki = Gollum::Wiki.new(wiki_path, {:base_path => Rails.application.routes.url_helpers.project_wiki_index_path(owner, self)}) + wiki.write_page('Home', :markdown, I18n.t("wiki.seed.welcome_content"), + {:name => owner.name, :email => owner.email, :message => 'Initial commit'}) + end + end + + def destroy_wiki + FileUtils.rm_rf wiki_path + end + + module ClassMethods + end + end + end +end diff --git a/lib/plugins/grack/base.rb b/lib/plugins/grack/base.rb index b464f44ee..99b2d160b 100644 --- a/lib/plugins/grack/base.rb +++ b/lib/plugins/grack/base.rb @@ -35,7 +35,7 @@ module Grack def project @project ||= begin uname, name = @env['PATH_INFO'].split('/')[1,2] - name.gsub!(/\.git$/, '').gsub!(/\.wiki$/, '') + name.gsub!(/(\.wiki)?\.git$/, '') Project.find_by_owner_and_name uname, name end end diff --git a/lib/tasks/add_branch.rake b/lib/tasks/add_branch.rake index c8d7cf48d..1857cb7c9 100644 --- a/lib/tasks/add_branch.rake +++ b/lib/tasks/add_branch.rake @@ -9,7 +9,7 @@ task :add_branch => :environment do Platform.find_by_name(dst_branch).repositories.each do |r| say "=== Process #{r.name} repo" r.projects.find_each do |p| - next if p.branches.map(&:name).include?(dst_branch) + next if p.repo.branches.map(&:name).include?(dst_branch) say "===== Process #{p.name} project" tmp_path = Rails.root.join('tmp', p.name) system("git clone #{p.path} #{tmp_path}") diff --git a/spec/controllers/admin/flash_notifies_controller_spec.rb b/spec/controllers/admin/flash_notifies_controller_spec.rb new file mode 100644 index 000000000..ad7494fda --- /dev/null +++ b/spec/controllers/admin/flash_notifies_controller_spec.rb @@ -0,0 +1,124 @@ +require 'spec_helper' + +describe Admin::FlashNotifiesController do + before(:each) do + stub_symlink_methods + + @user = FactoryGirl.create(:user) + @create_params = { + :flash_notify => { + :body_ru => "Hello! I`m ru body", + :body_en => "Hello! I`m en body", + :status => "error", + :published => true + } + } + + @flash_notify = FactoryGirl.create(:flash_notify) + @flash_notify2 = FactoryGirl.create(:flash_notify) + + @update_params = { + :id => @flash_notify, + :flash_notify => { + :body_ru => "updated!" + } + } + end + + context 'for guest' do + [:index, :create, :update, :edit, :new, :destroy].each do |action| + it "should not be able to perform #{ action } action" do + get action, :id => @flash_notify + response.should redirect_to(new_user_session_path) + end + end + + it 'should not change objects count on create' do + lambda { post :create, @create_params }.should change{ FlashNotify.count }.by(0) + end + + it 'should not change objects count on destroy' do + lambda { delete :destroy, :id => @flash_notify }.should change{ FlashNotify.count }.by(0) + end + + it 'should not change flash notify body on update' do + put :update, @update_params + @flash_notify.reload.body_ru.should_not == "updated!" + end + end + + context 'for global admin' do + before(:each) do + @admin = FactoryGirl.create(:admin) + @user = FactoryGirl.create(:user) + set_session_for(@admin) + end + + it 'should load 2 flash notifies objects on index' do + get :index + assigns[:flash_notifies].count.should == 2 + end + + [:index, :new, :edit].each do |action| + it "should be able to perform #{action} action" do + get action, :id => @flash_notify + response.should render_template(action) + end + end + + it 'should be able to perform create action' do + post :create, @create_params + response.should redirect_to(admin_flash_notifies_path) + end + + it 'should change objects count on create' do + lambda { post :create, @create_params }.should change{ FlashNotify.count }.by(1) + end + + it 'should be able to perform destroy action' do + delete :destroy, :id => @flash_notify + response.should redirect_to(admin_flash_notifies_path) + end + + it 'should change objects count on destroy' do + lambda { delete :destroy, :id => @flash_notify }.should change{ FlashNotify.count }.by(-1) + end + + it 'should be able to perform update action' do + put :update, @update_params + response.should redirect_to(admin_flash_notifies_path) + end + + it 'should change flash notify body on update' do + put :update, @update_params + @flash_notify.reload.body_ru.should == "updated!" + end + end + + context 'for simple user' do + before(:each) do + @user = FactoryGirl.create(:user) + set_session_for(@user) + end + + [:index, :create, :update, :edit, :new, :destroy].each do |action| + it "should not be able to perform #{ action } action" do + get action, :id => @flash_notify + response.should redirect_to(forbidden_path) + end + end + + it 'should not change objects count on create' do + lambda { post :create, @create_params }.should change{ FlashNotify.count }.by(0) + end + + it 'should not change objects count on destroy' do + lambda { delete :destroy, :id => @flash_notify }.should change{ FlashNotify.count }.by(0) + end + + it 'should not change flash notify body on update' do + put :update, @update_params + @flash_notify.reload.body_ru.should_not == "updated!" + end + end +end diff --git a/spec/controllers/platforms/mass_builds_controller_spec.rb b/spec/controllers/platforms/mass_builds_controller_spec.rb index 6a85981f9..1cd611d72 100644 --- a/spec/controllers/platforms/mass_builds_controller_spec.rb +++ b/spec/controllers/platforms/mass_builds_controller_spec.rb @@ -76,6 +76,7 @@ describe Platforms::MassBuildsController do before(:each) do stub_symlink_methods + FactoryGirl.create(:arch) @platform = FactoryGirl.create(:platform) @repository = FactoryGirl.create(:repository, :platform => @platform) @personal_platform = FactoryGirl.create(:platform, :platform_type => 'personal') @@ -91,13 +92,23 @@ describe Platforms::MassBuildsController do end context 'for guest' do - [:index, :create, :cancel, :failed_builds_list].each do |action| + [:index, :create].each do |action| it "should not be able to perform #{ action } action" do get action, :platform_id => @platform response.should redirect_to(new_user_session_path) end end + it "should not be able to perform failed_builds_list action" do + get :failed_builds_list, :platform_id => @platform, :id => @mass_build + response.should redirect_to(new_user_session_path) + end + + it "should not be able to perform cancel action" do + post :cancel, :platform_id => @platform, :id => @mass_build + response.should redirect_to(new_user_session_path) + end + it 'should not change objects count on create success' do lambda { post :create, @create_params }.should change{ MassBuild.count }.by(0) end diff --git a/spec/controllers/platforms/repositories_controller_spec.rb b/spec/controllers/platforms/repositories_controller_spec.rb index 35120683d..82c4a5712 100644 --- a/spec/controllers/platforms/repositories_controller_spec.rb +++ b/spec/controllers/platforms/repositories_controller_spec.rb @@ -32,7 +32,7 @@ end shared_examples_for 'registered user' do it 'should be able to perform index action' do - get :index + get :index, :platform_id => @platform.id response.should render_template(:index) end @@ -80,7 +80,7 @@ describe Platforms::RepositoriesController do context 'for guest' do [:index, :create].each do |action| it "should not be able to perform #{ action } action" do - get action + get action, :platform_id => @platform response.should redirect_to(new_user_session_path) end end diff --git a/spec/controllers/projects/build_lists_controller_spec.rb b/spec/controllers/projects/build_lists_controller_spec.rb index 1431004eb..ef95a4cf7 100644 --- a/spec/controllers/projects/build_lists_controller_spec.rb +++ b/spec/controllers/projects/build_lists_controller_spec.rb @@ -42,13 +42,13 @@ describe Projects::BuildListsController do it 'should save correct commit_hash for branch based build' do post :create, {:owner_name => @project.owner.uname, :project_name => @project.name}.merge(@create_params).deep_merge(:build_list => {:project_version => "latest_master"}) - @project.build_lists.last.commit_hash.should == @project.git_repository.commits('master').last.id + @project.build_lists.last.commit_hash.should == @project.repo.commits('master').last.id end it 'should save correct commit_hash for tag based build' do - system("cd #{@project.git_repository.path} && git tag 4.7.5.3") # TODO REDO through grit + system("cd #{@project.repo.path} && git tag 4.7.5.3") # TODO REDO through grit post :create, {:owner_name => @project.owner.uname, :project_name => @project.name}.merge(@create_params).deep_merge(:build_list => {:project_version => "4.7.5.3"}) - @project.build_lists.last.commit_hash.should == @project.git_repository.commits('4.7.5.3').last.id + @project.build_lists.last.commit_hash.should == @project.repo.commits('4.7.5.3').last.id end end @@ -283,7 +283,7 @@ describe Projects::BuildListsController do @build_list1 = FactoryGirl.create(:build_list_core) @build_list2 = FactoryGirl.create(:build_list_core) @build_list3 = FactoryGirl.create(:build_list_core) - @build_list4 = FactoryGirl.create(:build_list_core, :created_at => (Time.now - 1.day), + @build_list4 = FactoryGirl.create(:build_list_core, :updated_at => (Time.now - 1.day), :project => @build_list3.project, :save_to_platform => @build_list3.save_to_platform, :arch => @build_list3.arch) end @@ -305,9 +305,9 @@ describe Projects::BuildListsController do it 'should filter by project_name and start_date' do get :index, :filter => {:project_name => @build_list3.project.name, :ownership => 'index', - "created_at_start(1i)" => @build_list3.created_at.year.to_s, - "created_at_start(2i)" => @build_list3.created_at.month.to_s, - "created_at_start(3i)" => @build_list3.created_at.day.to_s} + :"updated_at_start(1i)" => @build_list3.updated_at.year.to_s, + :"updated_at_start(2i)" => @build_list3.updated_at.month.to_s, + :"updated_at_start(3i)" => @build_list3.updated_at.day.to_s} assigns[:build_lists].should_not include(@build_list1) assigns[:build_lists].should_not include(@build_list2) assigns[:build_lists].should include(@build_list3) @@ -326,7 +326,7 @@ describe Projects::BuildListsController do describe 'publish_build' do before { test_git_commit(build_list.project) - build_list.update_attribute :commit_hash, build_list.project.git_repository.commits('master').last.id + build_list.update_attribute :commit_hash, build_list.project.repo.commits('master').last.id build_list.update_attribute(:status, BuildList::BUILD_PUBLISH) build_list_package } @@ -343,8 +343,8 @@ describe Projects::BuildListsController do } it 'should create correct git tag for correct commit' do do_get(BuildServer::SUCCESS) - build_list.project.git_repository.tags.last.name.should == build_list.package_version - build_list.project.git_repository.commits(build_list.package_version).last.id.should == build_list.commit_hash + build_list.project.repo.tags.last.name.should == build_list.package_version + build_list.project.repo.commits(build_list.package_version).last.id.should == build_list.commit_hash end it(:passes) { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :status).to(BuildList::BUILD_PUBLISHED) } it(:passes) { lambda{ do_get(BuildServer::SUCCESS) }.should change(build_list, :package_version).to("#{ build_list_package.platform.name }-4.7.5.3-1") } diff --git a/spec/controllers/projects/comments_controller_for_commit_spec.rb b/spec/controllers/projects/comments_controller_for_commit_spec.rb index 3ddce850e..7555d5a79 100644 --- a/spec/controllers/projects/comments_controller_for_commit_spec.rb +++ b/spec/controllers/projects/comments_controller_for_commit_spec.rb @@ -78,8 +78,8 @@ describe Projects::CommentsController do before(:each) do stub_symlink_methods @project = FactoryGirl.create(:project) - %x(cp -Rf #{Rails.root}/spec/tests.git/* #{@project.git_repository.path}) # maybe FIXME ? - @commit = @project.git_repository.commits.first + %x(cp -Rf #{Rails.root}/spec/tests.git/* #{@project.repo.path}) # maybe FIXME ? + @commit = @project.repo.commits.first @create_params = {:comment => {:body => 'I am a comment!'}, :owner_name => @project.owner.uname, :project_name => @project.name, :commit_id => @commit.id} @update_params = {:comment => {:body => 'updated'}, :owner_name => @project.owner.uname, :project_name => @project.name, :commit_id => @commit.id} diff --git a/spec/controllers/projects/git/git_trees_controller_spec.rb b/spec/controllers/projects/git/git_trees_controller_spec.rb index ce9884232..f2baf5020 100644 --- a/spec/controllers/projects/git/git_trees_controller_spec.rb +++ b/spec/controllers/projects/git/git_trees_controller_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' describe Projects::Git::TreesController do def fill_project - %x(cp -Rf #{Rails.root}/spec/tests.git/* #{@project.git_repository.path}) # maybe FIXME ? + %x(cp -Rf #{Rails.root}/spec/tests.git/* #{@project.repo.path}) # maybe FIXME ? end before(:each) do @@ -12,7 +12,7 @@ describe Projects::Git::TreesController do @project = FactoryGirl.create(:project) @another_user = FactoryGirl.create(:user) - @params = {:owner_name => @project.owner.uname, :project_name => @project.name} + @params = {:owner_name => @project.owner.uname, :project_name => @project.name, :treeish => 'master'} end context 'for guest' do @@ -35,21 +35,21 @@ describe Projects::Git::TreesController do it 'should not be able to archive empty project' do @user = FactoryGirl.create(:user) set_session_for(@user) - expect { get :archive, @params.merge(:format => 'tar') }.to raise_error(ActiveRecord::RecordNotFound) + expect { get :archive, @params.merge(:format => 'tar') }.to raise_error(ActionController::RoutingError) end it 'should not be able to injection code with format' do @user = FactoryGirl.create(:user) set_session_for(@user) fill_project - expect { get :archive, @params.merge(:format => "tar master > /dev/null; echo 'I am hacker!';\#") }.to raise_error(ActiveRecord::RecordNotFound) + expect { get :archive, @params.merge(:format => "tar master > /dev/null; echo 'I am hacker!';\#") }.to raise_error(ActionController::RoutingError) end it 'should not be able to injection code with treeish' do @user = FactoryGirl.create(:user) set_session_for(@user) fill_project - expect { get :archive, @params.merge(:treeish => "master > /dev/null; echo 'I am hacker!';\#") }.to raise_error(ActiveRecord::RecordNotFound) + expect { get :archive, @params.merge(:treeish => "master > /dev/null; echo 'I am hacker!';\#") }.to raise_error(ActionController::RoutingError) end it 'should be able to perform archive action' do diff --git a/spec/controllers/users/profile_controller_spec.rb b/spec/controllers/users/profile_controller_spec.rb index 0451de6a8..76617cf8d 100644 --- a/spec/controllers/users/profile_controller_spec.rb +++ b/spec/controllers/users/profile_controller_spec.rb @@ -16,7 +16,7 @@ describe Users::ProfileController do context 'for guest' do it 'should not be able to view profile' do - get :show, :owner_name => @simple_user.uname + get :show, :uname => @simple_user.uname response.should redirect_to(new_user_session_path) end end diff --git a/spec/factories/flash_notify.rb b/spec/factories/flash_notify.rb new file mode 100644 index 000000000..b3f239540 --- /dev/null +++ b/spec/factories/flash_notify.rb @@ -0,0 +1,10 @@ +# -*- encoding : utf-8 -*- +FactoryGirl.define do + factory :flash_notify do + body_ru { FactoryGirl.generate(:string) } + body_en { FactoryGirl.generate(:string) } + status "error" + published true + end +end + diff --git a/spec/factories/platforms.rb b/spec/factories/platforms.rb index e8d6aad69..6877fb58c 100644 --- a/spec/factories/platforms.rb +++ b/spec/factories/platforms.rb @@ -8,7 +8,7 @@ FactoryGirl.define do association :owner, :factory => :user factory :platform_with_repos do - after_create {|p| FactoryGirl.create_list(:repository, 1, platform: p)} + after(:create) {|p| FactoryGirl.create_list(:repository, 1, platform: p)} end factory :personal_platform do diff --git a/spec/models/comment_for_commit_spec.rb b/spec/models/comment_for_commit_spec.rb index 181859d56..b56769e26 100644 --- a/spec/models/comment_for_commit_spec.rb +++ b/spec/models/comment_for_commit_spec.rb @@ -10,8 +10,8 @@ def set_comments_data_for_commit @ability = Ability.new(@user) @project = FactoryGirl.create(:project, :owner => @user) - %x(cp -Rf #{Rails.root}/spec/tests.git/* #{@project.git_repository.path}) # maybe FIXME ? - @commit = @project.git_repository.commits.first + %x(cp -Rf #{Rails.root}/spec/tests.git/* #{@project.repo.path}) # maybe FIXME ? + @commit = @project.repo.commits.first @comment = create_comment(@user) @stranger_comment = create_comment(@stranger) diff --git a/spec/models/flash_notify_spec.rb b/spec/models/flash_notify_spec.rb new file mode 100644 index 000000000..8501d64a4 --- /dev/null +++ b/spec/models/flash_notify_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe FlashNotify do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 572af1b76..b50c1e6a4 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1,6 +1,41 @@ # -*- encoding : utf-8 -*- require 'spec_helper' -#describe Project do -# pending "add some examples to (or delete) #{__FILE__}" -#end +describe Project do + before(:each) do + stub_symlink_methods + @root_project = FactoryGirl.create(:project) + @child_project = @root_project.fork(FactoryGirl.create(:user)) + @child_child_project = @child_project.fork(FactoryGirl.create(:user)) + end + + context 'for destroy root' do + before(:each) do + @root_project.destroy + end + + it "should not be delete child" do + Project.where(:id => @child_project).count.should == 1 + end + + it "should not be delete child of the child" do + Project.where(:id => @child_child_project).count.should == 1 + end + end + + # uncommit when will be available :orphan_strategy => :adopt + + #context 'for destroy middle node' do + # before(:each) do + # @child_project.destroy + # end + + # it "should set root project as a parent for orphan child" do + # Project.find(@child_child_project).ancestry == @root_project + # end + + # it "should not be delete child of the child" do + # Project.where(:id => @child_child_project).count.should == 1 + # end + #end +end \ No newline at end of file diff --git a/spec/routing/projects_routing_spec.rb.rb b/spec/routing/projects_routing_spec.rb.rb index 5bcc65d06..caa2042ee 100644 --- a/spec/routing/projects_routing_spec.rb.rb +++ b/spec/routing/projects_routing_spec.rb.rb @@ -13,7 +13,7 @@ describe Projects::ProjectsController do end it "routes to #edit" do - get("/import/glib2.0-mib/edit").should route_to("projects/projects#edit", :owner_name => 'import', :project_name => 'glib2.0-mib') + get("/import/glib2.0-mib/modify").should route_to("projects/projects#edit", :owner_name => 'import', :project_name => 'glib2.0-mib') end it "routes to #create" do @@ -39,6 +39,8 @@ describe Projects::Git::TreesController do get("/import/glib2.0-mib/tree/lib2safe-0.03").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib', :treeish => 'lib2safe-0.03') get("/import/glib2.0-mib/tree/branch-with.dot/folder_with.dot/path-with.dot").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib', :treeish => 'branch-with.dot', :path => 'folder_with.dot/path-with.dot') # get("/import/glib2.0-mib/tree/ветка-с.точкой/папка_с.точкой/путь-с.точкой").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib', :treeish => 'ветка-с.точкой', :path => 'папка_с.точкой/путь-с.точкой') + get("/import/glib2.0-mib/tree/branch-with/slash.dot/folder_with.dot/path-with.dot").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib', :treeish => 'branch-with/slash.dot', :path => 'folder_with.dot/path-with.dot') + get("/import/glib2.0-mib/tree/tag13.52-5").should route_to("projects/git/trees#show", :owner_name => 'import', :project_name => 'glib2.0-mib', :treeish => 'tag13.52-5') end # TODO write more specs also with slash in branch name! diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 843efa51f..72f943b66 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -39,8 +39,8 @@ def stub_symlink_methods end def test_git_commit(project) - project.git_repository.repo.index.add('test', 'TEST') - project.git_repository.repo.index.commit('Test commit') + project.repo.index.add('test', 'TEST') + project.repo.index.commit('Test commit') end Resque.inline = true diff --git a/vendor/assets/javascripts/bootstrap-alert.js b/vendor/assets/javascripts/bootstrap-alert.js new file mode 100644 index 000000000..57890a9a2 --- /dev/null +++ b/vendor/assets/javascripts/bootstrap-alert.js @@ -0,0 +1,90 @@ +/* ========================================================== + * bootstrap-alert.js v2.0.4 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT DATA-API + * ============== */ + + $(function () { + $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) + }) + +}(window.jQuery); \ No newline at end of file diff --git a/vendor/assets/javascripts/vendor.js b/vendor/assets/javascripts/vendor.js index fb26ee768..b02bf3d4a 100644 --- a/vendor/assets/javascripts/vendor.js +++ b/vendor/assets/javascripts/vendor.js @@ -13,6 +13,7 @@ //= require bootstrap-tab // require bootstrap-tooltip // require bootstrap-popover +//= require bootstrap-alert //= require chosen.jquery // require html5shiv // require_tree .