Merge branch 'master' into 123-activity-feed

This commit is contained in:
konstantin.grabar 2012-02-14 14:30:27 +04:00
commit 5039907431
64 changed files with 1195 additions and 94 deletions

View File

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

View File

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

View File

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

View File

@ -6,7 +6,8 @@ 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
redirect_to edit_project_collaborators_path(@project)
@ -130,4 +131,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,10 +230,10 @@ 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 'destroy' then "Removed page #{@name.to_s}"
when 'revert' then "Reverted page #{@name.to_s}"
when 'revert_wiki' then "Reverted wiki"
end
@ -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
@ -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

View File

@ -2,10 +2,11 @@
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
@ -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

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

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

@ -1,5 +1,5 @@
= 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}"

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,6 +4,7 @@
%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)
- 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

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

@ -57,3 +57,4 @@
#sidebar
= yield :sidebar
= render 'layouts/counters' unless current_user.try(:admin?)

View File

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

View File

@ -5,6 +5,7 @@
%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)
- 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

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,6 +5,7 @@
%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)
- 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

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

View File

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

View File

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

View File

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

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,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"
@ -330,9 +346,7 @@ ActiveRecord::Schema.define(:version => 20120131124517) do
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 "reset_password_token"
t.string "remember_token"
t.datetime "remember_created_at"
t.datetime "created_at"
t.datetime "updated_at"
@ -340,6 +354,7 @@ ActiveRecord::Schema.define(:version => 20120131124517) do
t.string "uname"
t.string "role"
t.string "language", :default => "en"
t.datetime "reset_password_sent_at"
t.integer "own_projects_count", :default => 0, :null => false
end

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_with_forced_encoding(name, version = @ref)
page_without_forced_encoding(force_grit_encoding(name), version)
end
alias_method_chain :page, :forced_encoding
def page(name, version = @ref)
native_gollum_page(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_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_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
def file(name, version = @ref)
native_gollum_file(force_grit_encoding(name), version)
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
def write_page(name, format, data, commit = {})
native_gollum_write_page(force_grit_encoding(name), format, data, commit)
files.each do |(path, name, format)|
dir = ::File.dirname(path)
dir = '' if dir == '.'
index.update_working_dir(dir, name, format)
end
end
def update_page(page, name, format, data, commit = {})
native_gollum_update_page(page, force_grit_encoding(name), format, data, commit)
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>

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

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

View File

@ -37,7 +37,7 @@ li.commit .message {
li.commit .trees {
padding-left: 5px;
width: 180px;
width: 200px;
}
li.commit .message a {

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