diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1585cd9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +Dockerfile +db_data diff --git a/.env.example b/.env.example index d3b2c45..49a8759 100644 --- a/.env.example +++ b/.env.example @@ -1,19 +1,33 @@ -RACK_ENV= -RAILS_ENV= -APP_SECRET= +RACK_ENV=production +RAILS_ENV=production +APP_SECRET=randomstringhere -DEPLOY_PATH= +DEPLOY_PATH=/var/www -PUMA_WORKERS=1 +PUMA_WORKERS=5 PUMA_MIN_THREADS=1 PUMA_MAX_THREADS=16 PUMA_PORT=4000 PUMA_TIMEOUT=30 +# Docker adds mysql to hosts +MYSQL_HOST=mysql + +# This is used by both rails + mysql MYSQL_DATABASE=ensl -MYSQL_USERNAME= -MYSQL_PASSWORD= -MYSQL_CONNECTION_POOL=8 + +# Add to allow docker image to connect +MYSQL_ROOT_HOST=% + +# FIXME: Use root since normal user does not work. atm. +MYSQL_ROOT_PASSWORD=randomstringhere + +# These variables are for ensl +MYSQL_USERNAME=root +MYSQL_PASSWORD=randomstringhere + +# More MySQL vars +MYSQL_CONNECTION_POOL=32 NEW_RELIC_APP_NAME=ENSL NEW_RELIC_LICENSE_KEY= diff --git a/.gitignore b/.gitignore index c9d3f82..30f40f0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ /log/* /tmp/* /spec/tmp/* +/env/production.sh +/env/development.sh .ruby-version .ruby-gemset .env @@ -12,6 +14,10 @@ *.rbc *.sassc +# Database and files +db_data/* +!db_data/.placeholder + # OS X .DS_Store @@ -20,6 +26,7 @@ /public/files/* /public/local /public/uploads +/public/assets # RubyMine /.idea diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..af6db94 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,36 @@ +FROM ruby:2.2 + +ENV RAILS_ENV production + +# Add 'web' user which will run the application +RUN adduser web --home /home/web --shell /bin/bash --disabled-password --gecos "" + +RUN apt-get update && apt-get -y upgrade +RUN apt-get -y install mysql-client libmysqlclient-dev memcached nodejs +RUN service memcached start + +# Separate Gemfile ADD so that `bundle install` can be cached more effectively + +ADD Gemfile /var/www/ +ADD Gemfile.lock /var/www/ +RUN chown -R web:web /var/www &&\ + mkdir -p /var/bundle &&\ + chown -R web:web /var/bundle + +RUN su -c "bundle config github.https true; cd /var/www && bundle install --path /var/bundle --jobs 4" -s /bin/bash -l web + +# Add application source +ADD . /var/www +RUN chown -R web:web /var/www + +WORKDIR /var/www +USER web + +RUN bundle config github.https true; cd /var/www && bundle install --path /var/bundle --jobs 4 +RUN bundle exec rake assets:precompile + +# This is a temporary solution to fix assets issue +RUN mv /var/www/public/assets /home/web/assets + +USER root +CMD ["/var/www/script/entry.sh"] diff --git a/Gemfile b/Gemfile index 978b2d0..0ce571a 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,7 @@ source 'http://rubygems.org' -ruby '2.2.2' +ruby '2.2.10' +#ruby '2.2.2' gem 'dotenv-rails', '~> 0.10.0' gem 'rails', '~> 3.2.22' @@ -8,6 +9,7 @@ gem 'mysql2', '~> 0.3.17' gem 'dalli', '~> 2.7.0' gem 'puma', '~> 2.11.1' +gem 'i18n-js' gem 'exceptional', '~> 2.0.33' gem 'oj', '~> 2.5.5' gem 'faraday', '~> 0.9.0' @@ -27,7 +29,7 @@ gem 'test-unit', '~> 3.1.3' gem 'google-api-client', '~> 0.10.3' # Please install nodejs locally. -gem 'therubyracer', '~> 0.12.1' if RUBY_PLATFORM == 'x86_64-linux' +#gem 'therubyracer', '~> 0.12.1' if RUBY_PLATFORM == 'x86_64-linux' gem 'sprockets', '~> 2.2.1' gem 'coffee-rails', '~> 3.2.2' diff --git a/Gemfile.lock b/Gemfile.lock index afaa8a6..a9743e7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -155,6 +155,8 @@ GEM hurley (0.2) i18n (0.9.1) concurrent-ruby (~> 1.0) + i18n-js (3.0.11) + i18n (>= 0.6.6, < 2) i18n_data (0.8.0) journey (1.0.4) jquery-rails (2.0.3) @@ -162,7 +164,6 @@ GEM thor (~> 0.14) json (1.8.6) jwt (1.5.6) - libv8 (3.16.14.19) little-plugger (1.1.4) logging (2.2.2) little-plugger (~> 1.1) @@ -236,7 +237,6 @@ GEM rake (10.5.0) rdoc (3.12.2) json (~> 1.4) - ref (2.0.0) representable (3.0.4) declarative (< 0.1.0) declarative-option (< 0.2.0) @@ -295,9 +295,6 @@ GEM net-ssh (>= 2.8.0) test-unit (3.1.9) power_assert - therubyracer (0.12.3) - libv8 (~> 3.16.14.15) - ref thor (0.20.0) tilt (1.4.1) timecop (0.7.4) @@ -350,6 +347,7 @@ DEPENDENCIES font-awesome-sass (~> 4.1.0.0) google-api-client (~> 0.10.3) haml (~> 4.0.5) + i18n-js jquery-rails (~> 2.0.2) mysql2 (~> 0.3.17) neat (~> 1.6.0) @@ -372,14 +370,13 @@ DEPENDENCIES sprockets (~> 2.2.1) steam-condenser! test-unit (~> 3.1.3) - therubyracer (~> 0.12.1) timecop (~> 0.7.1) tinymce-rails (~> 3.5.9) uglifier (~> 2.5.0) will_paginate (~> 3.0.5) RUBY VERSION - ruby 2.2.2p95 + ruby 2.2.10p489 BUNDLED WITH - 1.15.1 + 1.16.5 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a9fc489 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +REGISTRY ?= ensl +PROJECT ?= ensl.org +TAG ?= latest + +ifdef REGISTRY + IMAGE=$(REGISTRY)/$(PROJECT):$(TAG) +else + IMAGE=$(PROJECT):$(TAG) +endif + +all: + @echo "Available targets:" + @echo " * build - build a Docker image for $(IMAGE)" + @echo " * pull - pull $(IMAGE)" + @echo " * push - push $(IMAGE)" + @echo " * test - build and test $(IMAGE)" + +build: Dockerfile + docker build -t $(IMAGE) . + +pull: + docker pull $(IMAGE) || true + +push: + docker push $(IMAGE) + +test: build + fig run web ./env/test.sh ./test.sh + diff --git a/app/controllers/custom_urls_controller.rb b/app/controllers/custom_urls_controller.rb index 8105b41..1611999 100644 --- a/app/controllers/custom_urls_controller.rb +++ b/app/controllers/custom_urls_controller.rb @@ -22,6 +22,7 @@ class CustomUrlsController < ApplicationController def show custom_url = CustomUrl.find_by_name(params[:name]) + raise ActiveRecord::RecordNotFound unless custom_url @article = custom_url.article raise AccessError unless @article.can_show? cuser @article.read_by! cuser if cuser @@ -35,10 +36,13 @@ class CustomUrlsController < ApplicationController url = CustomUrl.find(params[:id]) rescue nil if url - if url.update_attributes(params[:custom_url]) + url.article_id = params[:custom_url][:article_id] + url.name= params[:custom_url][:name] + if url.save response[:status] = 200 response[:message] = 'Successfully updated!' - response[:obj] = url + resobj = {name: url.name, title: url.article.title} + response[:obj] = resobj else response[:status] = 400 message = 'Update failed! Errors:' diff --git a/app/controllers/shoutmsgs_controller.rb b/app/controllers/shoutmsgs_controller.rb index 041116c..6647daf 100644 --- a/app/controllers/shoutmsgs_controller.rb +++ b/app/controllers/shoutmsgs_controller.rb @@ -1,10 +1,6 @@ class ShoutmsgsController < ApplicationController respond_to :html, :js - def index - @shoutmsgs = Shoutmsg.lastXXX.typebox - end - def show if params[:id2] @shoutmsgs = Shoutmsg.recent.of_object(params[:id], params[:id2]).reverse diff --git a/app/models/group.rb b/app/models/group.rb index f7d61ec..ca22b60 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -22,7 +22,6 @@ class Group < ActiveRecord::Base PREDICTORS = 8 STAFF = 10 GATHER_MODERATORS = 14 - COMP_MOD_COUNCIL = 16 attr_protected :id, :updated_at, :created_at, :founder_id validates_length_of :name, :maximum => 20 @@ -50,7 +49,8 @@ class Group < ActiveRecord::Base def self.staff staff = [] - (find(ADMINS).groupers + find(PREDICTORS).groupers + find(CASTERS).groupers + find(STAFF).groupers + find(REFEREES).groupers).each do |g| + + (admins + casters + referees + extras).each do |g| staff << g unless staff.include? g end staff @@ -58,7 +58,10 @@ class Group < ActiveRecord::Base def self.admins admins = [] - (find(ADMINS).groupers).each do |g| + admin_group = where(id: ADMINS).first + return admins unless admin_group + + (admin_group.groupers).each do |g| admins << g unless admins.include? g end admins @@ -66,7 +69,10 @@ class Group < ActiveRecord::Base def self.referees referees = [] - (find(REFEREES).groupers).each do |g| + referee_group = where(id: REFEREES).first + return referees unless referee_group + + (referee_group.groupers).each do |g| referees << g unless referees.include? g end referees @@ -74,7 +80,13 @@ class Group < ActiveRecord::Base def self.extras extras = [] - (find(PREDICTORS).groupers + find(STAFF).groupers).each do |g| + extra_group = where(id: PREDICTORS).first + staff_group = where(id: STAFF).first + + extra_groupers = extra_group ? extra_group.groupers : [] + staff_groupers = staff_group ? staff_group.groupers : [] + + (extra_groupers + staff_groupers).each do |g| extras << g unless extras.include? g end extras @@ -82,7 +94,10 @@ class Group < ActiveRecord::Base def self.casters casters = [] - (find(CASTERS).groupers).each do |g| + caster_group = where(id:CASTERS).first + return casters unless caster_group + + (caster_group.groupers).each do |g| casters << g unless casters.include? g end casters @@ -90,17 +105,12 @@ class Group < ActiveRecord::Base def self.gathermods gathermods = [] - (find(GATHER_MODERATORS).groupers).each do |g| + gathermod_group = where(id:GATHER_MODERATORS).first + return gathermods unless gathermod_group + + (gathermod_group.groupers).each do |g| gathermods << g unless gathermods.include? g end gathermods end - - def self.compmodcouncil - compmodcouncil = [] - (find(COMP_MOD_COUNCIL).groupers).each do |g| - compmodcouncil << g unless compmodcouncil.include? g - end - compmodcouncil - end end diff --git a/app/views/about/staff.html.erb b/app/views/about/staff.html.erb index 19be4d6..c8c23b5 100644 --- a/app/views/about/staff.html.erb +++ b/app/views/about/staff.html.erb @@ -19,7 +19,6 @@
  • Referees
  • Casters
  • Gather Mods
  • -
  • Comp. Mod Council
  • Extras
  • Support
  • @@ -148,37 +147,6 @@ <% end %> -
    -

    COMP. MOD COUNCIL

    - - - - - - - - - <% Group.compmodcouncil.each do |grouper| %> - - - - <% if grouper.user.public_email %> - - <% else %> - - <% end %> - - - - <% end %> -
    UsernameEmailTaskAge
    <%= flag grouper.user.country %><%= namelink grouper.user %><%= h grouper.user.email_s %> - <% if grouper.task %> - <%= h grouper.task %> - <% else %> - <%= h grouper.group.name.singularize %> - <% end %> - <%= h grouper.user.age %>
    -

    Extras

    diff --git a/app/views/custom_urls/_controls.js.erb b/app/views/custom_urls/_controls.js.erb index be3769e..7b437d2 100644 --- a/app/views/custom_urls/_controls.js.erb +++ b/app/views/custom_urls/_controls.js.erb @@ -1,34 +1,34 @@ showEdit = function (url_id) { - var parent = $('#' + url_id); - parent.find('> td').toggleClass('hidden'); + var parent = $('#' + url_id); + parent.find('> td').toggleClass('hidden'); }; submitEdit = function (url_id) { - var parent = $('#' + url_id); - var form = parent.find('form'); + var parent = $('#' + url_id); + var form = parent.find('form'); - $.post('<%= custom_urls_url %>/' + url_id, form.serialize()) - .done(function (data) { - var nameField = parent.children('.name'); - var articleField = parent.children('.article'); + $.post('<%= custom_urls_path %>/' + url_id, form.serialize()) + .done(function (data) { + var nameField = parent.children('.name'); + var articleField = parent.children('.article'); - nameField.text(data.obj.name); - articleField.text(data.obj.title); - parent.find('> td').toggleClass('hidden'); + nameField.text(data.obj.name); + articleField.text(data.obj.title); + parent.find('> td').toggleClass('hidden'); - alert(data.message); - }).fail(function (errorRes) { - var error = JSON.parse(errorRes.responseText); - alert(error.message); - }); + alert(data.message); + }).fail(function (errorRes) { + var error = JSON.parse(errorRes.responseText); + alert(error.message); + }); } deleteUrl = function (url_id) { var confirmed = confirm('Are you sure you want to delete this item?'); - if(confirmed) { + if (confirmed) { $.ajax({ - url: '<%= custom_urls_url %>/' + url_id, + url: '<%= custom_urls_path %>/' + url_id, type: 'DELETE' }).done(function (data) { var trID = '#' + url_id; diff --git a/app/views/issues/new.html.erb b/app/views/issues/new.html.erb index 8b685eb..1f79cb4 100644 --- a/app/views/issues/new.html.erb +++ b/app/views/issues/new.html.erb @@ -1,6 +1,6 @@

    <%= cuser ? "New Issue" : "Contact" %>

    In case the contact form does not work write us on Steam (add the people from <%= link_to 'here', about_staff_path %>)

    -

    You can also reach us on our <%= link_to 'Official NSL Discord', 'https://discord.gg/tHte2pS', target: '_blank' %> or on the <%= link_to 'forums', forums_path %>

    +

    You can also reach us on our <%= link_to 'Official NSL Discord', 'https://discord.gg/aVdDwVC', target: '_blank' %> or on the <%= link_to 'forums', forums_path %>

    Please do not forget to include contact details, such as an email address or a Steam account in the case that you do not have an ENSL account.

    diff --git a/app/views/shoutmsgs/index.html.erb b/app/views/shoutmsgs/index.html.erb deleted file mode 100644 index 9299454..0000000 --- a/app/views/shoutmsgs/index.html.erb +++ /dev/null @@ -1,20 +0,0 @@ -

    Last 500 Shoutbox Messages

    - -
    - - - - - - - - <% @shoutmsgs.each do |shoutmsg| %> - - - - - - - <% end %> -
    DateTimeUserText
    <%= shoutmsg.created_at.strftime("%Y/%m/%d") %><%= shoutmsg.created_at.strftime("%H:%M") %><%= link_to shoutmsg.user, shoutmsg.user %><%= shoutmsg.text %>
    - diff --git a/app/views/widgets/_shoutbox.html.erb b/app/views/widgets/_shoutbox.html.erb index a962752..60582e4 100644 --- a/app/views/widgets/_shoutbox.html.erb +++ b/app/views/widgets/_shoutbox.html.erb @@ -6,7 +6,6 @@
    <%= render partial: "shoutmsgs/new", locals: { shoutmsg: Shoutmsg.new } %> - <%= link_to "Shoutbox Recent History", controller: :shoutmsgs, action: "index" %>
    <%= link_to "Shoutbox Rules", article_path(Article::SB_RULES) %> diff --git a/config/application.rb b/config/application.rb index aaa2b35..1ce42b6 100644 --- a/config/application.rb +++ b/config/application.rb @@ -10,6 +10,7 @@ module Ensl # Additional assets config.assets.precompile += ["themes/*/theme.css", "themes/*/errors.css"] + config.assets.initialize_on_precompile = false # Custom directories with classes and modules you want to be autoloadable. config.autoload_paths += Dir["#{config.root}/app/services/**/", "#{config.root}/app/models/concerns/"] diff --git a/config/database.yml b/config/database.yml index b91e757..bb0011b 100644 --- a/config/database.yml +++ b/config/database.yml @@ -1,7 +1,7 @@ base: &db adapter: mysql2 encoding: utf8 - host: localhost + host: <%= ENV['MYSQL_HOST'] %> database: <%= ENV['MYSQL_DATABASE'] %> username: <%= ENV['MYSQL_USERNAME'] %> password: <%= ENV['MYSQL_PASSWORD'] %> diff --git a/config/environments/production.rb b/config/environments/production.rb index 6cdc6d3..692d211 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -37,7 +37,7 @@ Ensl::Application.configure do # config.logger = SyslogLogger.new # Use a different cache store in production - config.cache_store = :dalli_store + config.cache_store = :dalli_store, 'memcached:11211', 'localhost' # Enable serving of images, stylesheets, and JavaScripts from an asset server # config.action_controller.asset_host = "http://assets.example.com" @@ -64,4 +64,7 @@ Ensl::Application.configure do # Custom Session Store config to allow gathers.staging.ensl.org config.session_store :cookie_store, key: "_ENSL_session_key", expire_after: 30.days.to_i, domain: ".ensl.org" -end \ No newline at end of file + +# config.cache_store = :dalli_store, 'cache', 'cache-2.example.com:11211:2', +# { :namespace => NAME_OF_RAILS_APP, :expires_in => 1.day, :compress => true } +end diff --git a/config/initializers/abstract_mysql2_adapter.rb b/config/initializers/abstract_mysql2_adapter.rb new file mode 100644 index 0000000..12ecd46 --- /dev/null +++ b/config/initializers/abstract_mysql2_adapter.rb @@ -0,0 +1,3 @@ +class ActiveRecord::ConnectionAdapters::Mysql2Adapter + NATIVE_DATABASE_TYPES[:primary_key] = "int(11) auto_increment PRIMARY KEY" +end diff --git a/config/puma.rb b/config/puma.rb index d5b690d..ca304e2 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -2,24 +2,24 @@ require "dotenv" Dotenv.load base_path = (ENV['DEPLOY_PATH'] || Dir.pwd) -current_path = "#{base_path}/current" -shared_path = "#{base_path}/shared" -stderr_path = "#{shared_path}/log/puma.stderr.log" -stdout_path = "#{shared_path}/log/puma.stdout.log" +#current_path = "#{base_path}/current" +#shared_path = "#{base_path}/shared" +stderr_path = "#{base_path}/lpuma.stderr.log" +stdout_path = "#{base_path}/lpuma.stdout.log" tag 'ENSL' preload_app! -daemonize true -directory current_path -pidfile "#{shared_path}/tmp/pids/puma.pid" -state_path "#{shared_path}/tmp/pids/puma.state" +daemonize false +directory base_path +pidfile "#{base_path}/tmp/puma.pid" +state_path "#{base_path}/tmp/puma.state" stdout_redirect stdout_path, stderr_path environment ENV['RACK_ENV'] || 'production' rackup DefaultRackup -bind "unix://#{shared_path}/tmp/sockets/puma.sock" +bind "unix://#{base_path}/tmp/puma.sock" port Integer(ENV['PUMA_PORT'] || 4000) worker_timeout Integer(ENV['PUMA_TIMEOUT'] || 30) diff --git a/config/routes.rb b/config/routes.rb index c783a93..0a21852 100755 --- a/config/routes.rb +++ b/config/routes.rb @@ -35,7 +35,7 @@ Ensl::Application.routes.draw do match "comments/quote" resources :comments - resources :shoutmsgs + resources :shoutmsgs, except: :index resources :teamers resources :teams resources :gathers diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b78ad50 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,29 @@ +version: "3" + +services: + web: + image: ensl/ensl.org:latest + volumes: + - "./public:/var/www/public" + ports: + - "4000:4000" + depends_on: + - db + - memcached + # - redis + db: + image: mariadb:latest + volumes: + - "./db_data:/var/lib/mysql" + - "./ext/mysql.conf.d:/etc/mysql/conf.d" + environment: + - MYSQL_DATABASE + - MYSQL_USER + - MYSQL_USERNAME + - MYSQL_PASSWORD + - MYSQL_ROOT_PASSWORD +# - MYSQL_ROOT_HOST + memcached: + image: memcached:latest + #redis: + # image: redis diff --git a/env/test.sh b/env/test.sh new file mode 100755 index 0000000..897d48f --- /dev/null +++ b/env/test.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +export RACK_ENV=test +export RAILS_ENV=test +export APP_SECRET=e0cdcb729c4b21d5259e957a2ffc13a3 + +export DEPLOY_PATH=/var/www + +export PUMA_WORKERS=1 +export PUMA_MIN_THREADS=1 +export PUMA_MAX_THREADS=16 +export PUMA_PORT=3000 +export PUMA_TIMEOUT=30 + +#export MYSQL_HOST="${MYSQL_PORT_3306_TCP_ADDR:-localhost}" +export MYSQL_DATABASE=ensl +export MYSQL_USER=root +export MYSQL_HOST="mysql" +export MYSQL_USERNAME=root +export MYSQL_ROOT_PASSWORD=test +export MYSQL_PASSWORD=test +export MYSQL_ROOT_HOST=172.% +export MYSQL_CONNECTION_POOL=32 + +exec "$@" diff --git a/ext/mysql.conf.d/opt.cnf b/ext/mysql.conf.d/opt.cnf new file mode 100644 index 0000000..a9545ea --- /dev/null +++ b/ext/mysql.conf.d/opt.cnf @@ -0,0 +1,31 @@ +[mysqld] + +skip-host-cache +skip-name-resolve + +key_buffer = 150M +max_allowed_packet = 20M +thread_stack = 196K +thread_cache_size = 16 + +max_connections = 96 +table_cache = 2000 +table_definition_cache = 800 +thread_concurrency = 128 + +query_cache_limit = 30M +query_cache_size = 150M +open_files_limit = 1800 +join_buffer_size = 1M +sort_buffer_size = 1M +read_buffer_size = 128K +tmp_table_size = 500M +max_heap_table_size = 500M + +innodb_buffer_pool_size = 1280M +innodb_flush_log_at_trx_commit = 1 +innodb_thread_concurrency = 16 +innodb_flush_method = O_DIRECT +#innodb_additional_mem_pool_size = 20M +innodb_file_per_table = 1 +transaction-isolation = READ-COMMITTED diff --git a/script/entry.sh b/script/entry.sh new file mode 100755 index 0000000..06580cd --- /dev/null +++ b/script/entry.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +env +cd /var/www +source /var/www/.env +rm -rf /var/www/public/assets +mv /home/web/assets /var/www/public/ +chown -R web:web /var/www/public + +#bundle exec rake assets:precompile +su -c "cd /var/www && bundle exec puma -C config/puma.rb" -s /bin/bash -l web diff --git a/script/test.sh b/script/test.sh new file mode 100755 index 0000000..e8fe1ed --- /dev/null +++ b/script/test.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +# Undo the `bundle --deployment --without development test` +# settings baked into the prod-ready Docker image's .bundle/config +bundle config --delete without +bundle config --delete frozen + +# Install gems in development and test groups +bundle + +# Ensure database exists and has latest migrations +bundle exec rake db:create +bundle exec rake db:migrate + +# Run tests +bundle exec rake