Browse Source

Workshop auth fixes and better error reporting

development
Godwin 7 years ago
parent
commit
e8ca73a801
  1. 4
      Gemfile
  2. 6
      Rakefile
  3. 6
      app/assets/javascripts/main.js
  4. 28
      app/assets/stylesheets/_application.scss
  5. 15
      app/assets/stylesheets/_settings.scss
  6. 66
      app/assets/stylesheets/user-mailer.scss
  7. 226
      app/controllers/application_controller.rb
  8. 5
      app/controllers/conferences_controller.rb
  9. 74
      app/controllers/workshops_controller.rb
  10. 30
      app/helpers/admin_helper.rb
  11. 46
      app/helpers/form_helper.rb
  12. 36
      app/mailers/user_mailer.rb
  13. 90
      app/views/user_mailer/error_report.html.haml
  14. 3
      app/views/workshops/facilitate.html.haml
  15. 5
      app/views/workshops/facilitate_request_sent.html.haml
  16. 4
      app/views/workshops/show.html.haml
  17. 7
      config/locales/en.yml
  18. 1
      config/locales/fr.yml
  19. 32
      db/schema.rb
  20. 21
      features/workshops.feature

4
Gemfile

@ -30,8 +30,8 @@ gem 'launchy'
# bundle config local.lingua_franca ../lingua_franca
# bundle config local.marmara ../marmara
gem 'bikecollectives_core', git: 'https://github.com/bikebike/bikecollectives_core.git', branch: 'master'
gem 'bumbleberry', git: 'https://github.com/bumbleberry/bumbleberry.git', branch: '2017'
gem 'lingua_franca', git: 'https://github.com/lingua-franca/lingua_franca.git', branch: '2017'
gem 'bumbleberry', git: 'https://github.com/bumbleberry/bumbleberry.git', branch: 'master'
gem 'lingua_franca', git: 'https://github.com/lingua-franca/lingua_franca.git', branch: 'master'
gem 'marmara', git: 'https://github.com/lingua-franca/marmara.git', branch: 'master'
# Bike!Bike! specific stuff

6
Rakefile

@ -135,3 +135,9 @@ namespace :cucumber do
raise exception unless exception.nil?
end
end
namespace :clean do
task requests: :environment do
Request.delete_all(['created_at < ?', DateTime.now - 1.day])
end
end

6
app/assets/javascripts/main.js

