diff --git a/Gemfile b/Gemfile index 9786479c..57bc91d0 100644 --- a/Gemfile +++ b/Gemfile @@ -26,6 +26,8 @@ gem 'google-analytics-rails' gem 'validates' gem 'virtus' gem 'js-routes' +gem 'backup' +gem 'whenever' # Gems used only for assets and not required # in production environments by default. diff --git a/Gemfile.lock b/Gemfile.lock index e0a82ee8..aab57aee 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -34,6 +34,9 @@ GEM ansi (1.4.3) arel (3.0.2) backports (2.6.7) + backup (3.0.27) + open4 (~> 1.3.0) + thor (>= 0.15.4, < 2) bcrypt-ruby (3.0.1) builder (3.0.4) capistrano (2.14.1) @@ -49,6 +52,7 @@ GEM carrierwave (0.6.2) activemodel (>= 3.2.0) activesupport (>= 3.2.0) + chronic (0.8.0) ci_reporter (1.8.3) builder (>= 2.1.2) ckeditor (3.7.3) @@ -130,6 +134,7 @@ GEM net-ssh (2.6.3) net-ssh-gateway (1.1.0) net-ssh (>= 1.99.1) + open4 (1.3.0) orm_adapter (0.4.0) pg (0.14.1) polyglot (0.3.3) @@ -228,6 +233,9 @@ GEM virtus (0.5.4) backports (~> 2.6.1) descendants_tracker (~> 0.0.1) + whenever (0.8.0) + activesupport (>= 2.3.4) + chronic (>= 0.6.3) ya_acl (0.0.7) rake @@ -236,6 +244,7 @@ PLATFORMS DEPENDENCIES airbrake + backup bcrypt-ruby (~> 3.0.0) capistrano capistrano-ext @@ -277,4 +286,5 @@ DEPENDENCIES usefull_scopes validates virtus + whenever ya_acl diff --git a/app/controllers/web/sessions_controller.rb b/app/controllers/web/sessions_controller.rb index 3d628bce..62ec7c23 100644 --- a/app/controllers/web/sessions_controller.rb +++ b/app/controllers/web/sessions_controller.rb @@ -2,21 +2,19 @@ class Web::SessionsController < Web::ApplicationController def new - @user = UserEditType.new + @type = UserSignInType.new end def create - user = UserEditType.find_by_email(params[:user][:email]) + @type = UserSignInType.new(params[:user_sign_in_type]) - if user.try(:authenticate, params[:user][:password]) + if @type.valid? + user = @type.user flash_success - sign_in(user) redirect_to root_path else - flash_error - - render action: 'new' + render :new end end diff --git a/app/controllers/web/users_controller.rb b/app/controllers/web/users_controller.rb index e37aafbc..770781c9 100644 --- a/app/controllers/web/users_controller.rb +++ b/app/controllers/web/users_controller.rb @@ -1,21 +1,34 @@ class Web::UsersController < Web::ApplicationController def index - @users = User.shown_as_participants.alphabetically + @users = User.activated.shown_as_participants.alphabetically end def new - @user = UserEditType.new + @user = UserRegistrationType.new + end + + def activate + token = User::AuthToken.find_by_authentication_token!(params[:auth_token]) + user = token.user + if token && user + user.activate! + flash_success + else + flash_error + end + redirect_to root_path end def create - @user = UserEditType.new(params[:user]) + @user = UserRegistrationType.new(params[:user]) if @user.save - UserMailer.welcome(@user).deliver - sign_in @user + token = @user.create_auth_token + UserMailer.confirm_registration(@user, token).deliver + #sign_in @user flash_success - redirect_to root_path + redirect_to new_session_path else flash_error render action: "new" diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index 6b24a431..f1379509 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -2,8 +2,9 @@ class UserMailer < ActionMailer::Base default_url_options[:host] = configus.mailer.default_host default from: configus.mailer.default_from - def welcome(user) + def confirm_registration(user, token) @user = user + @token = token mail :to => @user.email end diff --git a/app/models/user.rb b/app/models/user.rb index e8406329..b4d8b9d6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -9,27 +9,27 @@ class User < ActiveRecord::Base :show_as_participant, :photo, :state_event, :about validates :email, presence: true, uniqueness: true, email: true - validates :city, presence: true - validates :first_name, length: {maximum: 20} - validates :last_name, length: {maximum: 20} - validates :city, length: {maximum: 20} - validates :company, length: {maximum: 20} - validates :position, length: {maximum: 20} + validates :first_name, length: { maximum: 255 } + validates :last_name, length: { maximum: 255 } + validates :city, length: { maximum: 255 } + validates :company, length: { maximum: 255 } + validates :position, length: { maximum: 255 } mount_uploader :photo, UsersPhotoUploader has_many :auth_tokens - state_machine :state, initial: :active do + state_machine :state, initial: :new do + state :new state :active state :inactive event :activate do - transition any - :active => :active + transition [:inactive, :new] => :active end event :deactivate do - transition :active => :inactive + transition [:active, :new] => :inactive end end diff --git a/app/repositories/user_repository.rb b/app/repositories/user_repository.rb index 4fe1b7b4..ffca98fb 100644 --- a/app/repositories/user_repository.rb +++ b/app/repositories/user_repository.rb @@ -10,6 +10,8 @@ module UserRepository where show_as_participant: true } + scope :activated, -> { where state: :active } + scope :alphabetically, -> { order("last_name ASC") } def self.companies_by_term(company = nil) diff --git a/app/types/account_edit_type.rb b/app/types/account_edit_type.rb index eecd4667..14eb376b 100644 --- a/app/types/account_edit_type.rb +++ b/app/types/account_edit_type.rb @@ -5,5 +5,6 @@ class AccountEditType < User validates :first_name, presence: true validates :last_name, presence: true + validates :city, presence: true end \ No newline at end of file diff --git a/app/types/admin/user_edit_type.rb b/app/types/admin/user_edit_type.rb index 980dc930..0b58799a 100644 --- a/app/types/admin/user_edit_type.rb +++ b/app/types/admin/user_edit_type.rb @@ -1,9 +1,10 @@ class Admin::UserEditType < User include BasicType - attr_accessible :password_confirmation, :state_event + attr_accessible :password_confirmation, :state_event, :admin validates :first_name, presence: true validates :last_name, presence: true + validates :city, presence: true end \ No newline at end of file diff --git a/app/types/user_edit_type.rb b/app/types/user_registration_type.rb similarity index 76% rename from app/types/user_edit_type.rb rename to app/types/user_registration_type.rb index 38929e83..bb20653b 100644 --- a/app/types/user_edit_type.rb +++ b/app/types/user_registration_type.rb @@ -1,4 +1,4 @@ -class UserEditType < User +class UserRegistrationType < User include BasicType attr_accessible :password_confirmation, :state_event @@ -7,5 +7,7 @@ class UserEditType < User validates :first_name, presence: true validates :last_name, presence: true + validates :city, presence: true validates :password, presence: true, confirmation: true + end \ No newline at end of file diff --git a/app/types/user_sign_in_type.rb b/app/types/user_sign_in_type.rb new file mode 100644 index 00000000..67207a43 --- /dev/null +++ b/app/types/user_sign_in_type.rb @@ -0,0 +1,34 @@ +class UserSignInType + include ActiveModel::Validations + include ActiveModel::Conversion + include Virtus + + attribute :email, String + attribute :password, String + + validates :email, presence: true, email: true + validates :password, presence: true + + validates_each :email do |record, attr, value| + user = record.user + if user.try :new? + record.errors.add(attr, :user_new) + end + + if user.try :inactive? + record.errors.add(attr, :user_inactive) + end + + if !user.try(:authenticate, record.password) + record.errors.add(attr, :user_or_password_invalid) + end + end + + def persisted? + false + end + + def user + @user ||= User.find_by_email(email) + end +end \ No newline at end of file diff --git a/app/views/layouts/web/application.html.haml b/app/views/layouts/web/application.html.haml index 44b68386..8ebbff2b 100644 --- a/app/views/layouts/web/application.html.haml +++ b/app/views/layouts/web/application.html.haml @@ -7,7 +7,8 @@ %link{:href => "/favicon.ico", :rel => "icon", :type => "image/x-icon"}/ %link{:href => "/favicon.ico", :rel => "shortcut icon", :type => "image/x-icon"}/ %meta{:content => "http://nastachku.ru/assets/fb_logo.png", :property => "og:image"} - %title= content_for?(:title) ? yield(:title) : "Nastachku" + %meta{:content => "Digital-коммуникации, Программирование, IT-стартапы, Электронная коммерция, Менеджмент в IT, IT на службе общества", :property => "og:description"} + %title= content_for?(:title) ? yield(:title) : "Стачка! Конференция" = analytics_init if Rails.env.production? = csrf_meta_tags = stylesheet_link_tag "application", :media => "all" @@ -23,5 +24,5 @@ %br/ - = render "layouts/web/shared/reformal" + = render "layouts/web/shared/counters" = render "layouts/web/shared/footer" \ No newline at end of file diff --git a/app/views/layouts/web/shared/_reformal.html.haml b/app/views/layouts/web/shared/_counters.html.haml similarity index 52% rename from app/views/layouts/web/shared/_reformal.html.haml rename to app/views/layouts/web/shared/_counters.html.haml index dc69506d..56754bb5 100644 --- a/app/views/layouts/web/shared/_reformal.html.haml +++ b/app/views/layouts/web/shared/_counters.html.haml @@ -17,21 +17,36 @@ document.getElementsByTagName('head')[0].appendChild(script); })(); -{} %noscript = link_to 'http://reformal.ru' do = image_tag 'http://media.reformal.ru/reformal.png' = link_to 'http://nastachku.reformal.ru' - :javascript - (function(w, c) { -    (w[c] = w[c] || []).push(function() { -        try { -            w.yaCounter12986590 = new Ya.Metrika({id:12986590, enableAll: true, webvisor:true}); -        } -        catch(e) { } -    }); - })(window, "yandex_metrika_callbacks"); + (function (d, w, c) { + (w[c] = w[c] || []).push(function() { + try { + w.yaCounter20139103 = new Ya.Metrika({ + id:20139103, + webvisor:true, + clickmap:true, + trackLinks:true, + accurateTrackBounce:true + }); + } catch(e) { } + }); + var n = d.getElementsByTagName("script")[0], + s = d.createElement("script"), + f = function () { + n.parentNode.insertBefore(s, n); + }; + s.type = "text/javascript"; + s.async = true; + s.src = (d.location.protocol == "https:" ? "https:" : "http:") + "//mc.yandex.ru/metrika/watch.js"; + if (w.opera == "[object Opera]") { + d.addEventListener("DOMContentLoaded", f, false); + } else { + f(); + } + })(document, window, "yandex_metrika_callbacks"); -%script(src="//mc.yandex.ru/metrika/watch.js" type="text/javascript" defer="defer") diff --git a/app/views/layouts/web/shared/_liveinternet.html.haml b/app/views/layouts/web/shared/_liveinternet.html.haml new file mode 100644 index 00000000..23267fbd --- /dev/null +++ b/app/views/layouts/web/shared/_liveinternet.html.haml @@ -0,0 +1,9 @@ +:javascript + document.write("<\/a>") \ No newline at end of file diff --git a/app/views/layouts/web/shared/_navigation.html.haml b/app/views/layouts/web/shared/_navigation.html.haml index 923e0b56..b658f9da 100644 --- a/app/views/layouts/web/shared/_navigation.html.haml +++ b/app/views/layouts/web/shared/_navigation.html.haml @@ -13,7 +13,7 @@ %li= link_to t(".i_will_go"), new_user_path %li= link_to t(".login"), new_session_path - %li= navbar_link t(".participants"), users_path, with: User.shown_as_participants.count + %li= navbar_link t(".participants"), users_path, with: User.activated.count %li= link_to t(".news"), news_index_path %li= link_to t(".routes"), page_path(:routes) %li= link_to t(".contacts"), page_path(:contacts) diff --git a/app/views/layouts/web/shared/_social.html.haml b/app/views/layouts/web/shared/_social.html.haml index 3ed01517..05863df5 100644 --- a/app/views/layouts/web/shared/_social.html.haml +++ b/app/views/layouts/web/shared/_social.html.haml @@ -9,6 +9,8 @@ %li %a{:href => "http://vk.com/nastachku", :target => "_blank"} %i.ficon-vkontakte-rect + %li=render 'layouts/web/shared/liveinternet' + %nav.social-share-links %ul %li.twitter diff --git a/app/views/user_mailer/confirm_registration.html.erb b/app/views/user_mailer/confirm_registration.html.erb new file mode 100644 index 00000000..caa4d73e --- /dev/null +++ b/app/views/user_mailer/confirm_registration.html.erb @@ -0,0 +1,6 @@ +

