├── lib └── tasks │ └── .gitkeep ├── .rspec ├── vendor ├── plugins │ └── .gitkeep └── assets │ ├── stylesheets │ ├── icon.css │ ├── reset.css │ ├── code.css │ ├── wmd.css │ ├── form.css │ └── 960gs.css │ └── javascripts │ └── jquery.flash.js ├── app ├── helpers │ ├── items_helper.rb │ ├── pages_helper.rb │ ├── users_helper.rb │ ├── comments_helper.rb │ ├── searches_helper.rb │ ├── sessions_helper.rb │ ├── authentications_helper.rb │ └── application_helper.rb ├── assets │ ├── images │ │ ├── feed.png │ │ ├── guest.png │ │ ├── github_64.png │ │ ├── hpc128x92.png │ │ ├── open_id_64.png │ │ ├── twitter_64.png │ │ ├── icon-sprite.png │ │ ├── wmd-buttons.png │ │ ├── railsclub128x92.png │ │ ├── travis-ci50x50.png │ │ ├── iosonrails120x120.png │ │ └── digitalocean-badge-gray.png │ ├── javascripts │ │ └── application.js │ └── stylesheets │ │ └── application.css ├── views │ ├── comments │ │ ├── _preview.html.erb │ │ ├── _comment.html.erb │ │ ├── _form.html.erb │ │ ├── _new.html.erb │ │ └── create.js.erb │ ├── items │ │ ├── _preview.html.erb │ │ ├── edit.html.erb │ │ ├── new.html.erb │ │ ├── index.rss.builder │ │ ├── _form.html.erb │ │ ├── index.html.erb │ │ └── show.html.erb │ ├── pages │ │ └── show.html.erb │ ├── sessions │ │ └── new.html.erb │ ├── searches │ │ └── index.html.erb │ ├── users │ │ ├── index.html.erb │ │ └── show.html.erb │ └── layouts │ │ └── application.html.erb ├── models │ ├── search.rb │ ├── comment.rb │ ├── ability.rb │ ├── item.rb │ ├── authentication.rb │ └── user.rb └── controllers │ ├── sessions_controller.rb │ ├── pages_controller.rb │ ├── searches_controller.rb │ ├── comments_controller.rb │ ├── users_controller.rb │ ├── authentications_controller.rb │ ├── items_controller.rb │ └── application_controller.rb ├── Procfile ├── public ├── favicon.ico ├── markdown-reference │ ├── images │ │ ├── arrow_down.gif │ │ └── arrow_right.gif │ ├── javascripts │ │ └── guide.js │ ├── LICENCE │ ├── README.md │ ├── stylesheets │ │ └── markdown-reference.css │ ├── sv │ │ └── index.html │ ├── ru │ │ └── index.html │ ├── fr │ │ └── index.html │ ├── en │ │ └── index.html │ ├── ca │ │ └── index.html │ ├── tr │ │ └── index.html │ ├── index.html │ └── es │ │ └── index.html ├── robots.txt ├── 404.html ├── 422.html └── 500.html ├── config ├── locales │ ├── searches.ru.yml │ ├── comments.ru.yml │ ├── authentications.ru.yml │ ├── pagination.ru.yml │ ├── users.ru.yml │ ├── cancan.ru.yml │ ├── sessions.ru.yml │ ├── layouts.ru.yml │ ├── items.ru.yml │ ├── pages.ru.yml │ ├── activerecord.ru.yml │ └── active_support.yml ├── initializers │ ├── bugsnag.rb │ ├── mime_types.rb │ ├── action_mailer.rb │ ├── omniauth.rb │ ├── backtrace_silencers.rb │ ├── session_store.rb │ ├── secret_token.rb │ ├── wrap_parameters.rb │ └── inflections.rb ├── environment.rb ├── boot.rb ├── application.example.yml ├── unicorn.rb ├── database.example.yml ├── routes.rb ├── environments │ ├── development.rb │ ├── test.rb │ └── production.rb └── application.rb ├── spec ├── controllers │ ├── pages_controller_spec.rb │ ├── searches_controller_spec.rb │ ├── sessions_controller_spec.rb │ ├── comments_controller_spec.rb │ ├── authentications_controller_spec.rb │ ├── users_controller_spec.rb │ └── items_controller_spec.rb ├── factories │ ├── comment.rb │ ├── item.rb │ ├── authentication.rb │ └── user.rb ├── models │ ├── search_spec.rb │ ├── comment_spec.rb │ ├── authentication_spec.rb │ ├── item_spec.rb │ └── user_spec.rb ├── helpers │ ├── items_helper_spec.rb │ ├── pages_helper_spec.rb │ ├── users_helper_spec.rb │ ├── comments_helper_spec.rb │ ├── searches_helper_spec.rb │ ├── sessions_helper_spec.rb │ └── authentications_helper_spec.rb └── spec_helper.rb ├── config.ru ├── doc └── README_FOR_APP ├── Rakefile ├── script └── rails ├── README.md ├── db ├── seeds.rb └── migrate │ ├── 20101220184946_create_users.rb │ ├── 20101220185034_create_authentications.rb │ ├── 20101225114202_create_items.rb │ └── 20110107071143_create_comments.rb ├── .gitignore ├── Gemfile ├── LICENSE └── Gemfile.lock /lib/tasks/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --colour 2 | -------------------------------------------------------------------------------- /vendor/plugins/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/helpers/items_helper.rb: -------------------------------------------------------------------------------- 1 | module ItemsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/pages_helper.rb: -------------------------------------------------------------------------------- 1 | module PagesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/users_helper.rb: -------------------------------------------------------------------------------- 1 | module UsersHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/comments_helper.rb: -------------------------------------------------------------------------------- 1 | module CommentsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/searches_helper.rb: -------------------------------------------------------------------------------- 1 | module SearchesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/sessions_helper.rb: -------------------------------------------------------------------------------- 1 | module SessionsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/authentications_helper.rb: -------------------------------------------------------------------------------- 1 | module AuthenticationsHelper 2 | end 3 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec unicorn config.ru -c config/unicorn.rb -p $PORT -E $RAILS_ENV -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /app/assets/images/feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/feed.png -------------------------------------------------------------------------------- /app/assets/images/guest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/guest.png -------------------------------------------------------------------------------- /config/locales/searches.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | searches: 3 | index: 4 | title: "Результаты поиска" -------------------------------------------------------------------------------- /app/assets/images/github_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/github_64.png -------------------------------------------------------------------------------- /app/assets/images/hpc128x92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/hpc128x92.png -------------------------------------------------------------------------------- /app/assets/images/open_id_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/open_id_64.png -------------------------------------------------------------------------------- /app/assets/images/twitter_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/twitter_64.png -------------------------------------------------------------------------------- /config/initializers/bugsnag.rb: -------------------------------------------------------------------------------- 1 | Bugsnag.configure do |config| 2 | config.api_key = ENV['BUGSNAG_API_KEY'] 3 | end -------------------------------------------------------------------------------- /app/assets/images/icon-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/icon-sprite.png -------------------------------------------------------------------------------- /app/assets/images/wmd-buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/wmd-buttons.png -------------------------------------------------------------------------------- /spec/controllers/pages_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe PagesController do 4 | 5 | end 6 | -------------------------------------------------------------------------------- /app/assets/images/railsclub128x92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/railsclub128x92.png -------------------------------------------------------------------------------- /app/assets/images/travis-ci50x50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/travis-ci50x50.png -------------------------------------------------------------------------------- /app/assets/images/iosonrails120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/iosonrails120x120.png -------------------------------------------------------------------------------- /config/locales/comments.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | comments: 3 | new: 4 | create: "Добавить" 5 | processing: "Сохранение..." -------------------------------------------------------------------------------- /app/assets/images/digitalocean-badge-gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/app/assets/images/digitalocean-badge-gray.png -------------------------------------------------------------------------------- /public/markdown-reference/images/arrow_down.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/public/markdown-reference/images/arrow_down.gif -------------------------------------------------------------------------------- /public/markdown-reference/images/arrow_right.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soulim/rbflow/HEAD/public/markdown-reference/images/arrow_right.gif -------------------------------------------------------------------------------- /spec/factories/comment.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :comment do 3 | item 4 | user 5 | markdown "**bar**" 6 | end 7 | end -------------------------------------------------------------------------------- /spec/factories/item.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :item do 3 | user 4 | title "foo" 5 | markdown "**bar**" 6 | end 7 | end -------------------------------------------------------------------------------- /config/locales/authentications.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | authentications: 3 | destroy: 4 | successful: "Провайдер удален, но его всегда можно добавить обратно" -------------------------------------------------------------------------------- /app/views/comments/_preview.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
Просмотр
3 |
<%=raw comment.html %>
4 |
5 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rbflow::Application 5 | -------------------------------------------------------------------------------- /spec/factories/authentication.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :authentication do 3 | user 4 | sequence(:uid) { |n| "foo-#{n}" } 5 | provider "foo" 6 | end 7 | end -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the rails application 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the rails application 5 | Rbflow::Application.initialize! 6 | -------------------------------------------------------------------------------- /config/locales/pagination.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | views: 3 | pagination: 4 | first: "«" 5 | last: "»" 6 | previous: "←" 7 | next: "→" 8 | truncate: "..." -------------------------------------------------------------------------------- /app/views/items/_preview.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
Просмотр
3 |

<%= item.title %>

4 |
<%=raw item.html %>
5 |
6 | -------------------------------------------------------------------------------- /app/models/search.rb: -------------------------------------------------------------------------------- 1 | class Search 2 | def initialize(resource = Item) 3 | @resource = resource 4 | end 5 | 6 | def perform(query = '') 7 | @resource.basic_search(:html => query) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | 3 | # Set up gems listed in the Gemfile. 4 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 5 | 6 | require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) 7 | -------------------------------------------------------------------------------- /doc/README_FOR_APP: -------------------------------------------------------------------------------- 1 | Use this README file to introduce your application and point to useful places in the API for learning more. 2 | Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. 3 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-Agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | # Mime::Type.register_alias "text/html", :iphone 6 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < ApplicationController 2 | def new; end 3 | 4 | def destroy 5 | session[:user_id] = nil 6 | redirect_to root_url, :notice => t("sessions.destroy.successful") 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | //= require jquery 2 | //= require jquery_ujs 3 | //= require jquery.flash 4 | //= require highlight.pack 5 | //= require wmd.combined.min 6 | 7 | $(document).ready(function() { 8 | $.flash(); // toggle flash messages 9 | }); -------------------------------------------------------------------------------- /app/controllers/pages_controller.rb: -------------------------------------------------------------------------------- 1 | class PagesController < ApplicationController 2 | respond_to :html 3 | 4 | def show 5 | @page = params[:id] 6 | render(:layout => false, :file => "public/404.html", :status => :not_found) unless %w(about).include?(@page) 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/searches_controller.rb: -------------------------------------------------------------------------------- 1 | class SearchesController < ApplicationController 2 | respond_to :html 3 | 4 | def index 5 | @search = Search.new(Item) 6 | respond_with @items = @search.perform(params[:q]).page(params[:page]).per(20) 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | require 'rake' 6 | 7 | Rbflow::Application.load_tasks 8 | -------------------------------------------------------------------------------- /app/views/comments/_comment.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | <%= comment.user.name %> 5 |
6 | <%=raw comment.html %> 7 |
-------------------------------------------------------------------------------- /config/initializers/action_mailer.rb: -------------------------------------------------------------------------------- 1 | ActionMailer::Base.smtp_settings = { 2 | :address => ENV['SMTP_ADDRESS'], 3 | :port => ENV['SMTP_PORT'], 4 | :user_name => ENV['SMTP_USERNAME'], 5 | :password => ENV['SMTP_PASSWORD'] 6 | } 7 | ActionMailer::Base.default_url_options[:host] = ENV['SMTP_HOST'] 8 | -------------------------------------------------------------------------------- /config/application.example.yml: -------------------------------------------------------------------------------- 1 | # Add application configuration variables here, as shown below. 2 | # 3 | # PUSHER_APP_ID: "2954" 4 | # PUSHER_KEY: 7381a978f7dd7f9a1117 5 | # PUSHER_SECRET: abdc3b896a0ffb85d373 6 | # STRIPE_API_KEY: EdAvEPVEC3LuaTg5Q3z6WbDVqZlcBQ8Z 7 | # STRIPE_PUBLIC_KEY: pk_BRgD57O8fHja9HxduJUszhef6jCyS 8 | -------------------------------------------------------------------------------- /script/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. 3 | 4 | APP_PATH = File.expand_path('../../config/application', __FILE__) 5 | require File.expand_path('../../config/boot', __FILE__) 6 | require 'rails/commands' 7 | -------------------------------------------------------------------------------- /config/initializers/omniauth.rb: -------------------------------------------------------------------------------- 1 | require 'openid/store/filesystem' 2 | 3 | Rails.application.config.middleware.use OmniAuth::Builder do 4 | provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET'] 5 | provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET'] 6 | provider :openid, :store => OpenID::Store::Filesystem.new('/tmp') 7 | end -------------------------------------------------------------------------------- /config/locales/users.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | users: 3 | index: 4 | title: "Авторы" 5 | approve: "Доверять" 6 | unapprove: "Не доверять" 7 | destroy: "Удалить" 8 | show: 9 | title: "Аккаунт" 10 | providers: "Провайдеры аутентификации" 11 | add_provider: "Добавить" 12 | remove_provider: "Удалить" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RbFlow 2 | 3 | ## Descripton 4 | 5 | RbFlow is community blog engine which works behind rubyflow.ru 6 | 7 | ## Resources 8 | 9 | * Issue tracker -- [github.com/soulim/rbflow/issues](https://github.com/soulim/rbflow/issues) 10 | 11 | ## License 12 | 13 | See the file LICENSE 14 | 15 | Copyright (c) 2010-2016, Alexander Sulim 16 | -------------------------------------------------------------------------------- /app/controllers/comments_controller.rb: -------------------------------------------------------------------------------- 1 | class CommentsController < ApplicationController 2 | load_and_authorize_resource :item 3 | load_and_authorize_resource :comment, :through => :item 4 | 5 | respond_to :js 6 | 7 | def create 8 | @comment.user = current_user 9 | respond_with(@item, @comment.save) 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/views/pages/show.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, t(".#{@page}.title") %> 2 | 3 |
4 |   5 |
6 |
7 |

<%= t(".#{@page}.title") %>