@ -1,5 +1,5 @@
(function() {
window.onerror = function(message, url, lineNumber) {
window.onerror = function(message, url, lineNumber, column, errorObj) {
//save error and send to server for example.
var request = new XMLHttpRequest();
request.open('POST', '/js_error', true);
@ -7,7 +7,9 @@
request.send(
'message=' + encodeURI(message) +
'&url=' + encodeURI(url) +
'&lineNumber=' + encodeURI(lineNumber) +
'&line=' + encodeURI(lineNumber) +
'&col=' + encodeURI(column) +
(errorObj && errorObj.stack ? '&stack=' + encodeURI(errorObj.stack) : '') +
'&location=' + encodeURI(window.location.href)
);
return false;

28
app/assets/stylesheets/_application.scss

@ -803,26 +803,22 @@ ul.menu {
.message {
display: inline-block;
@include font-family(secondary);
font-size: 1.25em;
padding: 1em 2em;
border: 0.25rem solid $blue;
background-color: rgba($blue, 0.25);
background-color: $text-on-blue;
@include message;
}
&.error .message {
border-color: $red;
background-color: rgba($red, 0.25);
background-color: $text-on-red;
}
&.complete .message {
border-color: $green;
background-color: rgba($green, 0.25);
background-color: $text-on-green;
}
&.warning .message {
border-color: $yellow;
background-color: rgba($yellow, 0.25);
background-color: $text-on-yellow;
}
}
@ -1732,14 +1728,12 @@ ul.warnings {
.info-message {
position: relative;
min-height: 4em;
border: 0.2em solid rgba(0, 0, 0, 0.1);
background-color: rgba($colour-3, 0.333);
background-color: $text-on-yellow;
padding: 1em 1em 1em 4em;
@include font-family(secondary);
text-align: left;
margin: 1em;
width: auto;
@include default-box-shadow(top, 2);
@include message;
@include before {
content: '!';
@ -1754,7 +1748,7 @@ ul.warnings {
text-align: center;
line-height: 1.5em;
font-size: 1.5em;
background-color: $colour-3;
background-color: $yellow;
@include _(border-radius, 50%);
@include default-box-shadow(top, 2);
}
@ -1769,15 +1763,15 @@ ul.warnings {
}
.success-info {
background-color: rgba($colour-5, 0.333);
background-color: $text-on-green;
@include before {
background-color: $colour-5;
background-color: $green;
}
}
.error-info {
background-color: rgba($red, 0.333);
background-color: $text-on-red;
@include before {
background-color: $red;

15
app/assets/stylesheets/_settings.scss

@ -28,6 +28,13 @@ $yellow: $colour-3;
$orange: $colour-4;
$green: $colour-5;
$text-on-blue: rgba($blue, 0.333);
$text-on-pink: rgba($pink, 0.333);
$text-on-yellow: rgba($yellow, 0.333);
$text-on-orange: rgba($orange, 0.333);
$text-on-green: rgba($green, 0.333);
$text-on-red: rgba($red, 0.333);
$link-colour: darken($colour-1, 13%);
$selected-colour: rgba($blue, 0.5);
@ -105,7 +112,7 @@ $selected-colour: rgba($blue, 0.5);
}
@mixin text-stroke {
@include _(text-stroke, 1px rgba(0, 0, 0, 0.25));
@include _(text-stroke, 1px rgba($black, 0.25));
}
@mixin button {
@ -174,3 +181,9 @@ $selected-colour: rgba($blue, 0.5);
@mixin not-link-like {
text-decoration: none;
}
@mixin message {
@include font-family(secondary);
border: 0.2em solid rgba($black, 0.1);
@include default-box-shadow(top, 2);
}

66
app/assets/stylesheets/user-mailer.scss

@ -1,5 +1,7 @@
@import "settings";
$max-table-width: 512px;
body {
width: 100% !important;
-webkit-text-size-adjust: 100%;
@ -76,6 +78,10 @@ p {
p, blockquote {
margin: 1em;
line-height: 1.3333em;
&.signature {
margin: 0 0 1em;
}
}
blockquote {
@ -127,7 +133,7 @@ h1, h2, h3, h4, h5, h6 {
table {
border-collapse: collapse;
max-width: 512px;
max-width: $max-table-width;
min-width: 280px;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
@ -179,16 +185,34 @@ table#ecxbb_full_width {
}
code {
color: #C33;
font-size: 0.9em;
color: firebrick;
white-space: pre;
margin: 0 0 2em;
display: block;
max-width: $max-table-width;
overflow: auto;
box-sizing: border-box;
&.signature {
margin: 0 0 1em;
font-size: 1.5em;
color: navy;
text-align: left;
white-space: normal;
overflow: hidden;
}
&.backtrace {
padding: 1em;
border: 1px solid #CCC;
background-color: lemonchiffon;
}
}
pre {
font-size: 1.5em;
padding: 1em;
background-color: #333;
color: antiquewhite;
word-break: break-word;
word-break: break;
}
.diff, .ecxdiff {
@ -240,8 +264,8 @@ h3 {
padding: 10px 15px;
margin-left: 20px;
border-bottom: 3px solid darken($colour-5, 10%);
-webkit-box-shadow: 0 0.5em 1.5em -0.75em #000;
box-shadow: 0 0.5em 1.5em -0.75em #000;
-webkit-box-shadow: 0 0.5em 1.5em -0.75em $black;
box-shadow: 0 0.5em 1.5em -0.75em $black;
cursor: pointer !important;
}
@ -266,3 +290,29 @@ h3 {
}
}
}
.request-details {
width: 100%;
max-width: 800px;
overflow: auto;
th, td {
border: 1px solid #CCC;
font-size: 1em;
padding: 0.5em;
vertical-align: top;
font-family: monospace;
}
table tr {
background-color: aliceblue;
}
.spacer {
background-color: transparent;
td {
border: 0;
}
}
}

226
app/controllers/application_controller.rb

@ -1,35 +1,53 @@
class ApplicationController < BaseController
protect_from_forgery with: :exception, :except => [:do_confirm, :js_error, :admin_update]
before_filter :capture_page_info
before_filter :application_setup
after_filter :capture_page_info
helper_method :protect, :policies
# @@test_host
# @@test_location
def default_url_options
{ host: "#{request.protocol}#{request.host_with_port}", trailing_slash: true }
end
def capture_page_info
# capture request info in case an error occurs
# if request.method == "GET" && (params[:controller] != 'application' || params[:action] != 'contact')
# session[:last_request]
# request_info = {
# 'params' => params,
# 'request' => {
# 'remote_ip' => request.remote_ip,
# 'uuid' => request.uuid,
# 'original_url' => request.original_url,
# 'env' => Hash.new
# }
# }
# request.env.each do |key, value|
# request_info['request']['env'][key.to_s] = value.to_s
# end
# # session['request_info'] = request_info
# end
capture_response unless @user_type == :potential_bot || @user_type == :bot
end
def capture_response(response_code = nil)
Request.create(
request_id: request.uuid,
session_id: session.id,
application: :bikebike,
response: (response_code || response.code || 0).to_i,
data: {
user: logged_in? ? current_user.id : nil,
params: @original_params || params,
remote_ip: request.remote_ip,
request_method: request.method,
url: request.original_url,
user_agent: request.user_agent,
language: request.env['HTTP_ACCEPT_LANGUAGE'],
cookies: request.env['HTTP_COOKIE'],
requested_with: request.env['HTTP_X_REQUESTED_WITH']
})
@error_reports.each { |report| report_on(report) } if @error_reports
end
def report_on(report)
return if Rails.env.development? || Rails.env.test?
send_mail(:error_report, report.signature)
end
def application_setup
if request.user_agent =~ /Googlebot/
@user_type = :bot
elsif request.url =~ /^.*\.php(\?.*)?$/
@user_type = :potential_bot
else
@user_type = :normal
end
# get the current conferences and set them globally
status_hierarchy = {
@ -82,51 +100,6 @@ class ApplicationController < BaseController
@is_policy_page = true
end
def js_error
# send and email if this is production
report = "A JavaScript error has occurred on <code>#{params[:location]}</code>"
if params[:location] == params[:url]
report += " on line <code>#{params[:lineNumber]}</code>"
else
report += " in <code>#{params[:url]}:#{params[:lineNumber]}</code>"
end
begin
# log the error
logger.info "A JavaScript error has occurred on #{params[:location]}:#{params[:lineNumber]}: #{params[:message]}"
if Rails.env.preview? || Rails.env.production?
# don't worry about bots
unless request.user_agent =~ /Googlebot/
request_info = {
'remote_ip' => request.remote_ip,
'uuid' => request.uuid,
'original_url' => request.original_url,
'env' => Hash.new
}
request.env.each do |key, value|
request_info['env'][key.to_s] = value.to_s
end
send_mail(:error_report,
"A JavaScript error has occurred",
report,
params[:message],
nil,
request_info,
params,
current_user,
Time.now.strftime("%d/%m/%Y %H:%M")
)
end
end
rescue Exception => exception2
logger.info exception2.to_s
logger.info exception2.backtrace.join("\n")
end
render json: {}
end
def confirmation_sent(user)
template = 'login_confirmation_sent'
@page_title ||= 'page_titles.403.Please_Check_Email'
@ -150,6 +123,7 @@ class ApplicationController < BaseController
def locale_not_available!(locale = nil)
set_default_locale
@original_params = params.clone
params[:_original_action] = params[:action]
params[:action] = 'error-locale-not-available'
@page_title = 'page_titles.404.Locale_Not_Available'
@ -167,6 +141,28 @@ class ApplicationController < BaseController
render 'application/locale_not_available', status: 404
end
def on_error(report, exception = nil)
@error_reports ||= []
@error_reports << report
logger.info report.backtrace
raise exception if exception.present? && Rails.env.development?
end
def js_error
stack = params[:stack] || "#{params[:message]}\n\tat #{params[:url] || params[:location]}:#{params[:line]}:#{params[:col]}"
requests = Request.where(session_id: session.id).order("created_at DESC")
on_error(
Report.create(
request_id: requests.first.request_id,
signature: params[:message],
severity: :error,
source: :javascript,
backtrace: stack))
render json: {}
end
unless Rails.env.test?
rescue_from StandardError do |exception|
handle_exception exception
@ -177,37 +173,31 @@ class ApplicationController < BaseController
end
def handle_exception(exception)
# log the error
logger.info exception.to_s
logger.info exception.backtrace.join("\n")
# send and email if this is production
if Rails.env.preview? || Rails.env.production?
suppress(Exception) do
request_info = {
'remote_ip' => request.remote_ip,
'uuid' => request.uuid,
'original_url' => request.original_url,
'env' => Hash.new
}
request.env.each do |key, value|
request_info['env'][key.to_s] = value.to_s
end
send_mail(:error_report,
"An error has occurred in #{Rails.env}",
nil,
exception.to_s,
exception.backtrace.join("\n"),
request_info,
params,
current_user,
Time.now.strftime("%d/%m/%Y %H:%M")
)
end
end
# remove memory location from anonymous classes so tat we have a common signature
classMatcher = /#<(.*?):0x[0-9a-f]+>/
message = exception.message
message.gsub!(classMatcher, '\1') while message =~ classMatcher
stack = ([message] + exception.backtrace).join("\n ")
on_error(
Report.create(
request_id: request.uuid,
signature: message,
severity: :error,
source: :application,
backtrace: stack), exception)
end
# raise the error if we are in development so that we can debug it
raise exception if Rails.env.development?
def i18n_exception(str, exception, locale, key)
message = "#{exception.class.name}: #{exception.to_s}"
stack = "#{message}\n #{caller.join("\n ")}"
on_error(
Report.create(
request_id: request.uuid,
signature: message,
severity: :error,
source: :i18n,
backtrace: stack))
end
def protect(&block)
@ -291,6 +281,7 @@ class ApplicationController < BaseController
end
def error_404(args = {})
@original_params = params.clone
params[:_original_action] = params[:action]
params[:action] = 'error-404'
@page_title = 'page_titles.404.Page_Not_Found'
@ -308,6 +299,7 @@ class ApplicationController < BaseController
@template = template
@page_title ||= 'page_titles.403.Access_Denied'
@main_title ||= @page_title
@original_params = params.clone
params[:_original_action] = params[:action]
params[:action] = 'error-403'
@ -317,11 +309,13 @@ class ApplicationController < BaseController
def error_500(exception = nil)
@page_title = 'page_titles.500.An_Error_Occurred'
@main_title = 'error.500.title'
@original_params = params.clone
params[:_original_action] = params[:action]
params[:action] = 'error-500'
@exception = exception
super(exception)
capture_response(500)
end
def on_translation_change(object, data, locale, translator_id)
@ -353,39 +347,6 @@ class ApplicationController < BaseController
end
end
def i18n_exception(str, exception, locale, key)
# log it
logger.info "Missing translation found for: #{key}"
# send an email if this is production
if Rails.env.preview? || Rails.env.production?
begin
request_info = {
'remote_ip' => request.remote_ip,
'uuid' => request.uuid,
'original_url' => request.original_url,
'env' => Hash.new
}
request.env.each do |key, value|
request_info['env'][key.to_s] = value.to_s
end
send_mail(:error_report,
"A missing translation found in #{Rails.env}",
"<p>A translation for <code>#{key}</code> in <code>#{locale.to_s}</code> was found. The text that was rendered to the user was:</p><blockquote>#{str || 'nil'}</blockquote>",
exception.to_s,
nil,
request_info,
params,
current_user.id,
Time.now.strftime("%d/%m/%Y %H:%M")
)
rescue Exception => exception2
logger.info exception2.to_s
logger.info exception2.backtrace.join("\n")
end
end
end
def set_success_message(message, is_ajax = false)
if is_ajax
@success_message = message
@ -613,10 +574,15 @@ class ApplicationController < BaseController
end
def set_conference_registration!
@registration = set_conference_registration
set_conference_registration
raise ActiveRecord::PremissionDenied unless @registration.present?
end
def ensure_registration_is_complete!
set_conference_registration!
raise ActiveRecord::PremissionDenied unless @registration.registered?
end
def set_or_create_conference_registration
set_conference_registration
return @registration if @registration.present?

5
app/controllers/conferences_controller.rb

@ -82,6 +82,11 @@ class ConferencesController < ApplicationController
# get the current step
@step = current_registration_step(@this_conference, current_user)
if @update_status.nil? && flash[:status_message].present?
@update_status = flash[:status_message][:status]
@update_message = flash[:status_message][:message]
end
if @step == :payment_form && (params[:token].present? || @test_token.present?)
result = paypal_payment_confirm(@this_conference, current_user, params)
data_to_instance_variables(result)

74
app/controllers/workshops_controller.rb

@ -26,7 +26,8 @@ class WorkshopsController < ApplicationController
def create_workshop
set_conference
set_conference_registration!
ensure_registration_is_complete!
@workshop = Workshop.new
@languages = [I18n.locale.to_sym]
@needs = []
@ -47,7 +48,7 @@ class WorkshopsController < ApplicationController
def edit_workshop
set_conference
set_conference_registration!
ensure_registration_is_complete!
@workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless @workshop.present?
@ -82,7 +83,7 @@ class WorkshopsController < ApplicationController
def delete_workshop
set_conference
set_conference_registration!
ensure_registration_is_complete!
@workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless @workshop.present?
@ -95,9 +96,9 @@ class WorkshopsController < ApplicationController
@workshop.destroy
end
return redirect_to register_step_path(@this_conference.slug, 'workshops')
return redirect_to workshops_path(@this_conference.slug)
end
return redirect_to view_workshop_url(@this_conference.slug, @workshop.id)
return redirect_to view_workshop_path(@this_conference.slug, @workshop.id)
end
@register_template = :workshops
@ -106,13 +107,13 @@ class WorkshopsController < ApplicationController
def save_workshop
set_conference
set_conference_registration!
ensure_registration_is_complete!
if params[:button].to_sym != :save
if params[:workshop_id].present?
return redirect_to view_workshop_url(@this_conference.slug, params[:workshop_id])
return redirect_to view_workshop_path(@this_conference.slug, params[:workshop_id])
end
return redirect_to register_step_path(@this_conference.slug, 'workshops')
return redirect_to workshops_path(@this_conference.slug)
end
if params[:workshop_id].present?
@ -120,8 +121,8 @@ class WorkshopsController < ApplicationController
return do_404 unless workshop.present?
can_edit = workshop.can_edit?(current_user)
else
workshop = Workshop.new(:conference_id => @this_conference.id)
workshop.workshop_facilitators = [WorkshopFacilitator.new(:user_id => current_user.id, :role => :creator)]
workshop = Workshop.new(conference_id: @this_conference.id)
workshop.workshop_facilitators = [WorkshopFacilitator.new(user_id: current_user.id, role: :creator)]
can_edit = true
end
@ -157,27 +158,27 @@ class WorkshopsController < ApplicationController
workshop.save
# Rouge nil facilitators have been know to be created, just destroy them here now
WorkshopFacilitator.where(:user_id => nil).destroy_all
WorkshopFacilitator.where(user_id: nil).destroy_all
else
return do_403
end
redirect_to view_workshop_url(@this_conference.slug, workshop.id)
redirect_to view_workshop_path(@this_conference.slug, workshop.id)
end
def toggle_workshop_interest
set_conference
set_conference_registration!
ensure_registration_is_complete!
workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless workshop
# save the current state
interested = workshop.interested? current_user
# remove all associated fields
WorkshopInterest.delete_all(:workshop_id => workshop.id, :user_id => current_user.id)
WorkshopInterest.delete_all(workshop_id: workshop.id, user_id: current_user.id)
# creat the new interest row if we weren't interested before
WorkshopInterest.create(:workshop_id => workshop.id, :user_id => current_user.id) unless interested
WorkshopInterest.create(workshop_id: workshop.id, user_id: current_user.id) unless interested
if request.xhr?
render json: [
@ -192,13 +193,13 @@ class WorkshopsController < ApplicationController
]
else
# go back to the workshop
redirect_to view_workshop_url(@this_conference.slug, workshop.id)
redirect_to view_workshop_path(@this_conference.slug, workshop.id)
end
end
def facilitate_workshop
set_conference
set_conference_registration!
ensure_registration_is_complete!
@workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless @workshop
return do_403 if @workshop.facilitator?(current_user) || !current_user
@ -209,7 +210,7 @@ class WorkshopsController < ApplicationController
def facilitate_request
set_conference
set_conference_registration!
ensure_registration_is_complete!
workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless workshop
return do_403 if workshop.facilitator?(current_user) || !current_user
@ -219,12 +220,12 @@ class WorkshopsController < ApplicationController
send_mail(:workshop_facilitator_request, workshop.id, current_user.id, params[:message])
redirect_to sent_facilitate_workshop_url(@this_conference.slug, workshop.id)
redirect_to sent_facilitate_workshop_path(@this_conference.slug, workshop.id)
end
def sent_facilitate_request
set_conference
set_conference_registration!
ensure_registration_is_complete!
@workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless @workshop
return do_403 unless @workshop.requested_collaborator?(current_user)
@ -236,7 +237,7 @@ class WorkshopsController < ApplicationController
def approve_facilitate_request
return do_403 unless logged_in?
set_conference
set_conference_registration!
ensure_registration_is_complete!
workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless workshop.present?
@ -253,24 +254,24 @@ class WorkshopsController < ApplicationController
LinguaFranca.with_locale(user.locale) do
send_mail(:workshop_facilitator_request_approved, workshop.id, user.id)
end
return redirect_to view_workshop_url(@this_conference.slug, workshop.id)
return redirect_to view_workshop_path(@this_conference.slug, workshop.id)
end
when :deny
if workshop.active_facilitator?(current_user) && workshop.requested_collaborator?(User.find(user_id))
WorkshopFacilitator.delete_all(
:workshop_id => workshop.id,
:user_id => user_id)
workshop_id: workshop.id,
user_id: user_id)
LinguaFranca.with_locale user.locale do
send_mail(:workshop_facilitator_request_denied, workshop.id, user.id)
end
return redirect_to view_workshop_url(@this_conference.slug, workshop.id)
return redirect_to view_workshop_path(@this_conference.slug, workshop.id)
end
when :remove
if workshop.can_remove?(current_user, user)
WorkshopFacilitator.delete_all(
:workshop_id => workshop.id,
:user_id => user_id)
return redirect_to view_workshop_url(@this_conference.slug, workshop.id)
workshop_id: workshop.id,
user_id: user_id)
return redirect_to view_workshop_path(@this_conference.slug, workshop.id)
end
when :switch_ownership
if workshop.creator?(current_user)
@ -282,7 +283,7 @@ class WorkshopsController < ApplicationController
workshop.id, user_id)
f.role = :creator
f.save
return redirect_to view_workshop_url(@this_conference.slug, workshop.id)
return redirect_to view_workshop_path(@this_conference.slug, workshop.id)
end
end
@ -291,7 +292,7 @@ class WorkshopsController < ApplicationController
def add_workshop_facilitator
set_conference
set_conference_registration!
ensure_registration_is_complete!
user = User.find_user(params[:email])
@ -313,12 +314,12 @@ class WorkshopsController < ApplicationController
end
end
return redirect_to view_workshop_url(@this_conference.slug, params[:workshop_id])
return redirect_to view_workshop_path(@this_conference.slug, params[:workshop_id])
end
def add_comment
set_conference
set_conference_registration!
ensure_registration_is_complete!
workshop = Workshop.find_by_id_and_conference_id(params[:workshop_id], @this_conference.id)
return do_404 unless workshop && current_user
@ -335,7 +336,7 @@ class WorkshopsController < ApplicationController
elsif params[:button] = 'add_comment'
new_comment = workshop.add_comment(current_user, params[:comment])
workshop.active_facilitators.each do | u |
workshop.active_facilitators.each do |u|
unless u.id == current_user.id
LinguaFranca.with_locale u.locale do
send_mail(:workshop_comment, workshop.id, new_comment.id, u.id)
@ -346,20 +347,21 @@ class WorkshopsController < ApplicationController
return do_404
end
return redirect_to view_workshop_url(@this_conference.slug, workshop.id, anchor: "comment-#{new_comment.id}")
return redirect_to view_workshop_path(@this_conference.slug, workshop.id, anchor: "comment-#{new_comment.id}")
end
rescue_from ActiveRecord::PremissionDenied do |exception|
if !@this_conference.can_register?
do_404
elsif logged_in?
redirect_to 'conferences/register'
flash[:status_message] = { message: :registration_required, status: :warning }
redirect_to register_path(@this_conference.slug)
else
@register_template = :confirm_email
@page_title = "articles.conference_registration.headings.#{@this_conference.registration_status == :open ? '': 'Pre_'}Registration_Details"
@main_title = "articles.conference_registration.headings.#{@this_conference.registration_status == :open ? '': 'Pre_'}Register"
@main_title_vars = { vars: { title: @this_conference.title } }
render 'conferences/register'
render register_path(@this_conference.slug)
end
end

30
app/helpers/admin_helper.rb

@ -59,8 +59,8 @@ module AdminHelper
def get_administration_group(administration_step)
admin_step = administration_step.to_sym
admin_step = administration_sub_steps[admin_step] if administration_sub_steps[admin_step].present?
administration_steps.each do | group, steps |
steps.each do | step |
administration_steps.each do |group, steps|
steps.each do |step|
return group if step == admin_step
end
end
@ -75,35 +75,35 @@ module AdminHelper
case to.to_sym
when :registered
ConferenceRegistration.where(conference_id: conference.id).each do | r |
users << r.user if ((r.steps_completed || []).include? 'questions') && r.user.present? && r.is_attending != 'n'
ConferenceRegistration.where(conference_id: conference.id).each do |r|
users << r.user if r.registered? && r.user.present? && r.attending?
end
when :pre_registered
ConferenceRegistration.where(conference_id: conference.id).each do | r |
users << r.user if registration_status(r) == :preregistered && r.is_attending != 'n'
ConferenceRegistration.where(conference_id: conference.id).each do |r|
users << r.user if r.attending?
end
when :workshop_facilitators
user_hash = {}
Workshop.where(conference_id: conference.id).each do | w |
w.active_facilitators.each do | u |
Workshop.where(conference_id: conference.id).each do |w|
w.active_facilitators.each do |u|
user_hash[u.id] ||= u if u.present?
end
end
users = user_hash.values
when :unregistered
ConferenceRegistration.where(conference_id: conference.id).each do | r |
users << r.user if registration_status(r) == :unregistered && r.is_attending != 'n'
ConferenceRegistration.where(conference_id: conference.id).each do |r|
users << r.user if !r.registered? && r.attending?
end
when :housing_providers
ConferenceRegistration.where(conference_id: conference.id, can_provide_housing: true).each do | r |
ConferenceRegistration.where(conference_id: conference.id, can_provide_housing: true).each do |r|
users << r.user if r.user.present?
end
when :guests
ConferenceRegistration.where(conference_id: conference.id, housing: 'house').each do | r |
users << r.user if r.user.present? && r.is_attending != 'n'
ConferenceRegistration.where(conference_id: conference.id, housing: 'house').each do |r|
users << r.user if r.user.present? && r.attending?
end
when :all
User.all.each do | u |
User.all.each do |u|
users << u if u.present? && (u.is_subscribed.nil? || u.is_subscribed)
end
end
@ -151,7 +151,7 @@ module AdminHelper
end
end
(((((@schedule[@day] || {})[:times] || {})[@time] || {})[:item] || {})[:workshops] || {}).each do | l, w |
(((((@schedule[@day] || {})[:times] || {})[@time] || {})[:item] || {})[:workshops] || {}).each do |l, w|
if w[:workshop].id != workshop.id
f_a = w[:workshop].active_facilitators.map { | f | f.id }
f_b = workshop.active_facilitators.map { | f | f.id }

46
app/helpers/form_helper.rb

@ -704,58 +704,14 @@ module FormHelper
return options
end
def registration_step_menu
steps = current_registration_steps(@registration)
return '' unless steps.present? && steps.length > 1
pre_registration_steps = ''
post_registration_steps = ''
post_registration = false
steps.each do |step|
text = _"articles.conference_registration.headings.#{step[:name].to_s}"
if step[:name] == :workshops
post_registration = true
end
h = content_tag :li, class: [step[:enabled] ? :enabled : nil, @register_template == step[:name] ? :current : nil, post_registration ? :post : :pre].compact do
if step[:enabled]
content_tag :div, (link_to text, register_step_path(@this_conference.slug, step[:name])).html_safe, class: :step
else
content_tag :div, text, class: :step
end
end
if post_registration
post_registration_steps += h.html_safe
else
pre_registration_steps += h.html_safe
end
end
html = (
row class: 'flow-steps' do
columns do
(content_tag :ul, id: 'registration-steps' do
pre_registration_steps.html_safe +
post_registration_steps.html_safe
end).html_safe
end
end
)
return html.html_safe
end
def broadcast_options(conference = nil)
conference ||= @this_conference || @conference
options = [
:registered,
:pre_registered,
:workshop_facilitators,
:unregistered,
:workshop_facilitators,
:housing_providers,
:guests,
:all

36
app/mailers/user_mailer.rb

@ -123,15 +123,29 @@ class UserMailer < ActionMailer::Base
mail to: @user.named_email, subject: clean_subject(subject)
end
def error_report(subject, message, report, exception, request, params, user, time = nil)
@message = message
@report = report
@exception = exception
@request = request
@params = params
@time = time
@user = User.find(user) if user.present?
mail to: 'goodgodwin@hotmail.com', subject: clean_subject(subject)
def error_report(report_signature)
@reports = Report.where(signature: report_signature).order('created_at DESC')
@report = @reports.first
return unless @report.present?
@title = case @report.source.to_sym
when :javascript
"JavaScript fatal report"
when :i18n
"Missing translation report"
else
"Fatal report"
end
subject = "#{@title}: #{report_signature}"
@request = Request.find_by_request_id(@report.request_id)
return unless @request.present?
@user = User.find(@request.data['user'].to_i) if @request.data['user'].present?
mail to: administrators, subject: clean_subject(subject)
end
def contact(from, subject, message, email_list)
@ -172,4 +186,8 @@ class UserMailer < ActionMailer::Base
@subject = subject
return subject
end
def administrators
User.where(role: :administrator).map(&:named_email).join(',')
end
end

90
app/views/user_mailer/error_report.html.haml

@ -1,53 +1,43 @@
%p=@message.html_safe if @message.present?
%pre=@report
%h1=@title
- if @exception.present?
%h1 Backtrace
%pre=@exception
%h2 Error details
%code.signature{class: "#{@report.source}-signature"}
= "#{@report.signature}"
%code.backtrace{class: "#{@report.source}-backtrace"}=@report.backtrace
%h1 Details
%table.error-report
%tr
%th Key
%th Value
%tr
%td User ID
%td=@user.present? ? @user.id : ''
%tr
%td User Name
%td=@user.present? ? @user.name : ''
%tr
%td User Email
%td=@user.present? ? @user.email : ''
%tr
%td IP Address
%td=@request['remote_ip']
%tr
%td UUID
%td=@request['uuid']
%tr
%td URL
%td=@request['original_url']
%tr
%td Time
%td=@time
%h1 Params
%table.error-report
%tr
%th Key
%th Value
- @params.each do | key, value |
%tr
%td=key
%td=value
%h1 Request Environment
%table.error-report
%tr
%th Key
%th Value
- @request['env'].each do | key, value |
%h2 Request details
.request-details
%table
%tr
%td=key
%td=value
%th Response code
%td=@request.response
- @request.data.each do |key, value|
- if key.to_s == 'user'
- if @user
%tr
%th User ID
%td=@user.id
%tr
%th User Email
%td=@user.email
%tr
%th User Name
%td=@user.firstname
- else
%tr
%th User ID
%td NULL
%tr.spacer
%td{ colspan: 2 }
- else
%tr
%th=key.to_s.titlecase
%td
- if value.is_a?(Hash)
%table
- value.each do |k, v|
%tr
%th=k
%td=v
- else
= value.to_s

3
app/views/workshops/facilitate.html.haml

@ -1,11 +1,10 @@
= render 'conferences/page_header', page_key: 'Facilitate_Workshop'
%article
= row do
= form_tag facilitate_workshop_request_path(@this_conference.slug, @workshop.id), class: 'composition' do
= form_tag facilitate_workshop_request_path(@this_conference.slug, @workshop.id), class: :composition do
= (hidden_field_tag :workshop_id, @workshop.id) if @workshop
= columns(medium: 12) do
%h2=_'articles.workshops.headings.facilitate', "Request to Facilitate ‘#{@workshop.title}’", vars: { workshop_title: @workshop.title }
= registration_step_menu
=_('articles.workshops.paragraphs.facilitate_request','Please tell the current workshop facilitators who you are, why you want to help facilitate the workshop, and how you think you will help make the workshop better. All of the current facilitators will be emailed and they may ask more questions before approving or denying your request. Please note that this will reveal your email address to the facilitators.')
.text-area-field.input-field
= label_tag :message

5
app/views/workshops/facilitate_request_sent.html.haml

@ -3,10 +3,9 @@
%article
= row do
%h2=_'page_titles.conferences.Facilitate_Workshop'
= registration_step_menu
= columns(medium: 12) do
=_('articles.workshops.paragraphs.facilitate_request_sent','Your request has been sent. You will receive an email once your request is approved or denied or if the current facilitators have any questions.')
= columns(medium: 12) do
.actions
= link_to (_'actions.workshops.View'), view_workshop_path(@this_conference.slug, @workshop.id), :class => 'button'
= link_to (_'actions.workshops.View_All'), register_step_path(@this_conference.slug, :wokshops), :class => 'button'
= link_to (_'actions.workshops.View'), view_workshop_path(@this_conference.slug, @workshop.id), class: :button
= link_to (_'actions.workshops.View_All'), register_step_path(@this_conference.slug, :wokshops), class: :button

4
app/views/workshops/show.html.haml

@ -11,5 +11,5 @@
= row do
= columns(medium: 12) do
.actions.center
= (link_to (_'actions.workshops.Edit'), edit_workshop_path(@this_conference.slug, @workshop.id), :class => [:button, :modify]) if @workshop.can_edit?(current_user)
= (link_to (_'actions.workshops.Delete'), delete_workshop_path(@this_conference.slug, @workshop.id), :class => 'button delete') if @workshop.can_delete?(current_user)
= (link_to (_'actions.workshops.Edit'), edit_workshop_path(@this_conference.slug, @workshop.id), class: [:button, :modify]) if @workshop.can_edit?(current_user)
= (link_to (_'actions.workshops.Delete'), delete_workshop_path(@this_conference.slug, @workshop.id), class: 'button delete') if @workshop.can_delete?(current_user)

7
config/locales/en.yml

@ -1687,6 +1687,7 @@ en:
payment_pending: Thank you! Your payment is currently pending.
companion_unregistered: Your companion has not yet registered. Please ensure
that they do to guarantee you are housed together.
registration_required: Please complete your registration
step_names:
group_ride: Group ride?
hosting_other: Other
@ -2441,13 +2442,13 @@ en:
add: Add new
options:
send_to:
registered: Everyone who has registered
pre_registered: Everyone who has pre-registered or registered
registered: Everyone who has completed their registration
pre_registered: Everyone who has begun or completed the registration process
unregistered: Everyone who has not completed their registration
workshop_facilitators: All workshop facilitators
housing_providers: Housing providers
guests: Everyone who has requested housing
all: Everyone
all: Everyone who has ever registered for a conference
conferences:
types:
annual: Annual Bike!Bike!

1
config/locales/fr.yml

@ -1516,6 +1516,7 @@ fr:
companion_unregistered: Votre partenaire ne s’est pas encore inscrit ou inscrite.
Veuillez vous assurer qu’il ou elle le fasse pour que vous soyez hébergés
ensemble.
registration_required: Veuillez compléter votre inscription
policy:
headings:
The_Agreement: L’ Accord

32
db/schema.rb

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170613022506) do
ActiveRecord::Schema.define(version: 20170719024801) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -361,6 +361,26 @@ ActiveRecord::Schema.define(version: 20170613022506) do
t.datetime "updated_at"
end
create_table "reports", force: :cascade do |t|
t.string "request_id"
t.string "signature"
t.string "severity"
t.string "source"
t.string "backtrace"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "requests", force: :cascade do |t|
t.string "request_id"
t.string "session_id"
t.json "data"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "application"
t.integer "response"
end
create_table "sessions", force: :cascade do |t|
t.string "session_id", null: false
t.text "data"
@ -380,11 +400,11 @@ ActiveRecord::Schema.define(version: 20170613022506) do
end
create_table "translation_records", force: :cascade do |t|
t.string "locale"
t.integer "translator_id"
t.string "key"
t.text "value"
t.datetime "created_at"
t.string "locale"
t.integer "translator_id"
t.string "key"
t.text "value"
t.date "created_at"
end
create_table "translations", force: :cascade do |t|

21
features/workshops.feature

@ -3,12 +3,11 @@ Feature: Workshops
Given there is an upcoming conference
And registration is open
And I am logged in
And registered for the conference
And registered
And on the registration page
Then I should see 'New Workshop'
And should see 'View Workshops'
Then I should see 'New Workshop'
But I should not see any workshops
When I click on 'New Workshop'
@ -66,6 +65,24 @@ Feature: Workshops
Then I should see 'New Workshop'
But I should not see any workshops
Scenario: Un-Registered users cannot create workshops
Given there is an upcoming conference
And the conference has workshop info copy
And registration is open
And I am logged in
And on the landing page
Then I should see 'View Workshops'
When I click on 'View Workshops'
Then I should be on the workshops page
And I should see 'New Workshop'
But I should not see any workshops
When I click on 'New Workshop'
Then I should see 'Please complete your registration'
But I should not see 'Create a Workshop'
Scenario: Users can comment on and translate their own workshops
Given that there is an upcoming conference
And registration is open

Loading…
Cancel
Save