Добрый день, <%= @user.full_name %>.

+

Ваш почтовый ящик был указан при регистрации на сайте <%= link_to 'nastachku.ru', root_url %>.

+

Пожалуйста, ПОДТВЕРДИТЕ ВАШУ РЕГИСТРАЦИЮ, пройдя по +<%= link_to 'ссылке', activate_user_url(auth_token: @token.authentication_token) %> +

+

Не забудьте записать Ваш персональный номер для участия в конференции: <%= @user.id %>

\ No newline at end of file diff --git a/app/views/web/admin/users/edit.html.haml b/app/views/web/admin/users/edit.html.haml index fec4544e..4b283eba 100644 --- a/app/views/web/admin/users/edit.html.haml +++ b/app/views/web/admin/users/edit.html.haml @@ -13,6 +13,7 @@ = f.input :company = f.input :position = f.input :show_as_participant + = f.input :admin = f.input :email .span4 = f.input :photo, as: :image_preview diff --git a/app/views/web/admin/users/index.html.haml b/app/views/web/admin/users/index.html.haml index 7f1a48bb..9e459837 100644 --- a/app/views/web/admin/users/index.html.haml +++ b/app/views/web/admin/users/index.html.haml @@ -15,9 +15,9 @@ %td= link_to user.id, admin_user_path(user) %td= user.full_name %td= user.state - %td= user.created_at + %td= l user.created_at %td = link_to t('.edit'), edit_admin_user_path(user), :class => 'btn btn-mini' - = link_to t('.destroy'), admin_user_path(user), :method => :delete, :data => { :confirm => t('.confirm') }, :class => 'btn btn-mini btn-danger' + / = link_to t('.destroy'), admin_user_path(user), :method => :delete, :data => { :confirm => t('.confirm') }, :class => 'btn btn-mini btn-danger' = link_to t('.new_user'), new_admin_user_path, :class => 'btn btn-primary' \ No newline at end of file diff --git a/app/views/web/admin/users/show.html.haml b/app/views/web/admin/users/show.html.haml index 96fad109..15ffdbe6 100644 --- a/app/views/web/admin/users/show.html.haml +++ b/app/views/web/admin/users/show.html.haml @@ -37,4 +37,4 @@ .form-actions = link_to t('.back'), admin_users_path, :class => 'btn' = link_to t('.edit'), edit_admin_user_path(@user), :class => 'btn' - = link_to t('.destroy'), admin_user_path(@user), :method => "delete", :data => { :confirm => t('.confirm') }, :class => 'btn btn-danger' \ No newline at end of file + / = link_to t('.destroy'), admin_user_path(@user), :method => "delete", :data => { :confirm => t('.confirm') }, :class => 'btn btn-danger' \ No newline at end of file diff --git a/app/views/web/sessions/_form.html.haml b/app/views/web/sessions/_form.html.haml index 9a72f3f6..e310e320 100644 --- a/app/views/web/sessions/_form.html.haml +++ b/app/views/web/sessions/_form.html.haml @@ -4,7 +4,7 @@ .formy %h5= t '.login' .form - = simple_form_for :user, url: session_path, html: { class: 'form-type-login' } do |f| + = simple_form_for @type, url: session_path, html: { class: 'form-type-login' } do |f| = f.input :email, :tabindex => 1 = f.input :password, :tabindex => 2 diff --git a/config/backup.rb.sample b/config/backup.rb.sample new file mode 100644 index 00000000..d85a0fae --- /dev/null +++ b/config/backup.rb.sample @@ -0,0 +1,47 @@ +# encoding: utf-8 + +## +# Backup Generated: backup +# Once configured, you can run the backup with the following command: +# +# $ backup perform -t backup [-c ] +# +Backup::Model.new(:nastachku_staging, 'Nastachku staging backup') do + + database PostgreSQL do |db| + db.name = "nastachku_staging" + db.username = "nastachku_staging" + db.password = "password" + end + + store_with Local do |local| + local.path = "/var/tmp/" + local.keep = 5 + end + + compress_with Gzip do |compression| + compression.best = true + compression.fast = false + end + +end + +Backup::Model.new(:nastachku_production, 'Nastachku production backup') do + + database PostgreSQL do |db| + db.name = "nastachku_production" + db.username = "nastachku_production" + db.password = "password" + end + + store_with Local do |local| + local.path = "/var/tmp/" + local.keep = 18 + end + + compress_with Gzip do |compression| + compression.best = true + compression.fast = false + end + +end \ No newline at end of file diff --git a/config/deploy.rb b/config/deploy.rb index 22b028cd..0f4dcbce 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -19,6 +19,12 @@ task :symlink_db, :roles => :app do run "ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml" end + + desc "Symlinks the backup.rb" + task :symlink_backup, :roles => :app do + run "ln -nfs #{shared_path}/config/backup.rb #{release_path}/config/backup.rb" + end + desc "Seed database data" task :seed_data do run "cd #{current_path} && RAILS_ENV=#{rails_env} #{rake} db:seed" @@ -27,5 +33,6 @@ end before 'deploy:finalize_update', 'deploy:symlink_db' +after 'deploy:symlink_db', 'deploy:symlink_backup' after "deploy:update", "deploy:cleanup" after 'deploy:restart', 'unicorn:stop' \ No newline at end of file diff --git a/config/deploy/production.rb b/config/deploy/production.rb index f36fac43..dfd54828 100644 --- a/config/deploy/production.rb +++ b/config/deploy/production.rb @@ -8,4 +8,7 @@ role :web, '62.76.184.142' role :app, '62.76.184.142' -role :db, '62.76.184.142', :primary => true \ No newline at end of file +role :db, '62.76.184.142', :primary => true + +set :whenever_command, "bundle exec whenever" +require "whenever/capistrano" \ No newline at end of file diff --git a/config/environments/production.rb b/config/environments/production.rb index 794c3032..29d651e6 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -69,5 +69,5 @@ # config.active_record.auto_explain_threshold_in_seconds = 0.5 # google-analytics - GA.tracker = "UA-29741973-1" + GA.tracker = "UA-38587983-1" end diff --git a/config/locales/activemodel.yml b/config/locales/activemodel.yml index 8ca1e73d..3251e6ac 100644 --- a/config/locales/activemodel.yml +++ b/config/locales/activemodel.yml @@ -6,4 +6,11 @@ ru: attributes: email: email: 'Введите корректный email!' - user_should_not_exists: 'Пользователь с таким email не существует!' \ No newline at end of file + user_should_not_exists: 'Пользователь с таким email не существует!' + user_sign_in_type: + attributes: + email: + email: 'Введен некорректный email' + user_new: 'Пожалуйста, активируйте свой аккаунт, перейдя по ссылке из письма.' + user_inactive: "Ваш аккаунт заблокирован. Для возобновления работы аккаунта обратитесь в оргкомитет сайта info@nastachku.ru" + user_or_password_invalid: 'Email и/или пароль неверны' \ No newline at end of file diff --git a/config/locales/activerecord.yml b/config/locales/activerecord.yml index 9533518f..ec72c867 100644 --- a/config/locales/activerecord.yml +++ b/config/locales/activerecord.yml @@ -27,6 +27,7 @@ ru: state_event: "Изменить состояние" state: "Состояние" about: "О себе" + admin: "Администратор" errors: messages: @@ -48,5 +49,6 @@ ru: user: attributes: email: + email: 'Введен некорректный email' taken: 'Данный Email уже зарегистрирован' diff --git a/config/locales/flash.yml b/config/locales/flash.yml index 79fde1d5..8f34907a 100644 --- a/config/locales/flash.yml +++ b/config/locales/flash.yml @@ -4,8 +4,10 @@ ru: web: users: create: - success: 'Регистрация прошла успешно. На указанный электронный адрес отправлено письмо с персональным номером для участия в конференции.' + success: 'На указанный Email отправлено письмо со ссылкой на активацию аккаунта и персональным номером для участия в конференции.' error: 'Пожалуйста, заполните все обязательные поля.' + activate: + success: 'Ваш аккаунт успешно активирован!' account: passwords: diff --git a/config/locales/subject.yml b/config/locales/subject.yml index 258063e8..1c181484 100644 --- a/config/locales/subject.yml +++ b/config/locales/subject.yml @@ -1,6 +1,6 @@ ru: user_mailer: - welcome: - subject: "Персональный номер для участия в конференции Стачка" + confirm_registration: + subject: "Подтверждение регистрации" remind_password: subject: "Восстановление пароля" \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 3d379658..d60fda81 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,6 +14,10 @@ scope :module => :web do resources :users, only: [:new, :create, :index] + resource :user do + get :activate + end + resources :pages, only: [:show] resource :session, only: [:new, :create, :destroy] resources :news, only: [:index] diff --git a/config/schedule.rb b/config/schedule.rb new file mode 100644 index 00000000..a377dd95 --- /dev/null +++ b/config/schedule.rb @@ -0,0 +1,29 @@ +# Use this file to easily define all of your cron jobs. +# +# It's helpful, but not entirely necessary to understand cron before proceeding. +# http://en.wikipedia.org/wiki/Cron + +# Example: +# +# set :output, "/path/to/my/cron_log.log" +# +# every 2.hours do +# command "/usr/bin/some_great_command" +# runner "MyModel.some_method" +# rake "some:great:rake:task" +# end +# +# every 4.days do +# runner "AnotherModel.prune_old_records" +# end + +# Learn more: http://github.com/javan/whenever + +job_type :bundle_command, "cd :path && RAILS_ENV=#{environment} bundle exec :task" + +set :path, "/u/apps/nastachku/current" + +every 4.hours do + bundle_command "backup perform -t nastachku_#{environment} -c config/backup.rb --root_path ." + +end \ No newline at end of file diff --git a/lib/auth_helper.rb b/lib/auth_helper.rb index 9c5e297c..dce80ed9 100644 --- a/lib/auth_helper.rb +++ b/lib/auth_helper.rb @@ -9,7 +9,7 @@ def sign_out end def signed_in? - session[:user_id] && User.find_by_id(session[:user_id]) + current_user end def signed_as_admin? @@ -25,7 +25,7 @@ def authenticate_admin! end def current_user - @current_user ||= signed_in? + @current_user ||= User.find_by_id(session[:user_id]) end def basic_auth diff --git a/test/factories/user.rb b/test/factories/user.rb index 972a96dc..1d333a04 100644 --- a/test/factories/user.rb +++ b/test/factories/user.rb @@ -1,6 +1,6 @@ FactoryGirl.define do - factory :user, :class => UserEditType do + factory :user do password "sekret" first_name last_name diff --git a/test/functional/web/sessions_controller_test.rb b/test/functional/web/sessions_controller_test.rb index 0a0e9e75..c3eb4c72 100644 --- a/test/functional/web/sessions_controller_test.rb +++ b/test/functional/web/sessions_controller_test.rb @@ -9,8 +9,7 @@ class Web::SessionsControllerTest < ActionController::TestCase test "should authenticate" do attrs = { email: @user.email, password: @user.password } - post :create, user: attrs - + post :create, user_sign_in_type: attrs assert_response :redirect assert signed_in? end