diff --git a/Gemfile b/Gemfile index dd9ed33ea..048bda1da 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,6 @@ source 'http://rubygems.org' gem 'rails', '3.0.11' #, :git => 'git://github.com/rails/rails.git' -gem 'shotgun' gem 'pg', '~> 0.11.0' gem 'silent-postgres', '~> 0.1.1' @@ -54,13 +53,14 @@ end gem 'newrelic_rpm' group :development do - # gem 'letter_opener' + gem 'mailcatcher' # 'letter_opener' gem 'rails3-generators' gem 'web-app-theme' gem 'hpricot' gem 'ruby_parser' gem 'hirb' + gem 'shotgun' # deploy gem 'capistrano', :require => false diff --git a/Gemfile.lock b/Gemfile.lock index d71c4ed97..5a673d43e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -54,14 +54,14 @@ GEM activerecord (>= 2.2.2) arel (2.0.10) bcrypt-ruby (3.0.1) - bluepill (0.0.52) + bluepill (0.0.55) activesupport (>= 3.0.0) - daemons (~> 1.1.0) + daemons (~> 1.1.4) i18n (>= 0.5.0) state_machine (~> 1.1.0) builder (2.1.2) cancan (1.6.7) - cape (1.2.0) + cape (1.4.0) capistrano (2.9.0) highline net-scp (>= 1.0.0) @@ -74,7 +74,7 @@ GEM chronic (0.6.7) cocaine (0.2.1) creole (0.4.2) - daemons (1.1.6) + daemons (1.1.8) delayed_job (2.1.4) activesupport (~> 3.0) daemons @@ -85,13 +85,14 @@ GEM diff-lcs (1.1.3) erubis (2.6.6) abstract (>= 1.0.0) + eventmachine (0.12.10) expression_parser (0.9.0) factory_girl (2.3.2) activesupport factory_girl_rails (1.4.0) factory_girl (~> 2.3.0) railties (>= 3.0.0) - github-markup (0.7.0) + github-markup (0.7.1) gollum (1.3.1) albino (~> 1.3.2) github-markup (>= 0.4.0, < 1.0.0) @@ -121,6 +122,16 @@ GEM i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) + mailcatcher (0.2.4) + eventmachine + haml + i18n + json + mail + sinatra + skinny (>= 0.1.2) + sqlite3-ruby + thin meta-tags (1.2.4) actionpack mime-types (1.17.2) @@ -141,7 +152,7 @@ GEM omniauth (~> 1.0) rack-openid (~> 1.3.1) orm_adapter (0.0.6) - paperclip (2.5.2) + paperclip (2.6.0) activerecord (>= 2.3.0) activesupport (>= 2.3.2) cocaine (>= 0.0.2) @@ -168,7 +179,7 @@ GEM rails-xmlrpc (0.3.6) rails3-generators (0.17.4) railties (>= 3.0.0) - rails3-jquery-autocomplete (1.0.5) + rails3-jquery-autocomplete (1.0.6) rails (~> 3.0) railties (3.0.11) actionpack (= 3.0.11) @@ -212,7 +223,17 @@ GEM sinatra (1.2.8) rack (~> 1.1) tilt (>= 1.2.2, < 2.0) + skinny (0.2.0) + eventmachine (~> 0.12) + thin (~> 1.2) + sqlite3 (1.3.5) + sqlite3-ruby (1.3.3) + sqlite3 (>= 1.3.3) state_machine (1.1.2) + thin (1.3.1) + daemons (>= 1.0.9) + eventmachine (>= 0.12.6) + rack (>= 1.0.0) thor (0.14.6) tilt (1.3.3) treetop (1.4.10) @@ -260,6 +281,7 @@ DEPENDENCIES hirb hpricot jammit + mailcatcher meta-tags (~> 1.2.4) newrelic_rpm omniauth (~> 1.0.1) diff --git a/app/controllers/build_lists_controller.rb b/app/controllers/build_lists_controller.rb index 0104bee2d..9bed99bbf 100644 --- a/app/controllers/build_lists_controller.rb +++ b/app/controllers/build_lists_controller.rb @@ -49,7 +49,7 @@ class BuildListsController < ApplicationController Arch.where(:id => params[:arches]).each do |arch| Platform.main.where(:id => params[:bpls]).each do |bpl| @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 + @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.bpl = bpl; @build_list.arch = arch; @build_list.user = current_user flash_options = {:project_version => @build_list.project_version, :arch => arch.name, :bpl => bpl.name, :pl => @build_list.pl} if @build_list.save diff --git a/app/controllers/collaborators_controller.rb b/app/controllers/collaborators_controller.rb index f05ab25ac..44ab07f98 100644 --- a/app/controllers/collaborators_controller.rb +++ b/app/controllers/collaborators_controller.rb @@ -6,9 +6,10 @@ class CollaboratorsController < ApplicationController before_filter :find_users before_filter :find_groups - load_and_authorize_resource :project + load_resource :project + before_filter :authorize_collaborators - def index + def index redirect_to edit_project_collaborators_path(@project) end @@ -49,7 +50,7 @@ class CollaboratorsController < ApplicationController groups_for_removing.each do |u| Relation.by_object(u).by_target(@project).each {|r| r.destroy} end - + # Create relations Relation::ROLES.each { |r| #users_for_creating = users_for_creating params[:user].keys.map{|p| p.to_i} - @project.collaborators.map(&:id) @@ -130,4 +131,8 @@ class CollaboratorsController < ApplicationController def find_groups @groups = @project.groups#Group.all end + + def authorize_collaborators + authorize! :update, @project + end end diff --git a/app/controllers/git/blobs_controller.rb b/app/controllers/git/blobs_controller.rb index 0bfe6b4b4..0b93db28f 100644 --- a/app/controllers/git/blobs_controller.rb +++ b/app/controllers/git/blobs_controller.rb @@ -5,6 +5,7 @@ class Git::BlobsController < Git::BaseController before_filter :set_commit_hash def show + redirect_to project_repo_path(@project) and return unless @blob.present? if params[:raw] image_url = Rails.root.to_s + "/" + @path @@ -16,11 +17,34 @@ class Git::BlobsController < Git::BaseController end end + def edit + redirect_to project_repo_path(@project) and return unless @blob.present? + authorize! :write, @project + end + + def update + redirect_to project_repo_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], + :message => params[:message], :actor => current_user, :head => @treeish) + if res + flash[:notice] = t("flash.blob.successfully_updated", :name => params[:path].encode_to_default) + else + flash[:notice] = t("flash.blob.updating_error", :name => params[:path].encode_to_default) + end + redirect_to :action => :show + end + def blame @blame = Grit::Blob.blame(@git_repository.repo, @commit.try(:id), @path) end def raw + redirect_to project_repo_path(@project) and return unless @blob.present? headers["Content-Disposition"] = %[attachment;filename="#{@blob.name}"] render :text => @blob.data, :content_type => @blob.mime_type end @@ -28,7 +52,8 @@ class Git::BlobsController < Git::BaseController protected def set_path_blob @path = params[:path] - @blob = @tree / @path.encode_to_default + @path.force_encoding(Encoding::ASCII_8BIT) + @blob = @tree / @path end def set_commit_hash diff --git a/app/controllers/git/trees_controller.rb b/app/controllers/git/trees_controller.rb index 081fa7e8b..94b6b91e0 100644 --- a/app/controllers/git/trees_controller.rb +++ b/app/controllers/git/trees_controller.rb @@ -3,6 +3,7 @@ class Git::TreesController < Git::BaseController def show @path = params[:path] + @path.force_encoding(Encoding::ASCII_8BIT) if @path @tree = @git_repository.tree(@treeish) diff --git a/app/controllers/register_requests_controller.rb b/app/controllers/register_requests_controller.rb new file mode 100644 index 000000000..74ddd6627 --- /dev/null +++ b/app/controllers/register_requests_controller.rb @@ -0,0 +1,52 @@ +# -*- encoding : utf-8 -*- +class RegisterRequestsController < ApplicationController + load_and_authorize_resource + + before_filter :find_register_request, :only => [:approve, :reject] + + def index + @register_requests = @register_requests.unprocessed.paginate(:page => params[:page]) + end + + def new +# render :layout => 'sessions' + redirect_to '/invite.html' + end + + def show_message + end + + def create + RegisterRequest.create(params[:register_request]) + redirect_to '/thanks.html' #show_message_register_requests_path + end + + def update + if params[:update_type].present? and params[:request_ids].present? + updates = RegisterRequest.where(:id => params[:request_ids]) + case params[:update_type] + when 'approve' # see approve method + updates.each {|req| req.update_attributes(:approved => true, :rejected => false)} + when 'reject' # see reject method + updates.each {|req| req.update_attributes(:approved => false, :rejected => true)} + end + end + redirect_to :action => :index + end + + def approve + @register_request.update_attributes(:approved => true, :rejected => false) + redirect_to :action => :index + end + + def reject + @register_request.update_attributes(:approved => false, :rejected => true) + redirect_to :action => :index + end + + protected + + def find_register_request + @register_request = RegisterRequest.find(params[:register_request_id]) + end +end diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index a79e713b8..b334262e3 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -48,12 +48,10 @@ class WikiController < ApplicationController @name = CGI.unescape(params[:id]) @page = @wiki.page(@name) name = params[:rename] || @name - committer = Gollum::Committer.new(@wiki, commit) - commit_arg = {:committer => committer} - update_wiki_page(@wiki, @page, params[:content], commit_arg, name, params[:format]) - update_wiki_page(@wiki, @page.footer, params[:footer], commit_arg) if params[:footer] - update_wiki_page(@wiki, @page.sidebar, params[:sidebar], commit_arg) if params[:sidebar] + update_wiki_page(@wiki, @page, params[:content], {:committer => committer}, name, params[:format]) + update_wiki_page(@wiki, @page.footer, params[:footer], {:committer => committer}) if params[:footer] + update_wiki_page(@wiki, @page.sidebar, params[:sidebar], {:committer => committer}) if params[:sidebar] committer.commit @@ -68,9 +66,8 @@ class WikiController < ApplicationController def create @name = CGI.unescape(params['page']) format = params['format'].intern - begin - @wiki.write_page(@name, format, params['content'] || '', commit) + @wiki.write_page(@name, format, params['content'] || '', {:committer => committer}).commit redirect_to project_wiki_path(@project, CGI.escape(@name)) rescue Gollum::DuplicatePageError => e flash[:error] = t("flash.wiki.duplicate_page", :name => @name) @@ -82,7 +79,7 @@ class WikiController < ApplicationController @name = CGI.unescape(params[:id]) page = @wiki.page(@name) if page - @wiki.delete_page(page, commit.merge(:message => 'Page removed')) + @wiki.delete_page(page, {:committer => committer}).commit flash[:notice] = t("flash.wiki.page_successfully_removed") else flash[:notice] = t("flash.wiki.page_not_found", :name => params[:id]) @@ -145,7 +142,7 @@ class WikiController < ApplicationController sha1 = params[:sha1] sha2 = params[:sha2] - if @wiki.revert_page(@page, sha1, sha2, commit) + if @wiki.revert_page(@page, sha1, sha2, {:committer => committer}).commit flash[:notice] = t("flash.wiki.revert_success") redirect_to project_wiki_path(@project, CGI.escape(@name)) else @@ -165,7 +162,7 @@ class WikiController < ApplicationController def revert_wiki sha1 = params[:sha1] sha2 = params[:sha2] - if @wiki.revert_commit(sha1, sha2, commit) + if @wiki.revert_commit(sha1, sha2, {:committer => committer}).commit flash[:notice] = t("flash.wiki.revert_success") redirect_to project_wiki_index_path(@project) else @@ -233,11 +230,11 @@ class WikiController < ApplicationController if params['message'] and !params['message'].empty? msg = params['message'] else -# msg = "#{!!@wiki.page(@name) ? 'Updated page' : 'Created page'} #{@name}" msg = case action_name.to_s - when 'create' then "Created page #{@name.to_s}" - when 'update' then "Updated page #{@name.to_s}" - when 'revert' then "Reverted page #{@name.to_s}" + when 'create' then "Created page #{@name.to_s}" + when 'update' then "Updated page #{@name.to_s}" + when 'destroy' then "Removed page #{@name.to_s}" + when 'revert' then "Reverted page #{@name.to_s}" when 'revert_wiki' then "Reverted wiki" end msg += " (#{params['format']})" if params['format'] @@ -246,8 +243,13 @@ class WikiController < ApplicationController { :message => msg } end - def commit - commit_message.merge({:name => current_user.uname, :email => current_user.email}) + def committer + p = commit_message.merge({:name => current_user.uname, :email => current_user.email}) + @committer ||= Gollum::Committer.new(@wiki, p) + # @committer.after_commit do |committer, sha1| + # here goes callback for notification + # end + @committer end def show_or_create_page @@ -258,20 +260,19 @@ class WikiController < ApplicationController elsif file = @wiki.file(@name) render :text => file.raw_data, :content_type => file.mime_type elsif can? :write, @project -# @name = CGI.escape(@name) @new = true render :new else - redirect_to forbidden_path + redirect_to :action => :index #forbidden_path end end def authorize_read_actions - redirect_to forbidden_path and return if cannot? :read, @project + authorize! :read, @project end def authorize_write_actions - redirect_to forbidden_path and return if cannot? :write, @project + authorize! :write, @project end end diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index a7f1163cf..0addc764b 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -12,7 +12,7 @@ module DiffHelper res += "" res += "" - res.html_safe.force_encoding(Encoding.default_internal || Encoding::UTF_8) + res.html_safe.encode_to_default end end diff --git a/app/helpers/git_helper.rb b/app/helpers/git_helper.rb index f302b5aed..fef549d7e 100644 --- a/app/helpers/git_helper.rb +++ b/app/helpers/git_helper.rb @@ -29,6 +29,14 @@ module GitHelper res.encode_to_default.html_safe end + def blob_file_path + if @commit_hash.present? + blob_commit_path(@project, @commit_hash, @path) + else + blob_path(@project, @treeish, @path) + end + end + def render_line_numbers(n) res = "" 1.upto(n) {|i| res += "#{i}\n" } diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb index 9b406a88b..05ac815ab 100644 --- a/app/helpers/wiki_helper.rb +++ b/app/helpers/wiki_helper.rb @@ -86,7 +86,7 @@ module WikiHelper end def author - @page.version.author.name.force_encoding(Encoding.default_internal || Encoding::UTF_8) + @page.version.author.name.encode_to_default end def author_email diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 4fcc5488b..6609ac427 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -33,4 +33,9 @@ class UserMailer < ActionMailer::Base format.html end end + + def invite_approve_notification(register_request) + @register_request = register_request + mail :to => register_request.email, :subject => I18n.t("notifications.subjects.invite_approve_notification") + end end diff --git a/app/models/ability.rb b/app/models/ability.rb index 735aaed2a..113b50dd1 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -16,6 +16,7 @@ class Ability can :manage, :all cannot :destroy, Subscribe cannot :create, Subscribe + cannot :create, RegisterRequest else # Shared rights between guests and registered users can :forbidden, Platform @@ -26,6 +27,7 @@ class Ability if user.guest? # Guest rights can :create, User + can [:create, :show_message], RegisterRequest else # Registered user rights can [:show, :autocomplete_user_uname], User @@ -67,7 +69,7 @@ class Ability can :autocomplete_user_uname, Platform # TODO delegate to platform? - can :read, Repository, :visibility => 'open' + can :read, Repository, :platform => {:visibility => 'open'} can :read, Repository, :owner_type => 'User', :owner_id => user.id can :read, Repository, :owner_type => 'Group', :owner_id => user.group_ids can(:read, Repository, read_relations_for('repositories')) {|repository| local_reader? repository} @@ -97,6 +99,7 @@ class Ability can(:update, Comment) {|comment| comment.user_id == user.id or local_admin?(comment.project || comment.commentable.project)} #cannot :manage, Comment, :commentable => {:project => {:has_issues => false}} # switch off issues cannot(:manage, Comment) {|comment| comment.commentable_type == 'Issue' && !comment.commentable.project.has_issues} # switch off issues + cannot :manage, RegisterRequest end end diff --git a/app/models/git/repository.rb b/app/models/git/repository.rb index 4ed82b210..c1d0fec4d 100644 --- a/app/models/git/repository.rb +++ b/app/models/git/repository.rb @@ -2,16 +2,17 @@ class Git::Repository delegate :commits, :commit, :tree, :tags, :heads, :commit_count, :log, :branches, :to => :repo - attr_accessor :path, :name + 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 @@ -20,6 +21,65 @@ class Git::Repository @repo ||= Grit::Repo.new(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 = {}) + path.force_encoding(Encoding::ASCII_8BIT) # some magic + + 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 @@ -38,4 +98,35 @@ class Git::Repository [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/group.rb b/app/models/group.rb index a720995ef..c68147305 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -4,14 +4,14 @@ class Group < ActiveRecord::Base has_many :own_projects, :as => :owner, :class_name => 'Project' - has_many :relations, :as => :object, :dependent => :destroy has_many :objects, :as => :target, :class_name => 'Relation' has_many :targets, :as => :object, :class_name => 'Relation' has_many :members, :through => :objects, :source => :object, :source_type => 'User', :autosave => true has_many :projects, :through => :targets, :source => :target, :source_type => 'Project', :autosave => true - has_many :platforms, :through => :targets, :source => :target, :source_type => 'Platform', :autosave => true + has_many :platforms, :through => :targets, :source => :target, :source_type => 'Platform', :autosave => true, :dependent => :destroy has_many :repositories, :through => :targets, :source => :target, :source_type => 'Repository', :autosave => true + has_many :relations, :as => :object, :dependent => :destroy validates :name, :owner, :presence => true validates :uname, :presence => true, :uniqueness => {:case_sensitive => false}, :format => { :with => /^[a-z0-9_]+$/ } @@ -20,6 +20,7 @@ class Group < ActiveRecord::Base attr_readonly :uname, :own_projects_count delegate :ssh_key, :to => :owner + delegate :email, :to => :owner after_create :add_owner_to_members after_initialize lambda {|r| r.name ||= r.uname } # default diff --git a/app/models/register_request.rb b/app/models/register_request.rb new file mode 100644 index 000000000..a0299556f --- /dev/null +++ b/app/models/register_request.rb @@ -0,0 +1,25 @@ +class RegisterRequest < ActiveRecord::Base + default_scope order('created_at ASC') + + scope :rejected, where(:rejected => true) + scope :approved, where(:approved => true) + scope :unprocessed, where(:approved => false, :rejected => false) + + # before_create :generate_token + before_update :invite_approve_notification + + validates :email, :presence => true, :uniqueness => {:case_sensitive => false}, :format => { :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i } + + protected + + def generate_token + self.token = Digest::SHA1.hexdigest(name + email + Time.now.to_s + rand.to_s) + end + + def invite_approve_notification + if approved_changed? and approved == true + generate_token + UserMailer.invite_approve_notification(self).deliver + end + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 7cad3bd65..25e8dab2f 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,7 +4,7 @@ class User < ActiveRecord::Base LANGUAGES_FOR_SELECT = [['Russian', 'ru'], ['English', 'en']] LANGUAGES = LANGUAGES_FOR_SELECT.map(&:last) - devise :database_authenticatable, :registerable, :omniauthable, # :token_authenticatable, :encryptable, :timeoutable + devise :database_authenticatable, :registerable, #:omniauthable, # :token_authenticatable, :encryptable, :timeoutable :recoverable, :rememberable, :validatable #, :trackable, :confirmable, :lockable has_one :notifier, :class_name => 'Settings::Notifier' #:notifier diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index 5c9d0de5d..5b6ba193c 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -2,6 +2,7 @@ %h2= title t("devise.registrations.sign_up_header") .content = form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :class => "form" }) do |f| + = hidden_field_tag :invitation_token, @invitation_token - if resource.errors.present? .flash .message.error= resource.errors.full_messages.map { |msg| content_tag(:p, msg) }.join.html_safe @@ -16,7 +17,7 @@ .left = f.label :email, :class => "label" .right - = f.text_field :email, :class => "text_field" + = f.text_field :email, :class => "text_field", :readonly => 'readonly' .group.wat-cf .left diff --git a/app/views/devise/shared/_links.haml b/app/views/devise/shared/_links.haml index 958f5ec3c..3ae0900da 100644 --- a/app/views/devise/shared/_links.haml +++ b/app/views/devise/shared/_links.haml @@ -1,13 +1,14 @@ - if controller_name != 'sessions' = link_to t("layout.devise.shared_links.sign_in"), new_session_path(resource_name), :class => "text_button_padding link_button" - if devise_mapping.registerable? && controller_name != 'registrations' - = link_to t("layout.devise.shared_links.sign_up"), new_registration_path(resource_name), :class => "text_button_padding link_button" + =# link_to t("layout.devise.shared_links.sign_up"), new_registration_path(resource_name), :class => "text_button_padding link_button" + = link_to t("layout.devise.shared_links.sign_up"), new_register_request_path, :class => "text_button_padding link_button" # to prereg form - if devise_mapping.recoverable? && controller_name != 'passwords' = link_to t("layout.devise.shared_links.forgot_password"), new_password_path(resource_name), :class => "text_button_padding link_button" - if devise_mapping.confirmable? && controller_name != 'confirmations' = link_to t("layout.devise.shared_links.confirm_again"), new_confirmation_path(resource_name), :class => "text_button_padding link_button" - if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' = link_to t("layout.devise.shared_links.unlock"), new_unlock_path(resource_name), :class => "text_button_padding link_button" -- if devise_mapping.omniauthable? +-# if devise_mapping.omniauthable? - resource_class.omniauth_providers.each do |provider| = link_to t("layout.devise.shared_links.sign_in_through", :provider => provider.to_s.classify), omniauth_authorize_path(resource_name, provider), :class => "text_button_padding link_button" diff --git a/app/views/event_logs/_description.html.haml b/app/views/event_logs/_description.html.haml index 3d4606c91..eb6f9d25f 100644 --- a/app/views/event_logs/_description.html.haml +++ b/app/views/event_logs/_description.html.haml @@ -1,8 +1,8 @@ = surround '[', ']' do - = I18n.t "event_log.controllers.#{el.controller.underscore}", :default => lambda{el.controller} + = I18n.t "event_log.controllers.#{el.controller.underscore}", :default => el.controller = I18n.t "event_log.actions.#{el.controller.underscore}.#{el.action}", :default => :"event_log.actions.#{el.action}" - if el.object_id.present? and el.object_type.present? = I18n.t "activerecord.models.#{el.object_type.underscore}" = el.object_name = "(id##{el.object_id})" # link_to "id##{el.object_id}", el.object -= el.message \ No newline at end of file += el.message diff --git a/app/views/git/blobs/_editor.html.haml b/app/views/git/blobs/_editor.html.haml new file mode 100644 index 000000000..9851626e4 --- /dev/null +++ b/app/views/git/blobs/_editor.html.haml @@ -0,0 +1,26 @@ +#gollum-editor.edit{:'data-escaped-name' => @path.encode_to_default} + = form_tag blob_file_path, :name => 'blob-editor', :method => :put do + %fieldset#gollum-editor-fields + + = text_area_tag :content, @blob.data.encode_to_default, :id => "gollum-editor-body" + + #gollum-editor-edit-summary.singleline + = label_tag :message, t("layout.wiki.edit_commit_message"), :class => "jaws" + = text_field_tag :message, t("layout.wiki.commit_message_placeholder"), :id => "editor-commit-message-field" + + %span.jaws + %br + + = submit_tag t("layout.wiki.save_button"), :id => "gollum-editor-submit", :title => t("layout.wiki.save_changes") + = link_to t("layout.cancel"), blob_file_path, :class => 'minibutton', :id => 'gollum-editor-preview' + +:javascript + $(function() { + $.BlobEditor(); + }); + +- content_for :javascripts do + = javascript_include_tag 'gollum/gollum.placeholder.js', 'blob.editor.js' + +- content_for :stylesheets do + = stylesheet_link_tag 'gollum/editor.css' diff --git a/app/views/git/blobs/edit.html.haml b/app/views/git/blobs/edit.html.haml new file mode 100644 index 000000000..0452cc04d --- /dev/null +++ b/app/views/git/blobs/edit.html.haml @@ -0,0 +1,20 @@ +.block + = render :partial => "git/shared/navigation" + + = render :partial => "git/shared/info" + +- if @commit + .block + .content + .inner + = render :partial => "git/commits/commits", :object => [@commit] + +.block + .content + .inner + %h3 #{render_path} (#{@blob.mime_type}) + + = render :partial => 'editor' + +- content_for :sidebar, render(:partial => 'git/shared/sidebar') + diff --git a/app/views/git/blobs/show.html.haml b/app/views/git/blobs/show.html.haml index 43127ac7e..14f6e6164 100644 --- a/app/views/git/blobs/show.html.haml +++ b/app/views/git/blobs/show.html.haml @@ -19,9 +19,14 @@ .size #{(@blob.size / 1024.0).round(3)} Kb .buttons - if @commit_hash - #{link_to "Raw", raw_commit_path(@project, @commit_hash, @path)} #{link_to "Blame", blame_commit_path(@project, @commit_hash, @path)} #{link_to "History", commits_path(@project, @treeish, @path)} + #{link_to "Raw", raw_commit_path(@project, @commit_hash, @path)} + #{link_to "Blame", blame_commit_path(@project, @commit_hash, @path)} + #{link_to "History", commits_path(@project, @treeish, @path)} - else - #{link_to "Raw", raw_path(@project, @treeish, @path)} #{link_to "Blame", blame_path(@project, @treeish, @path)} #{link_to "History", commits_path(@project, @treeish, @path)} + #{link_to "Edit", edit_blob_path(@project, @treeish, @path) if choose_render_way(@blob) == :text and can? :write, @project} + #{link_to "Raw", raw_path(@project, @treeish, @path)} + #{link_to "Blame", blame_path(@project, @treeish, @path)} + #{link_to "History", commits_path(@project, @treeish, @path)} .clear - case choose_render_way(@blob) - when :image diff --git a/app/views/git/repositories/show.html.haml b/app/views/git/repositories/show.html.haml index 41c205ebd..c3131ed82 100644 --- a/app/views/git/repositories/show.html.haml +++ b/app/views/git/repositories/show.html.haml @@ -36,10 +36,13 @@ - else = image_tag("git/icons/folder_16.png") %td.tree_element + - entry_path = File.join([@path.present? ? @path.encode_to_default : nil, entry.name.encode_to_default].compact) - if entry.is_a?(Grit::Blob) - = link_to entry.name.encode_to_default, blob_path(@project, @treeish, File.join([@path, entry.name.encode_to_default].compact)) + = link_to entry.name.encode_to_default, + blob_path(@project, @treeish.encode_to_default, entry_path) - else - = link_to "#{entry.name.encode_to_default}/", tree_path(@project, @treeish, File.join([@path, entry.name.encode_to_default].compact)) + = link_to "#{entry.name.encode_to_default}/", + tree_path(@project, @treeish.encode_to_default, entry_path) %td==   %td.last==   diff --git a/app/views/git/shared/_navigation.html.haml b/app/views/git/shared/_navigation.html.haml index e09fcb051..fcd292c06 100644 --- a/app/views/git/shared/_navigation.html.haml +++ b/app/views/git/shared/_navigation.html.haml @@ -4,7 +4,8 @@ %li= link_to t("layout.projects.new"), new_project_path %li= link_to t("layout.projects.show"), project_path(@project) %li.active= link_to t("layout.git.repositories.source"), project_repo_path(@project) - %li= link_to t("layout.projects.build"), new_project_build_list_path(@project) + - if can? :write, @project + %li= link_to t("layout.projects.build"), new_project_build_list_path(@project) %ul#git_submenu.sub-wat-cf.wat-cf %li= link_to t("layout.git.repositories.commits"), commits_path(@project, :treeish => @treeish) @@ -25,4 +26,4 @@ %span.current= tag.name - else = link_to tag.name, tree_path(@project, :treeish => tag.name) - .clear \ No newline at end of file + .clear diff --git a/app/views/layouts/_counters.html.erb b/app/views/layouts/_counters.html.erb new file mode 100644 index 000000000..7b5fc6144 --- /dev/null +++ b/app/views/layouts/_counters.html.erb @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 1e72aff63..559bc979d 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -57,3 +57,4 @@ #sidebar = yield :sidebar + = render 'layouts/counters' unless current_user.try(:admin?) diff --git a/app/views/layouts/sessions.html.haml b/app/views/layouts/sessions.html.haml index 055710952..5aeb62a71 100644 --- a/app/views/layouts/sessions.html.haml +++ b/app/views/layouts/sessions.html.haml @@ -12,3 +12,5 @@ #box = render :partial => "layouts/flashes" = yield + + = render 'layouts/counters' unless current_user.try(:admin?) diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index cab48a9b3..30af680c4 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -5,7 +5,8 @@ %li= link_to t("layout.projects.new"), new_project_path %li.active= link_to t("layout.projects.show"), project_path(@project) %li= link_to t("layout.git.repositories.source"), project_repo_path(@project) - %li= link_to t("layout.projects.build"), new_project_build_list_path(@project) + - if can? :write, @project + %li= link_to t("layout.projects.build"), new_project_build_list_path(@project) %li= link_to t("layout.projects.issues"), project_issues_path(@project) - if @project.has_wiki %li= link_to t("layout.projects.wiki"), project_wiki_index_path(@project) diff --git a/app/views/register_requests/index.html.haml b/app/views/register_requests/index.html.haml new file mode 100644 index 000000000..a860887aa --- /dev/null +++ b/app/views/register_requests/index.html.haml @@ -0,0 +1,58 @@ +.block + .secondary-navigation + %ul.wat-cf + %li.first= link_to t("layout.users.list"), users_path + %li= link_to t("layout.users.new"), new_user_path + %li.active= link_to t("layout.users.register_requests"), register_requests_path + .content + %h2.title + = t("layout.register_request.list_header") + .inner + = form_tag register_requests_path, :method => :put, :class => 'update_form' do + = hidden_field_tag 'update_type' + %table.table + %tr + %th   + %th= t("activerecord.attributes.register_request.name") + %th= t("activerecord.attributes.register_request.email") + %th= t("activerecord.attributes.register_request.interest") + %th= t("activerecord.attributes.register_request.more") + %th= t("activerecord.attributes.register_request.created_at") + %th + - @register_requests.each do |request| + %tr{:class => cycle("odd", "even")} + %td= check_box_tag 'request_ids[]', request.id + %td= request.name + %td= request.email + %td= request.interest + %td= request.more + %td= request.created_at + %td + = link_to t("layout.approve"), register_request_approve_path(request) if can? :approve, request + | + = link_to t("layout.reject"), register_request_reject_path(request) if can? :reject, request + .actions-bar.wat-cf + .actions + + + =# button_tag t("layout.register_request.approve_selected"), :class => 'approve_registration' + =# button_tag t("layout.register_request.reject_selected"), :class => 'reject_registration' + .pagination + = will_paginate @register_requests +:javascript + $(function() { + var $form = $('form.update_form') + var change_update_type = function (type) { + $('input#update_type').val(type); + }; + $('#approve_registration').live('click', function(e) { + //set update_type to 'approve' + change_update_type('approve'); + $form.submit(); + }); + $('#reject_registration').live('click', function(e) { + //set update_type to 'reject' + change_update_type('reject'); + $form.submit(); + }); + }); diff --git a/app/views/register_requests/new.html.haml b/app/views/register_requests/new.html.haml new file mode 100644 index 000000000..5ff201c35 --- /dev/null +++ b/app/views/register_requests/new.html.haml @@ -0,0 +1,24 @@ +#block-login.block + %h2= title t("layout.register_request.get_token_header") + .content.login + - if flash.present? + .flash + - flash.each do |key, value| + .message{ :title => key.to_s.humanize, :class => (key == :alert ? "error" : key) } + %p= value + - form_for(@register_request, :html => { :class => "form login" }) do |f| + .group.wat-cf + .left + = f.label :name, :class => "label right" + .right + = f.text_field :name, :class => "text_field" + .group.wat-cf + .left + = f.label :email, :class => "label right" + .right + = f.text_field :email, :class => "text_field" + .group.navform.wat-cf + .right + %button.button{ :type => "submit" } + = t("layout.register_request.get_token_button") + %span.text_button_padding diff --git a/app/views/user_mailer/invite_approve_notification.html.haml b/app/views/user_mailer/invite_approve_notification.html.haml new file mode 100644 index 000000000..d669eb178 --- /dev/null +++ b/app/views/user_mailer/invite_approve_notification.html.haml @@ -0,0 +1,7 @@ +%p== Здравствуйте, #{@register_request.name}. + +%p + Вы приглашены в проект ABF. Чтобы зарегистрироваться перейдите по + = link_to 'ссылке', new_user_registration_url(:invitation_token => @register_request.token) + +%p== Команда поддержки «ROSA Build System» diff --git a/app/views/users/index.html.haml b/app/views/users/index.html.haml index 92ce0aef8..f48d594f0 100644 --- a/app/views/users/index.html.haml +++ b/app/views/users/index.html.haml @@ -3,6 +3,7 @@ %ul.wat-cf %li.first.active= link_to t("layout.users.list"), users_path %li= link_to t("layout.users.new"), new_user_path + %li= link_to t("layout.users.register_requests"), register_requests_path if can? :read, RegisterRequest .content %h2.title = t("layout.users.list_header") diff --git a/app/views/wiki/_history.html.haml b/app/views/wiki/_history.html.haml index a1f66a2a8..bb14ce8e2 100644 --- a/app/views/wiki/_history.html.haml +++ b/app/views/wiki/_history.html.haml @@ -16,13 +16,13 @@ - user = User.where(:email => v.author.email).first = link_to user_path_by_user(user) do %img{:src => gravatar_url(v.author.email), - :alt => "avatar: #{v.author.name.force_encoding(Encoding.default_internal || Encoding::UTF_8)}", + :alt => "avatar: #{v.author.name.encode_to_default}", :class => "mini-gravatar"} - %span.username= user.present? ? user.uname : v.author.name + %span.username= user.present? ? user.uname : v.author.name.encode_to_default %td.commit-name %span.time-elapsed= "#{l v.committed_date.to_date, :format => :long}:"   - = v.message.force_encoding(Encoding.default_internal) + = v.message.encode_to_default - if @name = raw "[#{link_to v.id[0..6], versioned_project_wiki_path(@project, escaped_name, v.id), :title => t("layout.wiki.view_commit")}]" - else diff --git a/app/views/wiki/_project_short.html.haml b/app/views/wiki/_project_short.html.haml index 4697ab479..258ea3373 100644 --- a/app/views/wiki/_project_short.html.haml +++ b/app/views/wiki/_project_short.html.haml @@ -5,7 +5,8 @@ %li= link_to t("layout.projects.new"), new_project_path %li= link_to t("layout.projects.show"), project_path(@project) %li= link_to t("layout.git.repositories.source"), project_repo_path(@project) - %li= link_to t("layout.projects.build"), new_project_build_list_path(@project) + - if can? :write, @project + %li= link_to t("layout.projects.build"), new_project_build_list_path(@project) %li= link_to t("layout.projects.issues"), project_issues_path(@project) %li.active= link_to t("layout.projects.wiki"), project_wiki_index_path(@project) diff --git a/config/environments/development.rb b/config/environments/development.rb index 3e4c691ae..38b0372c3 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -16,6 +16,8 @@ Rosa::Application.configure do # Don't care if the mailer can't send config.action_mailer.raise_delivery_errors = false + config.action_mailer.delivery_method = :smtp # :letter_opener + config.action_mailer.smtp_settings = { :host => "localhost", :port => 1025 } config.action_mailer.default_url_options = { :host => 'localhost:3000' } # Print deprecation notices to the Rails logger diff --git a/config/locales/en.yml b/config/locales/en.yml index 3d77afe55..0bb005ea5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -695,6 +695,10 @@ en: revert_success: Changes successfully reverted patch_does_not_apply: Patch does not apply + blob: + successfully_updated: File '%{name}' successfully updated + updating_error: Error updating file '%{name}' + attributes: password: Password password_confirmation: Confirmation @@ -949,6 +953,7 @@ en: new_user_notification: Registered on project «%{ project_name }» issue_assign_notification: New task assigned new_commit_comment_notification: New comment to commit + invite_approve_notification: Invitation to ABF project: category_id: Category diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 2c53cca66..0f3cb2ddc 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -552,6 +552,10 @@ ru: revert_success: Изменения успешно откачены patch_does_not_apply: Не удалось откатить изменения + blob: + successfully_updated: Файл '%{name}' успешно обновлен + updating_error: Ошибка обновления файла '%{name}' + attributes: password: Пароль password_confirmation: Подтверждение @@ -816,3 +820,4 @@ ru: title: Здравствуйте, %{user_name}. content: Вам была назначена задача %{issue_link} new_commit_comment_notification: Новый комментарий к коммиту + invite_approve_notification: Приглашение в ABF diff --git a/config/routes.rb b/config/routes.rb index 7bc6e79fc..e8c872689 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,7 +9,16 @@ Rosa::Application.routes.draw do resources :users do resources :groups, :only => [:new, :create, :index] - get :autocomplete_user_uname, :on => :collection + collection do + resources :register_requests, :only => [:index, :new, :create, :show_message, :approve, :reject] do + get :show_message, :on => :collection + put :update, :on => :collection + get :approve + get :reject + end + get :autocomplete_user_uname + end + namespace :settings do resource :notifier, :only => [:show, :update] end @@ -181,12 +190,18 @@ Rosa::Application.routes.draw do match '/projects/:project_id/git/commit/:commit_id/comments/:id(.:format)', :controller => "comments", :action => :update, :as => :project_commit_comment, :via => :put match '/projects/:project_id/git/commit/:commit_id/comments/:id(.:format)', :controller => "comments", :action => :destroy, :via => :delete match '/projects/:project_id/git/commit/:commit_id/comments(.:format)', :controller => "comments", :action => :create, :as => :project_commit_comments, :via => :post + # Commits subscribe match '/projects/:project_id/git/commit/:commit_id/subscribe', :controller => "commit_subscribes", :action => :create, :defaults => { :format => :html }, :as => :subscribe_commit, :via => :post match '/projects/:project_id/git/commit/:commit_id/unsubscribe', :controller => "commit_subscribes", :action => :destroy, :defaults => { :format => :html }, :as => :unsubscribe_commit, :via => :delete + + # Editing files + match '/projects/:project_id/git/blob/:treeish/*path/edit', :controller => "git/blobs", :action => :edit, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :edit_blob, :via => :get + match '/projects/:project_id/git/blob/:treeish/*path', :controller => "git/blobs", :action => :update, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :via => :put + # Blobs - match '/projects/:project_id/git/blob/:treeish/*path', :controller => "git/blobs", :action => :show, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :blob - match '/projects/:project_id/git/commit/blob/:commit_hash/*path', :controller => "git/blobs", :action => :show, :project_name => /[0-9a-zA-Z_.\-]*/, :as => :blob_commit + match '/projects/:project_id/git/blob/:treeish/*path', :controller => "git/blobs", :action => :show, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :blob, :via => :get + match '/projects/:project_id/git/commit/blob/:commit_hash/*path', :controller => "git/blobs", :action => :show, :project_id => /[0-9a-zA-Z_.\-]*/, :as => :blob_commit, :via => :get # Blame match '/projects/:project_id/git/blame/:treeish/*path', :controller => "git/blobs", :action => :blame, :treeish => /[0-9a-zA-Z_.\-]*/, :defaults => { :treeish => :master }, :as => :blame diff --git a/db/migrate/20120206194328_remove_orphan_platforms.rb b/db/migrate/20120206194328_remove_orphan_platforms.rb new file mode 100644 index 000000000..aa922710a --- /dev/null +++ b/db/migrate/20120206194328_remove_orphan_platforms.rb @@ -0,0 +1,8 @@ +class RemoveOrphanPlatforms < ActiveRecord::Migration + def self.up + Platform.all.each {|x| x.destroy unless x.owner.present?} + end + + def self.down + end +end diff --git a/db/migrate/20120209135822_create_register_requests.rb b/db/migrate/20120209135822_create_register_requests.rb new file mode 100644 index 000000000..6ae743fa7 --- /dev/null +++ b/db/migrate/20120209135822_create_register_requests.rb @@ -0,0 +1,21 @@ +class CreateRegisterRequests < ActiveRecord::Migration + def self.up + create_table :register_requests do |t| + t.string :name + t.string :email + t.string :token + t.boolean :approved, :default => false + t.boolean :rejected, :default => false + + t.timestamps + end + add_index :register_requests, [:email], :unique => true, :case_sensitive => false + add_index :register_requests, [:token], :unique => true, :case_sensitive => false + end + + def self.down + remove_index :register_requests, [:email] + remove_index :register_requests, [:token] + drop_table :register_requests + end +end diff --git a/db/migrate/20120210141153_add_more_fields_to_register_requests.rb b/db/migrate/20120210141153_add_more_fields_to_register_requests.rb new file mode 100644 index 000000000..cbe0dc71a --- /dev/null +++ b/db/migrate/20120210141153_add_more_fields_to_register_requests.rb @@ -0,0 +1,11 @@ +class AddMoreFieldsToRegisterRequests < ActiveRecord::Migration + def self.up + add_column :register_requests, :interest, :string + add_column :register_requests, :more, :text + end + + def self.down + remove_column :register_requests, :interest + remove_column :register_requests, :more + end +end diff --git a/db/schema.rb b/db/schema.rb index faca11b7f..bf68d3b7c 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 => 20120131124517) do +ActiveRecord::Schema.define(:version => 20120210141153) do create_table "activity_feeds", :force => true do |t| t.integer "user_id", :null => false @@ -98,12 +98,12 @@ ActiveRecord::Schema.define(:version => 20120131124517) do end create_table "comments", :force => true do |t| - t.string "commentable_id" t.string "commentable_type" t.integer "user_id" t.text "body" t.datetime "created_at" t.datetime "updated_at" + t.decimal "commentable_id", :precision => 50, :scale => 0 end create_table "containers", :force => true do |t| @@ -125,6 +125,7 @@ ActiveRecord::Schema.define(:version => 20120131124517) do t.string "locked_by" t.datetime "created_at" t.datetime "updated_at" + t.string "queue" end add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority" @@ -261,16 +262,31 @@ ActiveRecord::Schema.define(:version => 20120131124517) do t.text "description" t.string "ancestry" t.boolean "has_issues", :default => true + t.boolean "has_wiki", :default => false t.string "srpm_file_name" t.string "srpm_content_type" t.integer "srpm_file_size" t.datetime "srpm_updated_at" - t.boolean "has_wiki", :default => false end add_index "projects", ["category_id"], :name => "index_projects_on_category_id" add_index "projects", ["owner_id"], :name => "index_projects_on_name_and_owner_id_and_owner_type", :unique => true, :case_sensitive => false + create_table "register_requests", :force => true do |t| + t.string "name" + t.string "email" + t.string "token" + t.boolean "approved", :default => false + t.boolean "rejected", :default => false + t.datetime "created_at" + t.datetime "updated_at" + t.string "interest" + t.text "more" + end + + add_index "register_requests", ["email"], :name => "index_register_requests_on_email", :unique => true, :case_sensitive => false + add_index "register_requests", ["token"], :name => "index_register_requests_on_token", :unique => true, :case_sensitive => false + create_table "relations", :force => true do |t| t.integer "object_id" t.string "object_type" @@ -328,19 +344,18 @@ ActiveRecord::Schema.define(:version => 20120131124517) do create_table "users", :force => true do |t| t.string "name" - t.string "email", :default => "", :null => false - t.string "encrypted_password", :limit => 128, :default => "", :null => false - t.string "password_salt", :default => "", :null => false + t.string "email", :default => "", :null => false + t.string "encrypted_password", :limit => 128, :default => "", :null => false t.string "reset_password_token" - t.string "remember_token" t.datetime "remember_created_at" t.datetime "created_at" t.datetime "updated_at" t.text "ssh_key" t.string "uname" t.string "role" - t.string "language", :default => "en" - t.integer "own_projects_count", :default => 0, :null => false + t.string "language", :default => "en" + t.datetime "reset_password_sent_at" + t.integer "own_projects_count", :default => 0, :null => false end add_index "users", ["email"], :name => "index_users_on_email", :unique => true diff --git a/lib/gollum/page.rb b/lib/gollum/page.rb index 5850f0b3b..9fb1a31f9 100644 --- a/lib/gollum/page.rb +++ b/lib/gollum/page.rb @@ -1,11 +1,11 @@ # -*- encoding : utf-8 -*- module Gollum class Page - alias_method :native_gollum_name, :name - - def name - native_gollum_name.force_encoding(Encoding.default_internal || Encoding::UTF_8) + def name_with_encoding + name_without_encoding.encode_to_default end + alias_method_chain :name, :encoding + end end diff --git a/lib/gollum/wiki.rb b/lib/gollum/wiki.rb index 9916eea08..14e8ae614 100644 --- a/lib/gollum/wiki.rb +++ b/lib/gollum/wiki.rb @@ -2,26 +2,90 @@ module Gollum class Wiki - alias_method :native_gollum_page, :page - alias_method :native_gollum_file, :file - alias_method :native_gollum_write_page, :write_page - alias_method :native_gollum_update_page, :update_page - - def page(name, version = @ref) - native_gollum_page(force_grit_encoding(name), version) + def page_with_forced_encoding(name, version = @ref) + page_without_forced_encoding(force_grit_encoding(name), version) end + alias_method_chain :page, :forced_encoding - def file(name, version = @ref) - native_gollum_file(force_grit_encoding(name), version) + def file_with_forced_encoding(name, version = @ref) + file_without_forced_encoding(force_grit_encoding(name), version) end + alias_method_chain :file, :forced_encoding - def write_page(name, format, data, commit = {}) - native_gollum_write_page(force_grit_encoding(name), format, data, commit) + def write_page_with_forced_encoding(name, format, data, commit = {}) + write_page_without_forced_encoding(force_grit_encoding(name), format, data, commit) end + alias_method_chain :write_page, :forced_encoding - def update_page(page, name, format, data, commit = {}) - native_gollum_update_page(page, force_grit_encoding(name), format, data, commit) + def update_page_with_forced_encoding(page, name, format, data, commit = {}) + update_page_without_forced_encoding(page, force_grit_encoding(name), format, data, commit) end + alias_method_chain :update_page, :forced_encoding + + # Public: Applies a reverse diff for a given page. If only 1 SHA is given, + # the reverse diff will be taken from its parent (^SHA...SHA). If two SHAs + # are given, the reverse diff is taken from SHA1...SHA2. + # + # page - The Gollum::Page to delete. + # sha1 - String SHA1 of the earlier parent if two SHAs are given, + # or the child. + # sha2 - Optional String SHA1 of the child. + # commit - The commit Hash details: + # :message - The String commit message. + # :name - The String author full name. + # :email - The String email address. + # :parent - Optional Grit::Commit parent to this update. + # + # Returns a String SHA1 of the new commit, or nil if the reverse diff does + # not apply. + def revert_page_with_committer(page, sha1, sha2 = nil, commit = {}) + if sha2.is_a?(Hash) + commit = sha2 + sha2 = nil + end + + multi_commit = false + + patch = full_reverse_diff_for(page, sha1, sha2) + committer = if obj = commit[:committer] + multi_commit = true + obj + else + Committer.new(self, commit) + end + parent = committer.parents[0] + committer.options[:tree] = @repo.git.apply_patch(parent.sha, patch) + return false unless committer.options[:tree] + committer.after_commit do |index, sha| + @access.refresh + + files = [] + if page + files << [page.path, page.name, page.format] + else + # Grit::Diff can't parse reverse diffs.... yet + patch.each_line do |line| + if line =~ %r{^diff --git b/.+? a/(.+)$} + path = $1 + ext = ::File.extname(path) + name = ::File.basename(path, ext) + if format = ::Gollum::Page.format_for(ext) + files << [path, name, format] + end + end + end + end + + files.each do |(path, name, format)| + dir = ::File.dirname(path) + dir = '' if dir == '.' + index.update_working_dir(dir, name, format) + end + end + + multi_commit ? committer : committer.commit + end + alias_method_chain :revert_page, :committer private diff --git a/lib/grit/repo.rb b/lib/grit/repo.rb index d24bb6ff3..998ff7b30 100644 --- a/lib/grit/repo.rb +++ b/lib/grit/repo.rb @@ -2,12 +2,8 @@ module Grit class Repo - alias_method :native_grit_diff, :diff - - def diff(a, b, *paths) - diff = self.git.native('diff', {}, a, b, '--', *paths).force_encoding(Encoding.default_internal || Encoding::UTF_8) - Grit.log 'in grit' - Grit.log diff + def diff_with_encoding(a, b, *paths) + diff = self.git.native('diff', {}, a, b, '--', *paths).encode_to_default if diff =~ /diff --git "{0,1}a/ diff = diff.sub(/.*?(diff --git "{0,1}a)/m, '\1') else @@ -15,6 +11,7 @@ module Grit end Diff.list_from_string(self, diff) end + alias_method_chain :diff, :encoding end end diff --git a/lib/preregistration/devise/preregistration.rb b/lib/preregistration/devise/preregistration.rb new file mode 100644 index 000000000..da2635184 --- /dev/null +++ b/lib/preregistration/devise/preregistration.rb @@ -0,0 +1,59 @@ +# -*- encoding : utf-8 -*- +module Preregistration + module Devise + module RegistrationsController + extend ActiveSupport::Concern + + included do + alias_method_chain :create, :token + alias_method_chain :new, :token + end + + def new_with_token + if params['invitation_token'] + req = RegisterRequest.approved.where(:token => params['invitation_token'].strip).first + redirect_to new_register_request_path and return unless req + + resource = build_resource({}) + resource.name = req.name if resource.respond_to? :name + resource.email = req.email if resource.respond_to? :email + @invitation_token = req.token + + respond_with_navigational(resource){ render_with_scope :new } + else + redirect_to new_register_request_path + end + end + + def create_with_token + redirect_to new_register_request_path and return unless params['invitation_token'] + req = RegisterRequest.approved.where(:token => params['invitation_token'].strip).first + + build_resource + + redirect_to new_register_request_path and return unless req and resource.email == req.email + + @invitation_token = req.token + if resource.save + if resource.active_for_authentication? + set_flash_message :notice, :signed_up if is_navigational_format? + sign_in(resource_name, resource) + respond_with resource, :location => after_sign_up_path_for(resource) + else + set_flash_message :notice, :inactive_signed_up, :reason => inactive_reason(resource) if is_navigational_format? + expire_session_data_after_sign_in! + respond_with resource, :location => after_inactive_sign_up_path_for(resource) + end + else + clean_up_passwords(resource) + respond_with_navigational(resource) { render_with_scope :new } + end + end + + end #RegistrationsController + end #Devise +end #Preregistration + +Rails.application.config.to_prepare do + ::Devise::RegistrationsController.send :include, Preregistration::Devise::RegistrationsController +end diff --git a/public/invite.html b/public/invite.html new file mode 100644 index 000000000..4feb0c004 --- /dev/null +++ b/public/invite.html @@ -0,0 +1,126 @@ + + + + + Сборочная среда + + + + +
+ +
+ + +
+ Платформа разработки и управления жизненным циклом дистрибутивов: от исходного кода до ISO-образов +
+ +
+
+
+ + +
+
+

