Merge branch 'master' into openid
This commit is contained in:
commit
a822858761
27 changed files with 231 additions and 59 deletions
|
|
@ -82,7 +82,7 @@ You can read through current enabled rules in `.rubocop.yml` file. Explanations
|
|||
Additionally you can read through the [ruby style-guide](https://github.com/bbatsov/ruby-style-guide) to better understand core principles.
|
||||
|
||||
### Test Suite
|
||||
We are using [rspec](http://rspec.info/)+[capybara](http://jnicklas.github.io/capybara/)+[factory girl](https://github.com/thoughtbot/factory_girl) as a test suite. You can run it locally
|
||||
We are using [rspec](http://rspec.info/)+[capybara](http://teamcapybara.github.io/capybara/)+[factory girl](https://github.com/thoughtbot/factory_girl) as a test suite. You can run it locally
|
||||
|
||||
```shell
|
||||
vagrant exec bundle exec rspec
|
||||
|
|
|
|||
|
|
@ -98,6 +98,9 @@ $(function () {
|
|||
|
||||
$("#registration-period-start-datepicker").on("dp.change",function (e) {
|
||||
$('#registration-period-end-datepicker').data("DateTimePicker").setMinDate(e.date);
|
||||
if (!$('#registration-period-end-datepicker').val()) {
|
||||
$('#registration-period-end-datepicker').data("DateTimePicker").setDate(e.date);
|
||||
}
|
||||
});
|
||||
$("#registration-period-end-datepicker").on("dp.change",function (e) {
|
||||
$('#registration-period-start-datepicker').data("DateTimePicker").setMaxDate(e.date);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,26 @@ module Admin
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Received a file from user
|
||||
# Reads file and creates commercial for event
|
||||
# File content example:
|
||||
# EventID:MyURL
|
||||
def mass_upload
|
||||
errors = Commercial.read_file(params[:file]) if params[:file]
|
||||
|
||||
if errors.all? { |_k, v| v.blank? }
|
||||
flash[:notice] = 'Successfully added commercials.'
|
||||
else
|
||||
errors_text = ''
|
||||
errors_text << 'Unable to find event with ID: ' + errors[:no_event].join(', ') + '. ' if errors[:no_event].any?
|
||||
errors_text << 'There were some errors: ' + errors[:validation_errors].join('. ') if errors[:validation_errors].any?
|
||||
|
||||
flash[:error] = errors_text
|
||||
end
|
||||
redirect_to :back
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def commercial_params
|
||||
|
|
|
|||
|
|
@ -124,6 +124,15 @@ module Admin
|
|||
|
||||
def cancel
|
||||
update_state(:cancel, 'Event canceled!')
|
||||
selected_schedule = @event.program.selected_schedule
|
||||
event_schedule = EventSchedule.unscoped.where(event: @event).find_by(schedule: selected_schedule) if selected_schedule
|
||||
Rails.logger.debug "schedule: #{selected_schedule.inspect} and event_schedule #{event_schedule.inspect}"
|
||||
if selected_schedule && event_schedule
|
||||
event_schedule.enabled = false
|
||||
event_schedule.save
|
||||
else
|
||||
@event.event_schedules.destroy_all
|
||||
end
|
||||
end
|
||||
|
||||
def reject
|
||||
|
|
|
|||
|
|
@ -91,6 +91,15 @@ class ProposalsController < ApplicationController
|
|||
|
||||
begin
|
||||
@event.withdraw
|
||||
selected_schedule = @event.program.selected_schedule
|
||||
event_schedule = @event.event_schedules.find_by(schedule: selected_schedule) if selected_schedule
|
||||
Rails.logger.debug "schedule: #{selected_schedule.inspect} and event_schedule #{event_schedule.inspect}"
|
||||
if selected_schedule && event_schedule
|
||||
event_schedule.enabled = false
|
||||
event_schedule.save
|
||||
else
|
||||
@event.event_schedules.destroy_all
|
||||
end
|
||||
rescue Transitions::InvalidTransition
|
||||
redirect_to :back, error: "Event can't be withdrawn"
|
||||
return
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ class Commercial < ApplicationRecord
|
|||
|
||||
has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||
|
||||
validates :url, presence: true
|
||||
validates :url, presence: true, uniqueness: { scope: :commercialable }
|
||||
validates :url, format: URI::regexp(%w(http https))
|
||||
|
||||
validate :valid_url
|
||||
|
|
@ -20,6 +20,29 @@ class Commercial < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def self.read_file(file)
|
||||
errors = {}
|
||||
errors[:no_event] = []
|
||||
errors[:validation_errors] = []
|
||||
|
||||
file.read.each_line do |line|
|
||||
# Get the event id (text before :)
|
||||
id = line.match(/:/).pre_match.to_i
|
||||
# Get the commercial url (text after :)
|
||||
url = line.match(/:/).post_match
|
||||
event = Event.find_by(id: id)
|
||||
|
||||
# Go to next event, if the event is not found
|
||||
errors[:no_event] << id && next unless event
|
||||
|
||||
commercial = event.commercials.new(url: url)
|
||||
unless commercial.save
|
||||
errors[:validation_errors] << "Could not create commercial for event with ID #{event.id} (" + commercial.errors.full_messages.to_sentence + ')'
|
||||
end
|
||||
end
|
||||
errors
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def valid_url
|
||||
|
|
|
|||
|
|
@ -197,6 +197,14 @@ class Event < ApplicationRecord
|
|||
send(transition)
|
||||
end
|
||||
save
|
||||
# If the event was previously scheduled, and then withdrawn or cancelled
|
||||
# its event_schedule will have enabled set to false
|
||||
# If the event is now confirmed again, we want it to be available for scheduling
|
||||
Rails.logger.debug "transition is #{transition}"
|
||||
if transition == :confirm
|
||||
Rails.logger.debug "schedules #{EventSchedule.unscoped.where(event: self, enabled: false)}"
|
||||
EventSchedule.unscoped.where(event: self, enabled: false).destroy_all
|
||||
end
|
||||
rescue Transitions::InvalidTransition => e
|
||||
alert = "Update state failed. #{e.message}"
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
class EventSchedule < ApplicationRecord
|
||||
default_scope { where(enabled: true) }
|
||||
belongs_to :schedule
|
||||
belongs_to :event
|
||||
belongs_to :room
|
||||
|
|
@ -33,7 +34,7 @@ class EventSchedule < ApplicationRecord
|
|||
# Returns event schedules that are scheduled in the same room and start_time as event
|
||||
#
|
||||
def intersecting_event_schedules
|
||||
room.event_schedules.where(start_time: start_time, schedule: schedule).where.not(id: id)
|
||||
EventSchedule.unscoped.where(room: room, start_time: start_time, schedule: schedule).where.not(id: id)
|
||||
end
|
||||
|
||||
def replacement?
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ class User < ApplicationRecord
|
|||
end
|
||||
|
||||
def proposals(conference)
|
||||
events.where('program_id = ? AND event_users.event_role=?', conference.program.id, 'submitter')
|
||||
events.where('program_id = ? AND (event_users.event_role=? OR event_users.event_role=?)', conference.program.id, 'submitter', 'speaker')
|
||||
end
|
||||
|
||||
def proposal_count(conference)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
require 'open-uri'
|
||||
|
||||
class TicketPdf < Prawn::Document
|
||||
def initialize(conference, user, physical_ticket, ticket_layout, file_name)
|
||||
super(page_layout: ticket_layout, page_size: 'A4', filename: file_name)
|
||||
|
|
@ -43,11 +45,17 @@ class TicketPdf < Prawn::Document
|
|||
def draw_second_square
|
||||
move_up 150
|
||||
if @conference.picture?
|
||||
if 7 * @conference.picture.image[:width] > 12 * @conference.picture.image[:height]
|
||||
image "#{Rails.root}/public#{@conference.picture_url}", at: [@mid_horizontal + 30, cursor], width: 120
|
||||
else
|
||||
image "#{Rails.root}/public#{@conference.picture_url}", at: [@mid_horizontal + 30, cursor], height: 70
|
||||
conference_image = case @conference.picture.ticket.url[0, 4]
|
||||
when 'http', 'ftp:' # CDNs
|
||||
open(@conference.picture.ticket.url)
|
||||
when '/sys' # local storage
|
||||
open([
|
||||
Rails.root,
|
||||
'/public',
|
||||
@conference.picture.ticket.url
|
||||
].join)
|
||||
end
|
||||
image conference_image, at: [@mid_horizontal + 30, cursor]
|
||||
else
|
||||
image "#{Rails.root}/public/img/osem-logo.png", at: [@mid_horizontal + 30, cursor], height: 70
|
||||
end
|
||||
|
|
|
|||
|
|
@ -52,10 +52,6 @@ class PictureUploader < CarrierWave::Uploader::Base
|
|||
"system/#{object_class_name}/#{mounted_as}/#{model.id}"
|
||||
end
|
||||
|
||||
def image
|
||||
@image ||= MiniMagick::Image.open(file.file)
|
||||
end
|
||||
|
||||
# Create different versions of your uploaded files:
|
||||
version :large do
|
||||
process resize_to_fit: [300, 300]
|
||||
|
|
@ -80,6 +76,11 @@ class PictureUploader < CarrierWave::Uploader::Base
|
|||
process resize_and_pad: [320, 120, 'white']
|
||||
end
|
||||
|
||||
version :ticket, if: :conference?
|
||||
version :ticket do
|
||||
process resize_and_pad: [120, 70]
|
||||
end
|
||||
|
||||
# Add a white list of extensions which are allowed to be uploaded.
|
||||
# For images you might use something like this:
|
||||
def extension_white_list
|
||||
|
|
@ -95,4 +96,8 @@ class PictureUploader < CarrierWave::Uploader::Base
|
|||
def sponsor?(_picture)
|
||||
object_class_name == 'sponsors'
|
||||
end
|
||||
|
||||
def conference?(_picture)
|
||||
object_class_name == 'conferences'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,11 +4,15 @@
|
|||
%h1
|
||||
Events
|
||||
= "(#{@events.length})" if @events.any?
|
||||
.pull-right
|
||||
|
||||
.btn-group.pull-right
|
||||
%button.btn.btn-primary{ 'data-toggle' => 'modal', 'data-target' => '#mass-commercials-modal', title: 'Mass import of commercials for events' }
|
||||
Add Commercials
|
||||
|
||||
- if can? :create, Event
|
||||
=link_to 'Add Event', new_admin_conference_program_event_path(@conference.short_title), class: 'button btn btn-default btn-info'
|
||||
= link_to 'Add Event', new_admin_conference_program_event_path(@conference.short_title), class: 'button btn btn-default btn-info'
|
||||
|
||||
- if can? :read, Event
|
||||
.btn-group
|
||||
.btn-group
|
||||
%button.btn.btn-default.dropdown-toggle{ 'data-toggle' => 'dropdown', type: 'button', class: 'btn btn-success' }
|
||||
Export PDF
|
||||
|
|
@ -33,8 +37,27 @@
|
|||
%li= link_to 'All', admin_conference_program_events_path(@conference.short_title, format: :xlsx, event_export_option: 'all')
|
||||
%li= link_to 'Confirmed', admin_conference_program_events_path(@conference.short_title, format: :xlsx, event_export_option: 'confirmed')
|
||||
%li= link_to 'All with Comments', admin_conference_program_events_path(@conference.short_title, format: :xlsx, event_export_option: 'all_with_comments')
|
||||
|
||||
%p.text-muted
|
||||
All the submissions of your speakers
|
||||
|
||||
.modal#mass-commercials-modal
|
||||
.modal-dialog
|
||||
.modal-content
|
||||
.modal-header
|
||||
%h1 Add commercials to events
|
||||
.text-muted
|
||||
Upload your file with data in the following format:
|
||||
%b Event_ID:Commercial_Link
|
||||
, eg.
|
||||
%br
|
||||
%b 11:https://youtube.com/myvideo
|
||||
|
||||
.modal-body
|
||||
= semantic_form_for '', url: mass_upload_commercials_admin_conference_program_path(@conference.short_title), method: :post do |f|
|
||||
= f.input 'file', as: :file
|
||||
.modal-footer
|
||||
= f.submit 'Add', class: 'btn btn-primary'
|
||||
.row
|
||||
.col-md-4
|
||||
= render partial: 'admin/conferences/doughnut_chart', locals: { title: 'Events state', data: @event_distribution }
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
.row
|
||||
.col-md-8
|
||||
= semantic_form_for(@ticket, url: (@ticket.new_record? ? admin_conference_tickets_path : admin_conference_ticket_path(@conference.short_title, @ticket))) do |f|
|
||||
= f.input :title
|
||||
= f.input :description, input_html: { rows: 5, data: { provide: "markdown-editable" } }
|
||||
= f.input :title, input_html: { autofocus: true }
|
||||
= f.input :description, input_html: { rows: 5, data: { provide: 'markdown-editable' } }
|
||||
= f.input :price
|
||||
= f.input :price_currency, as: :select, class: 'form-control', collection: ['USD', 'EUR', 'GBP', 'INR', 'CNY', 'CHF'], include_blank: false
|
||||
= f.input :registration_ticket, hint: 'A registration ticket is with which user register for the conference.'
|
||||
|
|
|
|||
|
|
@ -104,6 +104,8 @@
|
|||
= humanized_money @total_price_per_ticket[ticket_id]
|
||||
%br
|
||||
- if @tickets.any?
|
||||
.btn-group
|
||||
= link_to 'View all tickets', conference_physical_tickets_path(@conference.short_title), class: "btn btn-success"
|
||||
= link_to 'Get more tickets', conference_tickets_path(@conference.short_title), class: "btn btn-default"
|
||||
- else
|
||||
You haven't bought any tickets.
|
||||
|
|
|
|||
|
|
@ -31,12 +31,7 @@
|
|||
= @user.email
|
||||
.col-md-5.col-md-offset-2.box.well
|
||||
- if @conference.picture?
|
||||
- width = @conference.picture.image[:width]
|
||||
- height = @conference.picture.image[:height]
|
||||
- if 10 * width > 15 * height
|
||||
= image_tag(@conference.picture_url, width: '150')
|
||||
- else
|
||||
= image_tag(@conference.picture_url, height: '100')
|
||||
= image_tag(@conference.picture.ticket.url, class: 'img-responsive')
|
||||
- else
|
||||
= image_tag('/img/osem-logo.png', class: 'img-responsive')
|
||||
%p.text-left
|
||||
|
|
|
|||
|
|
@ -36,8 +36,10 @@
|
|||
.col-md-8
|
||||
%h4
|
||||
= link_to speaker.name, user_path(speaker.id)
|
||||
%br
|
||||
- if speaker.email_public?
|
||||
= "(#{speaker.email})"
|
||||
= mail_to "#{ speaker.email }" do
|
||||
%i.fa.fa-envelope-o.fa-2x
|
||||
- if speaker.affiliation?
|
||||
.text-muted
|
||||
from
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ elif [[ "$ID" == "centos" || "$VERSION" == "7" ]]; then
|
|||
tar jxvf /tmp/phantomjs-2.1.1-linux-x86_64.tar.bz2 -C /tmp/ phantomjs-2.1.1-linux-x86_64/bin/phantomjs
|
||||
mv /tmp/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/local/bin
|
||||
|
||||
pushd /vagrant
|
||||
fi
|
||||
|
||||
echo -e "\ninstalling your bundle...\n"
|
||||
|
|
@ -64,7 +65,7 @@ if [ ! -f /vagrant/config/database.yml ] && [ -f /vagrant/config/database.yml.ex
|
|||
echo -e "\nSetting up your database from config/database.yml...\n"
|
||||
cp config/database.yml.example config/database.yml
|
||||
if [ ! -f db/development.sqlite3 ] && [ ! -f db/test.sqlite3 ]; then
|
||||
bundle exec rake db:setup
|
||||
su - vagrant -c "cd /vagrant/; bundle exec rake db:setup"
|
||||
else
|
||||
echo -e "\n\nWARNING: You have already have a development/test database."
|
||||
echo -e "WARNING: Please make sure this database works in this vagrant box!\n\n"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,35 @@ development:
|
|||
pool: 5
|
||||
timeout: 5000
|
||||
|
||||
## PostgreSQL
|
||||
## gem install pg
|
||||
##
|
||||
## Ensure the postgres gem is defined in your Gemfile
|
||||
## gem 'pg'
|
||||
## Update with your database name and login credentials
|
||||
# development:
|
||||
# adapter: postgresql
|
||||
# encoding: unicode
|
||||
# database: database_name
|
||||
# pool: 5
|
||||
# username: username
|
||||
# password: password
|
||||
|
||||
## MySQL
|
||||
## gem install mysql2
|
||||
##
|
||||
## Ensure the mysql gem is defined in your Gemfile
|
||||
## gem 'mysql2'
|
||||
## Update with your database name and login credentials
|
||||
# development:
|
||||
# adapter: mysql2
|
||||
# encoding: utf8
|
||||
# database: database_name
|
||||
# pool: 5
|
||||
# username: username
|
||||
# password: password
|
||||
# socket: /tmp/mysql.sock
|
||||
|
||||
# Warning: The database defined as "test" will be erased and
|
||||
# re-generated from your development database when you run "rake".
|
||||
# Do not set this db to the same as development or production.
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ Osem::Application.routes.draw do
|
|||
end
|
||||
resources :event_types
|
||||
resources :difficulty_levels
|
||||
post 'mass_upload_commercials' => 'commercials#mass_upload'
|
||||
resources :events do
|
||||
member do
|
||||
patch :toggle_attendance
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
class AddEnabledToEventSchedules < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :event_schedules, :enabled, :boolean, default: true
|
||||
end
|
||||
end
|
||||
9
db/migrate/20171130172334_rebuild_conference_pictures.rb
Normal file
9
db/migrate/20171130172334_rebuild_conference_pictures.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
class RebuildConferencePictures < ActiveRecord::Migration
|
||||
def up
|
||||
Conference.all.each do |conference|
|
||||
conference.picture.recreate_versions!
|
||||
end
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20171118113113) do
|
||||
ActiveRecord::Schema.define(version: 20171130172334) do
|
||||
|
||||
create_table "ahoy_events", force: :cascade do |t|
|
||||
t.integer "visit_id"
|
||||
|
|
@ -217,6 +217,7 @@ ActiveRecord::Schema.define(version: 20171118113113) do
|
|||
t.datetime "start_time"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.boolean "enabled", default: true
|
||||
t.index ["event_id", "schedule_id"], name: "index_event_schedules_on_event_id_and_schedule_id", unique: true
|
||||
t.index ["event_id"], name: "index_event_schedules_on_event_id"
|
||||
t.index ["room_id"], name: "index_event_schedules_on_room_id"
|
||||
|
|
@ -494,7 +495,7 @@ ActiveRecord::Schema.define(version: 20171118113113) do
|
|||
t.integer "user_id"
|
||||
t.integer "payment_id"
|
||||
t.integer "week"
|
||||
t.float "amount_paid", default: 0.0
|
||||
t.float "amount_paid"
|
||||
end
|
||||
|
||||
create_table "ticket_scannings", force: :cascade do |t|
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ dockerize -wait tcp://$DATABASE_HOST:$DATABASE_PORT -timeout 60s true
|
|||
if [ $(echo "show tables;" | mysql --host $DATABASE_HOST --port $DATABASE_PORT $MYSQL_DATABASE | wc -l) -le 1 ]; then
|
||||
echo ">>> Initializing database..."
|
||||
bundle exec rake db:schema:load
|
||||
|
||||
echo ">>> Seed database..."
|
||||
bundle exec rake db:seed
|
||||
fi
|
||||
|
||||
echo ">>> Upgrading database..."
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
FactoryGirl.define do
|
||||
factory :commercial do
|
||||
url 'https://www.youtube.com/watch?v=BTTygyxuGj8'
|
||||
sequence(:url) { |n| "https://www.youtube.com/watch?v=BTTygyxuGj#{n}" }
|
||||
|
||||
factory :conference_commercial do
|
||||
association :commercialable, factory: :conference
|
||||
|
|
|
|||
|
|
@ -98,7 +98,8 @@ feature Commercial do
|
|||
scenario 'does not update a commercial of an event with invalid data', feature: true, versioning: true, js: true do
|
||||
commercial = create(:commercial,
|
||||
commercialable_id: event.id,
|
||||
commercialable_type: 'Event')
|
||||
commercialable_type: 'Event',
|
||||
url: 'https://www.youtube.com/watch?v=BTTygyxuGj8')
|
||||
visit edit_conference_program_proposal_path(conference.short_title, event.id)
|
||||
click_link 'Commercials'
|
||||
fill_in "commercial_url_#{commercial.id}", with: 'invalid_commercial_url'
|
||||
|
|
|
|||
|
|
@ -1704,4 +1704,8 @@ describe Conference do
|
|||
|
||||
it { is_expected.to eq [past_conference1, past_conference2] }
|
||||
end
|
||||
|
||||
it 'should have a picture format for tickets' do
|
||||
expect(create(:conference).picture.ticket.url)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -345,24 +345,34 @@ describe User do
|
|||
end
|
||||
|
||||
describe 'proposals methods' do
|
||||
let(:submitter) { create(:submitter, user: user) }
|
||||
let(:submitter) { create(:user) }
|
||||
let(:speaker) { create(:user) }
|
||||
let(:event1) { create(:event, program: conference.program) }
|
||||
let(:event2) { create(:event, program: conference.program) }
|
||||
|
||||
before do
|
||||
event1.event_users << create(:event_user, user: user, event_role: 'submitter')
|
||||
event2.event_users << create(:event_user, user: user, event_role: 'submitter')
|
||||
event1.event_users << create(:event_user, user: submitter, event_role: 'submitter')
|
||||
event2.event_users << create(:event_user, user: submitter, event_role: 'submitter')
|
||||
event1.event_users << create(:event_user, user: speaker, event_role: 'speaker')
|
||||
end
|
||||
|
||||
describe '#proposals' do
|
||||
it 'returns events submitted by user' do
|
||||
expect(user.proposals(conference)).to match [event1, event2]
|
||||
expect(submitter.proposals(conference)).to match [event1, event2]
|
||||
end
|
||||
|
||||
it 'returns events in which user is a speaker' do
|
||||
expect(speaker.proposals(conference)).to match [event1]
|
||||
end
|
||||
end
|
||||
|
||||
describe '#proposal_count' do
|
||||
it 'returns number of events submitted by user' do
|
||||
expect(user.proposal_count(conference)).to eq 2
|
||||
expect(submitter.proposal_count(conference)).to eq 2
|
||||
end
|
||||
|
||||
it 'returns number of events in which the user is a speaker' do
|
||||
expect(speaker.proposal_count(conference)).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue