Merge branch 'master' into 96-upgrade_rails

Conflicts:
	Gemfile
	Gemfile.lock
	app/models/group.rb
	app/views/layouts/application.html.haml
	db/schema.rb
	public/stylesheets/git/style.css
This commit is contained in:
Pavel Chipiga 2012-02-14 02:14:03 +02:00
commit 7d74b0af13
59 changed files with 1223 additions and 134 deletions

View File

@ -55,10 +55,10 @@ group :production do
end
group :development do
gem 'shotgun'
# gem 'letter_opener'
gem 'mailcatcher' # 'letter_opener'
gem 'rails3-generators'
gem 'hirb'
gem 'shotgun'
# deploy
gem 'whenever', :require => false
gem 'capistrano', :require => false

View File

@ -100,23 +100,24 @@ GEM
delayed_job_active_record (0.3.2)
activerecord (> 2.1.0)
delayed_job (~> 3.0.0)
devise (2.0.0)
devise (2.0.1)
bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.0.3)
railties (~> 3.1)
warden (~> 1.1)
diff-lcs (1.1.3)
erubis (2.7.0)
eventmachine (0.12.10)
execjs (1.3.0)
multi_json (~> 1.0)
expression_parser (0.9.0)
factory_girl (2.5.1)
activesupport
factory_girl (2.5.2)
activesupport (>= 2.3.9)
factory_girl_rails (1.6.0)
factory_girl (~> 2.5.0)
railties (>= 3.0.0)
fssm (0.2.8.1)
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)
@ -148,6 +149,15 @@ GEM
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mailcatcher (0.5.5)
activesupport (~> 3.0)
eventmachine (~> 0.12)
haml (~> 3.1)
mail (~> 2.3)
sinatra (~> 1.2)
skinny (~> 0.2)
sqlite3 (~> 1.3)
thin (~> 1.2)
meta-tags (1.2.4)
actionpack
mime-types (1.17.2)
@ -234,7 +244,7 @@ GEM
i18n (>= 0.5.0)
sanitize (2.0.3)
nokogiri (>= 1.4.4, < 1.6)
sass (3.1.14)
sass (3.1.15)
sass-rails (3.2.4)
railties (~> 3.2.0)
sass (>= 3.1.10)
@ -245,13 +255,21 @@ GEM
rack (~> 1.3, >= 1.3.6)
rack-protection (~> 1.2)
tilt (~> 1.3, >= 1.3.3)
skinny (0.2.0)
eventmachine (~> 0.12)
thin (~> 1.2)
sprockets (2.1.2)
hike (~> 1.2)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.5)
state_machine (1.1.2)
therubyracer (0.9.9)
libv8 (~> 3.3.10)
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)
@ -302,6 +320,7 @@ DEPENDENCIES
highline (~> 1.6.11)
hirb
jquery-rails (~> 2.0.0)
mailcatcher
meta-tags (~> 1.2.4)
newrelic_rpm (~> 3.3.1)
omniauth (~> 1.0.2)

View File

@ -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);

View File

@ -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)
@ -129,4 +130,8 @@ class CollaboratorsController < ApplicationController
def find_groups
@groups = @project.groups#Group.all
end
def authorize_collaborators
authorize! :update, @project
end
end

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -12,7 +12,7 @@ module DiffHelper
res += "</tbody>"
res += "</table>"
res.html_safe.force_encoding(Encoding.default_internal || Encoding::UTF_8)
res.html_safe.encode_to_default
end
end

View File

@ -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 += "<span>#{i}</span>\n" }

View File

@ -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

View File

@ -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

View File

@ -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
@ -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

View File

@ -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 <filename>")
#
# 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{#<Git::Repository "#{@path}">}
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 <j.doe@example.com>
# * 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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'

View File

@ -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')

View File

@ -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

View File

@ -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== &nbsp;
%td.last== &nbsp;

View File

@ -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
.clear

View File

@ -0,0 +1,13 @@
<script type="text/javascript">
 var _gaq = _gaq || [];
 _gaq.push(['_setAccount', 'UA-29164163-1']);
 _gaq.push(['_trackPageview']);
 (function() {
   var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
   ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
   var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 })();