8 | <%= RDiscount.new(t(".#{@page}.markdown")).to_html.html_safe %> 9 |
10 |
11 |   12 |
-------------------------------------------------------------------------------- /config/locales/cancan.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | unauthorized: 3 | manage: 4 | all: "Неа, нужно быть админом!" 5 | create: 6 | all: "Сначала авторизуйтесь!" 7 | update: 8 | user: "Можно редактировать только свой аккаунт!" 9 | item: "Нет доступа, потому что вы не автор статьи!" 10 | destroy: 11 | all: "Неа, нужно быть админом!" 12 | -------------------------------------------------------------------------------- /spec/controllers/searches_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SearchesController do 4 | let(:result) { Kaminari.paginate_array([]) } 5 | 6 | describe "GET index" do 7 | it "performs search for some items" do 8 | Search.any_instance.should_receive(:perform).and_return(result) 9 | get :index 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /spec/factories/user.rb: -------------------------------------------------------------------------------- 1 | FactoryGirl.define do 2 | factory :user do 3 | name "John 'user' Doe" 4 | email "user@example.com" 5 | avatar_url "" 6 | role 0 7 | end 8 | 9 | factory :admin do 10 | name "John 'user' Doe" 11 | email "user@example.com" 12 | avatar_url "" 13 | role 1 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /spec/models/search_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Search do 4 | let(:resource) { double('resource') } 5 | 6 | subject { Search.new(resource) } 7 | 8 | describe '#find' do 9 | it 'should perform basic search on resource' do 10 | resource.should_receive(:basic_search) 11 | 12 | subject.perform('foo') 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }]) 7 | # Mayor.create(:name => 'Daley', :city => cities.first) 8 | -------------------------------------------------------------------------------- /app/views/comments/_form.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | <%= f.text_area :markdown, :placeholder => t("activerecord.attributes.comment.markdown"), :rows => 10, :autofocus => true %> 4 |
5 | <% content_for :footer_js do %> 6 | 11 | <% end %> -------------------------------------------------------------------------------- /config/unicorn.rb: -------------------------------------------------------------------------------- 1 | listen '/tmp/unicorn.rubyflow.sock' 2 | worker_processes 4 3 | timeout 30 4 | preload_app true 5 | 6 | before_fork do |server, worker| 7 | defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! 8 | end 9 | 10 | after_fork do |server, worker| 11 | defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection 12 | end -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | .DS_Store 3 | .ruby-version 4 | .env 5 | db/*.sqlite3 6 | db/schema.rb 7 | db/sphinx/**/* 8 | log/*.log 9 | log/*.pid 10 | tmp/**/* 11 | config/database.yml 12 | config/omniauth.yml 13 | config/mail.yml 14 | config/newrelic.yml 15 | config/thinking_sphinx.yml 16 | config/deploy.rb 17 | config/deploy 18 | config/*.sphinx.conf 19 | 20 | # Ignore application configuration 21 | /config/application.yml 22 | -------------------------------------------------------------------------------- /config/locales/sessions.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | sessions: 3 | new: 4 | choose_provider: "Выберите провайдера:" 5 | description: | 6 | ## Нужно дополнить список? 7 | 8 | Можно добавить любого провайдера, которого поддерживает [OmniAuth](https://github.com/intridea/omniauth). Напишите мне на [soulim@gmail.com](mailto:soulim@gmail.com) 9 | destroy: 10 | successful: "Удачи желаю! :)" -------------------------------------------------------------------------------- /app/models/comment.rb: -------------------------------------------------------------------------------- 1 | class Comment < ActiveRecord::Base 2 | belongs_to :item 3 | belongs_to :user 4 | 5 | validates_presence_of :item_id, :user_id, :markdown 6 | 7 | attr_accessible :markdown 8 | 9 | before_save :assign_html, :if => :markdown? 10 | 11 | private 12 | 13 | def assign_html 14 | self.html = RDiscount.new(self.markdown, :filter_styles, :filter_html, :autolink).to_html 15 | end 16 | end -------------------------------------------------------------------------------- /public/markdown-reference/javascripts/guide.js: -------------------------------------------------------------------------------- 1 | $(window).ready(function() { 2 | $('.section-name').each(function(i) { 3 | if(i > 0){ 4 | toggleSection(i); 5 | } 6 | 7 | $(this).click(function() { 8 | toggleSection(i) 9 | }); 10 | }); 11 | }); 12 | 13 | function toggleSection(i) { 14 | $('.section').slice(i, i + 1).toggle(); 15 | $('.section-name').slice(i, i + 1).toggleClass('deselected'); 16 | } -------------------------------------------------------------------------------- /db/migrate/20101220184946_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration 2 | def self.up 3 | create_table :users do |t| 4 | t.string :name 5 | t.string :email 6 | t.string :avatar_url 7 | t.integer :role, :default => 0, :null => false 8 | t.datetime :approved_at 9 | 10 | t.timestamps 11 | end 12 | end 13 | 14 | def self.down 15 | drop_table :users 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rbflow::Application.config.session_store :cookie_store, key: '_rbflow_session' 4 | 5 | # Use the database for sessions instead of the cookie-based default, 6 | # which shouldn't be used to store highly confidential information 7 | # (create the session table with "rails generate session_migration") 8 | # Rbflow::Application.config.session_store :active_record_store 9 | -------------------------------------------------------------------------------- /spec/controllers/sessions_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe SessionsController do 4 | before { session[:user_id] = 1 } 5 | 6 | describe "DELETE destroy" do 7 | it "drops user's session" do 8 | delete :destroy 9 | session[:user_id].should be_nil 10 | end 11 | 12 | it "redirects to home url" do 13 | delete :destroy 14 | response.should redirect_to(root_url) 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/views/comments/_new.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= render :partial => "comments/preview", :locals => { :comment => comment } %> 3 |
4 |
5 | <%= form_for [item, comment], :remote => true do |f| %> 6 | <%= render :partial => "comments/form", :locals => { :f => f } %> 7 |
8 | <%= f.submit t(".create"), :disable_with => t(".processing") %> 9 |
10 | <% end %> 11 |
-------------------------------------------------------------------------------- /db/migrate/20101220185034_create_authentications.rb: -------------------------------------------------------------------------------- 1 | class CreateAuthentications < ActiveRecord::Migration 2 | def self.up 3 | create_table :authentications do |t| 4 | t.integer :user_id 5 | t.string :provider 6 | t.string :uid 7 | 8 | t.timestamps 9 | end 10 | 11 | add_index :authentications, [:uid, :provider], :uniq => true 12 | end 13 | 14 | def self.down 15 | drop_table :authentications 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /app/views/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= t(".choose_provider") %>

3 | 8 |
9 |
10 | <%= markdown t(".description") %> 11 |
-------------------------------------------------------------------------------- /config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | Rbflow::Application.config.secret_token = ENV['SESSION_SECRET'] || 'afake32charactertokenfortesting' 8 | -------------------------------------------------------------------------------- /db/migrate/20101225114202_create_items.rb: -------------------------------------------------------------------------------- 1 | class CreateItems < ActiveRecord::Migration 2 | def self.up 3 | create_table :items do |t| 4 | t.belongs_to :user 5 | t.string :title 6 | t.text :markdown 7 | t.text :html 8 | 9 | t.timestamps 10 | end 11 | 12 | add_index :items, :created_at 13 | add_index :items, :user_id 14 | end 15 | 16 | def self.down 17 | drop_table :items 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /db/migrate/20110107071143_create_comments.rb: -------------------------------------------------------------------------------- 1 | class CreateComments < ActiveRecord::Migration 2 | def self.up 3 | create_table :comments do |t| 4 | t.belongs_to :item 5 | t.belongs_to :user 6 | t.text :markdown 7 | t.text :html 8 | t.timestamps 9 | end 10 | 11 | add_index :comments, :item_id 12 | add_index :comments, :user_id 13 | end 14 | 15 | def self.down 16 | drop_table :comments 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /spec/helpers/items_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the ItemsHelper. For example: 5 | # 6 | # describe ItemsHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe ItemsHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/pages_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the PagesHelper. For example: 5 | # 6 | # describe PagesHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe PagesHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/users_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the UsersHelper. For example: 5 | # 6 | # describe UsersHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe UsersHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/comments_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the CommentsHelper. For example: 5 | # 6 | # describe CommentsHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe CommentsHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/searches_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the SearchesHelper. For example: 5 | # 6 | # describe SearchesHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe SearchesHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /spec/helpers/sessions_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the SessionsHelper. For example: 5 | # 6 | # describe SessionsHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe SessionsHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /app/views/comments/create.js.erb: -------------------------------------------------------------------------------- 1 | <% if @comment.errors.any? %> 2 | $('#item-<%= @item.id %>-new-comment').html('<%= escape_javascript render(:partial => "comments/new", :locals => { :item => @item, :comment => @comment }) %>'); 3 | <% else %> 4 | $('#item-<%= @item.id %>-new-comment').before('<%= escape_javascript render(@comment)%>'); 5 | $('#item-<%= @item.id %>-new-comment').html('<%= escape_javascript render(:partial => "comments/new", :locals => { :item => @item, :comment => @item.comments.new }) %>'); 6 | <% end %> -------------------------------------------------------------------------------- /app/views/items/edit.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, t(".title") %> 2 | 3 |
4 | <%= render :partial => "preview", :locals => { :item => @item } %> 5 |
6 |
7 | <%= form_for @item do |f| %> 8 | <%= render :partial => "form", :locals => { :f => f } %> 9 |
10 | <%= f.submit t(".update"), :disable_with => t(".processing") %> 11 | <%= link_to t(".cancel"), :back %> 12 |
13 | <% end %> 14 |
15 | 16 | -------------------------------------------------------------------------------- /app/views/items/new.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, t(".title") %> 2 | 3 |
4 | <%= render :partial => "preview", :locals => { :item => @item } %> 5 |
6 |
7 | <%= form_for @item do |f| %> 8 | <%= render :partial => "form", :locals => { :f => f } %> 9 |
10 | <%= f.submit t(".create"), :disable_with => t(".processing") %> 11 | <%= link_to t(".cancel"), :back %> 12 |
13 | <% end %> 14 |
15 | 16 | -------------------------------------------------------------------------------- /spec/helpers/authentications_helper_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Specs in this file have access to a helper object that includes 4 | # the AuthenticationsHelper. For example: 5 | # 6 | # describe AuthenticationsHelper do 7 | # describe "string concat" do 8 | # it "concats two strings with spaces" do 9 | # helper.concat_strings("this","that").should == "this that" 10 | # end 11 | # end 12 | # end 13 | describe AuthenticationsHelper do 14 | pending "add some examples to (or delete) #{__FILE__}" 15 | end 16 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # Disable root element in JSON by default. 12 | ActiveSupport.on_load(:active_record) do 13 | self.include_root_in_json = false 14 | end 15 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format 4 | # (all these examples are active by default): 5 | # ActiveSupport::Inflector.inflections do |inflect| 6 | # inflect.plural /^(ox)$/i, '\1en' 7 | # inflect.singular /^(ox)en/i, '\1' 8 | # inflect.irregular 'person', 'people' 9 | # inflect.uncountable %w( fish sheep ) 10 | # end 11 | # 12 | # These inflection rules are supported but not enabled by default: 13 | # ActiveSupport::Inflector.inflections do |inflect| 14 | # inflect.acronym 'RESTful' 15 | # end 16 | -------------------------------------------------------------------------------- /app/views/items/index.rss.builder: -------------------------------------------------------------------------------- 1 | xml.instruct! :xml, :version => "1.0" 2 | xml.rss :version => "2.0" do 3 | xml.channel do 4 | xml.title t("layouts.application.title") 5 | xml.description t("layouts.application.meta_description") 6 | xml.link items_url 7 | xml.language('ru-ru') 8 | 9 | for item in @items.select{ |item| item.user.approved? } 10 | xml.item do 11 | xml.title item.title 12 | xml.description item.html 13 | xml.pubDate item.created_at.to_s(:rfc822) 14 | xml.link item_url(item) 15 | xml.guid item_url(item) 16 | end 17 | end 18 | end 19 | end -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | load_and_authorize_resource 3 | 4 | respond_to :html 5 | 6 | def index 7 | respond_with(@users = User.order("created_at DESC").page(params[:page]).per(20)) 8 | end 9 | 10 | def show 11 | respond_with(@user = current_user) 12 | end 13 | 14 | def approve 15 | respond_with(@user.approve!, :location => users_url) 16 | end 17 | 18 | def unapprove 19 | respond_with(@user.unapprove!, :location => users_url) 20 | end 21 | 22 | def destroy 23 | respond_with(@user.destroy) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/views/items/_form.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= f.text_field :title, :placeholder => t("activerecord.attributes.item.title"), :autofocus => true %> 3 |
4 |
5 |
6 | <%= f.text_area :markdown, :placeholder => t("activerecord.attributes.item.markdown") %> 7 |
8 | <% content_for :footer_js do %> 9 | 20 | <% end %> 21 | -------------------------------------------------------------------------------- /config/database.example.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3-ruby (not necessary on OS X Leopard) 3 | development: 4 | adapter: sqlite3 5 | database: db/development.sqlite3 6 | pool: 5 7 | timeout: 5000 8 | 9 | # Warning: The database defined as "test" will be erased and 10 | # re-generated from your development database when you run "rake". 11 | # Do not set this db to the same as development or production. 12 | test: 13 | adapter: sqlite3 14 | database: db/test.sqlite3 15 | pool: 5 16 | timeout: 5000 17 | 18 | production: 19 | adapter: sqlite3 20 | database: db/production.sqlite3 21 | pool: 5 22 | timeout: 5000 23 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/icon.css: -------------------------------------------------------------------------------- 1 | .icon { 2 | display:inline-block; 3 | vertical-align:middle; 4 | width:16px; 5 | height:16px; 6 | background:transparent url(/assets/icon-sprite.png) 0 0 no-repeat; 7 | } 8 | .item-edit { background-position:0 0; } 9 | .item-remove { background-position:-16px 0; } 10 | .comment-add { background-position:-0px 0; } 11 | .comment-edit { background-position:-48px 0; } 12 | .comment-remove { background-position:-64px 0; } 13 | .user-accept { background-position:-80px 0; } 14 | .user-cancel { background-position:-96px 0; } 15 | .user-edit { background-position:-112px 0; } 16 | .user-remove { background-position:-128px 0; } -------------------------------------------------------------------------------- /app/views/searches/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, t(".title") %> 2 | 3 |
4 |

<%= t(".title") %>

5 |
<%= @items.total_count %>
6 |
7 |
8 | <% for item in @items do %> 9 |
10 |
11 | <%= link_to item.title, item %><%= item.user.name %> 12 |
13 |
<%= item.html.html_safe %>
14 |
15 | <% end %> 16 | <%= paginate @items %> 17 |
18 |
19 |   20 |
21 | 22 | -------------------------------------------------------------------------------- /config/locales/layouts.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | layouts: 3 | application: 4 | meta_description: "Коллективный блог сообщества разработчиков, использующих Ruby" 5 | meta_keywords: "Ruby,JRuby,Rails,Sinatra,Rails3,Authlogic" 6 | meta_author: "" 7 | title: "RubyFlow.ru" 8 | new_item: "Добавить статью" 9 | vacancies: "Вакансии" 10 | account: "Аккаунт" 11 | search: "Поиск" 12 | sign_in: "Вход" 13 | sign_out: "Выход" 14 | about: "О проекте" 15 | terms: "Условия" 16 | users: "Пользователи" 17 | contacts: "Контактная информация" 18 | commons: 19 | destroy_confirmation: "Действительно удалить '%{subject}'?" -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rbflow::Application.routes.draw do 2 | get "searches/index" 3 | 4 | match '/auth/:provider/callback', :to => 'authentications#create' 5 | match '/sign_in', :to => 'sessions#new' 6 | match '/sign_out', :to => 'sessions#destroy' 7 | 8 | resources :sessions, :only => [ :new, :destroy ] 9 | resources :pages, :only => :show 10 | resources :searches, :only => :index 11 | resources :users do 12 | member do 13 | put 'approve' 14 | put 'unapprove' 15 | end 16 | resources :authentications, :only => :destroy 17 | end 18 | resources :items do 19 | resources :comments 20 | end 21 | 22 | root :to => "items#index" 23 | end 24 | -------------------------------------------------------------------------------- /app/models/ability.rb: -------------------------------------------------------------------------------- 1 | class Ability 2 | include CanCan::Ability 3 | 4 | def initialize(user) 5 | user ||= User.new # guest user 6 | 7 | if user.admin? 8 | can :manage, :all 9 | else 10 | can :read, Item 11 | 12 | if !user.guest? 13 | can(:update, Item) { |item| item.author?(user) && item.created_at.today? } 14 | can(:destroy, Item) { |item| item.author?(user) && item.created_at.today? } 15 | can(:create, [Item, Comment]) 16 | can(:show, User) { |_user| _user.me?(user) } 17 | can(:destroy, Authentication) { |authentication| authentication.user_id == user.id && user.authentications.size > 1 } 18 | end 19 | end 20 | end 21 | end -------------------------------------------------------------------------------- /app/models/item.rb: -------------------------------------------------------------------------------- 1 | class Item < ActiveRecord::Base 2 | belongs_to :user 3 | has_many :comments, :dependent => :destroy 4 | 5 | validates_presence_of :title, :markdown 6 | validates_presence_of :user_id, :on => :create 7 | 8 | attr_accessible :title, :markdown 9 | 10 | before_save :assign_html, :if => :markdown? 11 | 12 | scope :recent, includes(:user).order("created_at desc") 13 | 14 | def author?(user) 15 | self.user_id == user.id 16 | end 17 | 18 | def author_name 19 | self.user.blank? ? "" : self.user.name 20 | end 21 | 22 | private 23 | 24 | def assign_html 25 | self.html = RDiscount.new(self.markdown, :filter_styles, :filter_html, :autolink).to_html 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/models/authentication.rb: -------------------------------------------------------------------------------- 1 | class Authentication < ActiveRecord::Base 2 | PROVIDERS = { 3 | "open_id" => "OpenID", 4 | "github" => "GitHub", 5 | "twitter" => "Twitter" 6 | } 7 | 8 | belongs_to :user 9 | 10 | validates_presence_of :user_id, :uid, :provider 11 | validates_uniqueness_of :uid, :scope => :provider 12 | 13 | def self.create_with_omniauth!(auth, user = nil) 14 | user ||= User.create_with_omniauth!(auth) 15 | self.create! do |authentication| 16 | authentication.user = user 17 | authentication.uid = auth['uid'] 18 | authentication.provider = auth['provider'] 19 | end 20 | end 21 | 22 | def provider_name 23 | PROVIDERS[self.provider] 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /app/controllers/authentications_controller.rb: -------------------------------------------------------------------------------- 1 | class AuthenticationsController < ApplicationController 2 | load_and_authorize_resource :only => :destroy 3 | 4 | respond_to :html 5 | 6 | def new; end 7 | 8 | def create 9 | auth = request.env['omniauth.auth'] 10 | 11 | unless @auth = Authentication.find_by_provider_and_uid(auth["provider"], auth["uid"]) 12 | @auth = Authentication.create_with_omniauth!(auth, current_user) 13 | end 14 | self.current_user = @auth.user 15 | 16 | respond_with(@auth) do |format| 17 | format.html { redirect_back_or_default root_url } 18 | end 19 | end 20 | 21 | def destroy 22 | @authentication.destroy and flash[:notice] = t("authentications.destroy.successful") 23 | respond_with(@authentication, :location => user_url(current_user)) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/models/comment_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Comment do 4 | subject { FactoryGirl.build(:comment) } 5 | 6 | it "is valid with valid attributes" do 7 | subject.should be_valid 8 | end 9 | 10 | it "is not valid without user" do 11 | subject.user = nil 12 | subject.should_not be_valid 13 | end 14 | 15 | it "is not valid without item" do 16 | subject.item = nil 17 | subject.should_not be_valid 18 | end 19 | 20 | it "is not valid without markdown" do 21 | subject.markdown = nil 22 | subject.should_not be_valid 23 | end 24 | 25 | context "before save" do 26 | before { subject.save! } 27 | 28 | it "convert markdown to HTML" do 29 | subject.html.should include("") 30 | end 31 | 32 | it "assigns html" do 33 | subject.html.should_not be_blank 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /config/locales/items.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | items: 3 | index: 4 | title: "Коллективный блог сообщества разработчиков, использующих Ruby" 5 | comments: "Комментарии" 6 | new: 7 | title: "Новая статья" 8 | create: "Опубликовать" 9 | cancel: "Отмена" 10 | processing: "Сохранение..." 11 | create: 12 | successful: "Статья добавлена" 13 | edit: 14 | title: "Редактирование статьи" 15 | update: "Обновить" 16 | cancel: "Отмена" 17 | processing: "Сохранение..." 18 | update: 19 | successful: "Статья обновлена" 20 | show: 21 | edit: "Редактировать" 22 | destroy: "Удалить" 23 | comments: "Комментарии" 24 | new_comment: "Добавить свое мнение" 25 | please_sign_in_to_add_comment: "Пожалуйста авторизуйтесь, чтобы добавить комментарий." 26 | destroy: 27 | successful: "Статья удалена" 28 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "rails", "~> 3.2.13" 4 | 5 | gem "jquery-rails", "~> 2.2.1" 6 | gem "omniauth", "~> 1.1.4" 7 | gem "omniauth-openid", "~> 1.0.1" 8 | gem "omniauth-twitter", "~> 0.0.16" 9 | gem "omniauth-github", "~> 1.1.0" 10 | gem "cancan", "~> 1.6.9" 11 | gem "rdiscount", "~> 2.0.7.2" 12 | gem "kaminari", "~> 0.14.1" 13 | gem "pg", "~> 0.15.1" 14 | gem "textacular", "~> 3.0.0", require: "textacular/rails" 15 | gem "foreman", "~> 0.63.0" 16 | gem "unicorn", "~> 4.6.2" 17 | gem "bugsnag", "~> 1.3.6" 18 | gem "figaro", "~> 0.6.4" 19 | 20 | group :assets do 21 | gem "therubyracer", "~> 0.12.2" 22 | gem "uglifier", "~> 2.0.1" 23 | end 24 | 25 | group :development, :test do 26 | gem "rspec-rails", "~> 2.13.1" 27 | gem "mina", :git => "git://github.com/nadarei/mina.git" 28 | end 29 | 30 | group :test do 31 | gem "factory_girl_rails", "~> 4.2.1" 32 | end 33 | 34 | group :production do 35 | gem "newrelic_rpm", "~> 3.6.1.88" 36 | end 37 | -------------------------------------------------------------------------------- /app/controllers/items_controller.rb: -------------------------------------------------------------------------------- 1 | class ItemsController < ApplicationController 2 | load_and_authorize_resource 3 | 4 | respond_to :html 5 | respond_to :rss, :only => :index 6 | 7 | def index 8 | respond_with(@items = Item.recent.page(params[:page]).per(10)) 9 | end 10 | 11 | def new 12 | respond_with(@item = current_user.items.new) 13 | end 14 | 15 | def create 16 | @item = current_user.items.create(params[:item]) and flash[:notice] = t("items.create.successful") 17 | respond_with(@item) 18 | end 19 | 20 | def show 21 | respond_with(@item) 22 | end 23 | 24 | def edit 25 | respond_with(@item) 26 | end 27 | 28 | def update 29 | @item.update_attributes(params[:item]) and flash[:notice] = t("items.update.successful") 30 | respond_with(@item) 31 | end 32 | 33 | def destroy 34 | @item.destroy and flash[:notice] = t("items.destroy.successful") 35 | respond_with(@item) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery 3 | 4 | helper_method :current_user, :signed_in? 5 | 6 | protected 7 | 8 | def current_user 9 | @current_user ||= User.find_by_id(session[:user_id]) if session[:user_id] 10 | end 11 | 12 | def signed_in? 13 | !!current_user 14 | end 15 | 16 | def current_user=(user) 17 | @current_user = user 18 | session[:user_id] = user.id 19 | end 20 | 21 | def store_location 22 | session[:return_to] = request.fullpath 23 | end 24 | 25 | def redirect_back_or_default(default) 26 | redirect_to back_or_default_path(default) 27 | session[:return_to] = nil 28 | end 29 | 30 | def back_or_default_path(default) 31 | session[:return_to] || default 32 | end 33 | 34 | rescue_from CanCan::AccessDenied do |exception| 35 | store_location 36 | redirect_to sign_in_path, :notice => exception.message 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /app/views/users/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= t(".title") %>

3 |
4 |
5 | 6 | <% for user in @users %> 7 | 8 | 9 | 13 | 17 | 18 | <% end %> 19 |
<%= image_tag avatar_url(user), :size => "48x48", :alt => user.name, :class => "avatar" %> 10 | <%= user.name %>
11 | <%= mail_to user.email, nil, :encode => "hex" %> 12 |
14 | <%= (user.approved?) ? link_to(t(".unapprove"), unapprove_user_url(user), :method => :put, :class => "small button") : link_to(t(".approve"), approve_user_url(user), :method => :put, :class => "small button") %> 15 | <%= link_to t(".destroy"), user, :method => :delete, :confirm => t("layouts.commons.destroy_confirmation", :subject => user.name), :class => "small button" %> 16 |
20 | <%= paginate @users %> 21 |
-------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ActiveRecord::Base 2 | ROLES = { 3 | :user => 0, 4 | :admin => 1 5 | } 6 | ROLES.each_pair {|role, code| define_method("#{role}?") { self.role == code } } 7 | 8 | has_many :authentications, :dependent => :destroy 9 | has_many :items, :dependent => :nullify 10 | has_many :comments, :dependent => :destroy 11 | 12 | attr_protected :role 13 | 14 | def self.create_with_omniauth!(auth) 15 | self.create! do |user| 16 | user.name = auth["info"]["name"] 17 | user.email = auth["info"]["email"] 18 | user.avatar_url = auth["info"]["image"] 19 | end 20 | end 21 | 22 | def approved? 23 | !self.approved_at.nil? 24 | end 25 | 26 | def approve! 27 | self.update_attributes(:approved_at => Time.zone.now) 28 | self 29 | end 30 | 31 | def unapprove! 32 | self.update_attributes(:approved_at => nil) 33 | self 34 | end 35 | 36 | def guest? 37 | self.new_record? 38 | end 39 | 40 | def me?(user) 41 | self.id == user.id 42 | end 43 | 44 | def providers 45 | self.authentications.collect(&:provider) 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /public/markdown-reference/LICENCE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008 Pete Nicholls 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | -------------------------------------------------------------------------------- /spec/models/authentication_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Authentication do 4 | subject { FactoryGirl.build(:authentication) } 5 | 6 | it "is valid with valid attributes" do 7 | subject.should be_valid 8 | end 9 | 10 | it "is not valid without user" do 11 | subject.user = nil 12 | subject.should_not be_valid 13 | end 14 | 15 | it "is not valid without uid" do 16 | subject.uid = nil 17 | subject.should_not be_valid 18 | end 19 | 20 | it "is not valid without provider" do 21 | subject.provider = nil 22 | subject.should_not be_valid 23 | end 24 | 25 | it "is not valid without uniq uid scoped to provider" do 26 | other_authentication = FactoryGirl.create(:authentication, :uid => subject.uid, :provider => subject.provider) 27 | subject.should_not be_valid 28 | end 29 | 30 | describe ".create_with_omniauth" do 31 | it "creates a new authentication based on given params" 32 | end 33 | 34 | describe "#provider_name" do 35 | it "returns titleized provider name" do 36 | subject.provider_name.should == Authentication::PROVIDERS[subject.provider] 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | # Flash messages as html 3 | def flash_messages(messages = {}) 4 | messages = flash unless flash.empty? 5 | messages.collect{ |kind, message| flash_message(message, kind) }.join.html_safe 6 | end 7 | 8 | def flash_message(message, kind = :notice) 9 | content_tag :div, message, :class => "message #{kind.to_s}" 10 | end 11 | 12 | def markdown(source) 13 | source.blank? ? "" : RDiscount.new(source).to_html.html_safe 14 | end 15 | 16 | def avatar_url(user) 17 | if user.avatar_url.present? 18 | user.avatar_url 19 | else 20 | default_url = "#{root_url}images/guest.png" 21 | if !user.email.blank? 22 | gravatar_id = Digest::MD5::hexdigest(user.email).downcase 23 | "http://gravatar.com/avatar/#{gravatar_id}.png?s=48&d=#{CGI.escape(default_url)}" 24 | else 25 | default_url 26 | end 27 | end 28 | end 29 | 30 | def icon_tag(icon) 31 | content_tag :i, nil, :class => "icon #{icon}" 32 | end 33 | 34 | def years_tag(from = 2008, to = Date.current.year) 35 | if from != to 36 | "#{from}—#{to}".html_safe 37 | else 38 | from.to_s 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /config/locales/pages.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | pages: 3 | show: 4 | about: 5 | title: "Коллективный блог сообщества разработчиков" 6 | markdown: | 7 | На этом сайте публикуются статьи о языке Ruby и всем, что с ним связано. 8 | 9 | Концепцию RubyFlow создал Питер Купер ([Peter Cooper](http://peterc.org)), автор [Ruby Inside](http://www.rubyinside.com). Опубликованные материлы можно читать непосредственно на сайте, а также через [RSS](http://feedproxy.google.com/rubyflowru) или [Twitter](http://twitter.com/rubyflowru). Но в последние два источника статьи попадают только от проверенных временем авторов. 10 | 11 | Проект в эфире уже третий год и собрал более 1 000 статей. 12 | 13 | Данная версия RubyFlow.ru является проектом с открытым исходным кодом, который всегда можно найти на GitHub -- [github.com/soulim/rbflow](https://github.com/soulim/rbflow). 14 | 15 | Если у вас возникли вопросы, появились идеи или есть интересные предложения, то смело пишите. Постараюсь ответить в тот же день. 16 | 17 | Электронная почта: [soulim@gmail.com](mailto:soulim@gmail.com) 18 | Твиттер: [@rubyflowru](http://twitter.com/rubyflowru) 19 | 20 | 21 | *Александр Сулим, 22 | основатель и ведущий разработчик* 23 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/reset.css: -------------------------------------------------------------------------------- 1 | abbr,article,aside,audio,bb,canvas,datagrid,datalist,details,dialog,figure,footer,header,mark,menu,meter,nav,output,progress,section,time,video { 2 | display:block; 3 | } 4 | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p, 5 | blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn, 6 | em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup, 7 | tt,var,hr,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form, 8 | label,legend { 9 | padding:0; 10 | margin:0; 11 | border:none; 12 | outline:none; 13 | vertical-align:baseline; 14 | } 15 | dfn,i,cite,var,address,em { 16 | font-style:normal; 17 | } 18 | th,b,strong,h1,h2,h3,h4,h5,h6{ 19 | font-weight:normal; 20 | } 21 | textarea,input,select{ 22 | font-family:inherit; 23 | font-size:1em; 24 | } 25 | blockquote,q { 26 | quotes:none; 27 | } 28 | q:before,q:after, 29 | blockquote:before, 30 | blockquote:after { 31 | content:''; 32 | content:none; 33 | } 34 | ol,ul { 35 | list-style:none; 36 | } 37 | ins { 38 | text-decoration:none; 39 | } 40 | del { 41 | text-decoration:line-through; 42 | } 43 | table { 44 | border-collapse:collapse; 45 | border-spacing:0; 46 | } 47 | caption,th,td { 48 | text-align:left; 49 | } 50 | :focus { 51 | outline:none; 52 | } -------------------------------------------------------------------------------- /vendor/assets/javascripts/jquery.flash.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Flash Message Plugin v0.0.1 3 | * http://textro.ws 4 | * 5 | * This document is licensed as free software under the terms of the 6 | * MIT License: http://www.opensource.org/licenses/mit-license.php 7 | * 8 | * Copyright (c) 2010 by Alex Soulim (soulim@gmail.com). 9 | */ 10 | 11 | (function( $ ){ 12 | var $this = $("#flash"); 13 | 14 | var methods = { 15 | init: function () { 16 | if ( $this.html() != "" ) { 17 | $.flash("toggle"); 18 | }; 19 | }, 20 | toggle: function () { 21 | $this.slideDown("slow").delay(4000).slideUp("fast"); 22 | }, 23 | notice: function ( message ) { 24 | $this.html($("
", { "class": "message notice", text: message })); 25 | $.flash("toggle"); 26 | }, 27 | error: function ( message ) { 28 | $this.html($("
", { "class": "message error", text: message })); 29 | $.flash("toggle"); 30 | } 31 | }; 32 | 33 | $.flash = function( method ) { 34 | if ( methods[method] ) { 35 | return methods[method].apply(this, Array.prototype.slice.call( arguments, 1 )); 36 | } else if ( typeof method === 'object' || ! method ) { 37 | return methods.init.apply(this, arguments); 38 | } else { 39 | $.error( 'Method ' + method + ' does not exist on jQuery.flash' ); 40 | } 41 | }; 42 | })( jQuery ); 43 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV["RAILS_ENV"] ||= 'test' 3 | require File.expand_path("../../config/environment", __FILE__) 4 | require 'rspec/rails' 5 | require 'rspec/autorun' 6 | 7 | # Requires supporting ruby files with custom matchers and macros, etc, 8 | # in spec/support/ and its subdirectories. 9 | Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} 10 | 11 | RSpec.configure do |config| 12 | # == Mock Framework 13 | # 14 | # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line: 15 | # 16 | # config.mock_with :mocha 17 | # config.mock_with :flexmock 18 | # config.mock_with :rr 19 | config.mock_with :rspec 20 | 21 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 22 | # config.fixture_path = "#{::Rails.root}/spec/fixtures" 23 | 24 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 25 | # examples within a transaction, remove the following line or assign false 26 | # instead of true. 27 | config.use_transactional_fixtures = true 28 | 29 | # If true, the base class of anonymous controllers will be inferred 30 | # automatically. This will be the default behavior in future versions of 31 | # rspec-rails. 32 | config.infer_base_class_for_anonymous_controllers = false 33 | end 34 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rbflow::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Log error messages when you accidentally call methods on nil. 10 | config.whiny_nils = true 11 | 12 | # Show full error reports and disable caching 13 | config.consider_all_requests_local = true 14 | config.action_controller.perform_caching = false 15 | 16 | # Don't care if the mailer can't send 17 | config.action_mailer.raise_delivery_errors = false 18 | 19 | # Print deprecation notices to the Rails logger 20 | config.active_support.deprecation = :log 21 | 22 | # Only use best-standards-support built into browsers 23 | config.action_dispatch.best_standards_support = :builtin 24 | 25 | # Raise exception on mass assignment protection for Active Record models 26 | config.active_record.mass_assignment_sanitizer = :strict 27 | 28 | # Log the query plan for queries taking more than this (works 29 | # with SQLite, MySQL, and PostgreSQL) 30 | config.active_record.auto_explain_threshold_in_seconds = 0.5 31 | 32 | # Do not compress assets 33 | config.assets.compress = false 34 | 35 | # Expands the lines which load the assets 36 | config.assets.debug = true 37 | end 38 | -------------------------------------------------------------------------------- /app/views/users/show.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, t(".title") %> 2 | 3 |
4 | <%= image_tag avatar_url(@user), :size => "48x48", :alt => @user.name, :class => "avatar" %> 5 |

<%= link_to t("layouts.application.sign_out"), sign_out_url, :class => "link-with-icon" %>

6 |
7 |
8 |

<%= @user.name %> <%= @user.email %>

9 |
10 |
11 |

<%= t(".providers") %>:

12 | 13 | 14 | <% for provider in Authentication::PROVIDERS.keys - @user.providers %> 15 | 16 | 17 | 18 | 19 | 20 | <% end %> 21 | 22 | <% for authentication in @user.authentications %> 23 | 24 | 25 | 26 | 27 | 28 | <% end %> 29 |
<%= image_tag("#{provider}_64.png", :size => "64x64") %><%= Authentication::PROVIDERS[provider] %><%= link_to t(".add_provider"), "/auth/#{provider}", :class => "positive small button min-width uppercase" %>
<%= image_tag("#{authentication.provider}_64.png", :size => "64x64") %><%= authentication.provider_name %><%= link_to(t(".remove_provider"), [current_user, authentication], :method => :delete, :class => "negative small button min-width uppercase") if can?(:destroy, authentication) %>
30 |
-------------------------------------------------------------------------------- /spec/controllers/comments_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe CommentsController do 4 | let(:user) { mock_model(User, :admin? => false, :guest? => false) } 5 | let(:item) { mock_model(Item).as_null_object } 6 | let(:comment) { mock_model(Comment).as_null_object } 7 | 8 | before do 9 | controller.stub(:current_user).and_return(user) 10 | Item.stub(:find).and_return(item) 11 | end 12 | 13 | describe "XHR POST create" do 14 | before do 15 | item.stub_chain(:comments, :new).and_return(comment) 16 | end 17 | 18 | it "assigns @item" do 19 | xhr :post, :create, :item_id => item.id 20 | assigns[:item].should_not be_nil 21 | end 22 | 23 | it "creates a new comment" do 24 | item.comments.should_receive(:new) 25 | xhr :post, :create, :item_id => item.id 26 | end 27 | 28 | it "assigns @comment" do 29 | xhr :post, :create, :item_id => item.id 30 | assigns[:comment].should_not be_nil 31 | end 32 | 33 | it "saves the new comment" do 34 | comment.should_receive(:save) 35 | xhr :post, :create, :item_id => item.id 36 | end 37 | 38 | context "when user is a guest" do 39 | before { controller.stub(:current_user).and_return(nil) } 40 | 41 | it "sets flash notice" do 42 | xhr :post, :create, :item_id => item.id 43 | flash[:notice].should_not be_blank 44 | end 45 | 46 | it "redirects to sign in URL" do 47 | xhr :post, :create, :item_id => item.id 48 | response.should redirect_to(sign_in_url) 49 | end 50 | end 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/controllers/authentications_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe AuthenticationsController do 4 | let(:auth) { mock_model(Authentication).as_null_object } 5 | let(:auth_hash) { { "provider" => "twitter", "uid" => "1234", "info" => {} } } 6 | 7 | before(:each) do 8 | request.env["omniauth.auth"] = auth_hash 9 | end 10 | 11 | context "when authentication already exists" do 12 | before do 13 | Authentication.stub(:find_by_provider_and_uid).and_return(auth) 14 | end 15 | 16 | it "authenticates user" do 17 | controller.should_receive(:current_user=) 18 | get :create, :provider => "twitter" 19 | end 20 | 21 | it "redirects to home page" do 22 | get :create, :provider => "twitter" 23 | response.should redirect_to(root_url) 24 | end 25 | end 26 | 27 | context "when authentication does not exist yet" do 28 | before do 29 | Authentication.stub(:find_by_provider_and_uid).and_return(nil) 30 | Authentication.stub(:create_with_omniauth).and_return(auth) 31 | end 32 | 33 | it "creates a new athentication" do 34 | Authentication.should_receive(:create_with_omniauth!). 35 | with(auth_hash, nil). 36 | and_return(auth) 37 | get :create, :provider => "twitter" 38 | end 39 | 40 | it "authenticates user" do 41 | controller.should_receive(:current_user=) 42 | get :create, :provider => "twitter" 43 | end 44 | 45 | it "redirects to home page" do 46 | get :create, :provider => "twitter" 47 | response.should redirect_to(root_url) 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2016, Alexander Sulim 2 | http://rubyflow.ru/ 3 | All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction except as noted below, including without 8 | limitation the rights to use, copy, modify, merge, publish, distribute, and/or 9 | sublicense, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | - The Software and/or source code cannot be copied in whole and sold without 13 | meaningful modification for a profit. 14 | 15 | - The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | - Redistributions of source code must retain the above copyright notice, this 19 | list of conditions and the following disclaimer. 20 | 21 | - Redistributions in binary form must reproduce the above copyright notice, 22 | this list of conditions and the following disclaimer in the documentation 23 | and/or other materials provided with the distribution. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 27 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 28 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 29 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 14 | 15 | 16 | 17 |
18 |
19 |            444444444       000000000            444444444  
20 |           4::::::::4     00:::::::::00         4::::::::4  
21 |          4:::::::::4   00:::::::::::::00      4:::::::::4  
22 |         4::::44::::4  0:::::::000:::::::0    4::::44::::4  
23 |        4::::4 4::::4  0::::::0   0::::::0   4::::4 4::::4  
24 |       4::::4  4::::4  0:::::0     0:::::0  4::::4  4::::4  
25 |      4::::4   4::::4  0:::::0     0:::::0 4::::4   4::::4  
26 |     4::::444444::::4440:::::0 000 0:::::04::::444444::::444
27 |     4::::::::::::::::40:::::0 000 0:::::04::::::::::::::::4
28 |     4444444444:::::4440:::::0     0:::::04444444444:::::444
29 |               4::::4  0:::::0     0:::::0          4::::4  
30 |               4::::4  0::::::0   0::::::0          4::::4  
31 |               4::::4  0:::::::000:::::::0          4::::4  
32 |             44::::::44 00:::::::::::::00         44::::::44
33 |             4::::::::4   00:::::::::00           4::::::::4
34 |             4444444444     000000000             4444444444
35 |     
36 |

The page you were looking for doesn't exist.

37 |

You may have mistyped the address or the page may have moved.

38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rbflow::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Configure static asset server for tests with Cache-Control for performance 11 | config.serve_static_assets = true 12 | config.static_cache_control = "public, max-age=3600" 13 | 14 | # Log error messages when you accidentally call methods on nil 15 | config.whiny_nils = true 16 | 17 | # Show full error reports and disable caching 18 | config.consider_all_requests_local = true 19 | config.action_controller.perform_caching = false 20 | 21 | # Raise exceptions instead of rendering exception templates 22 | config.action_dispatch.show_exceptions = false 23 | 24 | # Disable request forgery protection in test environment 25 | config.action_controller.allow_forgery_protection = false 26 | 27 | # Tell Action Mailer not to deliver emails to the real world. 28 | # The :test delivery method accumulates sent emails in the 29 | # ActionMailer::Base.deliveries array. 30 | config.action_mailer.delivery_method = :test 31 | 32 | # Raise exception on mass assignment protection for Active Record models 33 | config.active_record.mass_assignment_sanitizer = :strict 34 | 35 | # Print deprecation notices to the stderr 36 | config.active_support.deprecation = :stderr 37 | end 38 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 14 | 15 | 16 | 17 |
18 |
19 |            444444444   222222222222222     222222222222222    
20 |           4::::::::4  2:::::::::::::::22  2:::::::::::::::22  
21 |          4:::::::::4  2::::::222222:::::2 2::::::222222:::::2 
22 |         4::::44::::4  2222222     2:::::2 2222222     2:::::2 
23 |        4::::4 4::::4              2:::::2             2:::::2 
24 |       4::::4  4::::4              2:::::2             2:::::2 
25 |      4::::4   4::::4           2222::::2           2222::::2  
26 |     4::::444444::::444    22222::::::22       22222::::::22   
27 |     4::::::::::::::::4  22::::::::222       22::::::::222     
28 |     4444444444:::::444 2:::::22222         2:::::22222        
29 |               4::::4  2:::::2             2:::::2             
30 |               4::::4  2:::::2             2:::::2             
31 |               4::::4  2:::::2       2222222:::::2       222222
32 |             44::::::442::::::2222222:::::22::::::2222222:::::2
33 |             4::::::::42::::::::::::::::::22::::::::::::::::::2
34 |             44444444442222222222222222222222222222222222222222
35 |     
36 |

The change you wanted was rejected.

37 |

Maybe you tried to change something you didn't have access to.

38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 14 | 15 | 16 | 17 |
18 |
19 |     555555555555555555      000000000          000000000     
20 |     5::::::::::::::::5    00:::::::::00      00:::::::::00   
21 |     5::::::::::::::::5  00:::::::::::::00  00:::::::::::::00 
22 |     5:::::555555555555 0:::::::000:::::::00:::::::000:::::::0
23 |     5:::::5            0::::::0   0::::::00::::::0   0::::::0
24 |     5:::::5            0:::::0     0:::::00:::::0     0:::::0
25 |     5:::::5555555555   0:::::0     0:::::00:::::0     0:::::0
26 |     5:::::::::::::::5  0:::::0 000 0:::::00:::::0 000 0:::::0
27 |     555555555555:::::5 0:::::0 000 0:::::00:::::0 000 0:::::0
28 |                 5:::::50:::::0     0:::::00:::::0     0:::::0
29 |                 5:::::50:::::0     0:::::00:::::0     0:::::0
30 |     5555555     5:::::50::::::0   0::::::00::::::0   0::::::0
31 |     5::::::55555::::::50:::::::000:::::::00:::::::000:::::::0
32 |      55:::::::::::::55  00:::::::::::::00  00:::::::::::::00 
33 |        55:::::::::55      00:::::::::00      00:::::::::00   
34 |          555555555          000000000          000000000     
35 |     
36 |

We're sorry, but something went wrong.

37 |

We've been notified about this issue and we'll take a look at it shortly.

38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /spec/models/item_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe Item do 4 | subject { FactoryGirl.build(:item) } 5 | 6 | it "is valid with valid attributes" do 7 | subject.should be_valid 8 | end 9 | 10 | it "is not valid without user" do 11 | subject.user = nil 12 | subject.should_not be_valid 13 | end 14 | 15 | it "is not valid without title" do 16 | subject.title = nil 17 | subject.should_not be_valid 18 | end 19 | 20 | it "is not valid without markdown" do 21 | subject.markdown = nil 22 | subject.should_not be_valid 23 | end 24 | 25 | context "before save" do 26 | before(:each) { subject.save! } 27 | 28 | it "convert markdown to HTML" do 29 | subject.html.should include("") 30 | end 31 | 32 | it "assigns html" do 33 | subject.html.should_not be_blank 34 | end 35 | end 36 | 37 | describe "#author?" do 38 | context "when given user is author of item" do 39 | it "returns true" do 40 | subject.author?(subject.user).should be_true 41 | end 42 | end 43 | context "when given user is not author of item" do 44 | it "returns false" do 45 | subject.author?(FactoryGirl.create(:user)).should be_false 46 | end 47 | end 48 | end 49 | 50 | describe "#author_name" do 51 | context "when item has author" do 52 | it "returns user's name" do 53 | subject.author_name.should == subject.user.name 54 | end 55 | end 56 | context "when item does not have author" do 57 | it "returns emtry string" do 58 | subject.user = nil 59 | subject.author_name.should == "" 60 | end 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /public/markdown-reference/README.md: -------------------------------------------------------------------------------- 1 | # Human Markdown Reference 2 | 3 | The Human Markdown Reference is a set of short, easy to understand HTML pages you can include in any project that uses Markdown. 4 | 5 | Consider this a fork of [Human Textile Reference](http://github.com/Aupajo/human-textile-reference). 6 | 7 | It is not designed to be a complete reference. Just a quick guide for the layman. For detailed detailed markdown syntax, check the [Markdown page at Daring Fireball](http://daringfireball.net/projects/markdown/). 8 | 9 | It is perfect for including as a pop-up help window next to your textarea. 10 | 11 | # Example 12 | 13 | You can see an example [here](https://webtranslateit.com/markdown-reference/). 14 | 15 | # How To Use 16 | 17 | Copy `markdown-reference` to your project. 18 | 19 | Add a help link to the reference: 20 | 21 | ## HTML Snippet 22 | 23 | You can format your text using 24 | Markdown. 25 | 26 | ## Rails Snippet 27 | 28 | You can format your text using 29 | <%= link_to 'Markdown', '/markdown-reference/index.html', :popup => ['markdown_reference', 'height=400,width=600,scrollbars=1'] %> 30 | 31 | # Internationalization 32 | 33 | You may need a different language than English. Human Markdown reference is current translated into: 34 | 35 | * Catalan 36 | * French 37 | * Russian 38 | * Spanish 39 | * Swedish 40 | 41 | If you spot a mistake or want to contribute a new language, [request an invitation](https://webtranslateit.com/projects/386-HTML-Markdown-Reference/invitation_request) to the translation project. 42 | 43 | Add a help link to the reference: 44 | 45 | ## HTML Snippet 46 | 47 | You can format your text using 48 | Markdown. 49 | 50 | where `xx` is the code of the locale you want to use. 51 | 52 | ## Rails Snippet 53 | 54 | You can format your text using 55 | <%= link_to 'Markdown', "/markdown-reference/#{I18n.locale}", :popup => ['markdown_reference', 'height=400,width=600,scrollbars=1'] %> 56 | 57 | # Contributors 58 | 59 | * Alex Soulim (Russian translations), 60 | * Pere Joan Martorell (Catalan and Spanish translations). 61 | -------------------------------------------------------------------------------- /app/views/items/index.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, t(".title") %> 2 | 3 | <% if params[:page].blank? %> 4 |
5 | 6 |
7 | 10 |
11 |
12 | <% end %> 13 | 14 | <% if !@items.blank? %> 15 | <% @items.group_by{ |item| item.created_at.to_date }.each do |created_at, items| %> 16 |
17 | 20 |
21 | <% for item in items %> 22 |
23 |
24 | <%= link_to item.title, item %><%= item.author_name %> 25 |
26 | 31 | <%=raw item.html %> 32 | <% if !item.comments.blank? %> 33 |
34 |
<%= link_to t(".comments"), item_url(item, :anchor => "comments") %>
35 |
36 |
37 |
38 | 39 | <%= item.comments.last.user.name %> 40 |
41 | <%=raw item.comments.last.html %> 42 |
43 |
44 |
45 | <% end %> 46 |
47 | <% end %> 48 |
49 |
50 | <% end %> 51 | <%= paginate @items %> 52 | <% end %> 53 | -------------------------------------------------------------------------------- /public/markdown-reference/stylesheets/markdown-reference.css: -------------------------------------------------------------------------------- 1 | /* General */ 2 | 3 | body, input, textarea, select { 4 | color: #222; 5 | font: 9pt "Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, sans-serif; 6 | } 7 | 8 | body { 9 | background-color: #d1d7e2; 10 | line-height: 1.6em; 11 | margin: 0; 12 | } 13 | 14 | /* Formatting */ 15 | 16 | p { 17 | margin-top: 0; 18 | } 19 | 20 | /* Headings */ 21 | 22 | h1, h2, h3 { 23 | margin: 0; 24 | } 25 | 26 | h1 { 27 | font-size: 1.6em; 28 | } 29 | 30 | h2 { 31 | font-size: 1.4em; 32 | } 33 | 34 | h3 { 35 | font-size: 1.2em; 36 | } 37 | 38 | /* Lists */ 39 | 40 | ul, ol { 41 | margin: 0; 42 | padding-left: 1.5em; 43 | } 44 | 45 | /* Links */ 46 | 47 | a:link, a:visited { 48 | color: #376bd5; 49 | } 50 | 51 | a:hover { 52 | color: #ff5c07; 53 | } 54 | 55 | a:active { 56 | color: #910; 57 | } 58 | 59 | a img { 60 | border-style: none; 61 | } 62 | 63 | /* Tables */ 64 | 65 | table { 66 | border-top: 1px solid #fff; 67 | border-collapse: collapse; 68 | width: 100%; 69 | } 70 | 71 | td, th { 72 | border-left: 1px solid #d9d9d9; 73 | padding: 5px 10px; 74 | width: 50%; 75 | } 76 | 77 | 78 | th { 79 | background-color: #eee; 80 | border-bottom: 1px solid #d9d9d9; 81 | text-align: left; 82 | } 83 | 84 | tr.alternate { 85 | background-color: #f1f5fa; 86 | } 87 | 88 | table table { 89 | margin: 10px 0; 90 | width: auto; 91 | } 92 | 93 | table table th, table table td { 94 | background-color: #fff; 95 | border: 1px solid #d9d9d9; 96 | padding: 0.2em 0.5em; 97 | width: auto; 98 | } 99 | 100 | /* Forms */ 101 | 102 | form { 103 | border-top: 1px solid #ccc; 104 | padding: 1em; 105 | margin-top: 1em; 106 | } 107 | 108 | /* Special */ 109 | 110 | #title { 111 | background-color: #a1adcb; 112 | border-bottom: 1px solid #b8bdc7; 113 | color: #444; 114 | padding: 10px 10px; 115 | text-shadow: 0px 1px 0px #cdd9fd; 116 | } 117 | 118 | .section-name { 119 | background: url('../images/arrow_down.gif') no-repeat center left; 120 | color: #525252; 121 | cursor: pointer; 122 | display: block; 123 | font-size: 1em; 124 | padding: 5px 10px 5px 16px; 125 | text-shadow: 0 1px 0 #fff; 126 | text-transform: uppercase; 127 | } 128 | 129 | .deselected { 130 | background-image: url('../images/arrow_right.gif'); 131 | } 132 | 133 | .section { 134 | border-color: #b8bdc7; 135 | border-style: solid; 136 | border-width: 1px 0; 137 | background-color: white; 138 | } -------------------------------------------------------------------------------- /app/views/items/show.html.erb: -------------------------------------------------------------------------------- 1 | <% content_for :title, @item.title %> 2 | <% content_for :meta_description, @item.title %> 3 | <% content_for :meta_author, @item.author_name %> 4 | 5 |
6 | 9 |
10 |
11 |
12 |
13 | <%= @item.title %><%= @item.author_name %> 14 |
15 | 20 |
<%= @item.html.html_safe %>
21 |
22 |
<%= t(".comments") %>
23 |
24 | <% for comment in @item.comments %> 25 | <%= render comment %> 26 | <% end %> 27 | <% if can?(:create, Comment) %> 28 |
29 | <%= render(:partial => "comments/new", :locals => { :item => @item, :comment => @item.comments.new }) %> 30 |
31 |

<%= link_to "#{icon_tag("comment-add")} #{t(".new_comment")}".html_safe, nil, :onclick => "$('#item-#{@item.id}-new-comment').slideDown('slow');$(this).hide('fast');return false;", :class => "link-with-icon" %>

32 | <% else %> 33 | <%= t(".please_sign_in_to_add_comment") %> <%= link_to t("layouts.application.sign_in"), sign_in_url %> 34 | <% end %> 35 |
36 |
37 |
38 |
39 |
40 | <% if can?(:edit, @item) %> 41 |
    42 | <%= content_tag :li, link_to("#{icon_tag("item-edit")} #{t(".edit")}".html_safe, edit_item_url(@item), :class => "link-with-icon") if can?(:edit, @item) %> 43 | <%= content_tag :li, link_to("#{icon_tag("item-remove")} #{t(".destroy")}".html_safe, item_url(@item), :method => :delete, :confirm => t("layouts.commons.destroy_confirmation", :subject => @item.title), :class => "link-with-icon") if can?(:destroy, @item) %> 44 |
45 | <% end %> 46 |
47 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rbflow::Application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb 3 | 4 | # Code is not reloaded between requests 5 | config.cache_classes = true 6 | 7 | # Full error reports are disabled and caching is turned on 8 | config.consider_all_requests_local = false 9 | config.action_controller.perform_caching = true 10 | 11 | # Disable Rails's static asset server (Apache or nginx will already do this) 12 | config.serve_static_assets = false 13 | 14 | # Compress JavaScripts and CSS 15 | config.assets.compress = true 16 | 17 | # Don't fallback to assets pipeline if a precompiled asset is missed 18 | config.assets.compile = false 19 | 20 | # Generate digests for assets URLs 21 | config.assets.digest = true 22 | 23 | # Defaults to nil and saved in location specified by config.assets.prefix 24 | # config.assets.manifest = YOUR_PATH 25 | 26 | # Specifies the header that your server uses for sending files 27 | # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache 28 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx 29 | 30 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 31 | # config.force_ssl = true 32 | 33 | # See everything in the log (default is :info) 34 | # config.log_level = :debug 35 | 36 | # Prepend all log lines with the following tags 37 | # config.log_tags = [ :subdomain, :uuid ] 38 | 39 | # Use a different logger for distributed setups 40 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 41 | 42 | # Use a different cache store in production 43 | # config.cache_store = :mem_cache_store 44 | 45 | # Enable serving of images, stylesheets, and JavaScripts from an asset server 46 | # config.action_controller.asset_host = "http://assets.example.com" 47 | 48 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 49 | # config.assets.precompile += %w( search.js ) 50 | 51 | # Disable delivery errors, bad email addresses will be ignored 52 | # config.action_mailer.raise_delivery_errors = false 53 | 54 | # Enable threaded mode 55 | # config.threadsafe! 56 | 57 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 58 | # the I18n.default_locale when a translation can not be found) 59 | config.i18n.fallbacks = true 60 | 61 | # Send deprecation notices to registered listeners 62 | config.active_support.deprecation = :notify 63 | 64 | # Log the query plan for queries taking more than this (works 65 | # with SQLite, MySQL, and PostgreSQL) 66 | # config.active_record.auto_explain_threshold_in_seconds = 0.5 67 | end 68 | -------------------------------------------------------------------------------- /config/locales/activerecord.ru.yml: -------------------------------------------------------------------------------- 1 | ru: 2 | activerecord: 3 | errors: 4 | template: 5 | header: 6 | one: "%{model}: сохранение не удалось из-за %{count} ошибки" 7 | few: "%{model}: сохранение не удалось из-за %{count} ошибок" 8 | many: "%{model}: сохранение не удалось из-за %{count} ошибок" 9 | other: "%{model}: сохранение не удалось из-за %{count} ошибки" 10 | 11 | body: "Проблемы возникли со следующими полями:" 12 | 13 | messages: 14 | inclusion: "имеет непредусмотренное значение" 15 | exclusion: "имеет зарезервированное значение" 16 | invalid: "имеет неверное значение" 17 | confirmation: "не совпадает с подтверждением" 18 | accepted: "нужно подтвердить" 19 | empty: "не может быть пустым" 20 | blank: "не может быть пустым" 21 | too_long: 22 | one: "слишком большой длины (не может быть больше чем %{count} символ)" 23 | few: "слишком большой длины (не может быть больше чем %{count} символа)" 24 | many: "слишком большой длины (не может быть больше чем %{count} символов)" 25 | other: "слишком большой длины (не может быть больше чем %{count} символа)" 26 | too_short: 27 | one: "недостаточной длины (не может быть меньше %{count} символа)" 28 | few: "недостаточной длины (не может быть меньше %{count} символов)" 29 | many: "недостаточной длины (не может быть меньше %{count} символов)" 30 | other: "недостаточной длины (не может быть меньше %{count} символа)" 31 | wrong_length: 32 | one: "неверной длины (может быть длиной ровно %{count} символ)" 33 | few: "неверной длины (может быть длиной ровно %{count} символа)" 34 | many: "неверной длины (может быть длиной ровно %{count} символов)" 35 | other: "неверной длины (может быть длиной ровно %{count} символа)" 36 | taken: "уже существует" 37 | not_a_number: "не является числом" 38 | greater_than: "может иметь значение большее %{count}" 39 | greater_than_or_equal_to: "может иметь значение большее или равное %{count}" 40 | equal_to: "может иметь лишь значение, равное %{count}" 41 | less_than: "может иметь значение меньшее чем %{count}" 42 | less_than_or_equal_to: "может иметь значение меньшее или равное %{count}" 43 | odd: "может иметь лишь четное значение" 44 | even: "может иметь лишь нечетное значение" 45 | record_invalid: "Возникли ошибки: %{errors}" 46 | 47 | full_messages: 48 | format: "%{attribute} %{message}" 49 | 50 | attributes: 51 | user: 52 | name: "Имя" 53 | email: "Электронная почта" 54 | item: 55 | title: "Заголовок" 56 | markdown: "Текст статьи" 57 | comment: 58 | markdown: "Текст комментария" -------------------------------------------------------------------------------- /vendor/assets/stylesheets/code.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 4 | 5 | */ 6 | pre { 7 | padding:0.5em 1em; 8 | -webkit-border-radius:5px; 9 | -moz-border-radius:5px; 10 | border-radius:5px; 11 | border:#CCC 1px dashed; 12 | background-color:#f8f8ff; 13 | -word-wrap:break-word; 14 | overflow:auto; 15 | font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; 16 | } 17 | code {} 18 | pre, 19 | code { 20 | font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif; 21 | font-size:12px; 22 | } 23 | pre code { 24 | -display: block; 25 | -padding: 0.5em; 26 | -color: #000; 27 | } 28 | 29 | pre .comment, 30 | pre .template_comment, 31 | pre .diff .header, 32 | pre .javadoc { 33 | color: #998; 34 | font-style: italic 35 | } 36 | 37 | pre .keyword, 38 | pre .css .rule .keyword, 39 | pre .winutils, 40 | pre .javascript .title, 41 | pre .lisp .title, 42 | pre .subst { 43 | color: #000; 44 | font-weight: bold 45 | } 46 | 47 | pre .number, 48 | pre .hexcolor { 49 | color: #40a070 50 | } 51 | 52 | pre .string, 53 | pre .tag .value, 54 | pre .phpdoc, 55 | pre .tex .formula { 56 | color: #d14 57 | } 58 | 59 | pre .title, 60 | pre .id { 61 | color: #900; 62 | font-weight: bold 63 | } 64 | 65 | pre .javascript .title, 66 | pre .lisp .title, 67 | pre .subst { 68 | font-weight: normal 69 | } 70 | 71 | pre .class .title, 72 | pre .tex .command { 73 | color: #458; 74 | font-weight: bold 75 | } 76 | 77 | pre .tag, 78 | pre .css .keyword, 79 | pre .html .keyword, 80 | pre .tag .title, 81 | pre .django .tag .keyword { 82 | color: #000080; 83 | font-weight: normal 84 | } 85 | 86 | pre .attribute, 87 | pre .variable, 88 | pre .instancevar, 89 | pre .lisp .body { 90 | color: #008080 91 | } 92 | 93 | pre .regexp { 94 | color: #009926 95 | } 96 | 97 | pre .class { 98 | color: #458; 99 | font-weight: bold 100 | } 101 | 102 | pre .symbol, 103 | pre .ruby .symbol .string, 104 | pre .ruby .symbol .keyword, 105 | pre .ruby .symbol .keymethods, 106 | pre .lisp .keyword, 107 | pre .tex .special { 108 | color: #990073 109 | } 110 | 111 | pre .builtin, 112 | pre .built_in, 113 | pre .lisp .title { 114 | color: #0086b3 115 | } 116 | 117 | pre .preprocessor, 118 | pre .pi, 119 | pre .doctype, 120 | pre .shebang, 121 | pre .cdata { 122 | color: #999; 123 | font-weight: bold 124 | } 125 | 126 | pre .deletion { 127 | background: #fdd 128 | } 129 | 130 | pre .addition { 131 | background: #dfd 132 | } 133 | 134 | pre .diff .change { 135 | background: #0086b3 136 | } 137 | 138 | pre .chunk { 139 | color: #aaa 140 | } 141 | 142 | pre .tex .formula { 143 | opacity: 0.5; 144 | } 145 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | if defined?(Bundler) 6 | # If you precompile assets before deploying to production, use this line 7 | Bundler.require(*Rails.groups(:assets => %w(development test))) 8 | # If you want your assets lazily compiled in production, use this line 9 | # Bundler.require(:default, :assets, Rails.env) 10 | end 11 | 12 | module Rbflow 13 | class Application < Rails::Application 14 | # Settings in config/environments/* take precedence over those specified here. 15 | # Application configuration should go into files in config/initializers 16 | # -- all .rb files in that directory are automatically loaded. 17 | 18 | # Custom directories with classes and modules you want to be autoloadable. 19 | # config.autoload_paths += %W(#{config.root}/extras) 20 | 21 | # Only load the plugins named here, in the order given (default is alphabetical). 22 | # :all can be used as a placeholder for all plugins not explicitly named. 23 | # config.plugins = [ :exception_notification, :ssl_requirement, :all ] 24 | 25 | # Activate observers that should always be running. 26 | # config.active_record.observers = :cacher, :garbage_collector, :forum_observer 27 | 28 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 29 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 30 | # config.time_zone = 'Central Time (US & Canada)' 31 | 32 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 33 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 34 | config.i18n.default_locale = :ru 35 | 36 | # Configure the default encoding used in templates for Ruby 1.9. 37 | config.encoding = "utf-8" 38 | 39 | # Configure sensitive parameters which will be filtered from the log file. 40 | config.filter_parameters += [:password] 41 | 42 | # Enable escaping HTML in JSON. 43 | config.active_support.escape_html_entities_in_json = true 44 | 45 | # Use SQL instead of Active Record's schema dumper when creating the database. 46 | # This is necessary if your schema can't be completely dumped by the schema dumper, 47 | # like if you have constraints or database-specific column types 48 | # config.active_record.schema_format = :sql 49 | 50 | # Enforce whitelist mode for mass assignment. 51 | # This will create an empty whitelist of attributes available for mass-assignment for all models 52 | # in your app. As such, your models will need to explicitly whitelist or blacklist accessible 53 | # parameters by using an attr_accessible or attr_protected declaration. 54 | config.active_record.whitelist_attributes = true 55 | 56 | # Enable the asset pipeline 57 | config.assets.enabled = true 58 | 59 | # Version of your assets, change this if you want to expire all your assets 60 | config.assets.version = '1.0' 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /spec/models/user_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe User do 4 | subject { FactoryGirl.build(:user) } 5 | 6 | describe ".create_with_omniauth!" do 7 | let(:auth) do 8 | { 9 | "info" => { 10 | "name" => "John Doe", 11 | "email" => "john.doe@example.com", 12 | "image" => "http://example.com/images/avatar.png" 13 | } 14 | } 15 | end 16 | subject { User.create_with_omniauth!(auth) } 17 | 18 | it "creates a new user with given name" do 19 | subject.name.should == auth["info"]["name"] 20 | end 21 | 22 | it "creates a new user with given email" do 23 | subject.email.should == auth["info"]["email"] 24 | end 25 | 26 | it "creates a new user with given avatar's URL" do 27 | subject.avatar_url.should == auth["info"]["image"] 28 | end 29 | end 30 | 31 | User::ROLES.each_key do |role| 32 | describe "##{role}?" do 33 | context "when a user has role '#{role}'" do 34 | before(:each) { subject.role = User::ROLES[role] } 35 | 36 | it "returns true" do 37 | subject.send("#{role}?").should be_true 38 | end 39 | end 40 | context "when a user does not have role 'admin'" do 41 | before(:each) { subject.role = nil } 42 | 43 | it "returns false" do 44 | subject.send("#{role}?").should be_false 45 | end 46 | end 47 | end 48 | end 49 | 50 | describe "#approved?" do 51 | context "when user is approved" do 52 | before(:each) { subject.update_attributes!(:approved_at => Time.now) } 53 | 54 | it "returns true" do 55 | subject.approved?.should be_true 56 | end 57 | end 58 | context "when user is not approved" do 59 | it "returns false" do 60 | subject.approved?.should be_false 61 | end 62 | end 63 | end 64 | 65 | describe "#approve!" do 66 | it "sets approved status" do 67 | subject.approve! 68 | subject.should be_approved 69 | end 70 | end 71 | 72 | describe "#unapprove!" do 73 | before(:each) { subject.update_attributes!(:approved_at => Time.now) } 74 | 75 | it "drops approved status" do 76 | subject.unapprove! 77 | subject.should_not be_approved 78 | end 79 | end 80 | 81 | describe "#guest?" do 82 | context "when a user has not been saved" do 83 | it "returns true" do 84 | subject.guest?.should be_true 85 | end 86 | end 87 | context "when a user has been saved" do 88 | before(:each) { subject.save! } 89 | 90 | it "returns false" do 91 | subject.guest?.should be_false 92 | end 93 | end 94 | end 95 | 96 | describe "#me?" do 97 | before(:each) { subject.save! } 98 | 99 | context "when given user is the same person" do 100 | it "returns true" do 101 | subject.me?(subject).should be_true 102 | end 103 | end 104 | context "when given user is not the same person" do 105 | it "returns false" do 106 | subject.me?(FactoryGirl.create(:user)).should be_false 107 | end 108 | end 109 | end 110 | end 111 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/wmd.css: -------------------------------------------------------------------------------- 1 | .wmd-panel { 2 | margin-left: 25%; 3 | margin-right: 25%; 4 | width: 50%; 5 | min-width: 500px; 6 | } 7 | 8 | #wmd-editor { 9 | background-color: Aquamarine; 10 | } 11 | 12 | .wmd-button-bar { 13 | width:100%; 14 | margin:0; 15 | padding:0; 16 | } 17 | 18 | .wmd-input { 19 | height: 500px; 20 | width: 100%; 21 | background-color: Gainsboro; 22 | border: 1px solid DarkGray; 23 | } 24 | 25 | .wmd-preview { 26 | min-height:380px; 27 | padding:6px 8px; 28 | -webkit-border-radius:4px; 29 | -moz-border-radius:4px; 30 | border-radius:4px; 31 | border:rgba(207, 60, 37, 0.6) 1px dashed; 32 | } 33 | .comments .wmd-preview { 34 | min-height:1em; 35 | } 36 | 37 | .wmd-output { 38 | background-color: Pink; 39 | } 40 | 41 | .wmd-button-row { 42 | position: relative; 43 | margin-left: 5px; 44 | margin-right: 5px; 45 | margin-bottom: 5px; 46 | margin-top: 10px; 47 | padding: 0px; 48 | height: 20px; 49 | } 50 | 51 | .wmd-spacer { 52 | width: 1px; 53 | height: 20px; 54 | margin-left: 7px; 55 | margin-right:7px; 56 | 57 | position: relative; 58 | background-color: Silver; 59 | display: inline-block; 60 | list-style: none; 61 | } 62 | 63 | .wmd-button { 64 | width: 20px; 65 | height: 20px; 66 | margin-left: 5px; 67 | margin-right: 5px; 68 | 69 | position: relative; 70 | background-image: url(/assets/wmd-buttons.png); 71 | background-repeat: no-repeat; 72 | background-position: 0px 0px; 73 | display: inline-block; 74 | list-style: none; 75 | cursor:pointer; 76 | } 77 | 78 | .wmd-button > a { 79 | width: 20px; 80 | height: 20px; 81 | margin-left: 5px; 82 | margin-right: 5px; 83 | 84 | position: absolute; 85 | display: inline-block; 86 | } 87 | 88 | 89 | /* sprite button slicing style information */ 90 | .wmd-bold-button {background-position: 0px 0;} 91 | .wmd-italic-button {background-position: -20px 0;} 92 | .wmd-spacer1 {} 93 | .wmd-link-button {background-position: -40px 0;} 94 | .wmd-quote-button {background-position: -60px 0;} 95 | .wmd-code-button {background-position: -80px 0;} 96 | .wmd-image-button {background-position: -100px 0;} 97 | .wmd-spacer2 {} 98 | .wmd-olist-button {background-position: -120px 0;} 99 | .wmd-ulist-button {background-position: -140px 0;} 100 | .wmd-heading-button {background-position: -160px 0;} 101 | .wmd-hr-button {background-position: -180px 0;} 102 | .wmd-spacer3 {} 103 | .wmd-undo-button {background-position: -200px 0;} 104 | .wmd-redo-button {background-position: -220px 0;} 105 | .wmd-help-button {position:absolute;right: 0px; background-position: -240px 0;} 106 | 107 | 108 | .wmd-prompt-background { 109 | background-color:#000; 110 | } 111 | 112 | .wmd-prompt-dialog { 113 | padding:0.5em 1em; 114 | -webkit-border-radius:5px; 115 | -moz-border-radius:5px; 116 | border-radius:5px; 117 | -border:1px solid #999999; 118 | background-color:#F5F5F5; 119 | } 120 | 121 | .wmd-prompt-dialog > div { 122 | -font-size: 0.8em; 123 | -font-family: arial, helvetica, sans-serif; 124 | } 125 | 126 | 127 | .wmd-prompt-dialog > form > input[type="text"] { 128 | -border: 1px solid #999999; 129 | -color: black; 130 | } 131 | 132 | .wmd-prompt-dialog > form > input[type="button"] { 133 | -border: 1px solid #888888; 134 | -font-family: trebuchet MS, helvetica, sans-serif; 135 | -font-size: 0.8em; 136 | -font-weight: bold; 137 | } 138 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/form.css: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------------------------------------ 2 | = Forms 3 | ------------------------------------------------------------------------ */ 4 | .form { 5 | position:relative; 6 | margin:0; 7 | padding:0; 8 | } 9 | .form label { 10 | display:inline-block; 11 | width:100px; 12 | font-weight:bold; 13 | } 14 | .form div { 15 | margin-bottom:1em; 16 | } 17 | .form div.indented { 18 | padding-left:104px; 19 | } 20 | .form .field_with_errors { 21 | display:inline; 22 | } 23 | .form .field_with_errors label { 24 | color:#B00; 25 | } 26 | .form .field_with_errors input, 27 | .form .field_with_errors textarea { 28 | border:#B00 1px solid; 29 | } 30 | .form .buttons { 31 | 32 | } 33 | .form .buttons a { 34 | font-size:12px; 35 | } 36 | 37 | input[type="password"], input[type="text"], textarea { 38 | margin:0; 39 | padding:6px 8px 6px; 40 | -webkit-border-radius:4px; 41 | -moz-border-radius:4px; 42 | border-radius:4px; 43 | border:1px solid #999; 44 | font-size:12px; 45 | color:inherit; 46 | } 47 | 48 | /* Buttons */ 49 | input[type="button"]::-moz-focus-inner, 50 | input[type="submit"]::-moz-focus-inner, 51 | input[type="reset"]::-moz-focus-inner, 52 | input[type="image"]::-moz-focus-inner, 53 | button::-moz-focus-inner, 54 | .button::-moz-focus-inner, 55 | .button.small::-moz-focus-inner { 56 | border:0; 57 | } 58 | input[type="button"], 59 | input[type="submit"], 60 | input[type="reset"], 61 | input[type="image"], 62 | button, 63 | .button, 64 | .button.small { 65 | display:inline-block; 66 | color:inherit; 67 | border:1px solid #999; 68 | margin:0; 69 | overflow:visible; 70 | background:-webkit-gradient(linear, left top, left bottom, from(#fff), to(#e9e9e9)); 71 | background:-moz-linear-gradient(top, #fff, #e9e9e9); 72 | text-decoration:none; 73 | } 74 | input[type="button"], 75 | input[type="submit"], 76 | input[type="reset"], 77 | input[type="image"], 78 | button, 79 | .button { 80 | padding:6px 8px 6px; 81 | font-size:12px; 82 | font-weight:bold; 83 | -webkit-border-radius:4px; 84 | -moz-border-radius:4px; 85 | border-radius:4px; 86 | } 87 | .button.small { 88 | padding:2px 4px; 89 | font-size:11px; 90 | font-weight:normal; 91 | -webkit-border-radius:3px; 92 | -moz-border-radius:3px; 93 | border-radius:3px; 94 | } 95 | input[type="button"]:disabled, 96 | input[type="submit"]:disabled, 97 | input[type="reset"]:disabled, 98 | input[type="image"]:disabled, 99 | button:disabled, 100 | .button:disabled, 101 | .button.small:disabled { 102 | opacity:.5; 103 | cursor:default !important; 104 | } 105 | input[type="button"]:hover, 106 | input[type="submit"]:hover, 107 | input[type="reset"]:hover, 108 | input[type="image"]:hover, 109 | button:hover, 110 | .button:hover, 111 | .button.small:hover { 112 | cursor:pointer; 113 | border:1px solid #555; 114 | } 115 | a.button:hover { 116 | background-color:transparent; 117 | color:inherit; 118 | } 119 | input[type="button"]:active, 120 | input[type="button"].active, 121 | input[type="submit"]:active, 122 | input[type="reset"]:active, 123 | input[type="image"]:active, 124 | button:active, 125 | .button:active, 126 | .button.active, 127 | .button.small:active { 128 | background:-webkit-gradient(linear, left top, left bottom, from(#AAA), to(#FFF)); 129 | background:-moz-linear-gradient(top, #AAA, #FFF); 130 | border:1px solid #555; 131 | } 132 | .button.min-width { 133 | min-width:65px; 134 | padding:0; 135 | text-align:center; 136 | font-size:9px; 137 | } 138 | .button.positive { 139 | background: #00AE3E; 140 | border-color: #393 #393 #277827; 141 | color:#FFF; 142 | } 143 | .button.negative { 144 | background:#C63738; 145 | border-color: #A33 #A33 #962C2C; 146 | color:#FFF; 147 | } 148 | /* ------------------------------------------------------------------------ 149 | = Item 150 | ------------------------------------------------------------------------ */ 151 | .new_item input[type="text"], 152 | .new_item textarea, 153 | .edit_item input[type="text"], 154 | .edit_item textarea, 155 | .new_comment textarea, 156 | .edit_comment textarea { 157 | width:95%; 158 | } 159 | .new_item div, 160 | .edit_item div { 161 | margin-bottom:3px; 162 | } -------------------------------------------------------------------------------- /public/markdown-reference/sv/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Markdown Handbok 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Markdown Handbok

13 | 14 |

Text

15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
MarkdownResultat
Texten är **fet**.Texten är fet.
Texten är *kursiv*.Texten är kursiv.
`Detta är lite kod.`Detta är lite kod.
35 |
36 | 37 |

Rubriker

38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
MarkdownResultat
# Första Rubrik

Första Rubriken

## Andra Rubriken

Andra Rubriken

### Tredje Rubriken

Tredje Rubriken

58 |
59 | 60 |

Citat

61 | 62 |
63 | 64 | 65 | 68 | 75 | 76 |
> Detta är den första nivån citera.
66 | >> Detta är kapslade blockquote.
67 | > Tillbaka till första nivån.
69 |
70 | Detta är den första nivån citera. 71 |
Detta är kapslade blockquote.
72 | Tillbaka till första nivån. 73 |
74 |
77 |
78 | 79 |

Länkar och Bilder

80 | 81 |
82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
Länk till [Google](http://google.se).Länk till Google.
Skicka mig ett e-post till <adressen@exempel.se>.Skicka mig ett e-post till adressen@exempel.se.
![37signals logotyp](http://www.37signals.com/images/logo-37signals.png)37signals logotyp
96 |
97 | 98 |

Listor

99 | 100 |
101 | 102 | 103 | 104 | 105 | 106 | 107 | 113 | 126 | 127 | 128 | 135 | 148 | 149 |
MarkdownResultat
* Mjölk
108 | * Bröd
109 | * Ost
110 |   * Cheddar
111 |   * Camembert
112 | * Ris
114 |
    115 |
  • Mjölk
  • 116 |
  • Bröd
  • 117 |
  • Ost 118 |
      119 |
    • Cheddar
    • 120 |
    • Camembert
    • 121 |
    122 |
  • 123 |
  • Ris
  • 124 |
125 |
1. Mjölk
129 | 2. Bröd
130 | 3. Ost
131 |   1. Cheddar
132 |   2. Camembert
133 | 4. Ris 134 |
136 |
    137 |
  1. Mjölk
  2. 138 |
  3. Bröd
  4. 139 |
  5. Ost 140 |
      141 |
    1. Cheddar
    2. 142 |
    3. Camembert
    4. 143 |
    144 |
  6. 145 |
  7. Ris
  8. 146 |
147 |
150 |
151 | 152 | 153 | -------------------------------------------------------------------------------- /public/markdown-reference/ru/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Справочник по Markdown 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Справочник по Markdown

13 | 14 |

Текст

15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
MarkdownРезультат
Это **жирный** текст.Это bold текст.
Это *курсив*.Это курсив.
`Это код.`Это код.
35 |
36 | 37 |

Заголовки

38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
MarkdownРезультат
# Заголовок первого уровня

Заголовок первого уровня

## Заголовок второго уровня

Заголовок второго уровня

### Заголовок третьего уровня

Заголовок третьего уровня

58 |
59 | 60 |

Цитаты

61 | 62 |
63 | 64 | 65 | 68 | 75 | 76 |
> Это первый уровень цитирования.
66 | >> Второй уровень цитирования.
67 | > И снова, первый уровень.
69 |
70 | Это первый уровень цитирования. 71 |
Второй уровень цитирования.
72 | И снова, первый уровень. 73 |
74 |
77 |
78 | 79 |

Ссылки и изображения

80 | 81 |
82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
Ссылка на [Google](http://google.com).Ссылка на Google.
Отправьте мне электронное письмо на <address@example.com>.Отправьте мне электронное письмо на address@example.com
![Логотип 37signals](http://www.37signals.com/images/logo-37signals.png)Логотип 37signals
96 |
97 | 98 |

Списки

99 | 100 |
101 | 102 | 103 | 104 | 105 | 106 | 107 | 113 | 126 | 127 | 128 | 135 | 148 | 149 |
MarkdownРезультат
* Молоко
108 | * Хлеб
109 | * Сыр
110 |   * Чеддер
111 |   * Камамбер
112 | * Рис
114 |
    115 |
  • Молоко
  • 116 |
  • Хлеб
  • 117 |
  • Сыр 118 |
      119 |
    • Чеддер
    • 120 |
    • Камамбер
    • 121 |
    122 |
  • 123 |
  • Рис
  • 124 |
125 |
1. Молоко
129 | 2. Хлеб
130 | 3. Сыр
131 |   1. Чеддер
132 |   2. Камамбер
133 | 4. Рис 134 |
136 |
    137 |
  1. Молоко
  2. 138 |
  3. Хлеб
  4. 139 |
  5. Сыр 140 |
      141 |
    1. Чеддер
    2. 142 |
    3. Камамбер
    4. 143 |
    144 |
  6. 145 |
  7. Рис
  8. 146 |
147 |
150 |
151 | 152 | 153 | -------------------------------------------------------------------------------- /public/markdown-reference/fr/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Guide de référence pour Markdown 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Guide de référence pour Markdown

13 | 14 |

Texte

15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
MarkdownRésultat
Ce texte est en **gras**.Ce texte est en gras.
Ce texte est en *italique*.Ce texte est en italique..
`Ceci est du code.`Ceci est du code.
35 |
36 | 37 |

Têtes de chapitre

38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
MarkdownRésultat
# Première tête de chapitre

Première tête de chapitre

## Seconde tête de chapitre

Seconde tête de chapitre

### Troisième tête de chapitre

Troisième tête de chapitre

58 |
59 | 60 |

Citations

61 | 62 |
63 | 64 | 65 | 70 | 77 | 78 |
66 | > Ceci est le premier niveau de citation.
67 | >> Ceci est une citation imbriquée.
68 | > Retour au premier niveau. 69 |
71 |
72 | Ceci est le premier niveau de citation. 73 |
Ceci est une citation imbriquée.
74 | Retour au premier niveau. 75 |
76 |
79 |
80 | 81 |

Liens et images

82 | 83 |
84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
Lien vers [Google](http://google.fr).Lien vers Google.
Envoyez-mopi un e-mail à <adresse@exemple.com>.Envoyez-moi un e-mail à adresse@exemple.com .
![Logo de 37signals](http://www.37signals.com/images/logo-37signals.png)Logo de 37signals
98 |
99 | 100 |

Listes

101 | 102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | 115 | 128 | 129 | 130 | 136 | 149 | 150 |
MarkdownRésultat
* Lait
110 | * Pain
111 | * Fromage
112 |   * Gruyère
113 |   * Camembert
114 | * Riz
116 |
    117 |
  • Lait
  • 118 |
  • Pain
  • 119 |
  • Fromage 120 |
      121 |
    • Gruyère
    • 122 |
    • Camembert
    • 123 |
    124 |
  • 125 |
  • Riz
  • 126 |
127 |
1. Lait
131 | 2. Pain
132 | 3. Fromage
133 |   1. Gruyère
134 |   2. Camembert
135 | 4. Riz
137 |
    138 |
  1. Lait
  2. 139 |
  3. Pain
  4. 140 |
  5. Fromage 141 |
      142 |
    1. Gruyère
    2. 143 |
    3. Camembert
    4. 144 |
    145 |
  6. 146 |
  7. Riz
  8. 147 |
148 |
151 |
152 | 153 | 154 | -------------------------------------------------------------------------------- /public/markdown-reference/en/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Markdown Guide 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Markdown Guide

13 | 14 |

Text

15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
MarkdownResult
This text is **bold**.This text is bold.
This text is *italicized*.This text is italicized.
`This is some code.`This is some code.
35 |
36 | 37 |

Headings

38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
MarkdownResult
# First Header

First Header

## Second Header

Second Header

### Third Header

Third Header

58 |
59 | 60 |

Quotes

61 | 62 |
63 | 64 | 65 | 70 | 79 | 80 |
66 | > This is the first level of quoting.
67 | >> This is nested blockquote.
68 | > Back to the first level. 69 |
71 |
72 | This is the first level of quoting. 73 |
74 | This is nested blockquote. 75 |
76 | Back to the first level. 77 |
78 |
81 |
82 | 83 |

Links and Images

84 | 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
Link to [Google](http://google.com).Link to Google.
Send me an email at .Send me an email at address@example.com.
![37signals logo](http://www.37signals.com/images/logo-37signals.png)37signals logo
100 |
101 | 102 |

Lists

103 | 104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 | 119 | 132 | 133 | 134 | 142 | 155 | 156 |
MarkdownResult
112 | * Milk
113 | * Bread
114 | * Cheese
115 |   * Cheddar
116 |   * Camembert
117 | * Rice 118 |
120 |
    121 |
  • Milk
  • 122 |
  • Bread
  • 123 |
  • Cheese 124 |
      125 |
    • Cheddar
    • 126 |
    • Camembert
    • 127 |
    128 |
  • 129 |
  • Rice
  • 130 |
131 |
135 | 1. Milk
136 | 2. Bread
137 | 3. Cheese
138 |   1. Cheddar
139 |   2. Camembert
140 | 4. Rice 141 |
143 |
    144 |
  1. Milk
  2. 145 |
  3. Bread
  4. 146 |
  5. Cheese 147 |
      148 |
    1. Cheddar
    2. 149 |
    3. Camembert
    4. 150 |
    151 |
  6. 152 |
  7. Rice
  8. 153 |
154 |
157 |
158 | 159 | 160 | -------------------------------------------------------------------------------- /public/markdown-reference/ca/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Guia de referència de Markdown 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Guia de referència de Markdown

13 | 14 |

Text

15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
MarkdownResultat
Aquest text està en **negreta**.Aquest text està en negreta.
Aquest text està en *cursiva*.Aquest text està en cursiva.
`Això és un tros de codi.`Això és un tros de codi.
35 |
36 | 37 |

Capçaleres

38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
MarkdownResultat
# Primera capçalera

Primera capçalera

## Segona capçalera

Segona capçalera

### Tercera capçalera

Tercera capçalera

58 |
59 | 60 |

Citacions

61 | 62 |
63 | 64 | 65 | 70 | 77 | 78 |
66 | > Aquest és el primer nivell de citació.
67 | >> Això és una citació sagnada.
68 | > Retorn al primer nivell. 69 |
71 |
72 | Aquest és el primer nivell de citació. 73 |
Això és una citació sagnada.
74 | Retorn al primer nivell. 75 |
76 |
79 |
80 | 81 |

Enllaços i imatges

82 | 83 |
84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
Enllaç a [Google](http://google.com).Enllaç a Google.
Envia'm un correu a <adreça@exemple.com>.Envia'm un correu a adreça@exemple.com.
![Logotip de 37signals](http://www.37signals.com/images/logo-37signals.png)Logotip de 37signals
98 |
99 | 100 |

Llistes

101 | 102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | 115 | 128 | 129 | 130 | 138 | 151 | 152 |
MarkdownResultat
* Llet
110 | * Pa
111 | * Formatge
112 |   * Gruyère
113 |   * Camembert
114 | * Arròs
116 |
    117 |
  • Llet
  • 118 |
  • Pa
  • 119 |
  • Formatge 120 |
      121 |
    • Gruyère
    • 122 |
    • Camembert
    • 123 |
    124 |
  • 125 |
  • Arròs
  • 126 |
127 |
131 | 1. Llet
132 | 2. Pa
133 | 3. Formatge
134 |   1. Gruyère
135 |   2. Camembert
136 | 4. Arròs 137 |
139 |
    140 |
  1. Llet
  2. 141 |
  3. Pa
  4. 142 |
  5. Formatge 143 |
      144 |
    1. Gruyère
    2. 145 |
    3. Camembert
    4. 146 |
    147 |
  6. 148 |
  7. Arròs
  8. 149 |
150 |
153 |
154 | 155 | 156 | -------------------------------------------------------------------------------- /public/markdown-reference/tr/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Markdown Rehberi 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Markdown Rehberi

13 | 14 |

Metin

15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
MarkdownSonuç
Bu metin **kalın**dır.Bu metin kalındır.
Bu metin *eğik*tir.Bu metin eğiktir.
`Bu bir örnek koddur.`Bu bir örnek koddur.
35 |
36 | 37 |

Başlıklar

38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
MarkdownSonuç
# İlk Başlık

İlk Başlık

## İkinci Başlık

İkinci Başlık

### Üçüncü Başlık

Üçüncü Başlık

58 |
59 | 60 |

Alıntılar

61 | 62 |
63 | 64 | 65 | 70 | 79 | 80 |
66 | > Bu ilk seviye bir alıntıdır.
67 | >> Bu içiçe bir alıntıdır.
68 | > İlk seviye'ye geri dönüyoruz. 69 |
71 |
72 | Bu ilk seviye bir alıntıdır. 73 |
74 | Bu içiçe bir alıntıdır. 75 |
76 | İlk seviye'ye geri dönüyoruz. 77 |
78 |
81 |
82 | 83 |

Bağlantı ve İmajlar

84 | 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
[Google](http://google.com) bağlantısı. Google bağlantısı.
bana bir email gönder.address@example.com bana bir email gönder.
![37signals logosu](http://www.37signals.com/images/logo-37signals.png)37signals logosu
100 |
101 | 102 |

Listeler

103 | 104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 | 119 | 132 | 133 | 134 | 142 | 155 | 156 |
MarkdownSonuç
112 | * Süt
113 | * Ekmek
114 | * Peynir
115 | * Çedar
116 | * Krema Peynir
117 | * Pirinç 118 |
120 |
    121 |
  • Süt
  • 122 |
  • Ekmek
  • 123 |
  • Peynir 124 |
      125 |
    • Çedar
    • 126 |
    • Krema Peynir
    • 127 |
    128 |
  • 129 |
  • Pirinç
  • 130 |
131 |
135 | 1. Süt
136 | 2. Ekmek
137 | 3. Peynir
138 | 1. Çedar
139 | 2. Krema Peynir
140 | 4. Pirinç 141 |
143 |
    144 |
  1. Süt
  2. 145 |
  3. Ekmek
  4. 146 |
  5. Peynir 147 |
      148 |
    1. Çedar
    2. 149 |
    3. Krema Peynir
    4. 150 |
    151 |
  6. 152 |
  7. Pirinç
  8. 153 |
154 |
157 |
158 | 159 | 160 | -------------------------------------------------------------------------------- /public/markdown-reference/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Markdown Guide 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Markdown Guide

13 | 14 |

Text

15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
MarkdownResult
This text is **bold**.This text is bold.
This text is *italicized*.This text is italicized.
`This is some code.`This is some code.
35 |
36 | 37 |

Headings

38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
MarkdownResult
# First Header

First Header

## Second Header

Second Header

### Third Header

Third Header

58 |
59 | 60 |

Quotes

61 | 62 |
63 | 64 | 65 | 70 | 79 | 80 |
66 | > This is the first level of quoting.
67 | >> This is nested blockquote.
68 | > Back to the first level. 69 |
71 |
72 | This is the first level of quoting. 73 |
74 | This is nested blockquote. 75 |
76 | Back to the first level. 77 |
78 |
81 |
82 | 83 |

Links and Images

84 | 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
Link to [Google](http://google.com).Link to Google.
Send me an email at <address@example.com>.Send me an email at address@example.com.
![37signals logo](http://www.37signals.com/images/logo-37signals.png)37signals logo
100 |
101 | 102 |

Lists

103 | 104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 | 119 | 132 | 133 | 134 | 142 | 155 | 156 |
MarkdownResult
112 | * Milk
113 | * Bread
114 | * Cheese
115 |   * Cheddar
116 |   * Camembert
117 | * Rice 118 |
120 |
    121 |
  • Milk
  • 122 |
  • Bread
  • 123 |
  • Cheese 124 |
      125 |
    • Cheddar
    • 126 |
    • Camembert
    • 127 |
    128 |
  • 129 |
  • Rice
  • 130 |
131 |
135 | 1. Milk
136 | 2. Bread
137 | 3. Cheese
138 |   1. Cheddar
139 |   2. Camembert
140 | 4. Rice 141 |
143 |
    144 |
  1. Milk
  2. 145 |
  3. Bread
  4. 146 |
  5. Cheese 147 |
      148 |
    1. Cheddar
    2. 149 |
    3. Camembert
    4. 150 |
    151 |
  6. 152 |
  7. Rice
  8. 153 |
154 |
157 |
158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /spec/controllers/users_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe UsersController do 4 | let(:user) { mock_model(User, :admin? => true, :guest? => false) } 5 | 6 | before { controller.stub(:current_user).and_return(user) } 7 | 8 | describe "GET index" do 9 | it "assigns @users" do 10 | User.stub_chain(:order, :page, :per).and_return([user]) 11 | get :index 12 | assigns[:users].should eq([user]) 13 | end 14 | 15 | context "when user is not an admin" do 16 | before { user.stub(:admin?).and_return(false) } 17 | 18 | it "sets flash notice" do 19 | get :index 20 | flash[:notice].should_not be_blank 21 | end 22 | 23 | it "redirects to sign in URL" do 24 | get :index 25 | response.should redirect_to(sign_in_url) 26 | end 27 | end 28 | 29 | context "when user is a guest" do 30 | before { controller.stub(:current_user).and_return(nil) } 31 | 32 | it "sets flash notice" do 33 | get :index 34 | flash[:notice].should_not be_blank 35 | end 36 | 37 | it "redirects to sign in URL" do 38 | get :index 39 | response.should redirect_to(sign_in_url) 40 | end 41 | end 42 | end 43 | 44 | describe "GET show" do 45 | it "assigns @user" do 46 | User.stub(:find).and_return(user) 47 | 48 | get :show, :id => user.id 49 | assigns[:user].should eq(user) 50 | end 51 | 52 | it "assigns only current user to @user" do 53 | another_user = mock_model(User) 54 | User.stub(:find).and_return(another_user) 55 | 56 | get :show, :id => another_user.id 57 | assigns[:user].should eq(user) 58 | end 59 | end 60 | 61 | describe "PUT approve" do 62 | let(:another_user) { mock_model(User) } 63 | 64 | before do 65 | another_user.stub(:approve!).and_return(another_user) 66 | User.stub(:find).and_return(another_user) 67 | end 68 | 69 | it "assigns @user" do 70 | put :approve, :id => another_user.id 71 | assigns[:user].should eq(another_user) 72 | end 73 | 74 | it "approves user" do 75 | another_user.should_receive(:approve!) 76 | put :approve, :id => another_user.id 77 | end 78 | 79 | it "redirects to users URL" do 80 | put :approve, :id => another_user.id 81 | response.should redirect_to(users_url) 82 | end 83 | 84 | context "when user is not an admin" do 85 | before { user.stub(:admin?).and_return(false) } 86 | 87 | it "sets flash notice" do 88 | put :approve, :id => another_user.id 89 | flash[:notice].should_not be_blank 90 | end 91 | 92 | it "redirects to sign in URL" do 93 | put :approve, :id => another_user.id 94 | response.should redirect_to(sign_in_url) 95 | end 96 | end 97 | end 98 | 99 | describe "PUT unapprove" do 100 | let(:another_user) { mock_model(User) } 101 | 102 | before do 103 | another_user.stub(:unapprove!).and_return(another_user) 104 | User.stub(:find).and_return(another_user) 105 | end 106 | 107 | it "assigns @user" do 108 | put :unapprove, :id => another_user.id 109 | assigns[:user].should eq(another_user) 110 | end 111 | 112 | it "unapproves user" do 113 | another_user.should_receive(:unapprove!) 114 | put :unapprove, :id => another_user.id 115 | end 116 | 117 | it "redirects to users URL" do 118 | put :unapprove, :id => another_user.id 119 | response.should redirect_to(users_url) 120 | end 121 | 122 | context "when user is not an admin" do 123 | before { user.stub(:admin?).and_return(false) } 124 | 125 | it "sets flash notice" do 126 | put :unapprove, :id => another_user.id 127 | flash[:notice].should_not be_blank 128 | end 129 | 130 | it "redirects to sign in URL" do 131 | put :unapprove, :id => another_user.id 132 | response.should redirect_to(sign_in_url) 133 | end 134 | end 135 | end 136 | 137 | describe "DELETE destroy" do 138 | let(:another_user) { mock_model(User) } 139 | 140 | before do 141 | another_user.stub(:destroy).and_return(another_user) 142 | User.stub(:find).and_return(another_user) 143 | end 144 | 145 | it "assigns @user" do 146 | delete :destroy, :id => another_user.id 147 | assigns[:user].should eq(another_user) 148 | end 149 | 150 | it "destroy user" do 151 | another_user.should_receive(:destroy) 152 | delete :destroy, :id => another_user.id 153 | end 154 | 155 | context "when user is not an admin" do 156 | before { user.stub(:admin?).and_return(false) } 157 | 158 | it "sets flash notice" do 159 | delete :destroy, :id => another_user.id 160 | flash[:notice].should_not be_blank 161 | end 162 | 163 | it "redirects to sign in URL" do 164 | delete :destroy, :id => another_user.id 165 | response.should redirect_to(sign_in_url) 166 | end 167 | end 168 | end 169 | end 170 | -------------------------------------------------------------------------------- /public/markdown-reference/es/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Guía de Markdown 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Guía de Markdown

13 | 14 |

Texto

15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
MarkdownResultado
Este texto está en **negrita**.Este texto está en negrita.
Este texto está en *cursiva*.Este texto está en cursiva.
`Esto es un trozo de código.`Esto es un trozo de código.
35 |
36 | 37 |

Encabezados

38 | 39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
MarkdownResultado
# Primer encabezado

Primer encabezado

## Segundo encabezado

Segundo encabezado

### Tercer encabezado

Tercer encabezado

58 |
59 | 60 |

Citas

61 | 62 |
63 | 64 | 65 | 70 | 79 | 80 |
66 | > Este es el primer nivel de la cita.
67 | >> Esto es una cita anidada
68 | > Vuelta al primer nivel. 69 |
71 |
72 | Este es el primer nivel de la cita. 73 |
74 | Esto es una cita anidada. 75 |
76 | Vuelta al primer nivel. 77 |
78 |
81 |
82 | 83 |

Enlaces y imágenes

84 | 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
Enlace a [Google](http://google.com).Enlace a Google.
Envíame un correo a <direccion@ejemplo.com>.Envíame un correo a direccion@ejemplo.com.
![Logo 37signals](http://www.37signals.com/images/logo-37signals.png)Logo 37signals
100 |
101 | 102 |

Listas

103 | 104 |
105 | 106 | 107 | 108 | 109 | 110 | 111 | 119 | 132 | 133 | 134 | 142 | 155 | 156 |
MarkdownResultado
112 | * Leche
113 | * Pan
114 | * Queso
115 |   * Gruyere
116 |   * Camembert
117 | * Arroz 118 |
120 |
    121 |
  • Leche
  • 122 |
  • Pan
  • 123 |
  • Queso 124 |
      125 |
    • Gruyere
    • 126 |
    • Camembert
    • 127 |
    128 |
  • 129 |
  • Arroz
  • 130 |
131 |
135 | 1. Leche
136 | 2. Pan
137 | 3. Queso
138 |   1. Gruyere
139 |   2. Camembert
140 | 3. Arroz 141 |
143 |
    144 |
  1. Leche
  2. 145 |
  3. Pan
  4. 146 |
  5. Queso 147 |
      148 |
    1. Gruyere
    2. 149 |
    3. Camembert
    4. 150 |
    151 |
  6. 152 |
  7. Arroz
  8. 153 |
154 |
157 |
158 | 159 | 160 | -------------------------------------------------------------------------------- /config/locales/active_support.yml: -------------------------------------------------------------------------------- 1 | # Russian localization for Ruby on Rails 2.2+ 2 | # by Yaroslav Markin 3 | # 4 | # Be sure to check out "russian" gem (http://github.com/yaroslav/russian) for 5 | # full Russian language support in Rails (month names, pluralization, etc). 6 | # The following is an excerpt from that gem. 7 | # 8 | # Для полноценной поддержки русского языка (варианты названий месяцев, 9 | # плюрализация и так далее) в Rails 2.2 нужно использовать gem "russian" 10 | # (http://github.com/yaroslav/russian). Следующие данные -- выдержка их него, чтобы 11 | # была возможность минимальной локализации приложения на русский язык. 12 | 13 | ru: 14 | date: 15 | formats: 16 | default: "%d.%m.%Y" 17 | short: "%d %b" 18 | long: "%d %B %Y" 19 | 20 | day_names: [воскресенье, понедельник, вторник, среда, четверг, пятница, суббота] 21 | standalone_day_names: [Воскресенье, Понедельник, Вторник, Среда, Четверг, Пятница, Суббота] 22 | abbr_day_names: [Вс, Пн, Вт, Ср, Чт, Пт, Сб] 23 | 24 | month_names: [~, января, февраля, марта, апреля, мая, июня, июля, августа, сентября, октября, ноября, декабря] 25 | # see russian gem for info on "standalone" day names 26 | standalone_month_names: [~, Январь, Февраль, Март, Апрель, Май, Июнь, Июль, Август, Сентябрь, Октябрь, Ноябрь, Декабрь] 27 | abbr_month_names: [~, янв., февр., марта, апр., мая, июня, июля, авг., сент., окт., нояб., дек.] 28 | standalone_abbr_month_names: [~, янв., февр., март, апр., май, июнь, июль, авг., сент., окт., нояб., дек.] 29 | 30 | order: [ ":day", ":month", ":year" ] 31 | 32 | time: 33 | formats: 34 | default: "%a, %d %b %Y, %H:%M:%S %z" 35 | short: "%d %b, %H:%M" 36 | long: "%d %B %Y, %H:%M" 37 | 38 | am: "утра" 39 | pm: "вечера" 40 | 41 | number: 42 | format: 43 | separator: "." 44 | delimiter: " " 45 | precision: 3 46 | 47 | currency: 48 | format: 49 | format: "%n %u" 50 | unit: "руб." 51 | separator: "." 52 | delimiter: " " 53 | precision: 2 54 | 55 | percentage: 56 | format: 57 | delimiter: "" 58 | 59 | precision: 60 | format: 61 | delimiter: "" 62 | 63 | human: 64 | format: 65 | delimiter: "" 66 | precision: 1 67 | # Rails 2.2 68 | # storage_units: [байт, КБ, МБ, ГБ, ТБ] 69 | 70 | # Rails 2.3 71 | storage_units: 72 | # Storage units output formatting. 73 | # %u is the storage unit, %n is the number (default: 2 MB) 74 | format: "%n %u" 75 | units: 76 | byte: 77 | one: "байт" 78 | few: "байта" 79 | many: "байт" 80 | other: "байта" 81 | kb: "КБ" 82 | mb: "МБ" 83 | gb: "ГБ" 84 | tb: "ТБ" 85 | 86 | datetime: 87 | distance_in_words: 88 | half_a_minute: "меньше минуты" 89 | less_than_x_seconds: 90 | one: "меньше %{count} секунды" 91 | few: "меньше %{count} секунд" 92 | many: "меньше %{count} секунд" 93 | other: "меньше %{count} секунды" 94 | x_seconds: 95 | one: "%{count} секунда" 96 | few: "%{count} секунды" 97 | many: "%{count} секунд" 98 | other: "%{count} секунды" 99 | less_than_x_minutes: 100 | one: "меньше %{count} минуты" 101 | few: "меньше %{count} минут" 102 | many: "меньше %{count} минут" 103 | other: "меньше %{count} минуты" 104 | x_minutes: 105 | one: "%{count} минуту" 106 | few: "%{count} минуты" 107 | many: "%{count} минут" 108 | other: "%{count} минуты" 109 | about_x_hours: 110 | one: "около %{count} часа" 111 | few: "около %{count} часов" 112 | many: "около %{count} часов" 113 | other: "около %{count} часа" 114 | x_days: 115 | one: "%{count} день" 116 | few: "%{count} дня" 117 | many: "%{count} дней" 118 | other: "%{count} дня" 119 | about_x_months: 120 | one: "около %{count} месяца" 121 | few: "около %{count} месяцев" 122 | many: "около %{count} месяцев" 123 | other: "около %{count} месяца" 124 | x_months: 125 | one: "%{count} месяц" 126 | few: "%{count} месяца" 127 | many: "%{count} месяцев" 128 | other: "%{count} месяца" 129 | about_x_years: 130 | one: "около %{count} года" 131 | few: "около %{count} лет" 132 | many: "около %{count} лет" 133 | other: "около %{count} лет" 134 | over_x_years: 135 | one: "больше %{count} года" 136 | few: "больше %{count} лет" 137 | many: "больше %{count} лет" 138 | other: "больше %{count} лет" 139 | prompts: 140 | year: "Год" 141 | month: "Месяц" 142 | day: "День" 143 | hour: "Часов" 144 | minute: "Минут" 145 | second: "Секунд" 146 | 147 | select: 148 | # default value for :prompt => true in FormOptionsHelper 149 | prompt: "Выберите: " 150 | support: 151 | array: 152 | # Rails 2.2 153 | sentence_connector: "и" 154 | skip_last_comma: true 155 | 156 | # Rails 2.3 157 | words_connector: ", " 158 | two_words_connector: " и " 159 | last_word_connector: " и " 160 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: git://github.com/nadarei/mina.git 3 | revision: 8248fba1222ac4da7f73d422c9a71e99e23df957 4 | specs: 5 | mina (0.2.1) 6 | open4 7 | rake 8 | 9 | GEM 10 | remote: https://rubygems.org/ 11 | specs: 12 | actionmailer (3.2.13) 13 | actionpack (= 3.2.13) 14 | mail (~> 2.5.3) 15 | actionpack (3.2.13) 16 | activemodel (= 3.2.13) 17 | activesupport (= 3.2.13) 18 | builder (~> 3.0.0) 19 | erubis (~> 2.7.0) 20 | journey (~> 1.0.4) 21 | rack (~> 1.4.5) 22 | rack-cache (~> 1.2) 23 | rack-test (~> 0.6.1) 24 | sprockets (~> 2.2.1) 25 | activemodel (3.2.13) 26 | activesupport (= 3.2.13) 27 | builder (~> 3.0.0) 28 | activerecord (3.2.13) 29 | activemodel (= 3.2.13) 30 | activesupport (= 3.2.13) 31 | arel (~> 3.0.2) 32 | tzinfo (~> 0.3.29) 33 | activeresource (3.2.13) 34 | activemodel (= 3.2.13) 35 | activesupport (= 3.2.13) 36 | activesupport (3.2.13) 37 | i18n (= 0.6.1) 38 | multi_json (~> 1.0) 39 | arel (3.0.2) 40 | bugsnag (1.3.6) 41 | httparty (>= 0.6, < 1.0) 42 | multi_json (~> 1.0) 43 | builder (3.0.4) 44 | cancan (1.6.9) 45 | diff-lcs (1.2.4) 46 | dotenv (0.7.0) 47 | erubis (2.7.0) 48 | execjs (1.4.0) 49 | multi_json (~> 1.0) 50 | factory_girl (4.2.0) 51 | activesupport (>= 3.0.0) 52 | factory_girl_rails (4.2.1) 53 | factory_girl (~> 4.2.0) 54 | railties (>= 3.0.0) 55 | faraday (0.8.7) 56 | multipart-post (~> 1.1) 57 | figaro (0.6.4) 58 | bundler (~> 1.0) 59 | rails (>= 3, < 5) 60 | foreman (0.63.0) 61 | dotenv (>= 0.7) 62 | thor (>= 0.13.6) 63 | hashie (2.0.4) 64 | hike (1.2.2) 65 | httparty (0.11.0) 66 | multi_json (~> 1.0) 67 | multi_xml (>= 0.5.2) 68 | httpauth (0.2.0) 69 | i18n (0.6.1) 70 | journey (1.0.4) 71 | jquery-rails (2.2.1) 72 | railties (>= 3.0, < 5.0) 73 | thor (>= 0.14, < 2.0) 74 | json (1.8.3) 75 | jwt (0.1.8) 76 | multi_json (>= 1.5) 77 | kaminari (0.14.1) 78 | actionpack (>= 3.0.0) 79 | activesupport (>= 3.0.0) 80 | kgio (2.11.0) 81 | libv8 (3.16.14.17) 82 | mail (2.5.3) 83 | i18n (>= 0.4.0) 84 | mime-types (~> 1.16) 85 | treetop (~> 1.4.8) 86 | mime-types (1.23) 87 | multi_json (1.7.2) 88 | multi_xml (0.5.3) 89 | multipart-post (1.2.0) 90 | newrelic_rpm (3.6.1.88) 91 | oauth (0.4.7) 92 | oauth2 (0.8.1) 93 | faraday (~> 0.8) 94 | httpauth (~> 0.1) 95 | jwt (~> 0.1.4) 96 | multi_json (~> 1.0) 97 | rack (~> 1.2) 98 | omniauth (1.1.4) 99 | hashie (>= 1.2, < 3) 100 | rack 101 | omniauth-github (1.1.0) 102 | omniauth (~> 1.0) 103 | omniauth-oauth2 (~> 1.1) 104 | omniauth-oauth (1.0.1) 105 | oauth 106 | omniauth (~> 1.0) 107 | omniauth-oauth2 (1.1.1) 108 | oauth2 (~> 0.8.0) 109 | omniauth (~> 1.0) 110 | omniauth-openid (1.0.1) 111 | omniauth (~> 1.0) 112 | rack-openid (~> 1.3.1) 113 | omniauth-twitter (0.0.16) 114 | multi_json (~> 1.3) 115 | omniauth-oauth (~> 1.0) 116 | open4 (1.3.0) 117 | pg (0.15.1) 118 | polyglot (0.3.3) 119 | rack (1.4.5) 120 | rack-cache (1.2) 121 | rack (>= 0.4) 122 | rack-openid (1.3.1) 123 | rack (>= 1.1.0) 124 | ruby-openid (>= 2.1.8) 125 | rack-ssl (1.3.3) 126 | rack 127 | rack-test (0.6.2) 128 | rack (>= 1.0) 129 | rails (3.2.13) 130 | actionmailer (= 3.2.13) 131 | actionpack (= 3.2.13) 132 | activerecord (= 3.2.13) 133 | activeresource (= 3.2.13) 134 | activesupport (= 3.2.13) 135 | bundler (~> 1.0) 136 | railties (= 3.2.13) 137 | railties (3.2.13) 138 | actionpack (= 3.2.13) 139 | activesupport (= 3.2.13) 140 | rack-ssl (~> 1.3.2) 141 | rake (>= 0.8.7) 142 | rdoc (~> 3.4) 143 | thor (>= 0.14.6, < 2.0) 144 | raindrops (0.17.0) 145 | rake (10.0.4) 146 | rdiscount (2.0.7.2) 147 | rdoc (3.12.2) 148 | json (~> 1.4) 149 | ref (2.0.0) 150 | rspec-core (2.13.1) 151 | rspec-expectations (2.13.0) 152 | diff-lcs (>= 1.1.3, < 2.0) 153 | rspec-mocks (2.13.1) 154 | rspec-rails (2.13.1) 155 | actionpack (>= 3.0) 156 | activesupport (>= 3.0) 157 | railties (>= 3.0) 158 | rspec-core (~> 2.13.0) 159 | rspec-expectations (~> 2.13.0) 160 | rspec-mocks (~> 2.13.0) 161 | ruby-openid (2.2.3) 162 | sprockets (2.2.2) 163 | hike (~> 1.2) 164 | multi_json (~> 1.0) 165 | rack (~> 1.0) 166 | tilt (~> 1.1, != 1.3.0) 167 | textacular (3.0.0) 168 | activerecord (>= 3.0, < 4.1) 169 | therubyracer (0.12.2) 170 | libv8 (~> 3.16.14.0) 171 | ref 172 | thor (0.18.1) 173 | tilt (1.4.0) 174 | treetop (1.4.12) 175 | polyglot 176 | polyglot (>= 0.3.1) 177 | tzinfo (0.3.37) 178 | uglifier (2.0.1) 179 | execjs (>= 0.3.0) 180 | multi_json (~> 1.0, >= 1.0.2) 181 | unicorn (4.6.2) 182 | kgio (~> 2.6) 183 | rack 184 | raindrops (~> 0.7) 185 | 186 | PLATFORMS 187 | ruby 188 | 189 | DEPENDENCIES 190 | bugsnag (~> 1.3.6) 191 | cancan (~> 1.6.9) 192 | factory_girl_rails (~> 4.2.1) 193 | figaro (~> 0.6.4) 194 | foreman (~> 0.63.0) 195 | jquery-rails (~> 2.2.1) 196 | kaminari (~> 0.14.1) 197 | mina! 198 | newrelic_rpm (~> 3.6.1.88) 199 | omniauth (~> 1.1.4) 200 | omniauth-github (~> 1.1.0) 201 | omniauth-openid (~> 1.0.1) 202 | omniauth-twitter (~> 0.0.16) 203 | pg (~> 0.15.1) 204 | rails (~> 3.2.13) 205 | rdiscount (~> 2.0.7.2) 206 | rspec-rails (~> 2.13.1) 207 | textacular (~> 3.0.0) 208 | therubyracer (~> 0.12.2) 209 | uglifier (~> 2.0.1) 210 | unicorn (~> 4.6.2) 211 | 212 | BUNDLED WITH 213 | 1.13.7 214 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | " /> 6 | " /> 7 | " /> 8 | 9 | 10 | <%= stylesheet_link_tag "application" %> 11 | <%= csrf_meta_tag %> 12 | <%= "#{yield(:title)} — ".html_safe unless yield(:title).blank? -%><%= t('.title') -%> 13 | 27 | 28 | 35 | 36 | 37 | 38 | <% if can?(:manage, :all) %> 39 | 44 | <% end %> 45 | 70 |
71 | <%= yield %> 72 |
73 |
74 |
75 |

76 | © <%= years_tag %>
77 | Alex Sulim 78 |

79 |
80 |
81 |

82 | <%= link_to image_tag('digitalocean-badge-gray.png', :size => '140x39'), 'http://www.digitalocean.com' %> 83 |

84 |
85 |
86 |

87 | <%= link_to image_tag('travis-ci50x50.png', :size => '50x50'), 'http://travis-ci.org/', :style => 'float:left;margin-right:10px;' %> 88 | Travis CI — простой и мощный сервис непрерывной интеграции для ваших проектов с открытым кодом. 89 | <%= link_to 'http://travis-ci.org', 'http://travis-ci.org' %> 90 |

91 |
92 |
93 | 94 |
95 |
96 | <%= javascript_include_tag "application" %> 97 | 100 | <%= yield(:footer_js) %> 101 | 102 | <% if Rails.env.production? %> 103 | <%= javascript_include_tag "http://static.evernote.com/noteit.js", :cache => false %> 104 | 115 | <% end %> 116 | 117 | 118 | -------------------------------------------------------------------------------- /vendor/assets/stylesheets/960gs.css: -------------------------------------------------------------------------------- 1 | /* Containers 2 | ----------------------------------------------------------------------------------------------------*/ 3 | .container_12 { 4 | margin-left: auto; 5 | margin-right: auto; 6 | width: 960px; 7 | } 8 | 9 | /* Grid >> Children (Alpha ~ First, Omega ~ Last) 10 | ----------------------------------------------------------------------------------------------------*/ 11 | 12 | .alpha { 13 | margin-left: 0 !important; 14 | } 15 | 16 | .omega { 17 | margin-right: 0 !important; 18 | } 19 | 20 | 21 | 22 | /* Grid >> Global 23 | ----------------------------------------------------------------------------------------------------*/ 24 | 25 | .grid_1, 26 | .grid_2, 27 | .grid_3, 28 | .grid_4, 29 | .grid_5, 30 | .grid_6, 31 | .grid_7, 32 | .grid_8, 33 | .grid_9, 34 | .grid_10, 35 | .grid_11, 36 | .grid_12{ 37 | display:inline; 38 | float: left; 39 | position: relative; 40 | margin-left: 10.0px; 41 | margin-right: 10.0px; 42 | } 43 | 44 | 45 | /* Grid >> 2 Columns 46 | ----------------------------------------------------------------------------------------------------*/ 47 | 48 | .container_12 .grid_1{ 49 | width:60px; 50 | } 51 | 52 | .container_12 .grid_2{ 53 | width:140px; 54 | } 55 | 56 | .container_12 .grid_3{ 57 | width:220px; 58 | } 59 | 60 | .container_12 .grid_4{ 61 | width:300px; 62 | } 63 | 64 | .container_12 .grid_5{ 65 | width:380px; 66 | } 67 | 68 | .container_12 .grid_6{ 69 | width:460px; 70 | } 71 | 72 | .container_12 .grid_7{ 73 | width:540px; 74 | } 75 | 76 | .container_12 .grid_8{ 77 | width:620px; 78 | } 79 | 80 | .container_12 .grid_9{ 81 | width:700px; 82 | } 83 | 84 | .container_12 .grid_10{ 85 | width:780px; 86 | } 87 | 88 | .container_12 .grid_11{ 89 | width:860px; 90 | } 91 | 92 | .container_12 .grid_12{ 93 | width:940px; 94 | } 95 | 96 | 97 | 98 | 99 | 100 | /* Prefix Extra Space >> 2 Columns 101 | ----------------------------------------------------------------------------------------------------*/ 102 | 103 | .container_12 .prefix_1 { 104 | padding-left:80px; 105 | } 106 | 107 | .container_12 .prefix_2 { 108 | padding-left:160px; 109 | } 110 | 111 | .container_12 .prefix_3 { 112 | padding-left:240px; 113 | } 114 | 115 | .container_12 .prefix_4 { 116 | padding-left:320px; 117 | } 118 | 119 | .container_12 .prefix_5 { 120 | padding-left:400px; 121 | } 122 | 123 | .container_12 .prefix_6 { 124 | padding-left:480px; 125 | } 126 | 127 | .container_12 .prefix_7 { 128 | padding-left:560px; 129 | } 130 | 131 | .container_12 .prefix_8 { 132 | padding-left:640px; 133 | } 134 | 135 | .container_12 .prefix_9 { 136 | padding-left:720px; 137 | } 138 | 139 | .container_12 .prefix_10 { 140 | padding-left:800px; 141 | } 142 | 143 | .container_12 .prefix_11 { 144 | padding-left:880px; 145 | } 146 | 147 | 148 | 149 | /* Suffix Extra Space >> 2 Columns 150 | ----------------------------------------------------------------------------------------------------*/ 151 | 152 | .container_12 .suffix_1 { 153 | padding-right:80px; 154 | } 155 | 156 | .container_12 .suffix_2 { 157 | padding-right:160px; 158 | } 159 | 160 | .container_12 .suffix_3 { 161 | padding-right:240px; 162 | } 163 | 164 | .container_12 .suffix_4 { 165 | padding-right:320px; 166 | } 167 | 168 | .container_12 .suffix_5 { 169 | padding-right:400px; 170 | } 171 | 172 | .container_12 .suffix_6 { 173 | padding-right:480px; 174 | } 175 | 176 | .container_12 .suffix_7 { 177 | padding-right:560px; 178 | } 179 | 180 | .container_12 .suffix_8 { 181 | padding-right:640px; 182 | } 183 | 184 | .container_12 .suffix_9 { 185 | padding-right:720px; 186 | } 187 | 188 | .container_12 .suffix_10 { 189 | padding-right:800px; 190 | } 191 | 192 | .container_12 .suffix_11 { 193 | padding-right:880px; 194 | } 195 | 196 | 197 | 198 | /* Push Space >> 2 Columns 199 | ----------------------------------------------------------------------------------------------------*/ 200 | 201 | .container_12 .push_1 { 202 | left:80px; 203 | } 204 | 205 | .container_12 .push_2 { 206 | left:160px; 207 | } 208 | 209 | .container_12 .push_3 { 210 | left:240px; 211 | } 212 | 213 | .container_12 .push_4 { 214 | left:320px; 215 | } 216 | 217 | .container_12 .push_5 { 218 | left:400px; 219 | } 220 | 221 | .container_12 .push_6 { 222 | left:480px; 223 | } 224 | 225 | .container_12 .push_7 { 226 | left:560px; 227 | } 228 | 229 | .container_12 .push_8 { 230 | left:640px; 231 | } 232 | 233 | .container_12 .push_9 { 234 | left:720px; 235 | } 236 | 237 | .container_12 .push_10 { 238 | left:800px; 239 | } 240 | 241 | .container_12 .push_11 { 242 | left:880px; 243 | } 244 | 245 | 246 | 247 | 248 | 249 | /* Pull Space >> 2 Columns 250 | ----------------------------------------------------------------------------------------------------*/ 251 | 252 | .container_12 .pull_1 { 253 | right:80px; 254 | } 255 | 256 | .container_12 .pull_2 { 257 | right:160px; 258 | } 259 | 260 | .container_12 .pull_3 { 261 | right:240px; 262 | } 263 | 264 | .container_12 .pull_4 { 265 | right:320px; 266 | } 267 | 268 | .container_12 .pull_5 { 269 | right:400px; 270 | } 271 | 272 | .container_12 .pull_6 { 273 | right:480px; 274 | } 275 | 276 | .container_12 .pull_7 { 277 | right:560px; 278 | } 279 | 280 | .container_12 .pull_8 { 281 | right:640px; 282 | } 283 | 284 | .container_12 .pull_9 { 285 | right:720px; 286 | } 287 | 288 | .container_12 .pull_10 { 289 | right:800px; 290 | } 291 | 292 | .container_12 .pull_11 { 293 | right:880px; 294 | } 295 | 296 | 297 | 298 | 299 | /* Clear Floated Elements 300 | ----------------------------------------------------------------------------------------------------*/ 301 | 302 | 303 | .clear { 304 | clear: both; 305 | display: block; 306 | overflow: hidden; 307 | visibility: hidden; 308 | width: 0; 309 | height: 0; 310 | } 311 | 312 | 313 | .clearfix:after { 314 | clear: both; 315 | content: ' '; 316 | display: block; 317 | font-size: 0; 318 | line-height: 0; 319 | visibility: hidden; 320 | width: 0; 321 | height: 0; 322 | } 323 | 324 | .clearfix { 325 | display: inline-block; 326 | } 327 | 328 | * html .clearfix { 329 | height: 1%; 330 | } 331 | 332 | .clearfix { 333 | display: block; 334 | } -------------------------------------------------------------------------------- /spec/controllers/items_controller_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe ItemsController do 4 | let(:user) { mock_model(User, :admin? => false, :guest? => false) } 5 | let(:item) { mock_model(Item).as_null_object } 6 | 7 | before { controller.stub(:current_user).and_return(user) } 8 | 9 | describe "GET index" do 10 | it "assigns @items" do 11 | Item.stub_chain(:recent, :page, :per).and_return([item]) 12 | get :index 13 | assigns[:items].should eq([item]) 14 | end 15 | end 16 | 17 | describe "GET new" do 18 | before { user.stub_chain(:items, :new).and_return(item) } 19 | 20 | it "creates a new item" do 21 | user.items.should_receive(:new) 22 | get :new 23 | end 24 | 25 | it "assigns @item" do 26 | get :new 27 | assigns[:item].should eq(item) 28 | end 29 | 30 | context "when user is a guest" do 31 | before { controller.stub(:current_user).and_return(nil) } 32 | 33 | it "sets flash notice" do 34 | get :new 35 | flash[:notice].should_not be_blank 36 | end 37 | 38 | it "redirects to sign in URL" do 39 | get :new 40 | response.should redirect_to(sign_in_url) 41 | end 42 | end 43 | end 44 | 45 | describe "POST create" do 46 | before { user.stub_chain(:items, :create).and_return(item) } 47 | 48 | it "creates a new item" do 49 | user.items.should_receive(:create) 50 | post :create 51 | end 52 | 53 | it "redirects to item URL" do 54 | post :create 55 | response.should redirect_to(item_url(item)) 56 | end 57 | 58 | context "when user is a guest" do 59 | before { controller.stub(:current_user).and_return(nil) } 60 | 61 | it "sets flash notice" do 62 | get :new 63 | flash[:notice].should_not be_blank 64 | end 65 | 66 | it "redirects to sign in URL" do 67 | get :new 68 | response.should redirect_to(sign_in_url) 69 | end 70 | end 71 | end 72 | 73 | describe "GET show" do 74 | before { Item.stub(:find).and_return(item) } 75 | 76 | it "assigns @item" do 77 | get :show, :id => item.id 78 | assigns[:item].should eq(item) 79 | end 80 | end 81 | 82 | describe "GET edit" do 83 | before { Item.stub(:find).and_return(item) } 84 | 85 | it "assigns @item" do 86 | get :edit, :id => item.id 87 | assigns[:item].should eq(item) 88 | end 89 | 90 | context "when user is a guest" do 91 | before { controller.stub(:current_user).and_return(nil) } 92 | 93 | it "sets flash notice" do 94 | get :edit, :id => item.id 95 | flash[:notice].should_not be_blank 96 | end 97 | 98 | it "redirects to sign in URL" do 99 | get :edit, :id => item.id 100 | response.should redirect_to(sign_in_url) 101 | end 102 | end 103 | 104 | context "when user is not an author" do 105 | before do 106 | item.stub(:author?).and_return(false) 107 | end 108 | 109 | it "sets flash notice" do 110 | get :edit, :id => item.id 111 | flash[:notice].should_not be_blank 112 | end 113 | 114 | it "redirects to sign in URL" do 115 | get :edit, :id => item.id 116 | response.should redirect_to(sign_in_url) 117 | end 118 | end 119 | end 120 | 121 | describe "GET show" do 122 | before { Item.stub(:find).and_return(item) } 123 | 124 | it "assigns @item" do 125 | get :show, :id => item.id 126 | assigns[:item].should eq(item) 127 | end 128 | end 129 | 130 | describe "PUT update" do 131 | let(:attributes) { { "title" => "Foo" } } 132 | before { Item.stub(:find).and_return(item) } 133 | 134 | it "assigns @item" do 135 | put :update, :id => item.id 136 | assigns[:item].should eq(item) 137 | end 138 | 139 | it "updates item" do 140 | item.should_receive(:update_attributes).with(attributes) 141 | put :update, :id => item.id, :item => attributes 142 | end 143 | 144 | it "redirects to item url" do 145 | put :update, :id => item.id 146 | response.should redirect_to(item_url(item)) 147 | end 148 | 149 | context "when user is a guest" do 150 | before { controller.stub(:current_user).and_return(nil) } 151 | 152 | it "sets flash notice" do 153 | put :update, :id => item.id 154 | flash[:notice].should_not be_blank 155 | end 156 | 157 | it "redirects to sign in URL" do 158 | put :update, :id => item.id 159 | response.should redirect_to(sign_in_url) 160 | end 161 | end 162 | 163 | context "when user is not an author" do 164 | before do 165 | item.stub(:author?).and_return(false) 166 | end 167 | 168 | it "sets flash notice" do 169 | put :update, :id => item.id 170 | flash[:notice].should_not be_blank 171 | end 172 | 173 | it "redirects to sign in URL" do 174 | put :update, :id => item.id 175 | response.should redirect_to(sign_in_url) 176 | end 177 | end 178 | end 179 | 180 | describe "DELETE destroy" do 181 | before { Item.stub(:find).and_return(item) } 182 | 183 | context "when user is an admin" do 184 | before { user.stub(:admin?).and_return(true) } 185 | 186 | it "assigns @item" do 187 | delete :destroy, :id => item.id 188 | assigns[:item].should eq(item) 189 | end 190 | 191 | it "destroy item" do 192 | item.should_receive(:destroy) 193 | delete :destroy, :id => item.id 194 | end 195 | 196 | it "redirects to items url" do 197 | delete :destroy, :id => item.id 198 | response.should redirect_to(items_url) 199 | end 200 | end 201 | 202 | context "when user is not an admin but author" do 203 | before { item.stub(:author?).and_return(true) } 204 | 205 | it "assigns @item" do 206 | delete :destroy, :id => item.id 207 | assigns[:item].should eq(item) 208 | end 209 | 210 | it "destroy item" do 211 | item.should_receive(:destroy) 212 | delete :destroy, :id => item.id 213 | end 214 | 215 | it "sets flash notice" do 216 | delete :destroy, :id => item.id 217 | flash[:notice].should_not be_blank 218 | end 219 | 220 | it "redirects to sign in URL" do 221 | delete :destroy, :id => item.id 222 | response.should redirect_to(items_url) 223 | end 224 | end 225 | 226 | context "when user is a guest" do 227 | before { controller.stub(:current_user).and_return(nil) } 228 | 229 | it "sets flash notice" do 230 | delete :destroy, :id => item.id 231 | flash[:notice].should_not be_blank 232 | end 233 | 234 | it "redirects to sign in URL" do 235 | delete :destroy, :id => item.id 236 | response.should redirect_to(sign_in_url) 237 | end 238 | end 239 | 240 | context "when user is not an admin and not author" do 241 | before { item.stub(:author?).and_return(false) } 242 | 243 | it "sets flash notice" do 244 | delete :destroy, :id => item.id 245 | flash[:notice].should_not be_blank 246 | end 247 | 248 | it "redirects to sign in URL" do 249 | delete :destroy, :id => item.id 250 | response.should redirect_to(sign_in_url) 251 | end 252 | end 253 | end 254 | end 255 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | *= require reset 3 | *= require 960gs 4 | *= require form 5 | *= require wmd 6 | *= require code 7 | *= require_self 8 | */ 9 | 10 | /* ------------------------------------------------------------------------ 11 | = Page 12 | ------------------------------------------------------------------------ */ 13 | body { 14 | font-family: Helvetica, Arial, sans-serif; 15 | font-size:14px; 16 | line-height:21px; 17 | color:#444; 18 | } 19 | h1 { 20 | margin-bottom:1em; 21 | padding:0; 22 | border:none; 23 | font-size:22px; 24 | font-weight:bold; 25 | } 26 | h2 { 27 | font-size:14px; 28 | font-weight:bold; 29 | margin-bottom:1em; 30 | } 31 | h1, h2, h3, h4, p { word-wrap:break-word; } 32 | article header a { 33 | color:#444; 34 | text-decoration:none; 35 | } 36 | strong { 37 | font-weight:bold; 38 | } 39 | p, 40 | pre, 41 | ul, 42 | ol { 43 | margin-bottom:1em; 44 | } 45 | ul, ol { 46 | padding-left:1.5em; 47 | } 48 | ul { 49 | list-style-type:circle; 50 | } 51 | ol { 52 | list-style-type:decimal; 53 | } 54 | ul li { 55 | list-style:disc outside none; 56 | } 57 | .providers { 58 | padding:0; 59 | font-weight:bold; 60 | } 61 | .providers li { 62 | display:inline-block; 63 | margin-right:2em; 64 | list-style:none outside none; 65 | } 66 | .providers a { 67 | text-decoration:none; 68 | } 69 | .providers img { 70 | vertical-align:middle; 71 | } 72 | em { 73 | font-style:italic; 74 | } 75 | 76 | article header a:hover, 77 | a { 78 | color:#758EA2; 79 | } 80 | a:hover { 81 | color:#5b6e7e; 82 | } 83 | .link-with-icon { 84 | text-decoration:none; 85 | text-transform:uppercase; 86 | line-height:16px; 87 | color:#444; 88 | font-size:11px; 89 | font-style:normal; 90 | } 91 | .link-with-icon .icon { 92 | margin-right:4px; 93 | } 94 | .uppercase { 95 | text-transform:uppercase; 96 | } 97 | /* ------------------------------------------------------------------------ 98 | = Flash message 99 | ------------------------------------------------------------------------ */ 100 | .flash { 101 | position:fixed; 102 | top:0; 103 | left:0; 104 | width:100%; 105 | z-index: 10000; 106 | border-bottom:2px solid rgba(0, 0, 0, 0.05); 107 | background-color:rgba(46, 46, 46, 0.95); 108 | } 109 | .flash .notice, 110 | .flash .error { 111 | margin:0 7%; 112 | padding:15px; 113 | font-size:14px; 114 | font-weight:bold; 115 | text-align:center; 116 | color:#FFF; 117 | } 118 | .flash .error { color:#CF3C25; } 119 | 120 | /* ------------------------------------------------------------------------ 121 | = Control panel 122 | ------------------------------------------------------------------------ */ 123 | #control-panel { 124 | border-bottom-right-radius:5px; 125 | border-bottom-left-radius:5px; 126 | background-color:#444; 127 | color:#CCC; 128 | font-size:11px; 129 | } 130 | #control-panel a { 131 | color:inherit; 132 | text-decoration:none; 133 | } 134 | #control-panel a:hover { 135 | color:#FFF; 136 | } 137 | #control-panel ul { 138 | margin:0; 139 | } 140 | #control-panel ul li { 141 | display:inline-block; 142 | list-style:none outside none; 143 | } 144 | /* ------------------------------------------------------------------------ 145 | = Header 146 | ------------------------------------------------------------------------ */ 147 | #header { 148 | position:relative; 149 | padding:24px 0; 150 | } 151 | /* http://www.colourlovers.com/palette/1388735/Diversion_II */ 152 | #header .logo { 153 | color:#000; 154 | font-size:22px; 155 | font-weight:bold; 156 | } 157 | #header .logo a { 158 | text-decoration:none; 159 | color:#000; 160 | } 161 | #header .logo span { 162 | border-radius:5px; 163 | margin-left:2px; 164 | padding:1px 4px; 165 | background-color:#CF3C25; 166 | -background-color:#C1DE4B; 167 | color:#FFF; 168 | text-shadow:0 1px 1px rgba(0, 0, 0, 0.3); 169 | } 170 | #header .search { 171 | text-align:right; 172 | } 173 | #header .search input { 174 | width:100%; 175 | } 176 | #header .account { 177 | position:absolute; 178 | right:20px; 179 | top:0; 180 | padding:4px 8px; 181 | -webkit-border-bottom-right-radius: 5px; 182 | -webkit-border-bottom-left-radius: 5px; 183 | -moz-border-radius-bottomright: 5px; 184 | -moz-border-radius-bottomleft: 5px; 185 | border-bottom-right-radius: 5px; 186 | border-bottom-left-radius: 5px; 187 | background-color:#758EA2; 188 | font-size:11px; 189 | line-height:1; 190 | } 191 | #header .account a { 192 | color:#FFF; 193 | text-decoration:none; 194 | } 195 | #header .account a:hover { 196 | } 197 | 198 | #header .menu { 199 | text-align:right; 200 | text-transform:uppercase; 201 | font-size:12px; 202 | font-weight:bold; 203 | } 204 | #header .menu nav ul { 205 | padding-top:1px; 206 | } 207 | #header .menu nav ul li { 208 | display:inline-block; 209 | vertical-align:middle; 210 | padding:0 6px; 211 | line-height:1; 212 | } 213 | #header .menu nav a { 214 | display:inline-block; 215 | margin:0; 216 | padding:4px 9px; 217 | line-height:1; 218 | text-decoration:none; 219 | border-radius:10px; 220 | } 221 | #header .menu nav a:hover { 222 | color:#FFF; 223 | background-color:#CF3C25; 224 | } 225 | 226 | #content { 227 | margin-top:12px; 228 | } 229 | /* ------------------------------------------------------------------------ 230 | = Event 231 | ------------------------------------------------------------------------ */ 232 | .event { 233 | margin-bottom:2em; 234 | padding-bottom:1em; 235 | border-bottom:#CCC 1px dotted; 236 | } 237 | .event header { 238 | margin-bottom:1em; 239 | color:#CF3C25; 240 | font-weight:bold; 241 | line-height:1; 242 | } 243 | .event .list ul { 244 | margin:0; 245 | padding:0; 246 | color:#B2B2B2; 247 | font-size:10px; 248 | line-height:16px; 249 | } 250 | .event .list ul li { 251 | margin:0 0 4px 0; 252 | padding:4px 6px; 253 | list-style:none outside none; 254 | cursor:pointer; 255 | } 256 | .event .list ul li.current { 257 | -webkit-border-top-left-radius: 4px; 258 | -webkit-border-bottom-left-radius: 4px; 259 | -moz-border-radius-topleft: 4px; 260 | -moz-border-radius-bottomleft: 4px; 261 | border-top-left-radius: 4px; 262 | border-bottom-left-radius: 4px; 263 | background-color:#EEE; 264 | } 265 | .event .list ul li.current a { 266 | text-decoration:none; 267 | } 268 | .event .list ul header { 269 | margin:0; 270 | color:#444; 271 | font-size:14px; 272 | font-weight:bold; 273 | } 274 | .event .slide { 275 | margin:0; 276 | padding:0; 277 | color:#888; 278 | font-size:12px; 279 | line-height:18px; 280 | } 281 | .event .slide .banner { 282 | -webkit-border-radius: 4px; 283 | -moz-border-radius: 4px; 284 | border-radius: 4px; 285 | } 286 | .event .slide p, 287 | .event .slide pre, 288 | .event .slide ul, 289 | .event .slide ol { 290 | margin-bottom:6px; 291 | } 292 | /* ------------------------------------------------------------------------ 293 | = Day 294 | ------------------------------------------------------------------------ */ 295 | .day {} 296 | .day time { 297 | text-align:center; 298 | } 299 | time .date-day, time .date-month, time .date-year { 300 | color:#B2B2B2; 301 | font-weight:bold; 302 | line-height:1; 303 | } 304 | time .date-day { 305 | font-size:30px; 306 | } 307 | time .date-month { 308 | font-size:14px; 309 | } 310 | time .date-year { 311 | display:block; 312 | font-size:12px; 313 | } 314 | article { 315 | position:relative; 316 | margin-bottom:4em; 317 | } 318 | article header, 319 | .header-with-comment { 320 | margin-bottom:0.5em; 321 | padding:0; 322 | font-size:22px; 323 | font-weight:bold; 324 | } 325 | article header span, 326 | .header-with-comment span { 327 | display:block; 328 | margin-top:3px; 329 | padding-top:3px; 330 | line-height:1; 331 | font-size:12px; 332 | border-top:#CCC 1px solid; 333 | color:#B2B2B2; 334 | } 335 | article aside { 336 | position:absolute; 337 | top:0; 338 | right:0; 339 | display:none; 340 | } 341 | article:hover aside { 342 | display:block; 343 | } 344 | article aside ul li { 345 | margin:0 0 2px 0; 346 | padding:0; 347 | list-style:none outside none; 348 | line-height:1; 349 | } 350 | article img { 351 | max-width:620px; 352 | } 353 | article .comments { 354 | font-style:italic; 355 | } 356 | article .comments pre { 357 | font-style:normal; 358 | } 359 | article .comments .new-comment { 360 | display:none; 361 | } 362 | article .comments header { 363 | margin:0; 364 | padding:0; 365 | border:none; 366 | font-size:14px; 367 | } 368 | article .comments header a { 369 | color:#444; 370 | text-decoration:underline; 371 | } 372 | article .comments .comment { 373 | margin:0 0 1em 0; 374 | padding:0; 375 | } 376 | .comment header {} 377 | .comment header time { 378 | float:right; 379 | margin:0; 380 | padding:2px 4px; 381 | -webkit-border-radius:4px; 382 | -moz-border-radius:4px; 383 | border-radius:4px; 384 | color:#B2B2B2; 385 | -background-color:#758EA2; 386 | background-color:rgba(243, 246, 250, 1); 387 | font-weight:normal; 388 | font-size:11px; 389 | line-height:1; 390 | } 391 | .preview { 392 | position:relative; 393 | } 394 | .preview header, 395 | .comments .preview header { 396 | position:absolute; 397 | right:0; 398 | top:0; 399 | padding:0px 4px; 400 | -webkit-border-top-right-radius:5px; 401 | -webkit-border-bottom-left-radius:5px; 402 | -moz-border-radius-topright:5px; 403 | -moz-border-radius-bottomleft:5px; 404 | border-top-right-radius:5px; 405 | border-bottom-left-radius:5px; 406 | font-size:12px; 407 | font-weight:normal; 408 | font-style:normal; 409 | color:#FFF; 410 | background-color:rgba(207, 60, 37, 0.6); 411 | } 412 | 413 | .avatar { 414 | -webkit-border-radius:5px; 415 | -moz-border-radius:5px; 416 | border-radius:5px; 417 | } 418 | 419 | .users { 420 | margin-bottom:1em; 421 | } 422 | .users tr { 423 | margin:0; 424 | padding:0; 425 | border-bottom:#758EA2 1px solid; 426 | } 427 | .users tr:hover { 428 | background-color:rgba(243, 246, 250, 1); 429 | } 430 | .users td { 431 | margin:0; 432 | padding:3px; 433 | } 434 | 435 | .admin-buttons { 436 | padding:0; 437 | } 438 | .admin-buttons li { 439 | margin:0 1em 0 0; 440 | padding:0; 441 | list-style:none outside; 442 | } 443 | .pagination { 444 | text-align:center; 445 | } 446 | .pagination em { 447 | font-style:normal; 448 | font-size:22px; 449 | font-weight:bold; 450 | } 451 | .pagination a { 452 | display:inline-block; 453 | min-width:1em; 454 | padding:1px 3px; 455 | text-decoration:none; 456 | } 457 | .pagination a:hover { 458 | border-radius:5px; 459 | background-color:#CF3C25; 460 | color:#FFF; 461 | } 462 | .pagination .gap {} 463 | .pagination .previous_page {} 464 | .pagination .next_page {} 465 | .pagination .disabled { 466 | display:none; 467 | } 468 | 469 | .search-results {} 470 | .search-results h1 { 471 | color:#B2B2B2; 472 | } 473 | .search-results .counter { 474 | padding:4px 4px; 475 | border-radius:5px; 476 | background-color:#C1DE4B; 477 | color:#FFF; 478 | text-align:center; 479 | font-size:22px; 480 | } 481 | 482 | #footer { 483 | margin-top:100px; 484 | margin-bottom:30px; 485 | color:#444; 486 | font-size:11px; 487 | } 488 | #footer a { 489 | color:#444; 490 | } 491 | #footer .partner { 492 | text-decoration:none; 493 | } 494 | #footer .counters { 495 | text-align:center; 496 | } 497 | #footer p { 498 | margin-bottom:10px; 499 | line-height:14px; 500 | } 501 | #footer a span { 502 | padding:1px 3px; 503 | border-radius:2px; 504 | color:#fff; 505 | background-color:#758EA2; 506 | } 507 | #footer nav ul { 508 | text-align:right; 509 | text-transform:uppercase; 510 | font-size:9px; 511 | } 512 | #footer nav ul li { 513 | display:inline; 514 | margin-left:2em; 515 | } 516 | #footer nav a {} 517 | #footer nav a:hover {} --------------------------------------------------------------------------------