Changed newrelic configuration to load from environment variables

Changed login field text
Changed database configuration connection pool size to be configured via dotenv
Use a single BBcode parser library
Added better translations coverage
Code formatting
Increases maximum article text limit
Added database cleaner with the deletion strategy during testing
This commit is contained in:
Luke Barratt 2014-03-30 20:50:52 +01:00
parent 3b9c807594
commit 704a6b4e9b
35 changed files with 277 additions and 180 deletions

View file

@ -1,12 +1,17 @@
RACK_ENV=
RAILS_ENV=
APP_SECRET=
UNICORN_USER=deploy
UNICORN_GROUP=deploy
UNICORN_WORKERS=4
UNICORN_PORT=5000
UNICORN_PORT=4000
UNICORN_SOCKET=/tmp/unicorn.ensl.sock
MYSQL_DATABASE=ensl
MYSQL_USERNAME=
MYSQL_PASSWORD=
MYSQL_CONNECTION_POOL=8
NEW_RELIC_APP_NAME=ENSL
NEW_RELIC_LICENSE_KEY=

View file

@ -13,11 +13,11 @@ gem 'sass-rails', '~> 3.2.5'
gem 'coffee-rails', '~> 3.2.2'
gem 'gruff', '~> 0.3.6'
gem 'nokogiri', '~> 1.6.1'
gem 'rbbcode', '~> 0.1.11'
gem 'bbcoder', '~> 1.0.1'
gem 'sanitize', '~> 2.1.0'
gem 'tinymce-rails', '~> 3.5.4.1'
gem 'carrierwave', '~> 0.10.0'
gem 'bluecloth', '~> 2.2.0'
gem 'bb-ruby', '~> 1.0.4'
gem 'therubyracer', '~> 0.12.1'
gem 'newrelic_rpm', '~> 3.7.2.195'
gem 'rmagick', '~> 2.13.2', require: false
@ -39,10 +39,12 @@ end
group :test do
gem 'simplecov', '~> 0.7.1', require: false
gem 'codeclimate-test-reporter', '~> 0.3.0', require: nil
gem 'database_cleaner', '~> 1.2.0'
gem 'rspec-rails', '~> 2.14.1'
gem 'rspec-given', '~> 3.5.4'
gem 'capybara', '~> 2.2.1'
gem 'poltergeist', '~> 1.5.0'
gem 'selenium-webdriver', '~> 2.41.0'
gem 'factory_girl_rails', '~> 4.4.1'
end

View file