</script>

View File

@ -47,3 +47,4 @@
.both
%footer= render "layouts/menu/bottom"
= render 'layouts/counters' unless current_user.try(:admin?)

View File

@ -11,3 +11,5 @@
#box
= render :partial => "layouts/flashes"
= yield
= render 'layouts/counters' unless current_user.try(:admin?)

View File

@ -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)

View File

@ -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 &nbsp;
%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
<input type='button' id='approve_registration' value="Approve Selected" />
<input type='button' id='reject_registration' value="Reject Selected" />
=# 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();
});
});

View File

@ -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

View File

@ -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»

View File

@ -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")

View File

@ -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}:"
&nbsp;
= 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

View File

@ -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)

View File

@ -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

View File

@ -661,6 +661,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
@ -915,6 +919,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

View File

@ -533,6 +533,10 @@ ru:
revert_success: Изменения успешно откачены
patch_does_not_apply: Не удалось откатить изменения
blob:
successfully_updated: Файл '%{name}' успешно обновлен
updating_error: Ошибка обновления файла '%{name}'
attributes:
password: Пароль
password_confirmation: Подтверждение
@ -777,3 +781,4 @@ ru:
new_user_notification: Регистрация на проекте «%{ project_name }»
issue_assign_notification: Вам назначили задачу
new_commit_comment_notification: Новый комментарий к коммиту
invite_approve_notification: Приглашение в ABF

View File

@ -10,7 +10,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
@ -180,12 +189,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

View File

@ -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

View File

@ -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

View File

@ -11,12 +11,12 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20120206225130) do
ActiveRecord::Schema.define(:version => 20120210141153) do
create_table "arches", :force => true do |t|
t.string "name", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "arches", ["name"], :name => "index_arches_on_name", :unique => true
@ -25,8 +25,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.integer "user_id"
t.string "provider"
t.string "uid"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "authentications", ["provider", "uid"], :name => "index_authentications_on_provider_and_uid", :unique => true
@ -37,8 +37,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.integer "arch_id"
t.integer "pl_id"
t.integer "bpl_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "build_list_items", :force => true do |t|
@ -46,8 +46,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.integer "level"
t.integer "status"
t.integer "build_list_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "version"
end
@ -61,8 +61,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.integer "project_id"
t.integer "arch_id"
t.datetime "notified_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "is_circle", :default => false
t.text "additional_repos"
t.string "name"
@ -85,16 +85,16 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.string "name"
t.string "ancestry"
t.integer "projects_count", :default => 0, :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "comments", :force => true do |t|
t.string "commentable_type"
t.integer "user_id"
t.text "body"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.decimal "commentable_id", :precision => 50, :scale => 0
end
@ -102,8 +102,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.string "name", :null => false
t.integer "project_id", :null => false
t.integer "owner_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "delayed_jobs", :force => true do |t|
@ -115,8 +115,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.datetime "locked_at"
t.datetime "failed_at"
t.string "locked_by"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "queue"
end
@ -128,8 +128,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.string "distro"
t.string "platform"
t.integer "counter", :default => 0
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "event_logs", :force => true do |t|
@ -144,15 +144,15 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.string "controller"
t.string "action"
t.text "message"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "groups", :force => true do |t|
t.string "name"
t.integer "owner_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "uname"
t.integer "own_projects_count", :default => 0, :null => false
end
@ -164,8 +164,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.string "title"
t.text "body"
t.string "status", :default => "open"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "issues", ["project_id", "serial_id"], :name => "index_issues_on_project_id_and_serial_id", :unique => true
@ -174,8 +174,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.string "description"
t.string "name"
t.integer "parent_platform_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "released", :default => false
t.integer "owner_id"
t.string "owner_type"
@ -188,8 +188,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.integer "platform_id"
t.string "login"
t.string "password"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
end
@ -197,8 +197,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.integer "product_id"
t.integer "status", :default => 2, :null => false
t.datetime "notified_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "product_build_lists", ["product_id"], :name => "index_product_build_lists_on_product_id"
@ -208,8 +208,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.integer "platform_id", :null => false
t.integer "build_status", :default => 2, :null => false
t.string "build_path"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.text "build_script"
t.text "counter"
t.text "ks"
@ -229,8 +229,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.string "name"
t.string "version"
t.datetime "file_mtime"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "platform_id"
end
@ -239,14 +239,14 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
create_table "project_to_repositories", :force => true do |t|
t.integer "project_id"
t.integer "repository_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "projects", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.integer "owner_id"
t.string "owner_type"
t.string "visibility", :default => "open"
@ -264,21 +264,36 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
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"
t.integer "target_id"
t.string "target_type"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "role"
end
create_table "repositories", :force => true do |t|
t.string "description", :null => false
t.integer "platform_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.string "name", :null => false
t.integer "owner_id"
t.string "owner_type"
@ -288,8 +303,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.string "name", :null => false
t.integer "arch_id", :null => false
t.integer "project_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "rpms", ["project_id", "arch_id"], :name => "index_rpms_on_project_id_and_arch_id"
@ -302,8 +317,8 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.boolean "new_comment_reply", :default => true
t.boolean "new_issue", :default => true
t.boolean "issue_assign", :default => true
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "new_comment_commit_owner", :default => true
t.boolean "new_comment_commit_repo_owner", :default => true
t.boolean "new_comment_commit_commentor", :default => true
@ -313,26 +328,26 @@ ActiveRecord::Schema.define(:version => 20120206225130) do
t.string "subscribeable_id"
t.string "subscribeable_type"
t.integer "user_id"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "status", :default => true
t.integer "project_id"
end
create_table "users", :force => true do |t|
t.string "name"
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
t.string "email", :default => "", :null => false
t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

126
public/invite.html Normal file
View File

@ -0,0 +1,126 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Сборочная среда</title>
<script type="text/javascript" src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<link rel="stylesheet" type="text/css" href="styles/prereg.css" />
</head>
<body>
<div class="wrap">
<!--Top block-->
<header>
<div class="logo">
</div>
<div class="text">
Платформа разработки и управления жизненным циклом дистрибутивов: от исходного кода до ISO-образов
</div>
<div class="both">
</div>
</header>
<!--Page-->
<article>
<div class="left">
<p>
Приветствуем Вас!<br /><br />
Вы находитесь на странице размещения заявок на участие в бета-тестировании сборочного сервиса ABF компании РОСА.<br /><br />
В первую очередь одобряются заявки от потенциальных майнтейнеров и представителей дистрибутивных команд.<br /><br />
Ознакомиться с документацией можно <a href="http://wiki.rosalab.ru/index.php/Сборочная_среда_ABF">здесь</a>.<br /><br />
Мы будем рады ответить на Ваши вопросы на <a href="http://forum.rosalab.ru/viewforum.php?f=10">форуме</a> проекта.
</p>
<div style="clear: both;">
</div>
</div>
<div class="right">
<h3>Хочу стать бета-тестером ABF!</h3>
<form accept-charset="UTF-8" name='invite_form' action="/users/register_requests" id="new_register_request" method="post">
<div class="signup-left">
Имя, Фамилия
</div>
<div class="signup-right">
<input type="text" id="email" name="register_request[name]" class="registartion-input-signup" onkeydown="buttonCheck();" onClick="this.className='registartion-input-focus';disError(this);" onfocus="if(this.value=='Логин или email'){this.value='';this.className='registartion-input-focus';};" onblur="if(this.value==''){this.value='';this.className='registartion-input-signup';}else{this.className='registartion-input-no-focus';};buttonCheck();" />
</div>
<div style="clear: both;">
</div>
<div class="signup-left">
Электронная почта
</div>
<div class="signup-right">
<input type="text" id="email" name="register_request[email]" class="registartion-input-signup" onkeydown="buttonCheck();" onClick="this.className='registartion-input-focus';disError(this);" onfocus="if(this.value=='Логин или email'){this.value='';this.className='registartion-input-focus';};" onblur="if(this.value==''){this.value='';this.className='registartion-input-signup';}else{this.className='registartion-input-no-focus';};buttonCheck();" />
</div>
<div style="clear: both;">
</div>
<div class="signup-left">
Степень интереса<br>к проекту
</div>
<div class="signup-right">
<select name="register_request[interest]" class="registartion-input-signup">
<option>Общеобразовательные цели</option>
<option>Хочу стать майнтейнером РОСы</option>
<option>Хочу собрать в ABF дистрибутив</option>
</select>
</div>
<div style="clear: both;">
</div>
<div class="signup-left">
Также хочу сказать
</div>
<div class="signup-right">
<textarea name="register_request[more]" class="registartion-input-signup" rows="3"></textarea>
</div>
<div style="clear: both;">
</div>
<div class="button">
<input class="button" type="submit" value="Отправить">
</div>
</form>
</div>
<div style="clear: both;">
</div>
<div class="both">
</div>
</article>
</div>
<!--Footer-->
<footer>
<ul>
<li>
ROSA Лаб. © 2012 <img src="pics/square.png" alt="_" />
</li>
<li>
<img src="pics/flag.png" alt="rosa" /> <img src="pics/square.png" alt="_" />
</li>
<li>
<a href="http://www.rosalab.ru/about">О компании</a> <img src="pics/square.png" alt="_" />
</li>
<li>
<a href="http://www.rosalab.ru/about/contacts">Контакты</a>
</li>
</ul>
</footer>
<script type="text/javascript">
 var _gaq = _gaq || [];
 _gaq.push(['_setAccount', 'UA-29164163-1']);
 _gaq.push(['_trackPageview']);
 (function() {
   var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
   ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
   var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 })();