+ Приветствуем Вас!

+ Вы находитесь на странице размещения заявок на участие в бета-тестировании сборочного сервиса ABF компании РОСА.

+ В первую очередь одобряются заявки от потенциальных майнтейнеров и представителей дистрибутивных команд.

+ Ознакомиться с документацией можно здесь.

+ Мы будем рады ответить на Ваши вопросы на форуме проекта. +

+ +
+
+ + +
+
+

Хочу стать бета-тестером ABF!

+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+
+
+ +
+
+ +
+
+
+ +
+ + + + + diff --git a/public/javascripts/blob.editor.js b/public/javascripts/blob.editor.js new file mode 100644 index 000000000..edcf8bf1c --- /dev/null +++ b/public/javascripts/blob.editor.js @@ -0,0 +1,14 @@ +(function($) { + $.BlobEditor = function() { + $.BlobEditor.Placeholder.add($('#gollum-editor-edit-summary input')); + $('#gollum-editor form[name="blob-editor"]').submit(function( e ) { + e.preventDefault(); + $.BlobEditor.Placeholder.clearAll(); + //debug('submitting'); + $(this).unbind('submit'); + $(this).submit(); + }); + }; + + $.BlobEditor.Placeholder = $.GollumPlaceholder; +})(jQuery); diff --git a/public/pics/bg-signup.png b/public/pics/bg-signup.png new file mode 100644 index 000000000..79676f161 Binary files /dev/null and b/public/pics/bg-signup.png differ diff --git a/public/pics/bg.png b/public/pics/bg.png new file mode 100644 index 000000000..62e74e049 Binary files /dev/null and b/public/pics/bg.png differ diff --git a/public/pics/button-green-disabled.png b/public/pics/button-green-disabled.png new file mode 100644 index 000000000..21159cb78 Binary files /dev/null and b/public/pics/button-green-disabled.png differ diff --git a/public/pics/button-green-hover.png b/public/pics/button-green-hover.png new file mode 100644 index 000000000..b639aa0ab Binary files /dev/null and b/public/pics/button-green-hover.png differ diff --git a/public/pics/button-green-normal.png b/public/pics/button-green-normal.png new file mode 100644 index 000000000..5fb90051c Binary files /dev/null and b/public/pics/button-green-normal.png differ diff --git a/public/pics/button-green-press.png b/public/pics/button-green-press.png new file mode 100644 index 000000000..66ce78c4a Binary files /dev/null and b/public/pics/button-green-press.png differ diff --git a/public/pics/flag.png b/public/pics/flag.png new file mode 100644 index 000000000..85b84ce4f Binary files /dev/null and b/public/pics/flag.png differ diff --git a/public/pics/logo.png b/public/pics/logo.png new file mode 100644 index 000000000..0fbda66db Binary files /dev/null and b/public/pics/logo.png differ diff --git a/public/pics/square.png b/public/pics/square.png new file mode 100644 index 000000000..a6f4b5f9b Binary files /dev/null and b/public/pics/square.png differ diff --git a/public/styles/prereg.css b/public/styles/prereg.css new file mode 100644 index 000000000..b958cc409 --- /dev/null +++ b/public/styles/prereg.css @@ -0,0 +1,243 @@ +html, body { + margin: 0; + padding: 0; + font-family: Tahoma, Arial; + color: #565667; + background: #1f60a1 url("../pics/bg.png") repeat-x; + min-width: 940px; + min-height: 300px; + text-align: center; + height: 100%; +} + +header, section, footer, aside, nav, article, menu { + display: block; +} + +input[type="text"]:focus { outline: none; } + +input[type="password"]:focus { outline: none; } + +input:focus { outline: none; } + +select:focus { outline: none; } + +a img { border: none; } + +.wrap { + width: 940px; + margin: 0 auto; + text-align: center; + min-height: 95%; +} + +.both { + clear: both; +} + + +/* Header */ + +header div.logo { + background: url("../pics/logo.png") no-repeat 50% 100%; + height: 89px; + width: 233px; + margin: 0 auto; + text-align: center; + padding-top: 8%; +} + +header div.text { + color: #FFF; + font-size: 28px; + width: 800px; + text-align: left; + margin-left: 90px; + margin-top: 50px; + font-family: Arial; + text-shadow: 0px 1px 1px #000000; + filter: dropshadow(color=#000000, offx=0, offy=1); + padding-left: 0px; +} + +/* Content */ + +article { + width: 760px; + height: 305px; + background: #1c394c url("../pics/bg-signup.png") repeat-x; + border-radius: 5px; + border: 1px solid #38658c; + margin: 0 auto; + text-align: center; + margin-top: 50px; + -webkit-box-shadow: 0px 3px 5px 0px rgba(0, 0, 0, 0.5); + -moz-box-shadow: 0px 3px 5px 0px rgba(0, 0, 0, 0.5); + box-shadow: 0px 3px 5px 0px rgba(0, 0, 0, 0.5); + padding-top: 5px; + color: #FFF; + font-size: 14px; +} + +article p{ + margin: 0; + padding: 10px 15px; + margin: 0px 0 0px 0; +} + +article div.left { + float: left; + width: 340px; + text-align: left; + font-size: 14px; + margin-top: 0px; + padding: 10px 20px; +} + +article div.right { + float: right; + width: 338px; + margin-top: 0px; + border-left: 2px solid #223e51; + padding: 10px 20px; +} + +article div.left a { + color: #FFF; +/* padding-right: 29px;*/ +} + +article div.left a.last { + padding-right: 0px; +} + +article div.right p { + text-align: left; +} + +article div.all a { + color: #FFF; +/* padding-right: 29px;*/ +} + +article div.all p { + text-align: left; +} + +article div.all { + float: left; + text-align: left; + font-size: 14px; + margin-top: 25px; + padding: 10px 20px; +} + + +article div.signup-left { + float: left; + color: #FFF; + font-size: 12px; + padding-top: 16px; + padding-left: 15px; +} + +article div.signup-right { + float: right; +} + +article div.signup-right input { + height: 21px; + width: 185px; + border: 1px solid #8199a9; + border-radius: 2px; + font-family: Tahoma; + font-size: 12px; +/* padding-left: 10px;*/ + margin-top: 6px; + margin-top: 14px; + margin-right: 15px; +} +article div.signup-right textarea, article div.signup-right select { + width: 185px; + border: 1px solid #8199a9; + border-radius: 2px; + font-family: Tahoma; + font-size: 12px; + margin-top: 6px; + margin-top: 14px; + margin-right: 15px; +} +article div.signup-right select { width: 190px; } + +article div.button { + float: right; + margin: 19px 15px 0px 0px; +} + +a.button { + background: #125687; + background: url("../pics/button-green-normal.png"); + border-radius: 3px; + color: #FFF; + font-family: Tahoma; + font-size: 12px; + -webkit-font-smoothing: antialiased; + font-weight: normal; + padding: 6px 25px; + text-align: center; + border: none; + height: 27px; + width: 106px; + text-decoration: none; +} + +a.button:hover { + background: #1874b6; + background: url("../pics/button-green-hover.png"); + cursor: pointer; +} + +a.button:active{ + background: url("../pics/button-green-press.png"); +} + +a.button:disabled, a.button.disabled { + background: #125687; + background: url("../pics/button-blue-disabled.png"); + padding: 5px 15px; + cursor: default; + } + +/* Footer */ + +footer { + height: 32px; + padding-left: 15px; + width: 900px; + margin: 0 auto; + text-align: center; +} + +footer ul { + margin: 0; + padding: 0; + list-style: none; + font-size: 12px; + color: #FFF; + padding-top: 10px; + text-align: center; +} + +footer ul li { + display: inline; +} + +footer ul li a { + font-size: 12px; + color: #FFF; + text-decoration: none; +} + +footer ul li a:hover { + text-decoration: underline; +} \ No newline at end of file diff --git a/public/stylesheets/git/style.css b/public/stylesheets/git/style.css index a20748d90..8428c17b1 100644 --- a/public/stylesheets/git/style.css +++ b/public/stylesheets/git/style.css @@ -37,7 +37,7 @@ li.commit .message { li.commit .trees { padding-left: 5px; - width: 180px; + width: 200px; } li.commit .message a { diff --git a/public/thanks.html b/public/thanks.html new file mode 100644 index 000000000..0e9f8ae7e --- /dev/null +++ b/public/thanks.html @@ -0,0 +1,72 @@ + + + + + Сборочная среда + + + + +
+ +
+ + +
+ Платформа разработки и управления жизненным циклом дистрибутивов: от исходного кода до ISO-образов +
+ +
+
+
+ + +
+
+

+ Спасибо!

+ Благодарим за интерес к нашему сервису ABF!

+ Приглашение будет выслано вам по указанной электронной почте.

+ Приглашаем Вас на форум проекта, где мы будем рады ответить на Ваши вопросы и получить Ваши пожелания.

+ Ознакомиться с документацией можно здесь. +

+
+ +
+
+
+ +
+ + + + + \ No newline at end of file diff --git a/spec/factories/register_requests.rb b/spec/factories/register_requests.rb new file mode 100644 index 000000000..7fd9c1446 --- /dev/null +++ b/spec/factories/register_requests.rb @@ -0,0 +1,10 @@ +# Read about factories at http://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :register_request do + name "MyString" + email "MyString" + token "MyString" + approved false + end +end diff --git a/spec/models/cancan_spec.rb b/spec/models/cancan_spec.rb index 8b48e44f6..597d5dd38 100644 --- a/spec/models/cancan_spec.rb +++ b/spec/models/cancan_spec.rb @@ -22,6 +22,7 @@ describe CanCan do let(:personal_repository) { Factory(:personal_repository) } let(:open_platform) { Factory(:platform, :visibility => 'open') } let(:hidden_platform) { Factory(:platform, :visibility => 'hidden') } + let(:register_request) { Factory(:register_request) } before(:each) do stub_rsync_methods @@ -44,6 +45,10 @@ describe CanCan do it 'should not be able to destroy personal repositories' do @ability.should_not be_able_to(:destroy, personal_repository) end + + it 'should not be able to create new register requests' do + @ability.should_not be_able_to(:create, RegisterRequest) + end end context 'Site guest' do @@ -69,6 +74,22 @@ describe CanCan do end end + it 'should be able to create register request' do + @ability.should be_able_to(:create, RegisterRequest) + end + + it 'should not be able to update register request' do + @ability.should_not be_able_to(:update, register_request) + end + + it 'should not be able to list register requests' do + @ability.should_not be_able_to(:read, register_request) + end + + it 'should not be able to destroy register requests' do + @ability.should_not be_able_to(:destroy, register_request) + end + it 'should be able to register new user' do @ability.should be_able_to(:create, User) end @@ -105,6 +126,10 @@ describe CanCan do @ability.should be_able_to(:create, Project) end + it "should not be able to manage register requests" do + @ability.should_not be_able_to(:manage, RegisterRequest) + end + context "private users relations" do before(:each) do @private_user = Factory(:private_user) diff --git a/spec/models/register_request_spec.rb b/spec/models/register_request_spec.rb new file mode 100644 index 000000000..eea8bb192 --- /dev/null +++ b/spec/models/register_request_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe RegisterRequest do + pending "add some examples to (or delete) #{__FILE__}" +end