@ -39,7 +39,7 @@ GEM
activerecord (>= 2.3.0)
rake (>= 0.8.7)
arel (3.0.3)
bb-ruby (1.0.4)
bbcoder (1.0.1)
bluecloth (2.2.0)
builder (3.0.4)
capistrano (3.1.0)
@ -68,6 +68,8 @@ GEM
activesupport (>= 3.2.0)
json (>= 1.7)
mime-types (>= 1.16)
childprocess (0.5.2)
ffi (~> 1.0, >= 1.0.11)
cliver (0.3.2)
codeclimate-test-reporter (0.3.0)
simplecov (>= 0.7.1, < 1.0.0)
@ -81,6 +83,7 @@ GEM
coffee-script-source (1.3.3)
columnize (0.3.6)
dalli (2.7.0)
database_cleaner (1.2.0)
debugger (1.6.6)
columnize (>= 0.3.1)
debugger-linecache (~> 1.2.0)
@ -99,6 +102,8 @@ GEM
factory_girl_rails (4.4.1)
factory_girl (~> 4.4.0)
railties (>= 3.0.0)
ffi (1.9.3)
ffi (1.9.3-x86-mingw32)
given_core (3.5.4)
sorcerer (>= 0.3.7)
gruff (0.3.6)
@ -170,8 +175,6 @@ GEM
thor (>= 0.14.6, < 2.0)
raindrops (0.13.0)
rake (10.1.1)
rbbcode (0.1.11)
sanitize-url (>= 0.1.3)
rdoc (3.12.2)
json (~> 1.4)
ref (1.0.5)
@ -195,12 +198,19 @@ GEM
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
sanitize-url (0.1.4)
rubyzip (1.1.2)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
sass (3.1.20)
sass-rails (3.2.5)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
selenium-webdriver (2.41.0)
childprocess (>= 0.5.0)
multi_json (~> 1.0)
rubyzip (~> 1.0)
websocket (~> 1.0.4)
simplecov (0.7.1)
multi_json (~> 1.0)
simplecov-html (~> 0.7.1)
@ -237,6 +247,7 @@ GEM
kgio (~> 2.6)
rack
raindrops (~> 0.7)
websocket (1.0.7)
websocket-driver (0.3.2)
win32console (1.3.2-x86-mingw32)
xpath (2.0.0)
@ -248,7 +259,7 @@ PLATFORMS
DEPENDENCIES
annotate (~> 2.6.2)
bb-ruby (~> 1.0.4)
bbcoder (~> 1.0.1)
bluecloth (~> 2.2.0)
capistrano (~> 3.1.0)
capistrano-bundler (~> 1.1.2)
@ -260,6 +271,7 @@ DEPENDENCIES
codeclimate-test-reporter (~> 0.3.0)
coffee-rails (~> 3.2.2)
dalli (~> 2.7.0)
database_cleaner (~> 1.2.0)
dotenv-rails (~> 0.10.0)
factory_girl_rails (~> 4.4.1)
gruff (~> 0.3.6)
@ -272,11 +284,12 @@ DEPENDENCIES
poltergeist (~> 1.5.0)
pry-debugger (~> 0.2.2)
rails (~> 3.2.17)
rbbcode (~> 0.1.11)
rmagick (~> 2.13.2)
rspec-given (~> 3.5.4)
rspec-rails (~> 2.14.1)
sanitize (~> 2.1.0)
sass-rails (~> 3.2.5)
selenium-webdriver (~> 2.41.0)
simplecov (~> 0.7.1)
therubyracer (~> 0.12.1)
tinymce-rails (~> 3.5.4.1)

View file

@ -79,7 +79,6 @@ div
&[type=submit]
@include shadow
height: 21px
width: 20px
border: 1px solid #cecece
background-color: #f7f7f7
color: #3a3a3a

View file

@ -6,9 +6,8 @@ class ArticlesController < ApplicationController
end
def news_index
@cat = params[:cat] ? Category.find(params[:cat]) : Article.onlynews.ordered.first.category
@news = Article.with_comments.ordered.limited.nodrafts.category @cat
@categories = Category.ordered.domain Category::DOMAIN_NEWS
@news = Article.with_comments.ordered.limited.nodrafts.onlynews
@categories = Category.ordered.domain(Category::DOMAIN_NEWS)
@nobody = true
end

View file

@ -7,9 +7,8 @@ class TopicsController < ApplicationController
def show
raise AccessError unless @topic.can_show? cuser
@posts = @topic.posts.basic.paginate \
:page => params[:page],
:per_page => Topic::POSTS_PAGE
@posts = @topic.posts.basic.paginate(:page => params[:page],
:per_page => Topic::POSTS_PAGE)
return_here
@topic.record_view_count(request.remote_ip, cuser.nil?)

View file

@ -16,7 +16,6 @@
#
require File.join(Rails.root, 'vendor', 'plugins', 'has_view_count', 'init.rb')
require 'rbbcode'
class Article < ActiveRecord::Base
include Exceptions
@ -60,7 +59,8 @@ class Article < ActiveRecord::Base
has_many :files, :class_name => "DataFile", :order => "created_at DESC", :dependent => :destroy
validates_length_of :title, :in => 1..50
validates_length_of :text, :in => 1..64000
validates_length_of :text, :in => 1..16000000
validates_presence_of :user, :category
validate :validate_status
@ -104,7 +104,7 @@ class Article < ActiveRecord::Base
def format_text
if text_coding == CODING_BBCODE
self.text_parsed = RbbCode::Parser.new.parse(text)
self.text_parsed = bbcode_to_html(text)
elsif text_coding == CODING_MARKDOWN
self.text_parsed = BlueCloth.new(text).to_html
end