</script>
</body>
</html>

BIN
public/pics/bg-signup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
public/pics/bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
public/pics/flag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
public/pics/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
public/pics/square.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

243
public/styles/prereg.css Normal file
View File

@ -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;
}

72
public/thanks.html Normal file
View File

@ -0,0 +1,72 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Сборочная среда</title>
<script type="text/javascript" src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<link rel="stylesheet" type="text/css" href="styles/prereg.css" />
</head>
<body>
<div class="wrap">
<!--Top block-->
<header>
<div class="logo">
</div>
<div class="text">
Платформа разработки и управления жизненным циклом дистрибутивов: от исходного кода до ISO-образов
</div>
<div class="both">
</div>
</header>
<!--Page-->
<article>
<div class="all">
<p>
<span style="font-size: 28px;">Спасибо!</span><br /><br />
Благодарим за интерес к нашему сервису ABF!<br /><br />
Приглашение будет выслано вам по указанной электронной почте.<br /><br />
Приглашаем Вас на <a href="http://forum.rosalab.ru/viewforum.php?f=10">форум</a> проекта, где мы будем рады ответить на Ваши вопросы и получить Ваши пожелания.<br /><br />
Ознакомиться с документацией можно <a href="http://wiki.rosalab.ru/index.php/Сборочная_среда_ABF">здесь</a>.
</p>
</div>
<div class="both">
</div>
</article>
</div>
<!--Footer-->
<footer>
<ul>
<li>
ROSA Лаб. © 2012 <img src="pics/square.png" alt="_" />
</li>
<li>
<img src="pics/flag.png" alt="rosa" /> <img src="pics/square.png" alt="_" />
</li>
<li>
<a href="http://www.rosalab.ru/about">О компании</a> <img src="pics/square.png" alt="_" />
</li>
<li>
<a href="http://www.rosalab.ru/about/contacts">Контакты</a>
</li>
</ul>
</footer>
<script type="text/javascript">
 var _gaq = _gaq || [];
 _gaq.push(['_setAccount', 'UA-29164163-1']);
 _gaq.push(['_trackPageview']);
 (function() {
   var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
   ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
   var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
 })();
</script>
</body>
</html>

View File

@ -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

View File

@ -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)

View File

@ -0,0 +1,5 @@
require 'spec_helper'
describe RegisterRequest do
pending "add some examples to (or delete) #{__FILE__}"
end