View file

@ -12,8 +12,6 @@
# text_parsed :text
#
require 'rbbcode'
class Comment < ActiveRecord::Base
include Extra
@ -35,28 +33,30 @@ class Comment < ActiveRecord::Base
before_save :parse_text
def parse_text
self.text_parsed = RbbCode::Parser.new.parse(text)
if self.text
self.text_parsed = bbcode_to_html(self.text)
end
end
def after_create
# if commentable_type == "Movie" or commentable_type == "Article" and commentable.user and commentable.user.profile.notify_own_stuff
# Notifications.deliver_comments commentable.user, commentable
# end
end
end
def can_create? cuser
def can_create? cuser
return false unless cuser
#errors.add_to_base I18n.t(:comments_locked) if !commentable.lock.nil? and commentable.lock
errors.add_to_base I18n.t(:bans_mute) if cuser.banned? Ban::TYPE_MUTE
errors.add_to_base I18n.t(:registered_for_week) unless cuser.verified?
return errors.count == 0
end
end
def can_update? cuser
def can_update? cuser
cuser and user == cuser or cuser.admin?
end
end
def can_destroy? cuser
def can_destroy? cuser
cuser and cuser.admin?
end
end
end

View file

@ -16,7 +16,6 @@
#
require File.join(Rails.root, 'vendor', 'plugins', 'acts-as-readable', 'init.rb')
require 'rbbcode'
class Issue < ActiveRecord::Base
STATUS_OPEN = 0
@ -79,7 +78,9 @@ class Issue < ActiveRecord::Base
end
def parse_text
self.text_parsed = RbbCode::Parser.new.parse(text)
if self.text
self.text_parsed = bbcode_to_html(self.text)
end
end
def remove_readings

View file

@ -14,8 +14,6 @@
# text_parsed :text
#
require 'rbbcode'
class Message < ActiveRecord::Base
include Extra
@ -54,7 +52,9 @@ class Message < ActiveRecord::Base
end
def parse_text
self.text_parsed = RbbCode::Parser.new.parse(text)
if self.text
self.text_parsed = bbcode_to_html(self.text)
end
end
def send_notifications

View file

@ -11,28 +11,9 @@
# text_parsed :text
#
require 'rbbcode'
require 'bb-ruby'
class Post < ActiveRecord::Base
BBCODE_DEFAULTS = {
'Quote' => [
/\[quote(:.*)?=(.*?)\](.*?)\[\/quote\1?\]/mi,
'<fieldset class="quote"><legend>\2</legend>\3</fieldset>',
'Quote with citation',
'[quote=mike]please quote me[/quote]',
:quote
],
'Quote without author' => [
/\[quote(:.*)\](.*?)\[\/quote\1?\]/mi,
'<fieldset class="quote">\2</fieldset>',
'Quote without citation',
'[quote]please quote me[/quote]',
:quote
],
}
include Extra
attr_protected :id, :updated_at, :created_at, :votes, :user_id
scope :basic, :include => [{:user => [:team, :profile]}, :topic]
@ -61,7 +42,9 @@ class Post < ActiveRecord::Base
end
def parse_text
self.text_parsed = self.text.bbcode_to_html(BBCODE_DEFAULTS) if self.text
if self.text
self.text_parsed = bbcode_to_html(self.text)
end
end
def remove_topics

View file

@ -54,8 +54,6 @@
# signature_parsed :string(255)
#
require 'rbbcode'
class Profile < ActiveRecord::Base
include Extra
@ -92,7 +90,7 @@ class Profile < ActiveRecord::Base
end
def parse_text
self.achievements_parsed = RbbCode::Parser.new.parse(achievements) if self.achievements
self.signature_parsed = RbbCode::Parser.new.parse(signature) if self.signature
self.achievements_parsed = bbcode_to_html(achievements) if self.achievements
self.signature_parsed = bbcode_to_html(signature) if self.signature
end
end

View file

@ -30,8 +30,7 @@ class Topic < ActiveRecord::Base
has_many :posts, :order => "id ASC", :dependent => :destroy
has_many :view_counts, :as => :viewable, :dependent => :destroy
scope :basic,
:include => [:latest, {:forum => :forumer}, :user]
scope :basic, :include => [:latest, {:forum => :forumer}, :user]
scope :ordered, :order => "state DESC, posts.id DESC"
scope :recent,
:conditions => "forumers.id IS NULL AND posts.id = (SELECT id FROM posts AS P WHERE P.topic_id = topics.id ORDER BY id DESC LIMIT 1)",

View file

@ -41,7 +41,7 @@
<%= f.text_area :text, :rows => 30, :cols => 80 %>
</p>
<p>
<%= f.submit 'Save' %>
<%= f.submit %>
</p>
<% end %>
</div>
@ -52,7 +52,7 @@
<%= render :partial => "data_files/list", :locals => {:files => @article.files} %>
<% if @file.can_create? cuser %>
<% if @file && @file.can_create?(cuser) %>
<h3>New file</h3>
<div class="wide box">

View file

@ -38,7 +38,7 @@
<tr>
<td class="text" id="post_<%= post.id %>">
<%= raw post.text_parsed %>
<%= post.text_parsed.html_safe %>
</td>
</tr>

View file

@ -3,8 +3,8 @@
<table>
<tr>
<td id="links">
<%= link_to "Register", new_user_path %> <br />
<%= link_to "Forgot Password?", "/users/forgot/1" %>
<%= link_to I18n.t('helpers.submit.user.create'), new_user_path %> <br />
<%= link_to I18n.t('sessions.form.forgot_password'), "/users/forgot/1" %>
</td>
<td>
<%= text_field "login", "username" %>
@ -13,7 +13,7 @@
<%= password_field "login", "password" %>
</td>
<td>
<%= submit_tag raw("&#187;") %>
<%= submit_tag I18n.t('helpers.submit.user.login') %>
</td>
</tr>
</table>

View file

@ -2,6 +2,6 @@
<div class="body">
<div class="content">
<% @poll = Poll.first :order => "created_at DESC" %>
<%= render :partial => "polls/show" %>
<%= render(:partial => "polls/show") if @poll %>
</div>
</div>

View file

@ -1,15 +1,14 @@
base: &db
adapter: mysql2
encoding: utf8
pool: 5
host: localhost
database: <%= ENV['MYSQL_DATABASE'] %>
username: <%= ENV['MYSQL_USERNAME'] %>
password: <%= ENV['MYSQL_PASSWORD'] %>
pool: <%= Integer(ENV['MYSQL_CONNECTION_POOL'] || 8) %>
development:
<<: *db
database: ensl_development
test:
<<: *db

View file

@ -19,7 +19,7 @@ set :unicorn_config_path, "config/unicorn.rb"
set :writable_dirs, %w{public tmp}
set :linked_files, %w{.env}
set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle
public/system public/local public/uploads}
public/system public/local public/uploads public/files}
set :normalize_asset_timestamps, %{public/images
public/javascripts

View file

@ -0,0 +1,27 @@
BBCoder.configure do
tag :b, :as => :strong
tag :sub, :singular => true do
%(<sub>#{singular? ? meta : content}</sub>)
end
tag :sup, :singular => true do
%(<sup>#{singular? ? meta : content}</sup>)
end
tag :ul
tag :ol
tag :li, :parents => [:ol, :ul]
tag :size do
%(<span style="font-size: #{meta}px;">#{content}</span>)
end
tag :url do
if meta.nil? || meta.empty?
%(<a href="#{content}">#{content}</a>)
else
%(<a href="#{meta}">#{content}</a>)
end
end
end

View file

@ -81,15 +81,23 @@ en:
votes_success: "Voted successfully."
error: "error"
prohibited: "prohibited"
sessions:
form:
forgot_password: "Forgot password?"
errors:
template:
header: "Please review the following errors:"
helpers:
submit:
user:
login: "Login"
create: "Register"
post:
create: "Create Article"
activerecord:
attributes:
article:
title: "Title"
user:
username: "Username"
email: "Email"

View file

@ -15,7 +15,7 @@ common: &default_settings
# You must specify the license key associated with your New Relic
# account. This key binds your Agent's data to your account in the
# New Relic service.
license_key: '<%= license_key %>'
license_key: '<%= ENV["NEW_RELIC_LICENSE_KEY"] %>'
# Agent Enabled (Ruby/Rails Only)
# Use this setting to force the agent to run or not run.
@ -42,7 +42,7 @@ common: &default_settings
# - Ajax Service
# - All Services
#
app_name: <%= @app_name %>
app_name: <%= ENV['NEW_RELIC_APP_NAME'] %>
# When "true", the agent collects performance data about your
# application and reports this data to the New Relic service at
@ -190,7 +190,7 @@ development:
<<: *default_settings
# Turn on communication to New Relic service in development mode
monitor_mode: true
app_name: <%= @app_name %> (Development)
app_name: <%= ENV['NEW_RELIC_APP_NAME'] %> (Development)
# Rails Only - when running in Developer Mode, the New Relic Agent will
# present performance information on the last 100 transactions you have
@ -222,4 +222,4 @@ production:
staging:
<<: *default_settings
monitor_mode: true
app_name: <%= @app_name %> (Staging)
app_name: <%= ENV['NEW_RELIC_APP_NAME'] %> (Staging)

View file

@ -0,0 +1,17 @@
class IncreaseArticleTextLimit < ActiveRecord::Migration
def up
change_column :articles, :text, :text, :limit => 16777215
change_column :articles, :text_parsed, :text, :limit => 16777215
change_column :article_versions, :text, :text, :limit => 16777215
change_column :article_versions, :text_parsed, :text, :limit => 16777215
end
def down
change_column :articles, :text, :text, :limit => 65535
change_column :articles, :text_parsed, :text, :limit => 65535
change_column :article_versions, :text, :text, :limit => 65535
change_column :article_versions, :text_parsed, :text, :limit => 65535
end
end

View file

@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20120122001951) do
ActiveRecord::Schema.define(:version => 20140330152235) do
create_table "admin_requests", :force => true do |t|
t.string "addr"
@ -31,10 +31,10 @@ ActiveRecord::Schema.define(:version => 20120122001951) do
t.integer "article_id"
t.integer "version"
t.string "title"
t.text "text"
t.text "text", :limit => 16777215
t.datetime "created_at"
t.datetime "updated_at"
t.text "text_parsed"
t.text "text_parsed", :limit => 16777215
t.integer "text_coding", :default => 0, :null => false
end
@ -44,12 +44,12 @@ ActiveRecord::Schema.define(:version => 20120122001951) do
t.string "title"
t.integer "status", :null => false
t.integer "category_id"
t.text "text"
t.text "text", :limit => 16777215
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "version"
t.text "text_parsed"
t.text "text_parsed", :limit => 16777215
t.integer "text_coding", :default => 0, :null => false
end

View file

@ -18,6 +18,10 @@ module Extra
{CODING_HTML => "Plain HTML", CODING_BBCODE => "BBCode", CODING_MARKDOWN => "Markdown"}
end
def bbcode_to_html(text)
Sanitize.clean(text.to_s).bbcode_to_html.gsub(/\n|\r\n/, "<br />").html_safe
end
def move_up scope, column = "position"
n = 0
objects = self.class.all :conditions => scope, :order => column

View file

@ -1,14 +1,6 @@
FactoryGirl.define do
sequence :title do |n|
"Article #{n}"
end
sequence :text do |n|
(0..100).map{ (0...8).map { (65 + rand(26)).chr }.join }.join(" ")
end
factory :article do
title
text
sequence(:title) { |n| "Article #{n}" }
sequence(:text) { |n| (0..100).map{ (0...8).map { (65 + rand(26)).chr }.join }.join(" ") }
end
end

View file

@ -0,0 +1,6 @@
FactoryGirl.define do
factory :category do
sequence(:name) { |n| "Category #{n}" }
sequence(:sort) { |n| n }
end
end

View file

@ -1,10 +1,7 @@
FactoryGirl.define do
sequence :name do |n|
"Team ##{n}"
end
factory :team do
name
sequence(:name) { |n| "Team ##{n}" }
irc "#team"
web "http://team.com"
tag "[TEAM]"

View file

@ -1,20 +1,9 @@
FactoryGirl.define do
sequence :username do |n|
"Player#{n}"
end
sequence :email do |n|
"player#{n}@ensl.org"
end
sequence :steamid do |n|
"0:1:#{n}"
end
factory :user do
username
email
steamid
sequence(:username) { |n| "Player#{n}" }
sequence(:email) { |n| "player#{n}@ensl.org" }
sequence(:steamid) { |n| "0:1:#{n}" }
firstname "ENSL"
lastname "Player"
country "EU"

View file

@ -1,14 +1,39 @@
require 'spec_helper'
feature 'User creates new article' do
let(:user) { create(:user) }
let!(:category) { create(:category, domain: Category::DOMAIN_NEWS) }
let(:article) { attributes_for(:article) }
describe 'with valid Title, Content, Category' do
context 'as a basic user' do
let!(:user) { create(:user) }
before do
sign_in_as(user)
visit new_article_path
end
describe 'with valid Title, Content: ' do
describe ''
it 'creates an article successfully' do
fill_in attribute_translation(:article, :title), with: article[:title]
fill_tinymce "#article_text", article[:text]
click_button I18n.t('helpers.submit.post.create')
expect(page).to have_content(I18n.t('articles_create'))
end
it 'creates an article with a text length greater than 65535 bytes' do
fill_in attribute_translation(:article, :title), with: article[:title]
fill_tinymce "#article_text", long_text
click_button I18n.t('helpers.submit.post.create')
expect(page).to have_content(I18n.t('articles_create'))
end
end
end
private
def long_text
(0..10000).map{ (0...8).map { (65 + rand(26)).chr }.join }.join(" ") # 90008
end
end

View file

@ -10,15 +10,29 @@ require 'rspec/rails'
require 'capybara/rspec'
require 'capybara/poltergeist'
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, :phantomjs_logger => File.open('/dev/null'))
end
Capybara.javascript_driver = :poltergeist
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.include Controllers::JsonHelpers, :type => :controller
config.include Controllers::JsonHelpers, type: :controller
config.include Features::FormHelpers, type: :feature
config.include Features::SessionHelpers, type: :feature
config.fixture_path = "#{::Rails.root}/spec/fixtures"
config.use_transactional_fixtures = true
config.order = "random"
config.order = 'random'
config.use_transactional_fixtures = false
config.before(:each) do
if example.metadata[:type] == :feature
Capybara.current_driver = :poltergeist
else
Capybara.use_default_driver
end
end
end

View file

@ -0,0 +1,21 @@
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:deletion)
end
config.before(:each) do
DatabaseCleaner.strategy = :deletion
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :deletion
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end

View file

@ -1,4 +0,0 @@
RSpec.configure do |config|
config.include Features::FormHelpers, type: :feature
config.include Features::SessionHelpers, type: :feature
end

View file

@ -6,12 +6,14 @@ module Features
end
end
def fill_tinymce(element, contents)
page.execute_script("$('#{element}').tinymce().setContent('#{contents}')")
end
def submit(model, action)
helper_translation(model, action)
end
private
def attribute_translation(model, attribute)
I18n.t("activerecord.attributes.#{model}.#{attribute}")
end

View file

@ -1,10 +1,12 @@
module Features
module SessionHelpers
def sign_in
def sign_in_as(user)
visit root_path
user = create(:user)
fill_form(:user, { email: user.email, password: user.raw_password })
click_button '»'
fill_in "login_username", with: user.username
fill_in "login_password", with: user.raw_password
click_button 'Login'
end
end
end