Merge branch 'master' into master
This commit is contained in:
commit
9cdf8398c1
415 changed files with 13432 additions and 4196 deletions
2
.dockerignore
Normal file
2
.dockerignore
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
Dockerfile
|
||||||
|
docker-compose.*
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -36,3 +36,7 @@ pickle-email-*.html
|
||||||
.env.development
|
.env.development
|
||||||
.env.test
|
.env.test
|
||||||
.env.local
|
.env.local
|
||||||
|
docker-compose.env
|
||||||
|
docker-compose.yml
|
||||||
|
.DS_Store
|
||||||
|
.byebug_history
|
||||||
|
|
|
||||||
1
.haml-lint.yml
Normal file
1
.haml-lint.yml
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
inherits_from: .haml-lint_todo.yml
|
||||||
460
.haml-lint_todo.yml
Normal file
460
.haml-lint_todo.yml
Normal file
|
|
@ -0,0 +1,460 @@
|
||||||
|
# This configuration was generated by
|
||||||
|
# `haml-lint --auto-gen-config`
|
||||||
|
# on 2017-06-09 04:02:20 +0530 using Haml-Lint version 0.24.0.
|
||||||
|
# The point is for the user to remove these configuration records
|
||||||
|
# one by one as the lints are removed from the code base.
|
||||||
|
# Note that changes in the inspected code, or installation of new
|
||||||
|
# versions of Haml-Lint, may require this file to be generated again.
|
||||||
|
|
||||||
|
linters:
|
||||||
|
|
||||||
|
# Offense count: 945
|
||||||
|
LineLength:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/booths/_change_state_dropdown.html.haml"
|
||||||
|
- "app/views/admin/booths/_form.html.haml"
|
||||||
|
- "app/views/admin/booths/index.html.haml"
|
||||||
|
- "app/views/admin/booths/show.html.haml"
|
||||||
|
- "app/views/admin/campaigns/_form.html.haml"
|
||||||
|
- "app/views/admin/campaigns/index.html.haml"
|
||||||
|
- "app/views/admin/cfps/_form.html.haml"
|
||||||
|
- "app/views/admin/cfps/show.html.haml"
|
||||||
|
- "app/views/admin/comments/_all_comments.html.haml"
|
||||||
|
- "app/views/admin/comments/_posted_comments.html.haml"
|
||||||
|
- "app/views/admin/comments/_unread_comments.html.haml"
|
||||||
|
- "app/views/admin/commercials/index.html.haml"
|
||||||
|
- "app/views/admin/conferences/_campaigns.html.haml"
|
||||||
|
- "app/views/admin/conferences/_doughnut_chart.html.haml"
|
||||||
|
- "app/views/admin/conferences/_line_chart.html.haml"
|
||||||
|
- "app/views/admin/conferences/_recent_registrations.html.haml"
|
||||||
|
- "app/views/admin/conferences/_recent_submissions.html.haml"
|
||||||
|
- "app/views/admin/conferences/_recent_users.html.haml"
|
||||||
|
- "app/views/admin/conferences/_targets.html.haml"
|
||||||
|
- "app/views/admin/conferences/_todo_list.html.haml"
|
||||||
|
- "app/views/admin/conferences/_top_submitter.html.haml"
|
||||||
|
- "app/views/admin/conferences/edit.html.haml"
|
||||||
|
- "app/views/admin/conferences/index.html.haml"
|
||||||
|
- "app/views/admin/conferences/new.html.haml"
|
||||||
|
- "app/views/admin/conferences/show.html.haml"
|
||||||
|
- "app/views/admin/contacts/edit.html.haml"
|
||||||
|
- "app/views/admin/difficulty_levels/_form.html.haml"
|
||||||
|
- "app/views/admin/difficulty_levels/index.html.haml"
|
||||||
|
- "app/views/admin/emails/_help.html.haml"
|
||||||
|
- "app/views/admin/emails/index.html.haml"
|
||||||
|
- "app/views/admin/event_types/_form.html.haml"
|
||||||
|
- "app/views/admin/event_types/index.html.haml"
|
||||||
|
- "app/views/admin/events/_all_events.csv.haml"
|
||||||
|
- "app/views/admin/events/_all_with_comments.csv.haml"
|
||||||
|
- "app/views/admin/events/_change_state_dropdown.html.haml"
|
||||||
|
- "app/views/admin/events/_confirmed_events.csv.haml"
|
||||||
|
- "app/views/admin/events/_nested_comments.html.haml"
|
||||||
|
- "app/views/admin/events/_proposal.html.haml"
|
||||||
|
- "app/views/admin/events/_voting.html.haml"
|
||||||
|
- "app/views/admin/events/_voting_index.html.haml"
|
||||||
|
- "app/views/admin/events/index.html.haml"
|
||||||
|
- "app/views/admin/events/registrations.html.haml"
|
||||||
|
- "app/views/admin/events/show.html.haml"
|
||||||
|
- "app/views/admin/lodgings/_form.html.haml"
|
||||||
|
- "app/views/admin/lodgings/index.html.haml"
|
||||||
|
- "app/views/admin/organizations/_form.html.haml"
|
||||||
|
- "app/views/admin/organizations/index.html.haml"
|
||||||
|
- "app/views/admin/programs/_form.html.haml"
|
||||||
|
- "app/views/admin/programs/show.html.haml"
|
||||||
|
- "app/views/admin/questions/_form.html.haml"
|
||||||
|
- "app/views/admin/questions/_questions.html.haml"
|
||||||
|
- "app/views/admin/questions/edit.html.haml"
|
||||||
|
- "app/views/admin/questions/index.html.haml"
|
||||||
|
- "app/views/admin/questions/show.html.haml"
|
||||||
|
- "app/views/admin/registration_periods/_form.html.haml"
|
||||||
|
- "app/views/admin/registration_periods/show.html.haml"
|
||||||
|
- "app/views/admin/registrations/edit.html.haml"
|
||||||
|
- "app/views/admin/registrations/index.html.haml"
|
||||||
|
- "app/views/admin/reports/_all_events.html.haml"
|
||||||
|
- "app/views/admin/reports/_events_with_requirements.html.haml"
|
||||||
|
- "app/views/admin/reports/_events_without_commercials.html.haml"
|
||||||
|
- "app/views/admin/reports/_missing_speakers.html.haml"
|
||||||
|
- "app/views/admin/resources/_form.html.haml"
|
||||||
|
- "app/views/admin/resources/index.html.haml"
|
||||||
|
- "app/views/admin/resources/show.html.haml"
|
||||||
|
- "app/views/admin/roles/_form.html.haml"
|
||||||
|
- "app/views/admin/roles/_users.html.haml"
|
||||||
|
- "app/views/admin/roles/_users_with_org_admin_role.haml"
|
||||||
|
- "app/views/admin/roles/index.html.haml"
|
||||||
|
- "app/views/admin/roles/show.html.haml"
|
||||||
|
- "app/views/admin/rooms/_form.html.haml"
|
||||||
|
- "app/views/admin/rooms/index.html.haml"
|
||||||
|
- "app/views/admin/schedules/_day_tab.html.haml"
|
||||||
|
- "app/views/admin/schedules/_event.html.haml"
|
||||||
|
- "app/views/admin/schedules/index.html.haml"
|
||||||
|
- "app/views/admin/schedules/show.html.haml"
|
||||||
|
- "app/views/admin/splashpages/_form.html.haml"
|
||||||
|
- "app/views/admin/splashpages/show.html.haml"
|
||||||
|
- "app/views/admin/sponsors/_form.html.haml"
|
||||||
|
- "app/views/admin/sponsors/index.html.haml"
|
||||||
|
- "app/views/admin/sponsorship_levels/_form.html.haml"
|
||||||
|
- "app/views/admin/sponsorship_levels/index.html.haml"
|
||||||
|
- "app/views/admin/targets/_form.html.haml"
|
||||||
|
- "app/views/admin/targets/index.html.haml"
|
||||||
|
- "app/views/admin/tickets/_form.html.haml"
|
||||||
|
- "app/views/admin/tickets/index.html.haml"
|
||||||
|
- "app/views/admin/tickets/show.html.haml"
|
||||||
|
- "app/views/admin/tracks/_form.html.haml"
|
||||||
|
- "app/views/admin/tracks/index.html.haml"
|
||||||
|
- "app/views/admin/tracks/show.html.haml"
|
||||||
|
- "app/views/admin/users/_event_registrations.html.haml"
|
||||||
|
- "app/views/admin/users/_form.html.haml"
|
||||||
|
- "app/views/admin/users/_submissions.html.haml"
|
||||||
|
- "app/views/admin/users/index.html.haml"
|
||||||
|
- "app/views/admin/users/show.html.haml"
|
||||||
|
- "app/views/admin/venues/_form.html.haml"
|
||||||
|
- "app/views/admin/venues/show.html.haml"
|
||||||
|
- "app/views/admin/versions/_object_desc_and_link.html.haml"
|
||||||
|
- "app/views/admin/versions/index.html.haml"
|
||||||
|
- "app/views/admin/volunteers/index.html.haml"
|
||||||
|
- "app/views/booths/_form.html.haml"
|
||||||
|
- "app/views/booths/index.html.haml"
|
||||||
|
- "app/views/booths/show.html.haml"
|
||||||
|
- "app/views/commercials/edit.html.haml"
|
||||||
|
- "app/views/commercials/new.html.haml"
|
||||||
|
- "app/views/conference_registrations/_form.html.haml"
|
||||||
|
- "app/views/conference_registrations/_questions.html.haml"
|
||||||
|
- "app/views/conference_registrations/_registration_info.html.haml"
|
||||||
|
- "app/views/conference_registrations/_volunteer.html.haml"
|
||||||
|
- "app/views/conference_registrations/show.html.haml"
|
||||||
|
- "app/views/conferences/_booths.html.haml"
|
||||||
|
- "app/views/conferences/_call_for_paper.html.haml"
|
||||||
|
- "app/views/conferences/_conference_details.html.haml"
|
||||||
|
- "app/views/conferences/_gallery.html.haml"
|
||||||
|
- "app/views/conferences/_lodging.html.haml"
|
||||||
|
- "app/views/conferences/_program.html.haml"
|
||||||
|
- "app/views/conferences/_registration.html.haml"
|
||||||
|
- "app/views/conferences/_schedule_splashpage.html.haml"
|
||||||
|
- "app/views/conferences/_sponsors.html.haml"
|
||||||
|
- "app/views/conferences/_tickets.html.haml"
|
||||||
|
- "app/views/conferences/_venue.html.haml"
|
||||||
|
- "app/views/conferences/_venue_map.html.haml"
|
||||||
|
- "app/views/conferences/index.html.haml"
|
||||||
|
- "app/views/conferences/show.html.haml"
|
||||||
|
- "app/views/devise/confirmations/new.html.haml"
|
||||||
|
- "app/views/devise/ichain_sessions/new.html.haml"
|
||||||
|
- "app/views/devise/ichain_sessions/new_test.html.haml"
|
||||||
|
- "app/views/devise/passwords/edit.html.haml"
|
||||||
|
- "app/views/devise/passwords/new.html.haml"
|
||||||
|
- "app/views/devise/registrations/_volunteeruser.html.haml"
|
||||||
|
- "app/views/devise/registrations/edit.html.haml"
|
||||||
|
- "app/views/devise/registrations/new.html.haml"
|
||||||
|
- "app/views/devise/sessions/new.html.haml"
|
||||||
|
- "app/views/devise/shared/_help.html.haml"
|
||||||
|
- "app/views/devise/shared/_links.html.haml"
|
||||||
|
- "app/views/devise/shared/_openid_links.html.haml"
|
||||||
|
- "app/views/devise/shared/_sign_in_form_embedded.html.haml"
|
||||||
|
- "app/views/devise/shared/_sign_up_form_embedded.html.haml"
|
||||||
|
- "app/views/layouts/_admin_sidebar.html.haml"
|
||||||
|
- "app/views/layouts/_admin_sidebar_index.html.haml"
|
||||||
|
- "app/views/layouts/_messages.html.haml"
|
||||||
|
- "app/views/layouts/_navigation.html.haml"
|
||||||
|
- "app/views/layouts/_user_menu.html.haml"
|
||||||
|
- "app/views/layouts/application.html.haml"
|
||||||
|
- "app/views/organizations/index.html.haml"
|
||||||
|
- "app/views/payments/_payment.html.haml"
|
||||||
|
- "app/views/proposals/_form.html.haml"
|
||||||
|
- "app/views/proposals/_proposal_form.html.haml"
|
||||||
|
- "app/views/proposals/_tooltip.html.haml"
|
||||||
|
- "app/views/proposals/index.html.haml"
|
||||||
|
- "app/views/proposals/new.html.haml"
|
||||||
|
- "app/views/proposals/registrations.html.haml"
|
||||||
|
- "app/views/proposals/show.html.haml"
|
||||||
|
- "app/views/schedules/_carousel.html.haml"
|
||||||
|
- "app/views/schedules/_event.html.haml"
|
||||||
|
- "app/views/schedules/_schedule.html.haml"
|
||||||
|
- "app/views/schedules/_schedule_item.html.haml"
|
||||||
|
- "app/views/schedules/_schedule_tabs.html.haml"
|
||||||
|
- "app/views/schedules/events.html.haml"
|
||||||
|
- "app/views/schedules/show.html.haml"
|
||||||
|
- "app/views/schedules/show.xml.haml"
|
||||||
|
- "app/views/shared/_changelog_actions.haml"
|
||||||
|
- "app/views/shared/_dynamic_association.html.haml"
|
||||||
|
- "app/views/shared/_media_item.html.haml"
|
||||||
|
- "app/views/shared/_media_items.html.haml"
|
||||||
|
- "app/views/shared/_object_changes.html.haml"
|
||||||
|
- "app/views/tickets/_ticket.html.haml"
|
||||||
|
- "app/views/tickets/index.html.haml"
|
||||||
|
- "app/views/users/edit.html.haml"
|
||||||
|
- "app/views/users/show.html.haml"
|
||||||
|
- "app/views/admin/cfps/index.html.haml"
|
||||||
|
- "app/views/tracks/_form.html.haml"
|
||||||
|
- "app/views/tracks/index.html.haml"
|
||||||
|
- "app/views/tracks/show.html.haml"
|
||||||
|
- "app/views/conferences/_call_for_tracks.html.haml"
|
||||||
|
- "app/views/admin/tracks/_change_state_dropdown.html.haml"
|
||||||
|
- "app/views/proposals/_encouragement_text.html.haml"
|
||||||
|
- "app/views/admin/schedules/_form.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 223
|
||||||
|
InstanceVariables:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/booths/_change_state_dropdown.html.haml"
|
||||||
|
- "app/views/admin/campaigns/_form.html.haml"
|
||||||
|
- "app/views/admin/cfps/_booths_cfp.html.haml"
|
||||||
|
- "app/views/admin/cfps/_form.html.haml"
|
||||||
|
- "app/views/admin/conferences/_todo_list.html.haml"
|
||||||
|
- "app/views/admin/difficulty_levels/_form.html.haml"
|
||||||
|
- "app/views/admin/event_types/_form.html.haml"
|
||||||
|
- "app/views/admin/events/_change_state_dropdown.html.haml"
|
||||||
|
- "app/views/admin/events/_form.html.haml"
|
||||||
|
- "app/views/admin/events/_proposal.html.haml"
|
||||||
|
- "app/views/admin/events/_voting.html.haml"
|
||||||
|
- "app/views/admin/events/_voting_index.html.haml"
|
||||||
|
- "app/views/admin/lodgings/_form.html.haml"
|
||||||
|
- "app/views/admin/organizations/_form.html.haml"
|
||||||
|
- "app/views/admin/questions/_questions.html.haml"
|
||||||
|
- "app/views/admin/registration_periods/_form.html.haml"
|
||||||
|
- "app/views/admin/reports/_all_events.html.haml"
|
||||||
|
- "app/views/admin/reports/_events_with_requirements.html.haml"
|
||||||
|
- "app/views/admin/reports/_events_without_commercials.html.haml"
|
||||||
|
- "app/views/admin/reports/_missing_speakers.html.haml"
|
||||||
|
- "app/views/admin/roles/_form.html.haml"
|
||||||
|
- "app/views/admin/roles/_users.html.haml"
|
||||||
|
- "app/views/admin/rooms/_form.html.haml"
|
||||||
|
- "app/views/admin/schedules/_day_tab.html.haml"
|
||||||
|
- "app/views/admin/schedules/_event.html.haml"
|
||||||
|
- "app/views/admin/splashpages/_form.html.haml"
|
||||||
|
- "app/views/admin/sponsors/_form.html.haml"
|
||||||
|
- "app/views/admin/sponsorship_levels/_form.html.haml"
|
||||||
|
- "app/views/admin/tickets/_form.html.haml"
|
||||||
|
- "app/views/admin/tracks/_form.html.haml"
|
||||||
|
- "app/views/admin/users/_form.html.haml"
|
||||||
|
- "app/views/admin/users/_submissions.html.haml"
|
||||||
|
- "app/views/admin/venues/_form.html.haml"
|
||||||
|
- "app/views/conference_registrations/_form.html.haml"
|
||||||
|
- "app/views/conference_registrations/_registration_info.html.haml"
|
||||||
|
- "app/views/conference_registrations/_volunteer.html.haml"
|
||||||
|
- "app/views/conferences/_call_for_paper.html.haml"
|
||||||
|
- "app/views/conferences/_lodging.html.haml"
|
||||||
|
- "app/views/conferences/_program.html.haml"
|
||||||
|
- "app/views/conferences/_registration.html.haml"
|
||||||
|
- "app/views/conferences/_schedule_splashpage.html.haml"
|
||||||
|
- "app/views/conferences/_sponsors.html.haml"
|
||||||
|
- "app/views/conferences/_tickets.html.haml"
|
||||||
|
- "app/views/conferences/_venue.html.haml"
|
||||||
|
- "app/views/conferences/_venue_map.html.haml"
|
||||||
|
- "app/views/layouts/_admin_sidebar.html.haml"
|
||||||
|
- "app/views/layouts/_user_menu.html.haml"
|
||||||
|
- "app/views/payments/_payment.html.haml"
|
||||||
|
- "app/views/proposals/_encouragement_text.html.haml"
|
||||||
|
- "app/views/proposals/_form.html.haml"
|
||||||
|
- "app/views/proposals/_proposal_form.html.haml"
|
||||||
|
- "app/views/schedules/_carousel.html.haml"
|
||||||
|
- "app/views/schedules/_event.html.haml"
|
||||||
|
- "app/views/schedules/_schedule.html.haml"
|
||||||
|
- "app/views/schedules/_schedule_item.html.haml"
|
||||||
|
- "app/views/schedules/_schedule_tabs.html.haml"
|
||||||
|
- "app/views/admin/cfps/_events_cfp.html.haml"
|
||||||
|
- "app/views/tracks/_form.html.haml"
|
||||||
|
- "app/views/admin/cfps/_tracks_cfp.html.haml"
|
||||||
|
- "app/views/conferences/_call_for_tracks.html.haml"
|
||||||
|
- "app/views/admin/tracks/_change_state_dropdown.html.haml"
|
||||||
|
- "app/views/admin/schedules/_form.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 32
|
||||||
|
IdNames:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/cfps/show.html.haml"
|
||||||
|
- "app/views/admin/comments/index.html.haml"
|
||||||
|
- "app/views/admin/conferences/index.html.haml"
|
||||||
|
- "app/views/admin/conferences/show.html.haml"
|
||||||
|
- "app/views/admin/difficulty_levels/index.html.haml"
|
||||||
|
- "app/views/admin/event_types/index.html.haml"
|
||||||
|
- "app/views/admin/programs/show.html.haml"
|
||||||
|
- "app/views/admin/questions/show.html.haml"
|
||||||
|
- "app/views/admin/roles/show.html.haml"
|
||||||
|
- "app/views/admin/schedules/index.html.haml"
|
||||||
|
- "app/views/admin/sponsorship_levels/index.html.haml"
|
||||||
|
- "app/views/admin/users/_event_registrations.html.haml"
|
||||||
|
- "app/views/admin/users/show.html.haml"
|
||||||
|
- "app/views/users/edit.html.haml"
|
||||||
|
- "app/views/admin/cfps/_events_cfp.html.haml"
|
||||||
|
- "app/views/admin/cfps/_tracks_cfp.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 4
|
||||||
|
UnnecessaryInterpolation:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/conferences/_doughnut_chart.html.haml"
|
||||||
|
- "app/views/admin/conferences/_recent_submissions.html.haml"
|
||||||
|
- "app/views/proposals/_proposal_form.html.haml"
|
||||||
|
- "app/views/proposals/new.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 48
|
||||||
|
UnnecessaryStringOutput:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/conferences/_targets.html.haml"
|
||||||
|
- "app/views/admin/event_types/index.html.haml"
|
||||||
|
- "app/views/admin/events/show.html.haml"
|
||||||
|
- "app/views/admin/users/_submissions.html.haml"
|
||||||
|
- "app/views/admin/venues/show.html.haml"
|
||||||
|
- "app/views/admin/versions/_object_desc_and_link.html.haml"
|
||||||
|
- "app/views/admin/volunteers/show.html.haml"
|
||||||
|
- "app/views/conference_registrations/show.html.haml"
|
||||||
|
- "app/views/conferences/_call_for_paper.html.haml"
|
||||||
|
- "app/views/conferences/_conference_details.html.haml"
|
||||||
|
- "app/views/conferences/_program.html.haml"
|
||||||
|
- "app/views/conferences/_venue.html.haml"
|
||||||
|
- "app/views/conferences/show.html.haml"
|
||||||
|
- "app/views/devise/registrations/edit.html.haml"
|
||||||
|
- "app/views/proposals/_encouragement_text.html.haml"
|
||||||
|
- "app/views/proposals/_form.html.haml"
|
||||||
|
- "app/views/users/edit.html.haml"
|
||||||
|
- "app/views/users/show.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 268
|
||||||
|
SpaceInsideHashAttributes:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/conferences/_todo_list.html.haml"
|
||||||
|
- "app/views/admin/emails/index.html.haml"
|
||||||
|
- "app/views/admin/questions/_form.html.haml"
|
||||||
|
- "app/views/admin/questions/index.html.haml"
|
||||||
|
- "app/views/admin/registrations/index.html.haml"
|
||||||
|
- "app/views/admin/reports/_all_events.html.haml"
|
||||||
|
- "app/views/admin/reports/index.html.haml"
|
||||||
|
- "app/views/admin/schedules/_day_tab.html.haml"
|
||||||
|
- "app/views/admin/schedules/_event.html.haml"
|
||||||
|
- "app/views/admin/schedules/index.html.haml"
|
||||||
|
- "app/views/admin/schedules/show.html.haml"
|
||||||
|
- "app/views/admin/sponsorship_levels/index.html.haml"
|
||||||
|
- "app/views/admin/targets/index.html.haml"
|
||||||
|
- "app/views/admin/tickets/show.html.haml"
|
||||||
|
- "app/views/admin/tracks/index.html.haml"
|
||||||
|
- "app/views/admin/users/show.html.haml"
|
||||||
|
- "app/views/admin/venues/_form.html.haml"
|
||||||
|
- "app/views/admin/venues/show.html.haml"
|
||||||
|
- "app/views/conference_registrations/_form.html.haml"
|
||||||
|
- "app/views/conference_registrations/_ticket.html.haml"
|
||||||
|
- "app/views/conference_registrations/_volunteer.html.haml"
|
||||||
|
- "app/views/conferences/_venue.html.haml"
|
||||||
|
- "app/views/conferences/_venue_map.html.haml"
|
||||||
|
- "app/views/conferences/index.html.haml"
|
||||||
|
- "app/views/devise/shared/_help.html.haml"
|
||||||
|
- "app/views/devise/shared/_openid_links.html.haml"
|
||||||
|
- "app/views/devise/shared/_sign_in_form_embedded.html.haml"
|
||||||
|
- "app/views/layouts/_admin_sidebar.html.haml"
|
||||||
|
- "app/views/layouts/_admin_sidebar_index.html.haml"
|
||||||
|
- "app/views/layouts/_messages.html.haml"
|
||||||
|
- "app/views/layouts/_navigation.html.haml"
|
||||||
|
- "app/views/layouts/application.html.haml"
|
||||||
|
- "app/views/payments/_payment.html.haml"
|
||||||
|
- "app/views/proposals/_form.html.haml"
|
||||||
|
- "app/views/proposals/_tooltip.html.haml"
|
||||||
|
- "app/views/proposals/index.html.haml"
|
||||||
|
- "app/views/proposals/new.html.haml"
|
||||||
|
- "app/views/proposals/show.html.haml"
|
||||||
|
- "app/views/schedules/_carousel.html.haml"
|
||||||
|
- "app/views/schedules/_schedule_item.html.haml"
|
||||||
|
- "app/views/shared/_changelog_actions.haml"
|
||||||
|
- "app/views/shared/_dynamic_association.html.haml"
|
||||||
|
- "app/views/shared/_media_item.html.haml"
|
||||||
|
- "app/views/shared/_media_items.html.haml"
|
||||||
|
- "app/views/shared/_object_changes.html.haml"
|
||||||
|
- "app/views/tickets/_ticket.html.haml"
|
||||||
|
- "app/views/tickets/index.html.haml"
|
||||||
|
- "app/views/tracks/index.html.haml"
|
||||||
|
- "app/views/tracks/show.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 23
|
||||||
|
ClassesBeforeIds:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/emails/index.html.haml"
|
||||||
|
- "app/views/admin/events/show.html.haml"
|
||||||
|
- "app/views/admin/reports/index.html.haml"
|
||||||
|
- "app/views/admin/users/show.html.haml"
|
||||||
|
- "app/views/admin/venues/_form.html.haml"
|
||||||
|
- "app/views/conferences/index.html.haml"
|
||||||
|
- "app/views/devise/shared/_help.html.haml"
|
||||||
|
- "app/views/devise/shared/_sign_in_form_embedded.html.haml"
|
||||||
|
- "app/views/layouts/_navigation.html.haml"
|
||||||
|
- "app/views/proposals/_form.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 55
|
||||||
|
SpaceBeforeScript:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/events/_form.html.haml"
|
||||||
|
- "app/views/admin/events/index.html.haml"
|
||||||
|
- "app/views/admin/registrations/index.html.haml"
|
||||||
|
- "app/views/admin/splashpages/show.html.haml"
|
||||||
|
- "app/views/admin/sponsors/_form.html.haml"
|
||||||
|
- "app/views/admin/targets/_form.html.haml"
|
||||||
|
- "app/views/admin/tracks/_form.html.haml"
|
||||||
|
- "app/views/admin/tracks/show.html.haml"
|
||||||
|
- "app/views/admin/venues/show.html.haml"
|
||||||
|
- "app/views/admin/versions/index.html.haml"
|
||||||
|
- "app/views/booths/index.html.haml"
|
||||||
|
- "app/views/conference_registrations/_form.html.haml"
|
||||||
|
- "app/views/conference_registrations/_ticket.html.haml"
|
||||||
|
- "app/views/conference_registrations/show.html.haml"
|
||||||
|
- "app/views/conferences/_lodging.html.haml"
|
||||||
|
- "app/views/conferences/_schedule_splashpage.html.haml"
|
||||||
|
- "app/views/conferences/_sponsors.html.haml"
|
||||||
|
- "app/views/conferences/_tickets.html.haml"
|
||||||
|
- "app/views/conferences/_venue.html.haml"
|
||||||
|
- "app/views/conferences/index.html.haml"
|
||||||
|
- "app/views/layouts/_admin.html.haml"
|
||||||
|
- "app/views/layouts/_navigation.html.haml"
|
||||||
|
- "app/views/layouts/_user_menu.html.haml"
|
||||||
|
- "app/views/layouts/application.html.haml"
|
||||||
|
- "app/views/proposals/_encouragement_text.html.haml"
|
||||||
|
- "app/views/proposals/new.html.haml"
|
||||||
|
- "app/views/proposals/registrations.html.haml"
|
||||||
|
- "app/views/proposals/show.html.haml"
|
||||||
|
- "app/views/schedules/events.html.haml"
|
||||||
|
- "app/views/schedules/show.xml.haml"
|
||||||
|
- "app/views/tickets/index.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 14
|
||||||
|
ConsecutiveSilentScripts:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/booths/_change_state_dropdown.html.haml"
|
||||||
|
- "app/views/admin/events/index.html.haml"
|
||||||
|
- "app/views/admin/schedules/_day_tab.html.haml"
|
||||||
|
- "app/views/admin/schedules/_event.html.haml"
|
||||||
|
- "app/views/admin/versions/_object_desc_and_link.html.haml"
|
||||||
|
- "app/views/booths/index.html.haml"
|
||||||
|
- "app/views/schedules/_carousel.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 29
|
||||||
|
TrailingWhitespace:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/organizations/_form.html.haml"
|
||||||
|
- "app/views/admin/users/index.html.haml"
|
||||||
|
- "app/views/admin/users/show.html.haml"
|
||||||
|
- "app/views/admin/volunteers/index.html.haml"
|
||||||
|
- "app/views/admin/volunteers/show.html.haml"
|
||||||
|
- "app/views/conference_registrations/_volunteer.html.haml"
|
||||||
|
- "app/views/devise/passwords/new.html.haml"
|
||||||
|
- "app/views/payments/new.html.haml"
|
||||||
|
- "app/views/tickets/index.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 2
|
||||||
|
FinalNewline:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/registrations/index.csv.haml"
|
||||||
|
- "app/views/layouts/_admin.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
ImplicitDiv:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/registrations/index.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 9
|
||||||
|
MultilinePipe:
|
||||||
|
exclude:
|
||||||
|
- "app/views/admin/schedules/_day_tab.html.haml"
|
||||||
|
- "app/views/admin/schedules/_event.html.haml"
|
||||||
|
- "app/views/schedules/_carousel.html.haml"
|
||||||
|
- "app/views/schedules/_event.html.haml"
|
||||||
|
- "app/views/schedules/_schedule_item.html.haml"
|
||||||
|
|
||||||
|
# Offense count: 7
|
||||||
|
ClassAttributeWithStaticValue:
|
||||||
|
exclude:
|
||||||
|
- "app/views/conferences/_gallery.html.haml"
|
||||||
|
- "app/views/layouts/_navigation.html.haml"
|
||||||
|
- "app/views/schedules/events.html.haml"
|
||||||
144
.rubocop.yml
144
.rubocop.yml
|
|
@ -1,127 +1,7 @@
|
||||||
Rails:
|
# Inherit style from another configuration
|
||||||
Enabled: true
|
|
||||||
inherit_from: .rubocop_todo.yml
|
inherit_from: .rubocop_todo.yml
|
||||||
|
|
||||||
Style/HashSyntax:
|
# Apply rule to all cops
|
||||||
Enabled: true
|
|
||||||
EnforcedStyle: ruby19
|
|
||||||
|
|
||||||
# Things deprecated in current ruby API
|
|
||||||
Lint/DeprecatedClassMethods:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Do not compare with nil. Use .nil? instead
|
|
||||||
Style/NilComparison:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Use one empty line between method definitions
|
|
||||||
Style/EmptyLineBetweenDefs:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# There should be only one empty line in designated place
|
|
||||||
Style/EmptyLines:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Keep a blank line before and after private.
|
|
||||||
Style/EmptyLinesAroundAccessModifier:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Use hash literal {} instead of Hash.new
|
|
||||||
Style/EmptyLiteral:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Prefer `each` over `for i`
|
|
||||||
Style/For:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Wrap your assignment in condition if you mean it, otherwise it is most likely equality check
|
|
||||||
Lint/AssignmentInCondition:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Align blocks of code properly
|
|
||||||
Lint/BlockAlignment:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Do not use literal in conditions. We have it enabled for now
|
|
||||||
Lint/LiteralInCondition:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
# Prefer `Kernel#loop -> break` over `begin -> while`
|
|
||||||
Lint/Loop:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# do not put space before arguments when they are in parentheses
|
|
||||||
Lint/ParenthesesAsGroupedExpression:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Do not rescue Exceptions class itself
|
|
||||||
Lint/RescueException:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# do not shadow local variables in blocks, choose other name
|
|
||||||
Lint/ShadowingOuterLocalVariable:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# use _ or variable_name to explicitly mark variable as unused
|
|
||||||
Lint/UnusedBlockArgument:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# use _ or _argument_name to explicitly mark argument as unused
|
|
||||||
Lint/UnusedMethodArgument:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# avoid useless assignment
|
|
||||||
Lint/UselessAssignment:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Do not use variables in void context
|
|
||||||
Lint/Void:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Align the elements of a hash literal if they span more than one line
|
|
||||||
Style/AlignHash:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Align the parameters of a method call if they span more than one line
|
|
||||||
Style/AlignParameters:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Use && instead of and, use || instead of or
|
|
||||||
Style/AndOr:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# avoid deep blocks nesting
|
|
||||||
Metrics/BlockNesting:
|
|
||||||
Max: 4
|
|
||||||
|
|
||||||
Metrics/ClassLength:
|
|
||||||
Max: 300
|
|
||||||
Exclude:
|
|
||||||
- 'app/models/conference.rb'
|
|
||||||
|
|
||||||
# avoid redundunt curly braces when it is obvious that hash is used
|
|
||||||
Style/BracesAroundHashParameters:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
# Checks that operators have space around them, except for ** which should not have surrounding space.
|
|
||||||
Style/SpaceAroundOperators:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
Style/CaseEquality:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
Style/ClassAndModuleChildren:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
Style/StringLiterals:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
Style/TrailingBlankLines:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
Style/TrailingWhitespace:
|
|
||||||
Enabled: true
|
|
||||||
|
|
||||||
AllCops:
|
AllCops:
|
||||||
Include:
|
Include:
|
||||||
- '**/Rakefile'
|
- '**/Rakefile'
|
||||||
|
|
@ -132,3 +12,23 @@ AllCops:
|
||||||
- 'bundle/**/*'
|
- 'bundle/**/*'
|
||||||
- 'config/**/*'
|
- 'config/**/*'
|
||||||
- 'bin/*'
|
- 'bin/*'
|
||||||
|
|
||||||
|
|
||||||
|
#################### Metrics ###############################
|
||||||
|
|
||||||
|
# Avoid deep blocks nesting
|
||||||
|
Metrics/BlockNesting:
|
||||||
|
Max: 4
|
||||||
|
|
||||||
|
# Avoid writing classes that are more than 300 lines
|
||||||
|
Metrics/ClassLength:
|
||||||
|
Max: 300
|
||||||
|
Exclude:
|
||||||
|
- 'app/models/conference.rb'
|
||||||
|
|
||||||
|
Metrics/BlockLength:
|
||||||
|
Exclude:
|
||||||
|
- 'spec/models/conference_spec.rb'
|
||||||
|
- 'spec/features/ability_spec.rb'
|
||||||
|
- 'spec/models/ability_spec.rb'
|
||||||
|
- 'spec/models/admin_ability_spec.rb'
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
12
.travis.yml
12
.travis.yml
|
|
@ -3,12 +3,12 @@ dist: trusty
|
||||||
language: ruby
|
language: ruby
|
||||||
cache: bundler
|
cache: bundler
|
||||||
rvm:
|
rvm:
|
||||||
- 2.2.3
|
- 2.4.0
|
||||||
before_install:
|
before_install:
|
||||||
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
||||||
- "echo `phantomjs -v`"
|
- "echo `phantomjs -v`"
|
||||||
addons:
|
addons:
|
||||||
mariadb: '10.1'
|
mariadb: '10.2'
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
on_success: change
|
on_success: change
|
||||||
|
|
@ -24,5 +24,9 @@ before_script:
|
||||||
- mysql -u root -e 'create database osem_test;'
|
- mysql -u root -e 'create database osem_test;'
|
||||||
- RAILS_ENV=test bundle exec rake db:migrate --trace
|
- RAILS_ENV=test bundle exec rake db:migrate --trace
|
||||||
script:
|
script:
|
||||||
- 'bundle exec rubocop -Dc .rubocop.yml'
|
- "./travis_script.sh $TEST_SUITE"
|
||||||
- 'bundle exec rspec --color --format documentation'
|
env:
|
||||||
|
- TEST_SUITE=rspec
|
||||||
|
- TEST_SUITE=linters
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
|
||||||
1
CODE_OF_CONDUCT.md
Normal file
1
CODE_OF_CONDUCT.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
OSEM is part of the openSUSE project. We follow all the [openSUSE Guiding Principles!](http://en.opensuse.org/openSUSE:Guiding_principles) If you think someone doesn't do that, please let us know at maintainers@osem.io
|
||||||
109
CONTRIBUTING.md
109
CONTRIBUTING.md
|
|
@ -71,59 +71,6 @@ You can access the app [localhost:3000](http://localhost:3000). Whatever you cha
|
||||||
* If you are already a contributor and you get a positive review, you can merge your pull-request yourself
|
* If you are already a contributor and you get a positive review, you can merge your pull-request yourself
|
||||||
* If you are not already a contributor please request a merge via the pull-request comments
|
* If you are not already a contributor please request a merge via the pull-request comments
|
||||||
|
|
||||||
### Getting Started
|
|
||||||
|
|
||||||
* When you get involved with OSEM for the first time, you can choose issues labeled as [Junior]( https://github.com/openSUSE/osem/issues?q=is%3Aissue+is%3Aopen+label%3AJunior)
|
|
||||||
* Leave a comment on the issue that you want to work on it
|
|
||||||
* We expect you to work on it and show progress by either opening a PR or commenting on the issue
|
|
||||||
* If you change your mind, and do not want to work on the issue any more, please be fair to others and leave a comment to let us know
|
|
||||||
* Do **not** work on issues that are assigned to others. If you are uncertain, ask and wait for a **contributor** to reply
|
|
||||||
* Avoid working on issues that have no label
|
|
||||||
* If you have opened a new issue, please wait for a contributor to add relevant labels
|
|
||||||
* If an issue is a feature, we should first have a rough idea on how we want to implement it
|
|
||||||
* If there is already such a discussion on the issue, you can go ahead and pick this up
|
|
||||||
* If not, please first leave a comment on how you want to implement it and wait for contributors' feedback
|
|
||||||
|
|
||||||
### Commits
|
|
||||||
* Commit title should be short and descriptive
|
|
||||||
* title (or summary line) is the first line of the commit message
|
|
||||||
* that says what the commit is doing
|
|
||||||
* in no more than 50 characters
|
|
||||||
* starting with a word like 'Fix' or 'Add' or 'Change'
|
|
||||||
* **without** a period (.) at the end
|
|
||||||
* followed by a blank line
|
|
||||||
* Commit messages are
|
|
||||||
* up to 72 characters
|
|
||||||
* with break lines
|
|
||||||
* Reference the issue(s) the commit closes
|
|
||||||
* https://help.github.com/articles/closing-issues-via-commit-messages
|
|
||||||
* If you haven't done so since the beginning, you should reference the issue when you squash your commits
|
|
||||||
|
|
||||||
### Pull Requests workflow
|
|
||||||
Please open a pull request (PR) only when you have finished coding, and your changes are ready to be reviewed for merging.
|
|
||||||
|
|
||||||
* Title
|
|
||||||
* Include a comprehensive title about what this PR is doing
|
|
||||||
* Referencing the issue number on the PR title is not giving any information about what this PR is about
|
|
||||||
* The title should be short (50 characters maximum); you can add more information in the description
|
|
||||||
* Description
|
|
||||||
* Add a couple of lines about what is the problem you are trying to solve and how you have addressed it
|
|
||||||
* Add bullet points about the new things you are introducing, if applicable
|
|
||||||
* Reference the issue(s) you are solving
|
|
||||||
* Add a screenshot of your change, if you are working on something that changes how the app looks like
|
|
||||||
* Automated checks
|
|
||||||
* We automatically run the [test suite](https://github.com/openSUSE/osem/blob/master/CONTRIBUTING.md#test-suite) and security checks on every PR
|
|
||||||
* Check back later to see if all checks were successful, if not, address them or leave a comment to ask for help
|
|
||||||
* Pushing new changes to your PR
|
|
||||||
* Always add **new** commits; this tremendously helps reviewers
|
|
||||||
* Do not squash commits, unless explicitly requested by the reviewer
|
|
||||||
* Take care of your PR
|
|
||||||
* Make sure you check the status of your PR regularly
|
|
||||||
* Address your reviews, make the necessary changes, ask if something is not clear to you
|
|
||||||
* Rebase against newest changes, when needed; we cannot properly review PRs that are not rebased
|
|
||||||
|
|
||||||
Reviewing your PR might take some time, as we are all volunteers. Please be responsive and respectful.
|
|
||||||
|
|
||||||
### Coding Style
|
### Coding Style
|
||||||
We are using [rubocop](https://github.com/bbatsov/rubocop) as a style checker. It is checking code style each time the test suite runs. You can run it locally with
|
We are using [rubocop](https://github.com/bbatsov/rubocop) as a style checker. It is checking code style each time the test suite runs. You can run it locally with
|
||||||
|
|
||||||
|
|
@ -131,7 +78,7 @@ We are using [rubocop](https://github.com/bbatsov/rubocop) as a style checker. I
|
||||||
vagrant exec bundle exec rubocop
|
vagrant exec bundle exec rubocop
|
||||||
```
|
```
|
||||||
|
|
||||||
You can read through current enabled rules in `.rubocop.yml` file. Explanations of the defined [rules](http://rubydoc.info/github/bbatsov/rubocop/master/frames) can be found in modules [Cop::Lint](http://rubydoc.info/github/bbatsov/rubocop/master/Rubocop/Cop/Lint) and [Cop::Style](http://rubydoc.info/github/bbatsov/rubocop/master/Rubocop/Cop/Style).
|
You can read through current enabled rules in `.rubocop.yml` file. Explanations of the defined [rules](http://rubydoc.info/github/bbatsov/rubocop/master/frames) can be found in modules [Cop::Lint](http://rubydoc.info/github/bbatsov/rubocop/master/Rubocop/Cop/Lint) and [Cop::Style](http://rubydoc.info/github/bbatsov/rubocop/master/Rubocop/Cop/Style) and [Cop:Rails](https://rubocop.readthedocs.io/en/latest/cops_rails/).
|
||||||
Additionally you can read through the [ruby style-guide](https://github.com/bbatsov/ruby-style-guide) to better understand core principles.
|
Additionally you can read through the [ruby style-guide](https://github.com/bbatsov/ruby-style-guide) to better understand core principles.
|
||||||
|
|
||||||
### Test Suite
|
### Test Suite
|
||||||
|
|
@ -141,16 +88,6 @@ We are using [rspec](http://rspec.info/)+[capybara](http://jnicklas.github.io/ca
|
||||||
vagrant exec bundle exec rspec
|
vagrant exec bundle exec rspec
|
||||||
```
|
```
|
||||||
|
|
||||||
### Review App of your PR
|
|
||||||
|
|
||||||
OSEM uses [Review Apps](https://devcenter.heroku.com/articles/github-integration-review-apps) on Heroku.
|
|
||||||
|
|
||||||
* The review app can be manually created by a maintainer, and when that happens you will see a relevant message in the PR
|
|
||||||
|
|
||||||
* Please help reviewers by adding the necessary data relevant to your PR,
|
|
||||||
eg. if your PR is doing something related to conference registrations, go to the review app and make sure there is a conference with registrations.
|
|
||||||
|
|
||||||
|
|
||||||
### Email Notifications
|
### Email Notifications
|
||||||
**Note**: We use [letter_opener](https://github.com/ryanb/letter_opener) in development environment. You can check out your mails by visiting [localhost:3000/letter_opener](http://localhost:3000/letter_opener).
|
**Note**: We use [letter_opener](https://github.com/ryanb/letter_opener) in development environment. You can check out your mails by visiting [localhost:3000/letter_opener](http://localhost:3000/letter_opener).
|
||||||
|
|
||||||
|
|
@ -169,41 +106,17 @@ config.ichain_force_test_username = "testuser"
|
||||||
# set email of 'testuser'
|
# set email of 'testuser'
|
||||||
config.ichain_force_test_attributes = {:email => "testuser@example.com"}
|
config.ichain_force_test_attributes = {:email => "testuser@example.com"}
|
||||||
```
|
```
|
||||||
## Labels for issues and PRs
|
|
||||||
...and what they mean!
|
|
||||||
|
|
||||||
1. **Bug**
|
### Using OpenID in developement
|
||||||
* A bug in the application, something is wrong and needs to be fixed!
|
OSEM supports [OpenID](https://openid.net/) logins via [OmniAuth](https://github.com/omniauth/omniauth) and related provider specific gems. OmniAuth provides the ablity to define per-provider mock accounts for testing. The supported providers are Facebook, Google, openSUSE and GitHub. If you want to use the OSEM provided mock accounts you need to set the appropriate `OSEM_PROVIDER_KEY` and `OSEM_PROVIDER_SECRET` environment variables to a non empty string in the `.env` file.
|
||||||
* Ideally the issue includes details on how to reproduce the bug
|
|
||||||
* Reproduce the bug in master branch, and send a PR that solves it
|
e.g.
|
||||||
2. **Design**
|
```
|
||||||
* Related to the looks and/or usability of the application; needs attention from someone who understands front-end and UX
|
OSEM_GITHUB_KEY='sample'
|
||||||
* If you are good with graphics and design, give it a shot!
|
OSEM_GITHUB_SECRET='sample'
|
||||||
3. **Documentation**
|
```
|
||||||
* Related to the documentation of our application, eg our INSTALL.md file or a wiki page with instructions on how to use the app, or part of it.
|
|
||||||
* If you are working on a documentation issue, make sure you are covering all cases.
|
If you don't already have a `.env` file you can use the `dotenv.example` as a template.
|
||||||
4. **Epic**
|
|
||||||
* We may, or may not, solve this, thus it is epic. It's bigger than a feature request, because it fundamentally changes or affects the app, or a significant part of it.
|
|
||||||
* Do **not** work on this without prior discussion with the maintainers, it's called epic for a reason!
|
|
||||||
5. **Feature**
|
|
||||||
* This is a new feature for something new in the app!
|
|
||||||
* If an issue is labeled *Feature*, don't work on the issue, unless the maintainers have decided on how to proceed
|
|
||||||
* Ideally, leave a comment with your proposed solution in the issue and wait for feedback
|
|
||||||
6. **Grooming**
|
|
||||||
* This is working, but could look better, thus needs some attention and grooming.
|
|
||||||
7. **Hacktoberfest**
|
|
||||||
* This is for the issues included in the coding event of Hacktoberfest. You can ignore it, when the event is not on
|
|
||||||
8. **in progress**
|
|
||||||
9. **Junior**
|
|
||||||
* For new comers! RoR beginners or people unfamiliar with the application. Where you must start if you are interested in a mentoring program we participate in.
|
|
||||||
10. **need feedback**
|
|
||||||
* Maintainers' attention is needed to decide if this is something we want in the app, and/or how it should be implemented
|
|
||||||
11. **Operation**
|
|
||||||
12. **ready**
|
|
||||||
13. **Refactorization**
|
|
||||||
* Our code needs to be re-written; to avoid code duplication, or make the code more readable, or do things in a simpler way!
|
|
||||||
14. **Research**
|
|
||||||
* Ideas to explore; and think if there is anything we want to include in our app.
|
|
||||||
|
|
||||||
## Code of Conduct
|
## Code of Conduct
|
||||||
OSEM is part of the openSUSE project. We follow all the [openSUSE Guiding Principles!](http://en.opensuse.org/openSUSE:Guiding_principles) If you think someone doesn't do that, please let us know at maintainers@osem.io
|
OSEM is part of the openSUSE project. We follow all the [openSUSE Guiding Principles!](http://en.opensuse.org/openSUSE:Guiding_principles) If you think someone doesn't do that, please let us know at maintainers@osem.io
|
||||||
|
|
|
||||||
45
Dockerfile
Normal file
45
Dockerfile
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
FROM ruby:2.3
|
||||||
|
|
||||||
|
MAINTAINER TheAssassin <theassassin@users.noreply.github.com>
|
||||||
|
|
||||||
|
# required for compiling assets
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y nodejs nodejs-legacy mariadb-client imagemagick
|
||||||
|
|
||||||
|
# used to run the container without root permissions
|
||||||
|
RUN adduser --home /osem/ --system --group --disabled-login --disabled-password osem
|
||||||
|
|
||||||
|
# required to detect when the database is up and running in init.sh
|
||||||
|
RUN cd /usr/bin && \
|
||||||
|
wget https://github.com/jwilder/dockerize/releases/download/v0.3.0/dockerize-linux-amd64-v0.3.0.tar.gz -O dockerize.tar.gz && \
|
||||||
|
echo "36e8319cdf9d2b07340f456ec61cfa0f495ec6c130b02ad9c116fd55a5c43fa1 dockerize.tar.gz" | sha256sum -c && \
|
||||||
|
tar -xf dockerize.tar.gz && \
|
||||||
|
rm dockerize.tar.gz
|
||||||
|
|
||||||
|
# explicitly add Gemfile and install dependencies using bundler to make use of
|
||||||
|
# Docker's caching
|
||||||
|
WORKDIR /osem/
|
||||||
|
COPY Gemfile /osem/
|
||||||
|
COPY Gemfile.lock /osem/
|
||||||
|
RUN bundle install --without test development
|
||||||
|
|
||||||
|
# add OSEM files and prepare them for use inside a Docker container
|
||||||
|
COPY . /osem/
|
||||||
|
RUN chown osem.osem /osem/ -R && \
|
||||||
|
mv /osem/config/database.yml.docker /osem/config/database.yml
|
||||||
|
|
||||||
|
# data directory is used to cache the secret key in a file
|
||||||
|
ENV DATA_DIR /data
|
||||||
|
RUN install -d -m 0700 -o osem $DATA_DIR
|
||||||
|
VOLUME ["$DATA_DIR"]
|
||||||
|
|
||||||
|
USER osem
|
||||||
|
EXPOSE 9292
|
||||||
|
|
||||||
|
COPY docker/init.sh /init.sh
|
||||||
|
|
||||||
|
# a user could override this if they wanted to serve the static files directly
|
||||||
|
# from a webserver
|
||||||
|
ENV RAILS_SERVE_STATIC_FILES 1
|
||||||
|
|
||||||
|
CMD ["bash", "/init.sh"]
|
||||||
29
Gemfile
29
Gemfile
|
|
@ -6,7 +6,7 @@ if Gem::Version.new(Bundler::VERSION) < Gem::Version.new('1.8.4')
|
||||||
end
|
end
|
||||||
|
|
||||||
# as web framework
|
# as web framework
|
||||||
gem 'rails', '~> 4.2'
|
gem 'rails', '~> 4.2.8'
|
||||||
|
|
||||||
# enables serving assets in production and setting your logger to standard out
|
# enables serving assets in production and setting your logger to standard out
|
||||||
# both of which are required to run an application on a twelve-factor provider
|
# both of which are required to run an application on a twelve-factor provider
|
||||||
|
|
@ -18,10 +18,9 @@ gem 'rails_12factor', group: :production
|
||||||
gem 'responders', '~> 2.0'
|
gem 'responders', '~> 2.0'
|
||||||
|
|
||||||
# as the database for Active Record
|
# as the database for Active Record
|
||||||
|
# choose only one
|
||||||
gem 'mysql2'
|
gem 'mysql2'
|
||||||
|
# gem 'pg'
|
||||||
# for observing records
|
|
||||||
gem 'rails-observers'
|
|
||||||
|
|
||||||
# for tracking data changes
|
# for tracking data changes
|
||||||
gem 'paper_trail'
|
gem 'paper_trail'
|
||||||
|
|
@ -58,7 +57,7 @@ gem 'unobtrusive_flash', '>=3'
|
||||||
gem 'transitions', :require => %w( transitions active_record/transitions )
|
gem 'transitions', :require => %w( transitions active_record/transitions )
|
||||||
|
|
||||||
# for comments
|
# for comments
|
||||||
gem 'awesome_nested_set', '~> 3.0.0.rc.5'
|
gem 'awesome_nested_set', '~> 3.1.3'
|
||||||
gem 'acts_as_commentable_with_threading'
|
gem 'acts_as_commentable_with_threading'
|
||||||
|
|
||||||
# as templating language
|
# as templating language
|
||||||
|
|
@ -84,6 +83,8 @@ gem 'jquery-ui-rails', '~> 4.2.1'
|
||||||
# for languages validation
|
# for languages validation
|
||||||
gem 'iso-639'
|
gem 'iso-639'
|
||||||
|
|
||||||
|
gem 'thor', '0.19.1'
|
||||||
|
|
||||||
# frontend javascripts
|
# frontend javascripts
|
||||||
source 'https://rails-assets.org' do
|
source 'https://rails-assets.org' do
|
||||||
# for placeholder images
|
# for placeholder images
|
||||||
|
|
@ -126,8 +127,11 @@ gem 'country_select'
|
||||||
|
|
||||||
# as PDF generator
|
# as PDF generator
|
||||||
gem 'prawn_rails'
|
gem 'prawn_rails'
|
||||||
|
gem 'rqrcode'
|
||||||
|
gem 'prawn-qrcode', '~> 0.2.2.1'
|
||||||
|
|
||||||
# to render XLS spreadsheets
|
# to render XLS spreadsheets
|
||||||
|
gem 'axlsx', git: 'https://github.com/randym/axlsx.git'
|
||||||
gem 'axlsx_rails'
|
gem 'axlsx_rails'
|
||||||
|
|
||||||
# as error catcher
|
# as error catcher
|
||||||
|
|
@ -193,13 +197,22 @@ gem 'stripe'
|
||||||
# Provides Sprockets implementation for Rails Asset Pipeline
|
# Provides Sprockets implementation for Rails Asset Pipeline
|
||||||
gem 'sprockets-rails'
|
gem 'sprockets-rails'
|
||||||
|
|
||||||
|
# for multiple speakers select on proposal/event forms
|
||||||
|
gem 'selectize-rails'
|
||||||
|
|
||||||
|
# Nokogiri < 1.8.1 is subject to:
|
||||||
|
# CVE-2017-0663, CVE-2017-7375, CVE-2017-7376, CVE-2017-9047, CVE-2017-9048,
|
||||||
|
# CVE-2017-9049, CVE-2017-9050
|
||||||
|
gem 'nokogiri', '>= 1.8.1'
|
||||||
|
|
||||||
# Use guard and spring for testing in development
|
# Use guard and spring for testing in development
|
||||||
group :development do
|
group :development do
|
||||||
# to launch specs when files are modified
|
# to launch specs when files are modified
|
||||||
gem 'guard-rspec', '~> 4.2.8'
|
gem 'guard-rspec'
|
||||||
gem 'spring-commands-rspec'
|
gem 'spring-commands-rspec'
|
||||||
|
gem 'haml_lint', '~> 0.24.0'
|
||||||
# for static code analisys
|
# for static code analisys
|
||||||
gem 'rubocop', require: false
|
gem 'rubocop', '~> 0.49.0', require: false
|
||||||
# as database
|
# as database
|
||||||
gem 'sqlite3'
|
gem 'sqlite3'
|
||||||
# to open mails
|
# to open mails
|
||||||
|
|
@ -214,7 +227,7 @@ end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
# as test framework
|
# as test framework
|
||||||
gem 'rspec-rails'
|
gem 'rspec-rails', '~> 3.5', '>= 3.5.2'
|
||||||
gem 'database_cleaner'
|
gem 'database_cleaner'
|
||||||
gem 'capybara'
|
gem 'capybara'
|
||||||
gem 'poltergeist'
|
gem 'poltergeist'
|
||||||
|
|
|
||||||
388
Gemfile.lock
388
Gemfile.lock
|
|
@ -1,41 +1,50 @@
|
||||||
|
GIT
|
||||||
|
remote: https://github.com/randym/axlsx.git
|
||||||
|
revision: c8ac844572b25fda358cc01d2104720c4c42f450
|
||||||
|
specs:
|
||||||
|
axlsx (2.1.0.pre)
|
||||||
|
htmlentities (~> 4.3.4)
|
||||||
|
mimemagic (~> 0.3)
|
||||||
|
nokogiri (>= 1.6.6)
|
||||||
|
rubyzip (>= 1.2.1)
|
||||||
|
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
remote: https://rails-assets.org/
|
remote: https://rails-assets.org/
|
||||||
specs:
|
specs:
|
||||||
actionmailer (4.2.7.1)
|
actionmailer (4.2.9)
|
||||||
actionpack (= 4.2.7.1)
|
actionpack (= 4.2.9)
|
||||||
actionview (= 4.2.7.1)
|
actionview (= 4.2.9)
|
||||||
activejob (= 4.2.7.1)
|
activejob (= 4.2.9)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||||
actionpack (4.2.7.1)
|
actionpack (4.2.9)
|
||||||
actionview (= 4.2.7.1)
|
actionview (= 4.2.9)
|
||||||
activesupport (= 4.2.7.1)
|
activesupport (= 4.2.9)
|
||||||
rack (~> 1.6)
|
rack (~> 1.6)
|
||||||
rack-test (~> 0.6.2)
|
rack-test (~> 0.6.2)
|
||||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||||
actionview (4.2.7.1)
|
actionview (4.2.9)
|
||||||
activesupport (= 4.2.7.1)
|
activesupport (= 4.2.9)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubis (~> 2.7.0)
|
erubis (~> 2.7.0)
|
||||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
||||||
active_model_serializers (0.9.4)
|
active_model_serializers (0.9.4)
|
||||||
activemodel (>= 3.2)
|
activemodel (>= 3.2)
|
||||||
activejob (4.2.7.1)
|
activejob (4.2.9)
|
||||||
activesupport (= 4.2.7.1)
|
activesupport (= 4.2.9)
|
||||||
globalid (>= 0.3.0)
|
globalid (>= 0.3.0)
|
||||||
activemodel (4.2.7.1)
|
activemodel (4.2.9)
|
||||||
activesupport (= 4.2.7.1)
|
activesupport (= 4.2.9)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
activerecord (4.2.7.1)
|
activerecord (4.2.9)
|
||||||
activemodel (= 4.2.7.1)
|
activemodel (= 4.2.9)
|
||||||
activesupport (= 4.2.7.1)
|
activesupport (= 4.2.9)
|
||||||
arel (~> 6.0)
|
arel (~> 6.0)
|
||||||
activesupport (4.2.7.1)
|
activesupport (4.2.9)
|
||||||
i18n (~> 0.7)
|
i18n (~> 0.7)
|
||||||
json (~> 1.7, >= 1.7.7)
|
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
thread_safe (~> 0.3, >= 0.3.4)
|
thread_safe (~> 0.3, >= 0.3.4)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 1.1)
|
||||||
|
|
@ -48,7 +57,8 @@ GEM
|
||||||
awesome_nested_set (>= 2.0)
|
awesome_nested_set (>= 2.0)
|
||||||
acts_as_list (0.4.0)
|
acts_as_list (0.4.0)
|
||||||
activerecord (>= 3.0)
|
activerecord (>= 3.0)
|
||||||
addressable (2.3.6)
|
addressable (2.5.1)
|
||||||
|
public_suffix (~> 2.0, >= 2.0.2)
|
||||||
ahoy_matey (1.0.0)
|
ahoy_matey (1.0.0)
|
||||||
addressable
|
addressable
|
||||||
browser (>= 0.4.0)
|
browser (>= 0.4.0)
|
||||||
|
|
@ -57,18 +67,13 @@ GEM
|
||||||
request_store
|
request_store
|
||||||
user_agent_parser
|
user_agent_parser
|
||||||
uuidtools
|
uuidtools
|
||||||
arel (6.0.3)
|
arel (6.0.4)
|
||||||
ast (2.2.0)
|
ast (2.3.0)
|
||||||
autoprefixer-rails (5.1.9)
|
autoprefixer-rails (7.1.1)
|
||||||
execjs
|
execjs
|
||||||
json
|
awesome_nested_set (3.1.3)
|
||||||
awesome_nested_set (3.0.0.rc.5)
|
activerecord (>= 4.0.0, < 5.2)
|
||||||
activerecord (>= 4.0.0, < 5)
|
|
||||||
aws_cf_signer (0.1.3)
|
aws_cf_signer (0.1.3)
|
||||||
axlsx (2.0.1)
|
|
||||||
htmlentities (~> 4.3.1)
|
|
||||||
nokogiri (>= 1.4.1)
|
|
||||||
rubyzip (~> 1.2.1)
|
|
||||||
axlsx_rails (0.2.0)
|
axlsx_rails (0.2.0)
|
||||||
axlsx (>= 2.0.1)
|
axlsx (>= 2.0.1)
|
||||||
rails (>= 3.1)
|
rails (>= 3.1)
|
||||||
|
|
@ -82,10 +87,8 @@ GEM
|
||||||
bootstrap3-datetimepicker-rails (3.0.3)
|
bootstrap3-datetimepicker-rails (3.0.3)
|
||||||
momentjs-rails (>= 2.8.1)
|
momentjs-rails (>= 2.8.1)
|
||||||
browser (0.6.0)
|
browser (0.6.0)
|
||||||
builder (3.2.2)
|
builder (3.2.3)
|
||||||
byebug (3.1.2)
|
byebug (9.0.6)
|
||||||
columnize (~> 0.8)
|
|
||||||
debugger-linecache (~> 1.2)
|
|
||||||
cancancan (1.13.1)
|
cancancan (1.13.1)
|
||||||
capybara (2.6.2)
|
capybara (2.6.2)
|
||||||
addressable
|
addressable
|
||||||
|
|
@ -103,28 +106,24 @@ GEM
|
||||||
activesupport (>= 3.2.0)
|
activesupport (>= 3.2.0)
|
||||||
carrierwave
|
carrierwave
|
||||||
fastimage
|
fastimage
|
||||||
celluloid (0.15.2)
|
|
||||||
timers (~> 1.1.0)
|
|
||||||
celluloid-io (0.15.0)
|
|
||||||
celluloid (>= 0.15.0)
|
|
||||||
nio4r (>= 0.5.0)
|
|
||||||
chart-js-rails (0.0.6)
|
chart-js-rails (0.0.6)
|
||||||
railties (> 3.1)
|
railties (> 3.1)
|
||||||
chronic (0.10.2)
|
chronic (0.10.2)
|
||||||
|
chunky_png (1.3.8)
|
||||||
cliver (0.3.2)
|
cliver (0.3.2)
|
||||||
cloudinary (1.1.6)
|
cloudinary (1.1.6)
|
||||||
aws_cf_signer
|
aws_cf_signer
|
||||||
rest-client
|
rest-client
|
||||||
cocoon (1.2.6)
|
cocoon (1.2.6)
|
||||||
coderay (1.1.0)
|
coderay (1.1.1)
|
||||||
coffee-rails (4.1.1)
|
coffee-rails (4.2.2)
|
||||||
coffee-script (>= 2.2.0)
|
coffee-script (>= 2.2.0)
|
||||||
railties (>= 4.0.0, < 5.1.x)
|
railties (>= 4.0.0)
|
||||||
coffee-script (2.4.1)
|
coffee-script (2.4.1)
|
||||||
coffee-script-source
|
coffee-script-source
|
||||||
execjs
|
execjs
|
||||||
coffee-script-source (1.10.0)
|
coffee-script-source (1.12.2)
|
||||||
columnize (0.8.9)
|
concurrent-ruby (1.0.5)
|
||||||
countable-rails (0.0.1)
|
countable-rails (0.0.1)
|
||||||
railties (>= 3.1)
|
railties (>= 3.1)
|
||||||
countries (1.2.5)
|
countries (1.2.5)
|
||||||
|
|
@ -139,18 +138,17 @@ GEM
|
||||||
term-ansicolor (~> 1.3)
|
term-ansicolor (~> 1.3)
|
||||||
thor (~> 0.19.1)
|
thor (~> 0.19.1)
|
||||||
tins (~> 1.6.0)
|
tins (~> 1.6.0)
|
||||||
crack (0.4.2)
|
crack (0.4.3)
|
||||||
safe_yaml (~> 1.0.0)
|
safe_yaml (~> 1.0.0)
|
||||||
currencies (0.4.2)
|
currencies (0.4.2)
|
||||||
daemons (1.1.9)
|
daemons (1.1.9)
|
||||||
dante (0.2.0)
|
dante (0.2.0)
|
||||||
database_cleaner (1.3.0)
|
database_cleaner (1.3.0)
|
||||||
debug_inspector (0.0.2)
|
debug_inspector (0.0.2)
|
||||||
debugger-linecache (1.2.0)
|
delayed_job (4.1.3)
|
||||||
delayed_job (4.1.1)
|
activesupport (>= 3.0, < 5.2)
|
||||||
activesupport (>= 3.0, < 5.0)
|
delayed_job_active_record (4.1.2)
|
||||||
delayed_job_active_record (4.1.0)
|
activerecord (>= 3.0, < 5.2)
|
||||||
activerecord (>= 3.0, < 5)
|
|
||||||
delayed_job (>= 3.0, < 5)
|
delayed_job (>= 3.0, < 5)
|
||||||
devise (4.2.0)
|
devise (4.2.0)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
|
|
@ -160,14 +158,14 @@ GEM
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
devise_ichain_authenticatable (0.3.1)
|
devise_ichain_authenticatable (0.3.1)
|
||||||
devise (>= 2.2)
|
devise (>= 2.2)
|
||||||
diff-lcs (1.2.5)
|
diff-lcs (1.3)
|
||||||
docile (1.1.5)
|
docile (1.1.5)
|
||||||
domain_name (0.5.20160310)
|
domain_name (0.5.20160310)
|
||||||
unf (>= 0.0.5, < 1.0.0)
|
unf (>= 0.0.5, < 1.0.0)
|
||||||
dotenv (2.1.1)
|
dotenv (2.2.1)
|
||||||
dotenv-rails (2.1.1)
|
dotenv-rails (2.2.1)
|
||||||
dotenv (= 2.1.1)
|
dotenv (= 2.2.1)
|
||||||
railties (>= 4.0, < 5.1)
|
railties (>= 3.2, < 5.2)
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
execjs (2.6.0)
|
execjs (2.6.0)
|
||||||
factory_girl (4.5.0)
|
factory_girl (4.5.0)
|
||||||
|
|
@ -181,27 +179,32 @@ GEM
|
||||||
multipart-post (>= 1.2, < 3)
|
multipart-post (>= 1.2, < 3)
|
||||||
fastimage (2.0.0)
|
fastimage (2.0.0)
|
||||||
addressable (~> 2)
|
addressable (~> 2)
|
||||||
ffi (1.9.3)
|
ffi (1.9.18)
|
||||||
font-awesome-rails (4.1.0.0)
|
font-awesome-rails (4.7.0.2)
|
||||||
railties (>= 3.2, < 5.0)
|
railties (>= 3.2, < 5.2)
|
||||||
formatador (0.2.4)
|
formatador (0.2.5)
|
||||||
formtastic (3.1.3)
|
formtastic (3.1.3)
|
||||||
actionpack (>= 3.2.13)
|
actionpack (>= 3.2.13)
|
||||||
formtastic-bootstrap (3.1.1)
|
formtastic-bootstrap (3.1.1)
|
||||||
formtastic (>= 3.0)
|
formtastic (>= 3.0)
|
||||||
geocoder (1.2.2)
|
geocoder (1.2.2)
|
||||||
globalid (0.3.6)
|
globalid (0.4.0)
|
||||||
activesupport (>= 4.1.0)
|
activesupport (>= 4.2.0)
|
||||||
gravtastic (3.2.6)
|
gravtastic (3.2.6)
|
||||||
guard (2.6.0)
|
guard (2.14.1)
|
||||||
formatador (>= 0.2.4)
|
formatador (>= 0.2.4)
|
||||||
listen (~> 2.7)
|
listen (>= 2.7, < 4.0)
|
||||||
lumberjack (~> 1.0)
|
lumberjack (~> 1.0)
|
||||||
|
nenv (~> 0.1)
|
||||||
|
notiffany (~> 0.0)
|
||||||
pry (>= 0.9.12)
|
pry (>= 0.9.12)
|
||||||
|
shellany (~> 0.0)
|
||||||
thor (>= 0.18.1)
|
thor (>= 0.18.1)
|
||||||
guard-rspec (4.2.8)
|
guard-compat (1.2.1)
|
||||||
|
guard-rspec (4.7.3)
|
||||||
guard (~> 2.1)
|
guard (~> 2.1)
|
||||||
rspec (>= 2.14, < 4.0)
|
guard-compat (~> 1.1)
|
||||||
|
rspec (>= 2.99.0, < 4.0)
|
||||||
haml (4.0.5)
|
haml (4.0.5)
|
||||||
tilt
|
tilt
|
||||||
haml-rails (0.5.3)
|
haml-rails (0.5.3)
|
||||||
|
|
@ -209,8 +212,14 @@ GEM
|
||||||
activesupport (>= 4.0.1)
|
activesupport (>= 4.0.1)
|
||||||
haml (>= 3.1, < 5.0)
|
haml (>= 3.1, < 5.0)
|
||||||
railties (>= 4.0.1)
|
railties (>= 4.0.1)
|
||||||
hashie (2.1.1)
|
haml_lint (0.24.0)
|
||||||
hike (1.2.3)
|
haml (>= 4.0, < 5.1)
|
||||||
|
rainbow
|
||||||
|
rake (>= 10, < 13)
|
||||||
|
rubocop (>= 0.47.0)
|
||||||
|
sysexits (~> 1.1)
|
||||||
|
hashdiff (0.3.4)
|
||||||
|
hashie (3.5.5)
|
||||||
hoptoad_notifier (2.4.11)
|
hoptoad_notifier (2.4.11)
|
||||||
activesupport
|
activesupport
|
||||||
builder
|
builder
|
||||||
|
|
@ -219,18 +228,19 @@ GEM
|
||||||
domain_name (~> 0.5)
|
domain_name (~> 0.5)
|
||||||
i18n (0.7.0)
|
i18n (0.7.0)
|
||||||
i18n_data (0.7.0)
|
i18n_data (0.7.0)
|
||||||
inversion (0.12.3)
|
inversion (1.0.0)
|
||||||
loggability (~> 0.4)
|
loggability (~> 0.12)
|
||||||
iso-639 (0.2.5)
|
iso-639 (0.2.5)
|
||||||
jquery-datatables-rails (2.2.3)
|
jquery-datatables-rails (2.2.3)
|
||||||
jquery-rails
|
jquery-rails
|
||||||
sass-rails
|
sass-rails
|
||||||
jquery-rails (3.1.4)
|
jquery-rails (4.3.1)
|
||||||
railties (>= 3.0, < 5.0)
|
rails-dom-testing (>= 1, < 3)
|
||||||
|
railties (>= 4.2.0)
|
||||||
thor (>= 0.14, < 2.0)
|
thor (>= 0.14, < 2.0)
|
||||||
jquery-ui-rails (4.2.1)
|
jquery-ui-rails (4.2.1)
|
||||||
railties (>= 3.2.16)
|
railties (>= 3.2.16)
|
||||||
json (1.8.3)
|
json (1.8.6)
|
||||||
json-schema (2.5.0)
|
json-schema (2.5.0)
|
||||||
addressable (~> 2.3)
|
addressable (~> 2.3)
|
||||||
jwt (1.0.0)
|
jwt (1.0.0)
|
||||||
|
|
@ -243,25 +253,25 @@ GEM
|
||||||
actionmailer (>= 3.2)
|
actionmailer (>= 3.2)
|
||||||
letter_opener (~> 1.0)
|
letter_opener (~> 1.0)
|
||||||
railties (>= 3.2)
|
railties (>= 3.2)
|
||||||
listen (2.7.2)
|
listen (3.1.5)
|
||||||
celluloid (>= 0.15.2)
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||||
celluloid-io (>= 0.15.0)
|
rb-inotify (~> 0.9, >= 0.9.7)
|
||||||
rb-fsevent (>= 0.9.3)
|
ruby_dep (~> 1.2)
|
||||||
rb-inotify (>= 0.9)
|
loggability (0.14.0)
|
||||||
loggability (0.11.0)
|
|
||||||
loofah (2.0.3)
|
loofah (2.0.3)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
lumberjack (1.0.5)
|
lumberjack (1.0.12)
|
||||||
mail (2.6.3)
|
mail (2.6.6)
|
||||||
mime-types (>= 1.16, < 3)
|
mime-types (>= 1.16, < 4)
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mime-types (2.99.1)
|
mime-types (2.99.3)
|
||||||
|
mimemagic (0.3.2)
|
||||||
mina (0.3.8)
|
mina (0.3.8)
|
||||||
open4 (~> 1.3.4)
|
open4 (~> 1.3.4)
|
||||||
rake
|
rake
|
||||||
mini_magick (4.5.1)
|
mini_magick (4.5.1)
|
||||||
mini_portile2 (2.1.0)
|
mini_portile2 (2.3.0)
|
||||||
minitest (5.9.0)
|
minitest (5.10.2)
|
||||||
momentjs-rails (2.8.1)
|
momentjs-rails (2.8.1)
|
||||||
railties (>= 3.1)
|
railties (>= 3.1)
|
||||||
monetize (1.4.0)
|
monetize (1.4.0)
|
||||||
|
|
@ -274,24 +284,26 @@ GEM
|
||||||
monetize (~> 1.4.0)
|
monetize (~> 1.4.0)
|
||||||
money (~> 6.7)
|
money (~> 6.7)
|
||||||
railties (>= 3.0)
|
railties (>= 3.0)
|
||||||
multi_json (1.11.2)
|
multi_json (1.12.1)
|
||||||
multi_xml (0.5.5)
|
multi_xml (0.5.5)
|
||||||
multipart-post (2.0.0)
|
multipart-post (2.0.0)
|
||||||
mysql2 (0.4.2)
|
mysql2 (0.4.9)
|
||||||
|
nenv (0.3.0)
|
||||||
netrc (0.11.0)
|
netrc (0.11.0)
|
||||||
nio4r (1.2.1)
|
nokogiri (1.8.1)
|
||||||
nokogiri (1.6.8)
|
mini_portile2 (~> 2.3.0)
|
||||||
mini_portile2 (~> 2.1.0)
|
notiffany (0.1.1)
|
||||||
pkg-config (~> 1.1.7)
|
nenv (~> 0.1)
|
||||||
oauth2 (0.9.4)
|
shellany (~> 0.0)
|
||||||
faraday (>= 0.8, < 0.10)
|
oauth2 (1.3.1)
|
||||||
|
faraday (>= 0.8, < 0.12)
|
||||||
jwt (~> 1.0)
|
jwt (~> 1.0)
|
||||||
multi_json (~> 1.3)
|
multi_json (~> 1.3)
|
||||||
multi_xml (~> 0.5)
|
multi_xml (~> 0.5)
|
||||||
rack (~> 1.2)
|
rack (>= 1.2, < 3)
|
||||||
omniauth (1.2.1)
|
omniauth (1.6.1)
|
||||||
hashie (>= 1.2, < 3)
|
hashie (>= 3.4.6, < 3.6.0)
|
||||||
rack (~> 1.0)
|
rack (>= 1.6.2, < 3)
|
||||||
omniauth-facebook (1.6.0)
|
omniauth-facebook (1.6.0)
|
||||||
omniauth-oauth2 (~> 1.1)
|
omniauth-oauth2 (~> 1.1)
|
||||||
omniauth-github (1.1.2)
|
omniauth-github (1.1.2)
|
||||||
|
|
@ -300,21 +312,20 @@ GEM
|
||||||
omniauth-google-oauth2 (0.2.4)
|
omniauth-google-oauth2 (0.2.4)
|
||||||
omniauth (~> 1.0)
|
omniauth (~> 1.0)
|
||||||
omniauth-oauth2 (~> 1.1)
|
omniauth-oauth2 (~> 1.1)
|
||||||
omniauth-oauth2 (1.1.2)
|
omniauth-oauth2 (1.4.0)
|
||||||
faraday (>= 0.8, < 0.10)
|
oauth2 (~> 1.0)
|
||||||
multi_json (~> 1.3)
|
|
||||||
oauth2 (~> 0.9.3)
|
|
||||||
omniauth (~> 1.2)
|
omniauth (~> 1.2)
|
||||||
omniauth-openid (1.0.1)
|
omniauth-openid (1.0.1)
|
||||||
omniauth (~> 1.0)
|
omniauth (~> 1.0)
|
||||||
rack-openid (~> 1.3.1)
|
rack-openid (~> 1.3.1)
|
||||||
open4 (1.3.4)
|
open4 (1.3.4)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
paper_trail (5.0.1)
|
paper_trail (5.2.1)
|
||||||
activerecord (>= 3.0, < 6.0)
|
activerecord (>= 3.0, < 6.0)
|
||||||
activesupport (>= 3.0, < 6.0)
|
activesupport (>= 3.0, < 6.0)
|
||||||
request_store (~> 1.1)
|
request_store (~> 1.1)
|
||||||
parser (2.3.0.3)
|
parallel (1.11.2)
|
||||||
|
parser (2.4.0.0)
|
||||||
ast (~> 2.2)
|
ast (~> 2.2)
|
||||||
pdf-core (0.2.5)
|
pdf-core (0.2.5)
|
||||||
phantomjs (2.1.1.0)
|
phantomjs (2.1.1.0)
|
||||||
|
|
@ -322,7 +333,6 @@ GEM
|
||||||
actionpack
|
actionpack
|
||||||
activesupport
|
activesupport
|
||||||
rails (>= 3.0.0)
|
rails (>= 3.0.0)
|
||||||
pkg-config (1.1.7)
|
|
||||||
poltergeist (1.9.0)
|
poltergeist (1.9.0)
|
||||||
capybara (~> 2.1)
|
capybara (~> 2.1)
|
||||||
cliver (~> 0.3.1)
|
cliver (~> 0.3.1)
|
||||||
|
|
@ -332,29 +342,33 @@ GEM
|
||||||
prawn (1.0.0)
|
prawn (1.0.0)
|
||||||
pdf-core (~> 0.2.2)
|
pdf-core (~> 0.2.2)
|
||||||
ttfunk (~> 1.1.1)
|
ttfunk (~> 1.1.1)
|
||||||
|
prawn-qrcode (0.2.2.1)
|
||||||
|
prawn (>= 0.11.1)
|
||||||
|
rqrcode (>= 0.4.1)
|
||||||
prawn_rails (0.0.11)
|
prawn_rails (0.0.11)
|
||||||
prawn (>= 0.11.1)
|
prawn (>= 0.11.1)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
pry (0.9.12.6)
|
pry (0.10.4)
|
||||||
coderay (~> 1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.8)
|
method_source (~> 0.8.1)
|
||||||
slop (~> 3.4)
|
slop (~> 3.4)
|
||||||
rack (1.6.4)
|
public_suffix (2.0.5)
|
||||||
|
rack (1.6.8)
|
||||||
rack-openid (1.3.1)
|
rack-openid (1.3.1)
|
||||||
rack (>= 1.1.0)
|
rack (>= 1.1.0)
|
||||||
ruby-openid (>= 2.1.8)
|
ruby-openid (>= 2.1.8)
|
||||||
rack-test (0.6.3)
|
rack-test (0.6.3)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rails (4.2.7.1)
|
rails (4.2.9)
|
||||||
actionmailer (= 4.2.7.1)
|
actionmailer (= 4.2.9)
|
||||||
actionpack (= 4.2.7.1)
|
actionpack (= 4.2.9)
|
||||||
actionview (= 4.2.7.1)
|
actionview (= 4.2.9)
|
||||||
activejob (= 4.2.7.1)
|
activejob (= 4.2.9)
|
||||||
activemodel (= 4.2.7.1)
|
activemodel (= 4.2.9)
|
||||||
activerecord (= 4.2.7.1)
|
activerecord (= 4.2.9)
|
||||||
activesupport (= 4.2.7.1)
|
activesupport (= 4.2.9)
|
||||||
bundler (>= 1.3.0, < 2.0)
|
bundler (>= 1.3.0, < 2.0)
|
||||||
railties (= 4.2.7.1)
|
railties (= 4.2.9)
|
||||||
sprockets-rails
|
sprockets-rails
|
||||||
rails-assets-bootstrap (3.3.6)
|
rails-assets-bootstrap (3.3.6)
|
||||||
rails-assets-jquery (>= 1.9.1, < 3)
|
rails-assets-jquery (>= 1.9.1, < 3)
|
||||||
|
|
@ -375,91 +389,98 @@ GEM
|
||||||
rails-assets-waypoints (4.0.0)
|
rails-assets-waypoints (4.0.0)
|
||||||
rails-deprecated_sanitizer (1.0.3)
|
rails-deprecated_sanitizer (1.0.3)
|
||||||
activesupport (>= 4.2.0.alpha)
|
activesupport (>= 4.2.0.alpha)
|
||||||
rails-dom-testing (1.0.7)
|
rails-dom-testing (1.0.8)
|
||||||
activesupport (>= 4.2.0.beta, < 5.0)
|
activesupport (>= 4.2.0.beta, < 5.0)
|
||||||
nokogiri (~> 1.6.0)
|
nokogiri (~> 1.6)
|
||||||
rails-deprecated_sanitizer (>= 1.0.1)
|
rails-deprecated_sanitizer (>= 1.0.1)
|
||||||
rails-html-sanitizer (1.0.3)
|
rails-html-sanitizer (1.0.3)
|
||||||
loofah (~> 2.0)
|
loofah (~> 2.0)
|
||||||
rails-i18n (4.0.8)
|
rails-i18n (4.0.8)
|
||||||
i18n (~> 0.7)
|
i18n (~> 0.7)
|
||||||
railties (~> 4.0)
|
railties (~> 4.0)
|
||||||
rails-observers (0.1.2)
|
|
||||||
activemodel (~> 4.0)
|
|
||||||
rails_12factor (0.0.3)
|
rails_12factor (0.0.3)
|
||||||
rails_serve_static_assets
|
rails_serve_static_assets
|
||||||
rails_stdout_logging
|
rails_stdout_logging
|
||||||
rails_serve_static_assets (0.0.4)
|
rails_serve_static_assets (0.0.4)
|
||||||
rails_stdout_logging (0.0.3)
|
rails_stdout_logging (0.0.3)
|
||||||
railties (4.2.7.1)
|
railties (4.2.9)
|
||||||
actionpack (= 4.2.7.1)
|
actionpack (= 4.2.9)
|
||||||
activesupport (= 4.2.7.1)
|
activesupport (= 4.2.9)
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.18.1, < 2.0)
|
thor (>= 0.18.1, < 2.0)
|
||||||
rainbow (2.1.0)
|
rainbow (2.2.2)
|
||||||
rake (10.5.0)
|
rake
|
||||||
rb-fsevent (0.9.4)
|
rake (12.0.0)
|
||||||
rb-inotify (0.9.4)
|
rb-fsevent (0.10.2)
|
||||||
ffi (>= 0.5.0)
|
rb-inotify (0.9.10)
|
||||||
rdoc (4.1.1)
|
ffi (>= 0.5.0, < 2)
|
||||||
json (~> 1.4)
|
rdoc (5.1.0)
|
||||||
rdoc-generator-fivefish (0.1.0)
|
rdoc-generator-fivefish (0.3.0)
|
||||||
inversion (~> 0.12)
|
inversion (~> 1.0)
|
||||||
loggability (~> 0.6)
|
loggability (~> 0.12)
|
||||||
rdoc (~> 4.0)
|
rdoc (~> 5.0)
|
||||||
yajl-ruby (~> 1.1)
|
yajl-ruby (~> 1.3)
|
||||||
redcarpet (3.2.3)
|
redcarpet (3.2.3)
|
||||||
referer-parser (0.2.1)
|
referer-parser (0.2.1)
|
||||||
request_store (1.1.0)
|
request_store (1.1.0)
|
||||||
responders (2.1.1)
|
responders (2.4.0)
|
||||||
railties (>= 4.2.0, < 5.1)
|
actionpack (>= 4.2.0, < 5.3)
|
||||||
|
railties (>= 4.2.0, < 5.3)
|
||||||
rest-client (1.8.0)
|
rest-client (1.8.0)
|
||||||
http-cookie (>= 1.0.2, < 2.0)
|
http-cookie (>= 1.0.2, < 2.0)
|
||||||
mime-types (>= 1.16, < 3.0)
|
mime-types (>= 1.16, < 3.0)
|
||||||
netrc (~> 0.7)
|
netrc (~> 0.7)
|
||||||
rolify (5.1.0)
|
rolify (5.1.0)
|
||||||
rspec (3.0.0)
|
rqrcode (0.10.1)
|
||||||
rspec-core (~> 3.0.0)
|
chunky_png (~> 1.0)
|
||||||
rspec-expectations (~> 3.0.0)
|
rspec (3.6.0)
|
||||||
rspec-mocks (~> 3.0.0)
|
rspec-core (~> 3.6.0)
|
||||||
|
rspec-expectations (~> 3.6.0)
|
||||||
|
rspec-mocks (~> 3.6.0)
|
||||||
rspec-activemodel-mocks (1.0.1)
|
rspec-activemodel-mocks (1.0.1)
|
||||||
activemodel (>= 3.0)
|
activemodel (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
rspec-mocks (>= 2.99, < 4.0)
|
rspec-mocks (>= 2.99, < 4.0)
|
||||||
rspec-core (3.0.2)
|
rspec-core (3.6.0)
|
||||||
rspec-support (~> 3.0.0)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-expectations (3.0.2)
|
rspec-expectations (3.6.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.0.0)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-mocks (3.0.2)
|
rspec-mocks (3.6.0)
|
||||||
rspec-support (~> 3.0.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-rails (3.0.0)
|
rspec-support (~> 3.6.0)
|
||||||
|
rspec-rails (3.6.0)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
railties (>= 3.0)
|
railties (>= 3.0)
|
||||||
rspec-core (~> 3.0.0)
|
rspec-core (~> 3.6.0)
|
||||||
rspec-expectations (~> 3.0.0)
|
rspec-expectations (~> 3.6.0)
|
||||||
rspec-mocks (~> 3.0.0)
|
rspec-mocks (~> 3.6.0)
|
||||||
rspec-support (~> 3.0.0)
|
rspec-support (~> 3.6.0)
|
||||||
rspec-support (3.0.2)
|
rspec-support (3.6.0)
|
||||||
rubocop (0.37.0)
|
rubocop (0.49.1)
|
||||||
parser (>= 2.3.0.2, < 3.0)
|
parallel (~> 1.10)
|
||||||
|
parser (>= 2.3.3.1, < 3.0)
|
||||||
powerpack (~> 0.1)
|
powerpack (~> 0.1)
|
||||||
rainbow (>= 1.99.1, < 3.0)
|
rainbow (>= 1.99.1, < 3.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (~> 0.3)
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||||
ruby-oembed (0.8.14)
|
ruby-oembed (0.8.14)
|
||||||
ruby-openid (2.5.0)
|
ruby-openid (2.5.0)
|
||||||
ruby-progressbar (1.7.5)
|
ruby-progressbar (1.8.1)
|
||||||
|
ruby_dep (1.5.0)
|
||||||
rubyzip (1.2.1)
|
rubyzip (1.2.1)
|
||||||
safe_yaml (1.0.4)
|
safe_yaml (1.0.4)
|
||||||
sass (3.2.19)
|
sass (3.2.19)
|
||||||
sass-rails (4.0.4)
|
sass-rails (5.0.6)
|
||||||
railties (>= 4.0.0, < 5.0)
|
railties (>= 4.0.0, < 6)
|
||||||
sass (~> 3.2.2)
|
sass (~> 3.1)
|
||||||
sprockets (~> 2.8, < 2.12)
|
sprockets (>= 2.8, < 4.0)
|
||||||
sprockets-rails (~> 2.0)
|
sprockets-rails (>= 2.0, < 4.0)
|
||||||
shoulda-matchers (2.6.1)
|
tilt (>= 1.1, < 3)
|
||||||
|
selectize-rails (0.12.4)
|
||||||
|
shellany (0.0.1)
|
||||||
|
shoulda-matchers (2.8.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
simplecov (0.11.2)
|
simplecov (0.11.2)
|
||||||
docile (~> 1.1.0)
|
docile (~> 1.1.0)
|
||||||
|
|
@ -473,11 +494,9 @@ GEM
|
||||||
spring (1.6.3)
|
spring (1.6.3)
|
||||||
spring-commands-rspec (1.0.4)
|
spring-commands-rspec (1.0.4)
|
||||||
spring (>= 0.9.1)
|
spring (>= 0.9.1)
|
||||||
sprockets (2.11.3)
|
sprockets (3.7.1)
|
||||||
hike (~> 1.2)
|
concurrent-ruby (~> 1.0)
|
||||||
multi_json (~> 1.0)
|
rack (> 1, < 3)
|
||||||
rack (~> 1.0)
|
|
||||||
tilt (~> 1.1, != 1.3.0)
|
|
||||||
sprockets-rails (2.3.3)
|
sprockets-rails (2.3.3)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
|
|
@ -489,26 +508,26 @@ GEM
|
||||||
dante (>= 0.2.0)
|
dante (>= 0.2.0)
|
||||||
multi_json (>= 1.0.0)
|
multi_json (>= 1.0.0)
|
||||||
stripe (>= 1.31.0, <= 1.43)
|
stripe (>= 1.31.0, <= 1.43)
|
||||||
|
sysexits (1.2.0)
|
||||||
term-ansicolor (1.3.2)
|
term-ansicolor (1.3.2)
|
||||||
tins (~> 1.0)
|
tins (~> 1.0)
|
||||||
thor (0.19.1)
|
thor (0.19.1)
|
||||||
thread_safe (0.3.5)
|
thread_safe (0.3.6)
|
||||||
tilt (1.4.1)
|
tilt (1.4.1)
|
||||||
timecop (0.7.1)
|
timecop (0.7.1)
|
||||||
timers (1.1.0)
|
|
||||||
tins (1.6.0)
|
tins (1.6.0)
|
||||||
transitions (0.1.12)
|
transitions (0.1.12)
|
||||||
ttfunk (1.1.1)
|
ttfunk (1.1.1)
|
||||||
turbolinks (2.5.3)
|
turbolinks (2.5.3)
|
||||||
coffee-rails
|
coffee-rails
|
||||||
tzinfo (1.2.2)
|
tzinfo (1.2.3)
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
uglifier (3.0.0)
|
uglifier (3.0.0)
|
||||||
execjs (>= 0.3.0, < 3)
|
execjs (>= 0.3.0, < 3)
|
||||||
unf (0.1.4)
|
unf (0.1.4)
|
||||||
unf_ext
|
unf_ext
|
||||||
unf_ext (0.0.7.2)
|
unf_ext (0.0.7.2)
|
||||||
unicode-display_width (0.3.1)
|
unicode-display_width (1.3.0)
|
||||||
unicode_utils (1.4.0)
|
unicode_utils (1.4.0)
|
||||||
unobtrusive_flash (3.1.0)
|
unobtrusive_flash (3.1.0)
|
||||||
railties
|
railties
|
||||||
|
|
@ -521,9 +540,10 @@ GEM
|
||||||
binding_of_caller (>= 0.7.2)
|
binding_of_caller (>= 0.7.2)
|
||||||
railties (>= 4.0)
|
railties (>= 4.0)
|
||||||
sprockets-rails (>= 2.0, < 4.0)
|
sprockets-rails (>= 2.0, < 4.0)
|
||||||
webmock (1.20.4)
|
webmock (3.0.1)
|
||||||
addressable (>= 2.3.6)
|
addressable (>= 2.3.6)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
|
hashdiff
|
||||||
websocket-driver (0.6.3)
|
websocket-driver (0.6.3)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.2)
|
websocket-extensions (0.1.2)
|
||||||
|
|
@ -532,7 +552,7 @@ GEM
|
||||||
chronic (>= 0.6.3)
|
chronic (>= 0.6.3)
|
||||||
xpath (2.0.0)
|
xpath (2.0.0)
|
||||||
nokogiri (~> 1.3)
|
nokogiri (~> 1.3)
|
||||||
yajl-ruby (1.2.0)
|
yajl-ruby (1.3.0)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
|
@ -544,7 +564,8 @@ DEPENDENCIES
|
||||||
acts_as_list
|
acts_as_list
|
||||||
ahoy_matey
|
ahoy_matey
|
||||||
autoprefixer-rails
|
autoprefixer-rails
|
||||||
awesome_nested_set (~> 3.0.0.rc.5)
|
awesome_nested_set (~> 3.1.3)
|
||||||
|
axlsx!
|
||||||
axlsx_rails
|
axlsx_rails
|
||||||
bootstrap-sass (~> 3.3.4.1)
|
bootstrap-sass (~> 3.3.4.1)
|
||||||
bootstrap-switch-rails (~> 3.0.0)
|
bootstrap-switch-rails (~> 3.0.0)
|
||||||
|
|
@ -572,8 +593,9 @@ DEPENDENCIES
|
||||||
formtastic (~> 3.1.1)
|
formtastic (~> 3.1.1)
|
||||||
formtastic-bootstrap
|
formtastic-bootstrap
|
||||||
gravtastic
|
gravtastic
|
||||||
guard-rspec (~> 4.2.8)
|
guard-rspec
|
||||||
haml-rails
|
haml-rails
|
||||||
|
haml_lint (~> 0.24.0)
|
||||||
hoptoad_notifier (~> 2.3)
|
hoptoad_notifier (~> 2.3)
|
||||||
iso-639
|
iso-639
|
||||||
jquery-datatables-rails (~> 2.2.1)
|
jquery-datatables-rails (~> 2.2.1)
|
||||||
|
|
@ -587,6 +609,7 @@ DEPENDENCIES
|
||||||
mini_magick
|
mini_magick
|
||||||
money-rails
|
money-rails
|
||||||
mysql2
|
mysql2
|
||||||
|
nokogiri (>= 1.8.1)
|
||||||
omniauth
|
omniauth
|
||||||
omniauth-facebook
|
omniauth-facebook
|
||||||
omniauth-github
|
omniauth-github
|
||||||
|
|
@ -596,8 +619,9 @@ DEPENDENCIES
|
||||||
phantomjs
|
phantomjs
|
||||||
piwik_analytics (~> 1.0.1)
|
piwik_analytics (~> 1.0.1)
|
||||||
poltergeist
|
poltergeist
|
||||||
|
prawn-qrcode (~> 0.2.2.1)
|
||||||
prawn_rails
|
prawn_rails
|
||||||
rails (~> 4.2)
|
rails (~> 4.2.8)
|
||||||
rails-assets-bootstrap-markdown!
|
rails-assets-bootstrap-markdown!
|
||||||
rails-assets-date.format!
|
rails-assets-date.format!
|
||||||
rails-assets-holderjs!
|
rails-assets-holderjs!
|
||||||
|
|
@ -610,23 +634,25 @@ DEPENDENCIES
|
||||||
rails-assets-trianglify!
|
rails-assets-trianglify!
|
||||||
rails-assets-waypoints!
|
rails-assets-waypoints!
|
||||||
rails-i18n (~> 4.0.0)
|
rails-i18n (~> 4.0.0)
|
||||||
rails-observers
|
|
||||||
rails_12factor
|
rails_12factor
|
||||||
rdoc-generator-fivefish
|
rdoc-generator-fivefish
|
||||||
redcarpet
|
redcarpet
|
||||||
responders (~> 2.0)
|
responders (~> 2.0)
|
||||||
rolify
|
rolify
|
||||||
|
rqrcode
|
||||||
rspec-activemodel-mocks
|
rspec-activemodel-mocks
|
||||||
rspec-rails
|
rspec-rails (~> 3.5, >= 3.5.2)
|
||||||
rubocop
|
rubocop (~> 0.49.0)
|
||||||
ruby-oembed
|
ruby-oembed
|
||||||
sass-rails (>= 4.0.2)
|
sass-rails (>= 4.0.2)
|
||||||
|
selectize-rails
|
||||||
shoulda-matchers
|
shoulda-matchers
|
||||||
spring-commands-rspec
|
spring-commands-rspec
|
||||||
sprockets-rails
|
sprockets-rails
|
||||||
sqlite3
|
sqlite3
|
||||||
stripe
|
stripe
|
||||||
stripe-ruby-mock
|
stripe-ruby-mock
|
||||||
|
thor (= 0.19.1)
|
||||||
timecop
|
timecop
|
||||||
transitions
|
transitions
|
||||||
turbolinks
|
turbolinks
|
||||||
|
|
@ -637,4 +663,4 @@ DEPENDENCIES
|
||||||
whenever
|
whenever
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.14.3
|
1.15.4
|
||||||
|
|
|
||||||
56
INSTALL.md
56
INSTALL.md
|
|
@ -11,7 +11,9 @@ OSEM is an [semantic versioned](http://semver.org/) app. That means given a vers
|
||||||
## Download
|
## Download
|
||||||
You can find the latest OSEM releases on our [release page](https://github.com/openSUSE/osem/releases/latest) ([older release here](https://github.com/openSUSE/osem/releases))
|
You can find the latest OSEM releases on our [release page](https://github.com/openSUSE/osem/releases/latest) ([older release here](https://github.com/openSUSE/osem/releases))
|
||||||
|
|
||||||
|
|
||||||
## Deploy
|
## Deploy
|
||||||
|
|
||||||
OSEM is a *Ruby on Rails* application. We recommend to run OSEM in production with [mod_passenger](https://www.phusionpassenger.com/download/#open_source)
|
OSEM is a *Ruby on Rails* application. We recommend to run OSEM in production with [mod_passenger](https://www.phusionpassenger.com/download/#open_source)
|
||||||
and the [apache web-server](https://www.apache.org/). There are tons of guides on how to deploy rails apps on various
|
and the [apache web-server](https://www.apache.org/). There are tons of guides on how to deploy rails apps on various
|
||||||
base operating systems. [Check Google](https://encrypted.google.com/search?hl=en&q=ruby%20on%20rails%20apache%20passenger) ;-)
|
base operating systems. [Check Google](https://encrypted.google.com/search?hl=en&q=ruby%20on%20rails%20apache%20passenger) ;-)
|
||||||
|
|
@ -24,6 +26,55 @@ If you have an heroku account you can also
|
||||||
<img src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy">
|
<img src="https://www.herokucdn.com/deploy/button.svg" alt="Deploy">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
### Deploy with Docker
|
||||||
|
|
||||||
|
You can deploy OSEM using [Docker](https://docker.com/) and [Docker-Compose](https://docs.docker.com/compose/overview/).
|
||||||
|
|
||||||
|
*This is just a short guide and does not explain how to use Docker and/or Docker-Compose. You need some experience with these tools to be able to deploy OSEM with Docker properly.*
|
||||||
|
|
||||||
|
First of all, copy `docker-compose.yml.example` to `docker-compose.yml` and `docker-compose.env.example` to `docker-compose.env`. You should immediately change
|
||||||
|
`docker-compose.env`'s permissions to `0600` to make sure all the passphrases in it are kept secret.
|
||||||
|
(Tip: the easiest and most secure way to do it is to do it with a single command, for example `install -m 0600 docker-compose.env.example docker-compose.env`).
|
||||||
|
|
||||||
|
There are two configurations to deploy OSEM with Docker: *evaluation mode* and *production mode*.
|
||||||
|
|
||||||
|
#### Evaluation mode
|
||||||
|
|
||||||
|
If you want to evaluate OSEM to see if it fits your needs, the default configuration in `docker-compose.env` will work perfectly fine for you.
|
||||||
|
For convenience reasons, `docker-compose.yml` already contains a [MailHog](https://github.com/mailhog/MailHog) service configuration. MailHog
|
||||||
|
is going to catch every email sent by OSEM and displays them on a special web service. Thus, it eliminitates the need to set up an SMTP server just to try out OSEM.
|
||||||
|
Just point your browser to http://localhost:8025 to get access to registration confirmation links etc.
|
||||||
|
|
||||||
|
Run `docker-compose up --build` to start the services. On first run, it will take a few minutes to initialize the database. Thus, wait a few minutes before you open up
|
||||||
|
http://localhost:9292 in your browser.
|
||||||
|
|
||||||
|
#### Production mode
|
||||||
|
|
||||||
|
To deploy OSEM for production, you have to make a few changes to `docker-compose.yml`. First, remove (or comment) the `mailhog` service, as it is only useful for evaluation and
|
||||||
|
cannot be used for production.
|
||||||
|
You can change the forwarded port from port `9292` to any other value if this port is already in use or you just want to use another one.
|
||||||
|
|
||||||
|
Next, you have to modify `docker-compose.env`. This file works as a Docker-like replacement for the regular Rails `.env` files described below.
|
||||||
|
You can configure any of the configuration values shown in the **Configure** section below in it. The most essential variables are already configured to standard
|
||||||
|
values in `docker-compose.env` which you most likely want to change.
|
||||||
|
|
||||||
|
First, you need to modify the email related settings. You need a working SMTP server for OSEM to send out registration confirmation mails etc.
|
||||||
|
|
||||||
|
For security reasons, the following variables have to be changed, too:
|
||||||
|
|
||||||
|
- `MYSQL_PASSWORD`
|
||||||
|
- `MYSQL_ROOT_PASSWORD`
|
||||||
|
- `SECRET_KEY_BASE`
|
||||||
|
|
||||||
|
These variables need to be set to the correct values at first, as they are used to initialize everything. Modification of these variables after installation and initialization is more
|
||||||
|
complicated and out of this document's scope.
|
||||||
|
|
||||||
|
As with any other Docker-Compose configuration, run `docker-compose up --build` (or `docker-compose up --build -d` to run in background) to start the services. During the first
|
||||||
|
start, the database has to be initialized which can take several minutes. The web service is by default exposed on localhost only as it is intended to be served by a reverse proxy (for SSL
|
||||||
|
termination, caching etc.).
|
||||||
|
You should not directly expose the web server port unless you have a good reason to do so.
|
||||||
|
|
||||||
|
|
||||||
## Configure
|
## Configure
|
||||||
There are a couple of environment variables you can set to configure OSEM. Check out the *dotenv.example* file.
|
There are a couple of environment variables you can set to configure OSEM. Check out the *dotenv.example* file.
|
||||||
|
|
||||||
|
|
@ -43,7 +94,8 @@ There are a couple of environment variables you can set to configure OSEM. Check
|
||||||
| OSEM_FACEBOOK_SECRET | *string* | OMNIAUTH Developer Secret for Facebook
|
| OSEM_FACEBOOK_SECRET | *string* | OMNIAUTH Developer Secret for Facebook
|
||||||
| OSEM_GITHUB_KEY | *string* | OMNIAUTH Developer Key for GitHub
|
| OSEM_GITHUB_KEY | *string* | OMNIAUTH Developer Key for GitHub
|
||||||
| OSEM_GITHUB_SECRET | *string* | OMNIAUTH Developer Secret for GitHub
|
| OSEM_GITHUB_SECRET | *string* | OMNIAUTH Developer Secret for GitHub
|
||||||
| OSEM_SCHEDULE_CELL_SIZE | *integer* | Schedule timeslot size to use (in minutes), should be greater than zero, should be divisor of 60
|
| OSEM_SUSE_KEY | *string* | OMNIAUTH Developer Key for openSUSE
|
||||||
|
| OSEM_SUSE_SECRET | *string* | OMNIAUTH Developer Secret for openSUSE
|
||||||
| OSEM_SMTP_ADDRESS | smtp.opensuse.org | The smtp server to use
|
| OSEM_SMTP_ADDRESS | smtp.opensuse.org | The smtp server to use
|
||||||
| OSEM_SMTP_PORT | *int* | The port on the smtp server
|
| OSEM_SMTP_PORT | *int* | The port on the smtp server
|
||||||
| OSEM_SMTP_USERNAME | *string* | The user for the smtp server
|
| OSEM_SMTP_USERNAME | *string* | The user for the smtp server
|
||||||
|
|
@ -70,7 +122,7 @@ $ bundle exec rake logo:reprocess
|
||||||
```
|
```
|
||||||
|
|
||||||
### openID
|
### openID
|
||||||
In order to use [openID](http://openid.net/) logins for your OSEM installation you need to register your application with the providers ([Google](https://code.google.com/apis/console#:access), [GitHub](https://github.com/settings/applications/new) or [Facebook](https://developers.facebook.com/)) and enter their API keys, changing the existing sample values, in `config/secrets.yml` file, or in your environment variables found in *.env.production* file.
|
In order to use [openID](http://openid.net/) logins for your OSEM installation you need to register your application with the providers ([Google](https://code.google.com/apis/console#:access), [GitHub](https://github.com/settings/applications/new) or [Facebook](https://developers.facebook.com/)) and enter their API keys in the environment variables found in your *.env* file(s).
|
||||||
|
|
||||||
## Recurring Jobs
|
## Recurring Jobs
|
||||||
Open a separate terminal and go into the directory where the rails app is present, and type the following to start the delayed_jobs worker for sending email notifications.
|
Open a separate terminal and go into the directory where the rails app is present, and type the following to start the delayed_jobs worker for sending email notifications.
|
||||||
|
|
|
||||||
2
Vagrantfile
vendored
2
Vagrantfile
vendored
|
|
@ -12,7 +12,7 @@ Vagrant.configure(2) do |config|
|
||||||
|
|
||||||
# Every Vagrant development environment requires a box. You can search for
|
# Every Vagrant development environment requires a box. You can search for
|
||||||
# boxes at https://atlas.hashicorp.com/search.
|
# boxes at https://atlas.hashicorp.com/search.
|
||||||
config.vm.box = "opensuse/openSUSE-42.1-x86_64"
|
config.vm.box = "opensuse/openSUSE-42.2-x86_64"
|
||||||
|
|
||||||
# Disable automatic box update checking. If you disable this, then
|
# Disable automatic box update checking. If you disable this, then
|
||||||
# boxes will only be checked for updates when the user runs
|
# boxes will only be checked for updates when the user runs
|
||||||
|
|
|
||||||
4
app.json
4
app.json
|
|
@ -54,10 +54,6 @@
|
||||||
"description": "The user for the smtp server",
|
"description": "The user for the smtp server",
|
||||||
"required": false
|
"required": false
|
||||||
},
|
},
|
||||||
"OSEM_SCHEDULE_CELL_SIZE": {
|
|
||||||
"description": "Schedule timeslot size in minutes",
|
|
||||||
"required": false
|
|
||||||
},
|
|
||||||
"RACK_ENV": {
|
"RACK_ENV": {
|
||||||
"required": false
|
"required": false
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@
|
||||||
//= require unobtrusive_flash
|
//= require unobtrusive_flash
|
||||||
//= require unobtrusive_flash_bootstrap
|
//= require unobtrusive_flash_bootstrap
|
||||||
//= require countable
|
//= require countable
|
||||||
|
//= require selectize
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('a[disabled=disabled]').click(function(event){
|
$('a[disabled=disabled]').click(function(event){
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,6 @@ $(function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function draw_line_chart(animation, $canvas){
|
function draw_line_chart(animation, $canvas){
|
||||||
var options = get_animation({}, animation);
|
|
||||||
var chart_data = create_dataset($canvas);
|
var chart_data = create_dataset($canvas);
|
||||||
var weeks = $canvas.parent().data('weeks');
|
var weeks = $canvas.parent().data('weeks');
|
||||||
var data = {
|
var data = {
|
||||||
|
|
@ -63,10 +62,27 @@ $(function() {
|
||||||
datasets : chart_data
|
datasets : chart_data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var options = get_animation(wholeNumberAxisFix(data), animation);
|
||||||
var ctx = $canvas.get(0).getContext("2d");
|
var ctx = $canvas.get(0).getContext("2d");
|
||||||
new Chart(ctx).Line(data, options);
|
new Chart(ctx).Line(data, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wholeNumberAxisFix(data){
|
||||||
|
var maxValue = false;
|
||||||
|
for(datasetIndex = 0; datasetIndex < data.datasets.length; ++datasetIndex){
|
||||||
|
var setMax = Math.max.apply(null, data.datasets[datasetIndex].data);
|
||||||
|
if (maxValue === false || setMax > maxValue) maxValue = setMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
var steps = maxValue;
|
||||||
|
var stepWidth = 1;
|
||||||
|
if (maxValue > 10) {
|
||||||
|
stepWidth = Math.floor(maxValue / 10);
|
||||||
|
steps = Math.ceil(maxValue / stepWidth);
|
||||||
|
}
|
||||||
|
return { scaleOverride: true, scaleSteps: steps, scaleStepWidth: stepWidth, scaleStartValue: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
function create_dataset($canvas){
|
function create_dataset($canvas){
|
||||||
var selected = getSelectedConferences($canvas);
|
var selected = getSelectedConferences($canvas);
|
||||||
var chart_data = $canvas.parent().data('chart');
|
var chart_data = $canvas.parent().data('chart');
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
$(function () {
|
$(function () {
|
||||||
$(document).ready(function() {
|
|
||||||
$('.datatable').DataTable({
|
$('.datatable').DataTable({
|
||||||
// ajax: ...,
|
// ajax: ...,
|
||||||
stateSave: true,
|
stateSave: true,
|
||||||
autoWidth: false,
|
autoWidth: false,
|
||||||
pagingType: 'full_numbers',
|
pagingType: 'full_numbers',
|
||||||
"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
|
"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#versionstable').DataTable({
|
$('#versionstable').DataTable({
|
||||||
|
|
@ -13,6 +12,3 @@ $(function () {
|
||||||
order: [[ 0, 'desc' ]]
|
order: [[ 0, 'desc' ]]
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,11 +78,12 @@ var Schedule = {
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).ready( function() {
|
$(document).ready( function() {
|
||||||
// hide the remove button for unscheduled events
|
// hide the remove button for unscheduled and non schedulable events
|
||||||
$('.unscheduled-events .schedule-event-delete-button').hide();
|
$('.unscheduled-events .schedule-event-delete-button').hide();
|
||||||
|
$('.non_schedulable .schedule-event-delete-button').hide();
|
||||||
|
|
||||||
// set events as draggable
|
// set events as draggable
|
||||||
$('.schedule-event').draggable({
|
$('.schedule-event').not('.non_schedulable').draggable({
|
||||||
snap: '.schedule-room-slot',
|
snap: '.schedule-room-slot',
|
||||||
revertDuration: 200,
|
revertDuration: 200,
|
||||||
revert: function (event, ui) {
|
revert: function (event, ui) {
|
||||||
|
|
@ -99,7 +100,7 @@ $(document).ready( function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// set room cells as droppable
|
// set room cells as droppable
|
||||||
$('.schedule-room-slot').droppable({
|
$('.schedule-room-slot').not('.non_schedulable .schedule-room-slot').droppable({
|
||||||
accept: '.schedule-event',
|
accept: '.schedule-event',
|
||||||
tolerance: "pointer",
|
tolerance: "pointer",
|
||||||
drop: function(event, ui) {
|
drop: function(event, ui) {
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ function update_price($this){
|
||||||
// Calculate price for row
|
// Calculate price for row
|
||||||
var value = $this.val();
|
var value = $this.val();
|
||||||
var price = $('#price_' + id).text();
|
var price = $('#price_' + id).text();
|
||||||
$('#total_row_' + id).text(value * price);
|
$('#total_row_' + id).text((value * price).toFixed(2));
|
||||||
|
|
||||||
// Calculate total price
|
// Calculate total price
|
||||||
var total = 0;
|
var total = 0;
|
||||||
$('.total_row').each(function( index ) {
|
$('.total_row').each(function( index ) {
|
||||||
total += parseInt($(this).text());
|
total += parseFloat($(this).text());
|
||||||
});
|
});
|
||||||
$('#total_price').text(total);
|
$('#total_price').text(total);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,4 +16,6 @@
|
||||||
*= require bootstrap3-switch
|
*= require bootstrap3-switch
|
||||||
*= require osem-payments
|
*= require osem-payments
|
||||||
*= require osem-navbar
|
*= require osem-navbar
|
||||||
|
*= require selectize
|
||||||
|
*= require selectize.bootstrap3
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,6 @@
|
||||||
color: black;
|
color: black;
|
||||||
background-color: #eeeeee;
|
background-color: #eeeeee;
|
||||||
}
|
}
|
||||||
input[type=text],
|
|
||||||
input[type=password] {
|
|
||||||
text-align: center;
|
|
||||||
padding: 5px;
|
|
||||||
display: block;
|
|
||||||
margin: auto;
|
|
||||||
width: 255px;
|
|
||||||
}
|
|
||||||
.btn-group {
|
.btn-group {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
@ -37,7 +29,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
padding: 17px 17px 0px 17px;
|
padding: 17px;
|
||||||
min-width: 225px;
|
min-width: 225px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,11 @@ background-image: -webkit-gradient(
|
||||||
}
|
}
|
||||||
|
|
||||||
.speakerinfo {
|
.speakerinfo {
|
||||||
margin-top: 20px;
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.speakerbio {
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schedule-title, .schedule-subtitle, .schedule-speaker, .schedule-track {
|
.schedule-title, .schedule-subtitle, .schedule-speaker, .schedule-track {
|
||||||
|
|
@ -263,6 +267,10 @@ td.no-padding{
|
||||||
font-size: 7px;
|
font-size: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.non_schedulable{
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
/* Small devices (tablets, 768px and up) */
|
/* Small devices (tablets, 768px and up) */
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
.room, .event-title{
|
.room, .event-title{
|
||||||
|
|
|
||||||
|
|
@ -90,3 +90,17 @@ p.comment-body {
|
||||||
.changeset{
|
.changeset{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.box{
|
||||||
|
height: 230px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sidebar hamburger btn */
|
||||||
|
.side-nav-btn{
|
||||||
|
margin-left: 10px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-image{
|
||||||
|
margin-left: 120px;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,22 @@ module Admin
|
||||||
class BaseController < ApplicationController
|
class BaseController < ApplicationController
|
||||||
before_filter :verify_user_admin
|
before_filter :verify_user_admin
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def current_ability
|
||||||
|
@current_ability ||= AdminAbility.new(current_user)
|
||||||
|
end
|
||||||
|
|
||||||
def verify_user_admin
|
def verify_user_admin
|
||||||
if (current_user.nil?)
|
if (current_user.nil?)
|
||||||
redirect_to sign_in_path
|
redirect_to sign_in_path
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
unless (current_user.has_role? :organizer, :any) || (current_user.has_role? :cfp, :any) ||
|
unless (current_user.has_role? :organizer, :any) || (current_user.has_role? :cfp, :any) ||
|
||||||
(current_user.has_role? :info_desk, :any) ||
|
(current_user.has_role? :info_desk, :any) || (current_user.has_role? :organization_admin, :any) ||
|
||||||
(current_user.has_role? :volunteers_coordinator, :any) || current_user.is_admin
|
(current_user.has_role? :volunteers_coordinator, :any) ||
|
||||||
raise CanCan::AccessDenied.new('You are not authorized to access this area!')
|
(current_user.has_role? :track_organizer, :any) || current_user.is_admin
|
||||||
|
raise CanCan::AccessDenied.new('You are not authorized to access this page.')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
116
app/controllers/admin/booths_controller.rb
Normal file
116
app/controllers/admin/booths_controller.rb
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
module Admin
|
||||||
|
class BoothsController < Admin::BaseController
|
||||||
|
load_and_authorize_resource :conference, find_by: :short_title
|
||||||
|
load_and_authorize_resource through: :conference
|
||||||
|
|
||||||
|
def index; end
|
||||||
|
|
||||||
|
def show; end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@url = admin_conference_booths_path(@conference.short_title)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@url = admin_conference_booths_path(@conference.short_title)
|
||||||
|
|
||||||
|
@booth = @conference.booths.new(booth_params)
|
||||||
|
|
||||||
|
@booth.submitter = current_user
|
||||||
|
|
||||||
|
if @booth.save
|
||||||
|
redirect_to admin_conference_booths_path,
|
||||||
|
notice: 'Booth successfully created.'
|
||||||
|
else
|
||||||
|
flash.now[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}."
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
@url = admin_conference_booth_path(@conference.short_title, @booth.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@url = admin_conference_booth_path(@conference.short_title, @booth.id)
|
||||||
|
|
||||||
|
@booth.update_attributes(booth_params)
|
||||||
|
|
||||||
|
if @booth.save
|
||||||
|
redirect_to admin_conference_booths_path,
|
||||||
|
notice: "Successfully updated booth for #{@booth.title}."
|
||||||
|
else
|
||||||
|
flash.now[:error] = "An error prohibited the Booth for #{@booth.title} "\
|
||||||
|
"#{@booth.errors.full_messages.join('. ')}."
|
||||||
|
render :edit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def accept
|
||||||
|
@booth.accept!
|
||||||
|
|
||||||
|
if @booth.save
|
||||||
|
if @conference.email_settings.send_on_booths_acceptance
|
||||||
|
Mailbot.conference_booths_acceptance_mail(@booth).deliver
|
||||||
|
end
|
||||||
|
redirect_to admin_conference_booths_path(conference_id: @conference.short_title),
|
||||||
|
notice: 'Booth successfully accepted!'
|
||||||
|
else
|
||||||
|
redirect_to admin_conference_booths_path(conference_id: @conference.short_title)
|
||||||
|
flash[:error] = "Booth could not be accepted. #{@booth.errors.full_messages.to_sentence}."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_accept
|
||||||
|
update_state(:to_accept, 'Booth to accept')
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_reject
|
||||||
|
update_state(:to_reject, 'Booth to reject')
|
||||||
|
end
|
||||||
|
|
||||||
|
def reject
|
||||||
|
@booth.reject!
|
||||||
|
|
||||||
|
if @booth.save
|
||||||
|
Mailbot.conference_booths_rejection_mail(@booth).deliver
|
||||||
|
redirect_to admin_conference_booths_path(conference_id: @conference.short_title),
|
||||||
|
notice: 'Booth successfully rejected.'
|
||||||
|
else
|
||||||
|
redirect_to admin_conference_booths_path(conference_id: @conference.short_title)
|
||||||
|
flash[:error] = "Booth could not be rejected. #{@booth.errors.full_messages.to_sentence}."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def restart
|
||||||
|
update_state(:restart, 'Booth is submitted')
|
||||||
|
end
|
||||||
|
|
||||||
|
def cancel
|
||||||
|
update_state(:cancel, 'Booth is canceled')
|
||||||
|
end
|
||||||
|
|
||||||
|
def confirm
|
||||||
|
update_state(:confirm, 'Booth successfully confirmed')
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def update_state(transition, notice)
|
||||||
|
alert = @booth.update_state(transition, notice)
|
||||||
|
|
||||||
|
if alert.blank?
|
||||||
|
flash[:notice] = notice
|
||||||
|
redirect_back_or_to(admin_conference_booths_path(conference_id: @conference.short_title)) && return
|
||||||
|
else
|
||||||
|
flash[:error] = alert
|
||||||
|
return redirect_back_or_to(admin_conference_booths_path(conference_id: @conference.short_title)) && return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def booth_params
|
||||||
|
params.require(:booth).permit(:title, :description, :reasoning, :state, :picture, :conference_id,
|
||||||
|
:created_at, :updated_at, :submitter_relationship, :website_url, responsible_ids: [])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -15,7 +15,7 @@ module Admin
|
||||||
redirect_to admin_conference_campaigns_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_campaigns_path(conference_id: @conference.short_title),
|
||||||
notice: 'Campaign successfully created.'
|
notice: 'Campaign successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = 'Campaign creation failed. ' + @campaign.errors.full_messages.to_sentence
|
flash.now[:error] = 'Campaign creation failed. ' + @campaign.errors.full_messages.to_sentence
|
||||||
render action: 'new'
|
render action: 'new'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -29,7 +29,7 @@ module Admin
|
||||||
redirect_to admin_conference_campaigns_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_campaigns_path(conference_id: @conference.short_title),
|
||||||
notice: "Campaign '#{@campaign.name}' successfully updated."
|
notice: "Campaign '#{@campaign.name}' successfully updated."
|
||||||
else
|
else
|
||||||
flash[:error] = "Campaign update failed. #{@campaign.errors.full_messages.to_sentence}"
|
flash.now[:error] = "Campaign update failed. #{@campaign.errors.full_messages.to_sentence}"
|
||||||
render action: 'edit'
|
render action: 'edit'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,51 +2,52 @@ module Admin
|
||||||
class CfpsController < Admin::BaseController
|
class CfpsController < Admin::BaseController
|
||||||
load_and_authorize_resource :conference, find_by: :short_title
|
load_and_authorize_resource :conference, find_by: :short_title
|
||||||
load_and_authorize_resource :program, through: :conference, singleton: true
|
load_and_authorize_resource :program, through: :conference, singleton: true
|
||||||
load_and_authorize_resource through: :program, singleton: true
|
load_and_authorize_resource through: :program
|
||||||
|
|
||||||
|
def index; end
|
||||||
|
|
||||||
def show; end
|
def show; end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@cfp = @program.build_cfp
|
@cfp = @program.cfps.new
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit; end
|
def edit; end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@cfp = @program.build_cfp(cfp_params)
|
@cfp = @program.cfps.new(cfp_params)
|
||||||
send_mail_on_cfp_dates_updates = @cfp.notify_on_cfp_date_update?
|
send_mail_on_cfp_dates_updates = @cfp.notify_on_cfp_date_update?
|
||||||
|
|
||||||
if @cfp.save
|
if @cfp.save
|
||||||
ConferenceCfpUpdateMailJob.perform_later(@conference) if send_mail_on_cfp_dates_updates
|
ConferenceCfpUpdateMailJob.perform_later(@conference) if send_mail_on_cfp_dates_updates
|
||||||
redirect_to admin_conference_program_cfp_path,
|
redirect_to admin_conference_program_cfps_path,
|
||||||
notice: 'Call for papers successfully created.'
|
notice: 'Call for papers successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating the call for papers failed. #{@cfp.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating the call for papers failed. #{@cfp.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@cfp = @program.cfp
|
|
||||||
@cfp.assign_attributes(cfp_params)
|
@cfp.assign_attributes(cfp_params)
|
||||||
|
|
||||||
send_mail_on_cfp_dates_updates = @cfp.notify_on_cfp_date_update?
|
send_mail_on_cfp_dates_updates = @cfp.notify_on_cfp_date_update?
|
||||||
|
|
||||||
if @cfp.update_attributes(cfp_params)
|
if @cfp.update_attributes(cfp_params)
|
||||||
ConferenceCfpUpdateMailJob.perform_later(@conference) if send_mail_on_cfp_dates_updates
|
ConferenceCfpUpdateMailJob.perform_later(@conference) if send_mail_on_cfp_dates_updates
|
||||||
redirect_to admin_conference_program_cfp_path(@conference.short_title),
|
redirect_to admin_conference_program_cfps_path(@conference.short_title),
|
||||||
notice: 'Call for papers successfully updated.'
|
notice: 'Call for papers successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Updating call for papers failed. #{@cfp.errors.to_a.join('. ')}."
|
flash.now[:error] = "Updating call for papers failed. #{@cfp.errors.to_a.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
if @cfp.destroy
|
if @cfp.destroy
|
||||||
redirect_to admin_conference_program_cfp_path, notice: 'Call for Papers was successfully deleted.'
|
redirect_to admin_conference_program_cfps_path, notice: 'Call for Papers was successfully deleted.'
|
||||||
else
|
else
|
||||||
redirect_to admin_conference_program_cfp_path, error: 'An error prohibited this Call for Papers from being destroyed: '\
|
redirect_to admin_conference_program_cfps_path, error: 'An error prohibited this Call for Papers from being destroyed: '\
|
||||||
"#{@cfp.errors.full_messages.join('. ')}."
|
"#{@cfp.errors.full_messages.join('. ')}."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -54,7 +55,7 @@ module Admin
|
||||||
private
|
private
|
||||||
|
|
||||||
def cfp_params
|
def cfp_params
|
||||||
params.require(:cfp).permit(:start_date, :end_date)
|
params.require(:cfp).permit(:start_date, :end_date, :cfp_type)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ module Admin
|
||||||
@commercials = @conference.commercials
|
@commercials = @conference.commercials
|
||||||
|
|
||||||
@commercial = @conference.commercials.build
|
@commercial = @conference.commercials.build
|
||||||
authorize! :create, @conference.commercials.new
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ module Admin
|
||||||
@new_submissions = Event.where('created_at > ?', current_user.last_sign_in_at).count
|
@new_submissions = Event.where('created_at > ?', current_user.last_sign_in_at).count
|
||||||
|
|
||||||
@active_conferences = Conference.get_active_conferences_for_dashboard # pending or the last two
|
@active_conferences = Conference.get_active_conferences_for_dashboard # pending or the last two
|
||||||
@deactive_conferences = Conference.
|
@deactive_conferences = Conference
|
||||||
get_conferences_without_active_for_dashboard(@active_conferences) # conferences without active
|
.get_conferences_without_active_for_dashboard(@active_conferences) # conferences without active
|
||||||
@conferences = @active_conferences + @deactive_conferences
|
@conferences = @active_conferences + @deactive_conferences
|
||||||
|
|
||||||
@recent_users = User.limit(5).order(created_at: :desc)
|
@recent_users = User.limit(5).order(created_at: :desc)
|
||||||
|
|
@ -37,6 +37,9 @@ module Admin
|
||||||
@registrations = {}
|
@registrations = {}
|
||||||
@registration_weeks = [0]
|
@registration_weeks = [0]
|
||||||
|
|
||||||
|
@tickets = {}
|
||||||
|
@ticket_weeks = [0]
|
||||||
|
|
||||||
@conferences.each do |c|
|
@conferences.each do |c|
|
||||||
# Event submissions over time chart
|
# Event submissions over time chart
|
||||||
@submissions[c.short_title] = c.get_submissions_per_week
|
@submissions[c.short_title] = c.get_submissions_per_week
|
||||||
|
|
@ -45,6 +48,10 @@ module Admin
|
||||||
# Conference registrations over time chart
|
# Conference registrations over time chart
|
||||||
@registrations[c.short_title] = c.get_registrations_per_week
|
@registrations[c.short_title] = c.get_registrations_per_week
|
||||||
@registration_weeks.push(@registrations[c.short_title].length)
|
@registration_weeks.push(@registrations[c.short_title].length)
|
||||||
|
|
||||||
|
# Tickets sold over time chart
|
||||||
|
@tickets[c.short_title] = c.get_tickets_sold_per_week
|
||||||
|
@ticket_weeks.push(@tickets[c.short_title].length)
|
||||||
end
|
end
|
||||||
|
|
||||||
@cfp_weeks = @cfp_weeks.max
|
@cfp_weeks = @cfp_weeks.max
|
||||||
|
|
@ -55,12 +62,17 @@ module Admin
|
||||||
@registrations = normalize_array_length(@registrations, @registration_weeks)
|
@registrations = normalize_array_length(@registrations, @registration_weeks)
|
||||||
@registration_weeks = @registration_weeks > 0 ? (1..@registration_weeks).to_a : 1
|
@registration_weeks = @registration_weeks > 0 ? (1..@registration_weeks).to_a : 1
|
||||||
|
|
||||||
|
@ticket_weeks = @ticket_weeks.max
|
||||||
|
@tickets = normalize_array_length(@tickets, @ticket_weeks)
|
||||||
|
@ticket_weeks = @ticket_weeks > 0 ? (1..@ticket_weeks).to_a : 1
|
||||||
|
|
||||||
@event_distribution = Conference.event_distribution
|
@event_distribution = Conference.event_distribution
|
||||||
@user_distribution = Conference.user_distribution
|
@user_distribution = Conference.user_distribution
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@conference = Conference.new
|
@conference = Conference.new
|
||||||
|
@organizations = Organization.accessible_by(current_ability, :update).pluck(:name, :id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
|
@ -73,7 +85,7 @@ module Admin
|
||||||
redirect_to admin_conference_path(id: @conference.short_title),
|
redirect_to admin_conference_path(id: @conference.short_title),
|
||||||
notice: 'Conference was successfully created.'
|
notice: 'Conference was successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = 'Could not create conference. ' + @conference.errors.full_messages.to_sentence
|
flash.now[:error] = 'Could not create conference. ' + @conference.errors.full_messages.to_sentence
|
||||||
render action: 'new'
|
render action: 'new'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -82,7 +94,6 @@ module Admin
|
||||||
short_title = @conference.short_title
|
short_title = @conference.short_title
|
||||||
@conference.assign_attributes(conference_params)
|
@conference.assign_attributes(conference_params)
|
||||||
send_mail_on_conf_update = @conference.notify_on_dates_changed?
|
send_mail_on_conf_update = @conference.notify_on_dates_changed?
|
||||||
delete_event_schedules if @conference.start_hour_changed? || @conference.end_hour_changed?
|
|
||||||
|
|
||||||
if @conference.update_attributes(conference_params)
|
if @conference.update_attributes(conference_params)
|
||||||
ConferenceDateUpdateMailJob.perform_later(@conference) if send_mail_on_conf_update
|
ConferenceDateUpdateMailJob.perform_later(@conference) if send_mail_on_conf_update
|
||||||
|
|
@ -106,8 +117,8 @@ module Admin
|
||||||
@new_reg = @conference.registrations.where('created_at > ?', current_user.last_sign_in_at).count
|
@new_reg = @conference.registrations.where('created_at > ?', current_user.last_sign_in_at).count
|
||||||
|
|
||||||
@total_submissions = @program.events.count
|
@total_submissions = @program.events.count
|
||||||
@new_submissions = @program.events.
|
@new_submissions = @program.events
|
||||||
where('created_at > ?', current_user.last_sign_in_at).count
|
.where('created_at > ?', current_user.last_sign_in_at).count
|
||||||
|
|
||||||
@program_length = @conference.current_program_hours
|
@program_length = @conference.current_program_hours
|
||||||
@new_program_length = @conference.new_program_hours(current_user.last_sign_in_at)
|
@new_program_length = @conference.new_program_hours(current_user.last_sign_in_at)
|
||||||
|
|
@ -134,13 +145,27 @@ module Admin
|
||||||
@submissions_data = @submissions_data.except('Weeks')
|
@submissions_data = @submissions_data.except('Weeks')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tickets_data = {}
|
||||||
|
@tickets_data = @conference.get_tickets_data
|
||||||
|
@ticket_weeks = 0
|
||||||
|
if @tickets_data['Weeks']
|
||||||
|
@ticket_weeks = @tickets_data['Weeks']
|
||||||
|
@tickets_data = @tickets_data.except('Weeks')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Set line color using a hash function
|
||||||
|
@tickets = []
|
||||||
|
@tickets_data.keys.each do |title|
|
||||||
|
@tickets.append(short_title: title, color: "\##{Digest::MD5.hexdigest(title)[0..5]}")
|
||||||
|
end
|
||||||
|
|
||||||
# Doughnut charts
|
# Doughnut charts
|
||||||
@event_type_distribution = @conference.event_type_distribution
|
@event_type_distribution = @conference.event_type_distribution
|
||||||
@event_type_distribution_confirmed = @conference.event_type_distribution(:confirmed)
|
@event_type_distribution_confirmed = @conference.event_type_distribution(:confirmed)
|
||||||
|
|
||||||
@difficulty_levels_distribution = @conference.difficulty_levels_distribution
|
@difficulty_levels_distribution = @conference.difficulty_levels_distribution
|
||||||
@difficulty_levels_distribution_confirmed = @conference.
|
@difficulty_levels_distribution_confirmed = @conference
|
||||||
difficulty_levels_distribution(:confirmed)
|
.difficulty_levels_distribution(:confirmed)
|
||||||
|
|
||||||
@tracks_distribution = @conference.tracks_distribution
|
@tracks_distribution = @conference.tracks_distribution
|
||||||
@tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed)
|
@tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed)
|
||||||
|
|
@ -187,16 +212,7 @@ module Admin
|
||||||
:vpositions_attributes, :use_volunteers, :color,
|
:vpositions_attributes, :use_volunteers, :color,
|
||||||
:sponsorship_levels_attributes, :sponsors_attributes,
|
:sponsorship_levels_attributes, :sponsors_attributes,
|
||||||
:targets, :targets_attributes,
|
:targets, :targets_attributes,
|
||||||
:campaigns, :campaigns_attributes, :registration_limit)
|
:campaigns, :campaigns_attributes, :registration_limit, :organization_id, :ticket_layout, :booth_limit)
|
||||||
end
|
|
||||||
|
|
||||||
def delete_event_schedules
|
|
||||||
event_schedules = EventSchedule.select do |e|
|
|
||||||
e.start_time.strftime('%H').to_i < @conference.start_hour ||
|
|
||||||
e.end_time.strftime('%H').to_i > @conference.end_hour ||
|
|
||||||
(e.end_time.strftime('%H').to_i == @conference.end_hour && e.end_time.strftime('%M').to_i > 0)
|
|
||||||
end
|
|
||||||
event_schedules.each(&:destroy)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ module Admin
|
||||||
redirect_to admin_conference_program_difficulty_levels_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_program_difficulty_levels_path(conference_id: @conference.short_title),
|
||||||
notice: 'Difficulty level successfully created.'
|
notice: 'Difficulty level successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating difficulty level failed: #{@difficulty_level.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating difficulty level failed: #{@difficulty_level.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -30,7 +30,7 @@ module Admin
|
||||||
redirect_to admin_conference_program_difficulty_levels_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_program_difficulty_levels_path(conference_id: @conference.short_title),
|
||||||
notice: 'Difficulty level successfully updated.'
|
notice: 'Difficulty level successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Update difficulty level failed: #{@difficulty_level.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Update difficulty level failed: #{@difficulty_level.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,9 @@ module Admin
|
||||||
:send_on_conference_registration_dates_updated, :conference_registration_dates_updated_subject, :conference_registration_dates_updated_body,
|
:send_on_conference_registration_dates_updated, :conference_registration_dates_updated_subject, :conference_registration_dates_updated_body,
|
||||||
:send_on_venue_updated, :venue_updated_subject, :venue_updated_body,
|
:send_on_venue_updated, :venue_updated_subject, :venue_updated_body,
|
||||||
:send_on_cfp_dates_updated, :cfp_dates_updated_subject, :cfp_dates_updated_body,
|
:send_on_cfp_dates_updated, :cfp_dates_updated_subject, :cfp_dates_updated_body,
|
||||||
:send_on_program_schedule_public, :program_schedule_public_subject, :program_schedule_public_body)
|
:send_on_program_schedule_public, :program_schedule_public_subject, :program_schedule_public_body,
|
||||||
|
:send_on_booths_acceptance, :booths_acceptance_subject, :booths_acceptance_body,
|
||||||
|
:send_on_booths_rejection, :booths_rejection_subject, :booths_rejection_body)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ module Admin
|
||||||
redirect_to admin_conference_program_event_types_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_program_event_types_path(conference_id: @conference.short_title),
|
||||||
notice: 'Event type successfully created.'
|
notice: 'Event type successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating event type failed: #{@event_type.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating event type failed: #{@event_type.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -28,7 +28,7 @@ module Admin
|
||||||
redirect_to admin_conference_program_event_types_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_program_event_types_path(conference_id: @conference.short_title),
|
||||||
notice: 'Event type successfully updated.'
|
notice: 'Event type successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Update event type failed: #{@event_type.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Update event type failed: #{@event_type.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@ module Admin
|
||||||
load_and_authorize_resource :program, through: :conference, singleton: true
|
load_and_authorize_resource :program, through: :conference, singleton: true
|
||||||
load_and_authorize_resource :event, through: :program
|
load_and_authorize_resource :event, through: :program
|
||||||
load_and_authorize_resource :events_registration, only: :toggle_attendance
|
load_and_authorize_resource :events_registration, only: :toggle_attendance
|
||||||
|
# For some reason this doesn't work, so a workaround is used
|
||||||
|
# load_and_authorize_resource :track, through: :program, only: [:index, :show, :edit]
|
||||||
|
|
||||||
before_action :get_event, except: [:index, :create, :reports]
|
before_action :get_tracks, only: [:index, :show, :edit]
|
||||||
|
|
||||||
# FIXME: The timezome should only be applied on output, otherwise
|
# FIXME: The timezome should only be applied on output, otherwise
|
||||||
# you get lost in timezone conversions...
|
# you get lost in timezone conversions...
|
||||||
|
|
@ -16,8 +18,6 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@events = @program.events
|
|
||||||
@tracks = @program.tracks
|
|
||||||
@difficulty_levels = @program.difficulty_levels
|
@difficulty_levels = @program.difficulty_levels
|
||||||
@event_types = @program.event_types
|
@event_types = @program.event_types
|
||||||
@tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed)
|
@tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed)
|
||||||
|
|
@ -43,22 +43,20 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@tracks = @program.tracks
|
|
||||||
@event_types = @program.event_types
|
@event_types = @program.event_types
|
||||||
@comments = @event.root_comments
|
@comments = @event.root_comments
|
||||||
@comment_count = @event.comment_threads.count
|
@comment_count = @event.comment_threads.count
|
||||||
@ratings = @event.votes.includes(:user)
|
@ratings = @event.votes.includes(:user)
|
||||||
@difficulty_levels = @program.difficulty_levels
|
@difficulty_levels = @program.difficulty_levels
|
||||||
@versions = @event.versions |
|
@versions = @event.versions |
|
||||||
PaperTrail::Version.where(item_type: 'Commercial').where_object(commercialable_id: @event.id, commercialable_type: 'Event') |
|
PaperTrail::Version.where(item_type: 'Commercial').where('object LIKE ?', "%commercialable_id: #{@event.id}\ncommercialable_type: Event%") |
|
||||||
PaperTrail::Version.where(item_type: 'Commercial').where_object_changes(commercialable_id: @event.id, commercialable_type: 'Event') |
|
PaperTrail::Version.where(item_type: 'Commercial').where('object_changes LIKE ?', "%commercialable_id:\n- \n- #{@event.id}\ncommercialable_type:\n- \n- Event%") |
|
||||||
PaperTrail::Version.where(item_type: 'Vote').where('object_changes LIKE ?', "%\nevent_id:\n- \n- #{@event.id}\n%") |
|
PaperTrail::Version.where(item_type: 'Vote').where('object_changes LIKE ?', "%\nevent_id:\n- \n- #{@event.id}\n%") |
|
||||||
PaperTrail::Version.where(item_type: 'Vote').where('object LIKE ?', "%\nevent_id: #{@event.id}\n%")
|
PaperTrail::Version.where(item_type: 'Vote').where('object LIKE ?', "%\nevent_id: #{@event.id}\n%")
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@event_types = @program.event_types
|
@event_types = @program.event_types
|
||||||
@tracks = Track.all
|
|
||||||
@comments = @event.root_comments
|
@comments = @event.root_comments
|
||||||
@comment_count = @event.comment_threads.count
|
@comment_count = @event.comment_threads.count
|
||||||
@user = @event.submitter
|
@user = @event.submitter
|
||||||
|
|
@ -79,6 +77,7 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
|
@languages = @program.languages_list
|
||||||
if @event.update_attributes(event_params)
|
if @event.update_attributes(event_params)
|
||||||
|
|
||||||
if request.xhr?
|
if request.xhr?
|
||||||
|
|
@ -89,12 +88,29 @@ module Admin
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@url = admin_conference_program_event_path(@conference.short_title, @event)
|
@url = admin_conference_program_event_path(@conference.short_title, @event)
|
||||||
flash[:error] = 'Update not successful. ' + @event.errors.full_messages.to_sentence
|
flash.now[:error] = 'Update not successful. ' + @event.errors.full_messages.to_sentence
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create; end
|
def create
|
||||||
|
@url = admin_conference_program_events_path(@conference.short_title, @event)
|
||||||
|
@languages = @program.languages_list
|
||||||
|
@event.submitter = current_user
|
||||||
|
|
||||||
|
if @event.save
|
||||||
|
ahoy.track 'Event submission', title: 'New submission'
|
||||||
|
redirect_to admin_conference_program_events_path(@conference.short_title), notice: 'Event was successfully submitted.'
|
||||||
|
else
|
||||||
|
flash.now[:error] = "Could not submit proposal: #{@event.errors.full_messages.join(', ')}"
|
||||||
|
render action: 'new'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@url = admin_conference_program_events_path(@conference.short_title, @event)
|
||||||
|
@languages = @program.languages_list
|
||||||
|
end
|
||||||
|
|
||||||
def accept
|
def accept
|
||||||
send_mail = @event.program.conference.email_settings.send_on_accepted
|
send_mail = @event.program.conference.email_settings.send_on_accepted
|
||||||
|
|
@ -152,17 +168,6 @@ module Admin
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def reports
|
|
||||||
@events = @program.events
|
|
||||||
@events_commercials = Commercial.where(commercialable_type: 'Event', commercialable_id: @events.pluck(:id))
|
|
||||||
@events_missing_commercial = @events.where.not(id: @events_commercials.pluck(:commercialable_id))
|
|
||||||
@events_with_requirements = @events.where.not(description: ['', nil])
|
|
||||||
|
|
||||||
attended_registrants_ids = @conference.registrations.where(attended: true).pluck(:user_id)
|
|
||||||
@missing_event_speakers = EventUser.joins(:event).where('event_role = ? and program_id = ?', 'submitter', @program.id).
|
|
||||||
where.not(user_id: attended_registrants_ids).includes(:user, :event)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def event_params
|
def event_params
|
||||||
|
|
@ -172,23 +177,14 @@ module Admin
|
||||||
# Set only in admin/events controller
|
# Set only in admin/events controller
|
||||||
:track_id, :state, :language, :is_highlight, :max_attendees,
|
:track_id, :state, :language, :is_highlight, :max_attendees,
|
||||||
# Not used anymore?
|
# Not used anymore?
|
||||||
:proposal_additional_speakers, :user, :users_attributes)
|
:proposal_additional_speakers, :user, :users_attributes,
|
||||||
|
speaker_ids: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
def comment_params
|
def comment_params
|
||||||
params.require(:comment).permit(:commentable, :body, :user_id)
|
params.require(:comment).permit(:commentable, :body, :user_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_event
|
|
||||||
@event = @conference.program.events.find(params[:id])
|
|
||||||
unless @event
|
|
||||||
redirect_to admin_conference_program_events_path(conference_id: @conference.short_title),
|
|
||||||
error: 'Error! Could not find event!'
|
|
||||||
return
|
|
||||||
end
|
|
||||||
@event
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_state(transition, notice, mail = false, subject = false, send_mail = false)
|
def update_state(transition, notice, mail = false, subject = false, send_mail = false)
|
||||||
alert = @event.update_state(transition, mail, subject, send_mail, params[:send_mail].blank?)
|
alert = @event.update_state(transition, mail, subject, send_mail, params[:send_mail].blank?)
|
||||||
|
|
||||||
|
|
@ -200,5 +196,9 @@ module Admin
|
||||||
return redirect_back_or_to(admin_conference_program_events_path(conference_id: @conference.short_title)) && return
|
return redirect_back_or_to(admin_conference_program_events_path(conference_id: @conference.short_title)) && return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_tracks
|
||||||
|
@tracks = Track.accessible_by(current_ability).where(program: @program).confirmed
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ module Admin
|
||||||
redirect_to admin_conference_lodgings_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_lodgings_path(conference_id: @conference.short_title),
|
||||||
notice: 'Lodging successfully created.'
|
notice: 'Lodging successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating Lodging failed: #{@lodging.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating Lodging failed: #{@lodging.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -28,7 +28,7 @@ module Admin
|
||||||
redirect_to admin_conference_lodgings_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_lodgings_path(conference_id: @conference.short_title),
|
||||||
notice: 'Lodging successfully updated.'
|
notice: 'Lodging successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Update Lodging failed: #{@lodging.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Update Lodging failed: #{@lodging.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
94
app/controllers/admin/organizations_controller.rb
Normal file
94
app/controllers/admin/organizations_controller.rb
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
module Admin
|
||||||
|
class OrganizationsController < Admin::BaseController
|
||||||
|
load_and_authorize_resource :organization
|
||||||
|
before_action :verify_user, only: [:assign_org_admins, :unassign_org_admins]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@organizations = Organization.all
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@organization = Organization.new(organization_params)
|
||||||
|
if @organization.save
|
||||||
|
redirect_to admin_organizations_path,
|
||||||
|
notice: 'Organization successfully created'
|
||||||
|
else
|
||||||
|
redirect_to new_admin_organization_path,
|
||||||
|
error: @organization.errors.full_messages.join(', ')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@organization = Organization.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit; end
|
||||||
|
|
||||||
|
def update
|
||||||
|
if @organization.update_attributes(organization_params)
|
||||||
|
redirect_to admin_organizations_path,
|
||||||
|
notice: 'Organization successfully updated'
|
||||||
|
else
|
||||||
|
redirect_to edit_admin_organization_path(@organization),
|
||||||
|
error: @organization.errors.full_messages.join(', ')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if @organization.destroy
|
||||||
|
redirect_to admin_organizations_path,
|
||||||
|
notice: 'Organization successfully destroyed'
|
||||||
|
else
|
||||||
|
redirect_to admin_organizations_path,
|
||||||
|
error: 'Organization cannot be destroyed'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assign_org_admins
|
||||||
|
if @user.has_role? 'organization_admin', @organization
|
||||||
|
flash[:error] = "User #{@user.email} already has the role organization admin"
|
||||||
|
elsif @user.add_role 'organization_admin', @organization
|
||||||
|
flash[:notice] = "Successfully added role organization admin to user #{@user.email}"
|
||||||
|
else
|
||||||
|
flash[:error] = "Coud not add role organization admin to #{@user.email}"
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to admins_admin_organization_path(@organization)
|
||||||
|
end
|
||||||
|
|
||||||
|
def unassign_org_admins
|
||||||
|
if @user.remove_role 'organization_admin', @organization
|
||||||
|
flash[:notice] = "Successfully removed role organization admin from user #{@user.email}"
|
||||||
|
else
|
||||||
|
flash[:error] = "Could not remove role organization admin from user #{@user.email}"
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to admins_admin_organization_path(@organization)
|
||||||
|
end
|
||||||
|
|
||||||
|
def admins
|
||||||
|
@role = @organization.roles.first
|
||||||
|
@users = @role.users
|
||||||
|
render 'show_org_admins'
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def user_params
|
||||||
|
params.require(:user).permit(:email)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_user
|
||||||
|
@user = User.find_by(email: user_params[:email])
|
||||||
|
unless @user
|
||||||
|
redirect_to admins_admin_organization_path(@organization),
|
||||||
|
error: 'Could not find user. Please provide a valid email!'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def organization_params
|
||||||
|
params.require(:organization).permit(:name, :description, :picture)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
14
app/controllers/admin/physical_tickets_controller.rb
Normal file
14
app/controllers/admin/physical_tickets_controller.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
module Admin
|
||||||
|
class PhysicalTicketsController < Admin::BaseController
|
||||||
|
before_action :authenticate_user!
|
||||||
|
load_resource :conference, find_by: :short_title
|
||||||
|
load_and_authorize_resource
|
||||||
|
authorize_resource :conference_registrations, class: Registration
|
||||||
|
|
||||||
|
def index
|
||||||
|
@physical_tickets = @conference.physical_tickets
|
||||||
|
@tickets_sold_distribution = @conference.tickets_sold_distribution
|
||||||
|
@tickets_turnover_distribution = @conference.tickets_turnover_distribution
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -12,23 +12,25 @@ module Admin
|
||||||
@program = @conference.program
|
@program = @conference.program
|
||||||
@program.assign_attributes(program_params)
|
@program.assign_attributes(program_params)
|
||||||
send_mail_on_schedule_public = @program.notify_on_schedule_public?
|
send_mail_on_schedule_public = @program.notify_on_schedule_public?
|
||||||
|
event_schedules_count_was = @program.event_schedules.count
|
||||||
|
|
||||||
if @program.update_attributes(program_params)
|
if @program.update_attributes(program_params)
|
||||||
ConferenceScheduleUpdateMailJob.perform_later(@conference) if send_mail_on_schedule_public
|
ConferenceScheduleUpdateMailJob.perform_later(@conference) if send_mail_on_schedule_public
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
redirect_to admin_conference_program_path(@conference.short_title),
|
notice = 'The program was successfully updated.'
|
||||||
notice: 'The program was successfully updated.'
|
notice += ' You changed schedule interval and some events were unscheduled.' if @program.event_schedules.count != event_schedules_count_was
|
||||||
|
redirect_to admin_conference_program_path(@conference.short_title), notice: notice
|
||||||
end
|
end
|
||||||
format.js { render json: {} }
|
format.js { render json: {} }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
flash[:error] = "Updating program failed. #{@program.errors.to_a.join('. ')}."
|
flash.now[:error] = "Updating program failed. #{@program.errors.to_a.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
format.js { render json: { errors: "The selected schedule couldn't been updated #{@program.errors.to_a.join('. ')}" }, status: 422 }
|
format.js { render json: { errors: "The selected schedule couldn't be updated #{@program.errors.to_a.join('. ')}" }, status: 422 }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -36,7 +38,7 @@ module Admin
|
||||||
private
|
private
|
||||||
|
|
||||||
def program_params
|
def program_params
|
||||||
params.require(:program).permit(:rating, :schedule_public, :schedule_fluid, :languages, :blind_voting, :voting_start_date, :voting_end_date, :selected_schedule_id)
|
params.require(:program).permit(:rating, :schedule_public, :schedule_interval, :schedule_fluid, :languages, :blind_voting, :voting_start_date, :voting_end_date, :selected_schedule_id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Admin
|
module Admin
|
||||||
class RegistrationPeriodsController < ApplicationController
|
class RegistrationPeriodsController < Admin::BaseController
|
||||||
load_and_authorize_resource :conference, find_by: :short_title
|
load_and_authorize_resource :conference, find_by: :short_title
|
||||||
load_and_authorize_resource through: :conference, singleton: true
|
load_and_authorize_resource through: :conference, singleton: true
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ module Admin
|
||||||
redirect_to admin_conference_registration_period_path(@conference.short_title),
|
redirect_to admin_conference_registration_period_path(@conference.short_title),
|
||||||
notice: 'Registration Period successfully updated.'
|
notice: 'Registration Period successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "An error prohibited the Registration Period from being saved: #{@registration_period.errors.full_messages.join('. ')}."
|
flash.now[:error] = "An error prohibited the Registration Period from being saved: #{@registration_period.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -36,7 +36,7 @@ module Admin
|
||||||
redirect_to admin_conference_registration_period_path(@conference.short_title),
|
redirect_to admin_conference_registration_period_path(@conference.short_title),
|
||||||
notice: 'Registration Period successfully updated.'
|
notice: 'Registration Period successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = 'An error prohibited the Registration Period from being saved: ' \
|
flash.now[:error] = 'An error prohibited the Registration Period from being saved: ' \
|
||||||
"#{@registration_period.errors.full_messages.join('. ')}."
|
"#{@registration_period.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ module Admin
|
||||||
redirect_to admin_conference_registrations_path(@conference.short_title),
|
redirect_to admin_conference_registrations_path(@conference.short_title),
|
||||||
notice: "Successfully updated registration for #{@registration.user.email}!"
|
notice: "Successfully updated registration for #{@registration.user.email}!"
|
||||||
else
|
else
|
||||||
flash[:error] = "An error prohibited the Registration for #{@registration.user.email}: "\
|
flash.now[:error] = "An error prohibited the Registration for #{@registration.user.email}: "\
|
||||||
"#{@registration.errors.full_messages.join('. ')}."
|
"#{@registration.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
|
|
|
||||||
21
app/controllers/admin/reports_controller.rb
Normal file
21
app/controllers/admin/reports_controller.rb
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
module Admin
|
||||||
|
class ReportsController < Admin::BaseController
|
||||||
|
load_and_authorize_resource :conference, find_by: :short_title
|
||||||
|
load_and_authorize_resource :program, through: :conference, singleton: true
|
||||||
|
# For some reason this doesn't work, so a workaround is used
|
||||||
|
# load_and_authorize_resource :event, through: :program
|
||||||
|
|
||||||
|
def index
|
||||||
|
@events = Event.accessible_by(current_ability).where(program: @program)
|
||||||
|
@events_commercials = Commercial.where(commercialable_type: 'Event', commercialable_id: @events.pluck(:id))
|
||||||
|
@events_missing_commercial = @events.where.not(id: @events_commercials.pluck(:commercialable_id))
|
||||||
|
@events_with_requirements = @events.where.not(description: ['', nil])
|
||||||
|
|
||||||
|
attended_registrants_ids = @conference.registrations.where(attended: true).pluck(:user_id)
|
||||||
|
@missing_event_speakers = EventUser.joins(:event)
|
||||||
|
.where('event_role = ? and program_id = ?', 'submitter', @program.id)
|
||||||
|
.where.not(user_id: attended_registrants_ids)
|
||||||
|
.includes(:user, :event)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
module Admin
|
module Admin
|
||||||
class ResourcesController < ApplicationController
|
class ResourcesController < Admin::BaseController
|
||||||
load_and_authorize_resource :conference, find_by: :short_title
|
load_and_authorize_resource :conference, find_by: :short_title
|
||||||
load_and_authorize_resource :resource, only: [:show, :edit, :update, :destroy]
|
load_and_authorize_resource :resource, only: [:show, :edit, :update, :destroy]
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ module Admin
|
||||||
redirect_to admin_conference_resources_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_resources_path(conference_id: @conference.short_title),
|
||||||
notice: 'Resource successfully created.'
|
notice: 'Resource successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating resource failed: #{@resource.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating resource failed: #{@resource.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -27,7 +27,7 @@ module Admin
|
||||||
redirect_to admin_conference_resources_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_resources_path(conference_id: @conference.short_title),
|
||||||
notice: 'Resource successfully updated.'
|
notice: 'Resource successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Resource update failed: #{@resource.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Resource update failed: #{@resource.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,26 @@ module Admin
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@roles = Role.where(resource: @conference)
|
@roles = Role.where(resource: @conference)
|
||||||
|
tracks = @conference.program.tracks.where.not(submitter: nil)
|
||||||
|
@roles += Role.where(resource: tracks)
|
||||||
authorize! :index, @role
|
authorize! :index, @role
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
@url = if @track
|
||||||
|
toggle_user_admin_conference_program_track_role_path(@conference.short_title, @track, @role.name)
|
||||||
|
else
|
||||||
|
toggle_user_admin_conference_role_path(@conference.short_title, @role.name)
|
||||||
|
end
|
||||||
@users = @role.users
|
@users = @role.users
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
|
@url = if @track
|
||||||
|
admin_conference_program_track_role_path(@conference.short_title, @track, @role.name)
|
||||||
|
else
|
||||||
|
admin_conference_role_path(@conference.short_title, @role.name)
|
||||||
|
end
|
||||||
@users = @role.users
|
@users = @role.users
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -23,11 +35,17 @@ module Admin
|
||||||
role_name = @role.name
|
role_name = @role.name
|
||||||
|
|
||||||
if @role.update_attributes(role_params)
|
if @role.update_attributes(role_params)
|
||||||
redirect_to admin_conference_role_path(@conference.short_title, @role.name),
|
url = if @track
|
||||||
|
admin_conference_program_track_role_path(@conference.short_title, @track, @role.name)
|
||||||
|
else
|
||||||
|
admin_conference_role_path(@conference.short_title, @role.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_to url,
|
||||||
notice: 'Successfully updated role ' + @role.name
|
notice: 'Successfully updated role ' + @role.name
|
||||||
else
|
else
|
||||||
@role.name = role_name
|
@role.name = role_name
|
||||||
flash[:error] = 'Could not update role! ' + @role.errors.full_messages.to_sentence
|
flash.now[:error] = 'Could not update role! ' + @role.errors.full_messages.to_sentence
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -36,8 +54,14 @@ module Admin
|
||||||
user = User.find_by(email: user_params[:email])
|
user = User.find_by(email: user_params[:email])
|
||||||
state = user_params[:state]
|
state = user_params[:state]
|
||||||
|
|
||||||
|
url = if @track
|
||||||
|
admin_conference_program_track_role_path(@conference.short_title, @track, @role.name)
|
||||||
|
else
|
||||||
|
admin_conference_role_path(@conference.short_title, @role.name)
|
||||||
|
end
|
||||||
|
|
||||||
unless user
|
unless user
|
||||||
redirect_to admin_conference_role_path(@conference.short_title, @role.name),
|
redirect_to url,
|
||||||
error: 'Could not find user. Please provide a valid email!'
|
error: 'Could not find user. Please provide a valid email!'
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
@ -49,17 +73,23 @@ module Admin
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if @role.resource_type == 'Conference'
|
||||||
|
role_resource = @conference
|
||||||
|
elsif @role.resource_type == 'Track'
|
||||||
|
role_resource = @track
|
||||||
|
end
|
||||||
|
|
||||||
# Remove user
|
# Remove user
|
||||||
if state == 'false'
|
if state == 'false'
|
||||||
if user.remove_role @role.name, @conference
|
if user.remove_role @role.name, role_resource
|
||||||
flash[:notice] = "Successfully removed role #{@role.name} from user #{user.email}"
|
flash[:notice] = "Successfully removed role #{@role.name} from user #{user.email}"
|
||||||
else
|
else
|
||||||
flash[:error] = "Could not remove role #{@role.name} from user #{user.email}"
|
flash[:error] = "Could not remove role #{@role.name} from user #{user.email}"
|
||||||
end
|
end
|
||||||
elsif user.has_role? @role.name, @conference
|
elsif user.has_role? @role.name, role_resource
|
||||||
flash[:error] = "User #{user.email} already has the role #{@role.name}"
|
flash[:error] = "User #{user.email} already has the role #{@role.name}"
|
||||||
# Add user
|
# Add user
|
||||||
elsif user.add_role @role.name, @conference
|
elsif user.add_role @role.name, role_resource
|
||||||
flash[:notice] = "Successfully added role #{@role.name} to user #{user.email}"
|
flash[:notice] = "Successfully added role #{@role.name} to user #{user.email}"
|
||||||
else
|
else
|
||||||
flash[:error] = "Coud not add role #{@role.name} to #{user.email}"
|
flash[:error] = "Coud not add role #{@role.name} to #{user.email}"
|
||||||
|
|
@ -67,7 +97,7 @@ module Admin
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.js
|
format.js
|
||||||
format.html { redirect_to admin_conference_role_path(@conference.short_title, @role.name) }
|
format.html { redirect_to url }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -77,8 +107,13 @@ module Admin
|
||||||
# Set 'organizer' as default role, when there is no other selection
|
# Set 'organizer' as default role, when there is no other selection
|
||||||
@selection = params[:id] ? params[:id].parameterize.underscore : 'organizer'
|
@selection = params[:id] ? params[:id].parameterize.underscore : 'organizer'
|
||||||
|
|
||||||
|
if @selection == 'track_organizer'
|
||||||
|
@track = @conference.program.tracks.find_by(short_name: params[:track_id])
|
||||||
|
@role = Role.find_by(name: @selection, resource: @track)
|
||||||
|
else
|
||||||
@role = Role.find_by(name: @selection, resource: @conference)
|
@role = Role.find_by(name: @selection, resource: @conference)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def role_params
|
def role_params
|
||||||
params.require(:role).permit(:name, :description, user_ids: [])
|
params.require(:role).permit(:name, :description, user_ids: [])
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ module Admin
|
||||||
redirect_to admin_conference_venue_rooms_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_venue_rooms_path(conference_id: @conference.short_title),
|
||||||
notice: 'Room successfully created.'
|
notice: 'Room successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating Room failed: #{@room.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating Room failed: #{@room.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -28,7 +28,7 @@ module Admin
|
||||||
redirect_to admin_conference_venue_rooms_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_venue_rooms_path(conference_id: @conference.short_title),
|
||||||
notice: 'Room successfully updated.'
|
notice: 'Room successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Update Room failed: #{@room.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Update Room failed: #{@room.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,21 @@ module Admin
|
||||||
# the schedule of a conference, which should not be accessed in the first place
|
# the schedule of a conference, which should not be accessed in the first place
|
||||||
load_and_authorize_resource :conference, find_by: :short_title
|
load_and_authorize_resource :conference, find_by: :short_title
|
||||||
load_and_authorize_resource :program, through: :conference, singleton: true
|
load_and_authorize_resource :program, through: :conference, singleton: true
|
||||||
load_and_authorize_resource :schedule, through: :program
|
load_and_authorize_resource :schedule, through: :program, except: [:new, :create]
|
||||||
load_resource :event_schedules, through: :schedule
|
load_resource :event_schedules, through: :schedule
|
||||||
load_resource :selected_schedule, through: :program, singleton: true
|
load_resource :selected_schedule, through: :program, singleton: true
|
||||||
load_resource :venue, through: :conference, singleton: true
|
load_resource :venue, through: :conference, singleton: true
|
||||||
|
|
||||||
def index; end
|
def index; end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@schedule = @program.schedules.build(track: @program.tracks.new)
|
||||||
|
authorize! :new, @schedule
|
||||||
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
@schedule = @program.schedules.new(schedule_params)
|
||||||
|
authorize! :create, @schedule
|
||||||
if @schedule.save
|
if @schedule.save
|
||||||
redirect_to admin_conference_schedule_path(@conference.short_title, @schedule.id),
|
redirect_to admin_conference_schedule_path(@conference.short_title, @schedule.id),
|
||||||
notice: 'Schedule was successfully created.'
|
notice: 'Schedule was successfully created.'
|
||||||
|
|
@ -23,10 +30,25 @@ module Admin
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@event_schedules = @schedule.event_schedules
|
@event_schedules = @schedule.event_schedules
|
||||||
@unscheduled_events = @program.events.confirmed - @schedule.events
|
|
||||||
|
if @schedule.track
|
||||||
|
track = @schedule.track
|
||||||
|
@unscheduled_events = track.events.confirmed - @schedule.events
|
||||||
|
@dates = track.start_date..track.end_date
|
||||||
|
@rooms = [track.room]
|
||||||
|
else
|
||||||
|
@program.tracks.self_organized.confirmed.each do |t|
|
||||||
|
@event_schedules += t.selected_schedule.event_schedules if t.selected_schedule
|
||||||
|
end
|
||||||
|
self_organized_tracks_events = @program.tracks.self_organized.confirmed.map do |t|
|
||||||
|
t.events.confirmed
|
||||||
|
end
|
||||||
|
self_organized_tracks_events.flatten.compact!
|
||||||
|
@unscheduled_events = @program.events.confirmed - @schedule.events - self_organized_tracks_events
|
||||||
@dates = @conference.start_date..@conference.end_date
|
@dates = @conference.start_date..@conference.end_date
|
||||||
@rooms = @conference.venue.rooms if @conference.venue
|
@rooms = @conference.venue.rooms if @conference.venue
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
if @schedule.destroy
|
if @schedule.destroy
|
||||||
|
|
@ -37,5 +59,11 @@ module Admin
|
||||||
error: "Schedule couldn't be deleted. #{@schedule.errors.full_messages.join('. ')}."
|
error: "Schedule couldn't be deleted. #{@schedule.errors.full_messages.join('. ')}."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def schedule_params
|
||||||
|
params.require(:schedule).permit(:track_id) if params[:schedule]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,8 @@ module Admin
|
||||||
:include_tracks, :include_program, :include_cfp,
|
:include_tracks, :include_program, :include_cfp,
|
||||||
:include_venue, :include_registrations,
|
:include_venue, :include_registrations,
|
||||||
:include_tickets, :include_lodgings,
|
:include_tickets, :include_lodgings,
|
||||||
:include_sponsors, :include_social_media)
|
:include_sponsors, :include_social_media,
|
||||||
|
:include_booths)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ module Admin
|
||||||
redirect_to admin_conference_sponsors_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_sponsors_path(conference_id: @conference.short_title),
|
||||||
notice: 'Sponsor successfully created.'
|
notice: 'Sponsor successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating sponsor failed: #{@sponsor.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating sponsor failed: #{@sponsor.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -31,7 +31,7 @@ module Admin
|
||||||
conference_id: @conference.short_title),
|
conference_id: @conference.short_title),
|
||||||
notice: 'Sponsor successfully updated.'
|
notice: 'Sponsor successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Update sponsor failed: #{@sponsor.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Update sponsor failed: #{@sponsor.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ module Admin
|
||||||
redirect_to admin_conference_sponsorship_levels_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_sponsorship_levels_path(conference_id: @conference.short_title),
|
||||||
notice: 'Sponsorship level successfully created.'
|
notice: 'Sponsorship level successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating Sponsorship Level failed: #{@sponsorship_level.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating Sponsorship Level failed: #{@sponsorship_level.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -30,7 +30,7 @@ module Admin
|
||||||
conference_id: @conference.short_title),
|
conference_id: @conference.short_title),
|
||||||
notice: 'Sponsorship level successfully updated.'
|
notice: 'Sponsorship level successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Update Sponsorship level failed: #{@sponsorship_level.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Update Sponsorship level failed: #{@sponsorship_level.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ module Admin
|
||||||
redirect_to admin_conference_targets_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_targets_path(conference_id: @conference.short_title),
|
||||||
notice: 'Target successfully created.'
|
notice: 'Target successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating target failed: #{@target.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating target failed: #{@target.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -27,7 +27,7 @@ module Admin
|
||||||
redirect_to admin_conference_targets_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_targets_path(conference_id: @conference.short_title),
|
||||||
notice: 'Target successfully updated.'
|
notice: 'Target successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Target update failed: #{@target.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Target update failed: #{@target.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
16
app/controllers/admin/ticket_scannings_controller.rb
Normal file
16
app/controllers/admin/ticket_scannings_controller.rb
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
module Admin
|
||||||
|
class TicketScanningsController < Admin::BaseController
|
||||||
|
before_action :authenticate_user!
|
||||||
|
load_resource :physical_ticket, find_by: :token
|
||||||
|
# We authorize manually in these actions
|
||||||
|
skip_authorize_resource only: [:create]
|
||||||
|
|
||||||
|
def create
|
||||||
|
@ticket_scanning = TicketScanning.new(physical_ticket: @physical_ticket)
|
||||||
|
authorize! :create, @ticket_scanning
|
||||||
|
@ticket_scanning.save
|
||||||
|
redirect_to conferences_path,
|
||||||
|
notice: "Ticket with token #{@physical_ticket.token} successfully scanned."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -5,6 +5,8 @@ module Admin
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize! :update, Ticket.new(conference_id: @conference.id)
|
authorize! :update, Ticket.new(conference_id: @conference.id)
|
||||||
|
@tickets_sold_distribution = @conference.tickets_sold_distribution
|
||||||
|
@tickets_turnover_distribution = @conference.tickets_turnover_distribution
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
|
@ -17,7 +19,7 @@ module Admin
|
||||||
redirect_to admin_conference_tickets_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_tickets_path(conference_id: @conference.short_title),
|
||||||
notice: 'Ticket successfully created.'
|
notice: 'Ticket successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating Ticket failed: #{@ticket.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating Ticket failed: #{@ticket.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -29,7 +31,7 @@ module Admin
|
||||||
redirect_to admin_conference_tickets_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_tickets_path(conference_id: @conference.short_title),
|
||||||
notice: 'Ticket successfully updated.'
|
notice: 'Ticket successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Ticket update failed: #{@ticket.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Ticket update failed: #{@ticket.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -48,7 +50,7 @@ module Admin
|
||||||
private
|
private
|
||||||
|
|
||||||
def ticket_params
|
def ticket_params
|
||||||
params.require(:ticket).permit(:conference, :title, :url, :description, :conference_id, :price_cents, :price_currency, :price)
|
params.require(:ticket).permit(:conference, :title, :url, :description, :conference_id, :price_cents, :price_currency, :price, :registration_ticket)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@ module Admin
|
||||||
class TracksController < Admin::BaseController
|
class TracksController < Admin::BaseController
|
||||||
load_and_authorize_resource :conference, find_by: :short_title
|
load_and_authorize_resource :conference, find_by: :short_title
|
||||||
load_and_authorize_resource :program, through: :conference, singleton: true
|
load_and_authorize_resource :program, through: :conference, singleton: true
|
||||||
load_and_authorize_resource through: :program
|
load_and_authorize_resource through: :program, find_by: :short_name
|
||||||
|
|
||||||
|
# Show flash message with ajax calls
|
||||||
|
after_action :prepare_unobtrusive_flash, only: :toggle_cfp_inclusion
|
||||||
|
|
||||||
def index; end
|
def index; end
|
||||||
|
|
||||||
|
|
@ -19,11 +22,13 @@ module Admin
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@track = @program.tracks.new(track_params)
|
@track = @program.tracks.new(track_params)
|
||||||
|
@track.state = 'confirmed'
|
||||||
|
@track.cfp_active = true
|
||||||
if @track.save
|
if @track.save
|
||||||
redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title),
|
||||||
notice: 'Track successfully created.'
|
notice: 'Track successfully created.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Creating Track failed: #{@track.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Creating Track failed: #{@track.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -35,7 +40,7 @@ module Admin
|
||||||
redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title),
|
||||||
notice: 'Track successfully updated.'
|
notice: 'Track successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Track update failed: #{@track.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Track update failed: #{@track.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -50,10 +55,80 @@ module Admin
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def toggle_cfp_inclusion
|
||||||
|
@track.cfp_active = !@track.cfp_active
|
||||||
|
if @track.save
|
||||||
|
flash[:notice] = "Successfully changed cfp inclusion of #{@track.name} to #{@track.cfp_active}"
|
||||||
|
else
|
||||||
|
flash[:error] = "Failed to toggle cfp inclusion of #{@track.name} to #{@track.cfp_active}"
|
||||||
|
end
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.js
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def restart
|
||||||
|
update_state(:restart, "Review for #{@track.name} started!")
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_accept
|
||||||
|
update_state(:to_accept, "Track #{@track.name} marked as a possible acceptance!")
|
||||||
|
end
|
||||||
|
|
||||||
|
def accept
|
||||||
|
if @track.room && @track.start_date && @track.end_date
|
||||||
|
update_state(:accept, "Track #{@track.name} accepted!")
|
||||||
|
else
|
||||||
|
flash[:alert] = 'Please make sure that the track has a room and start/end dates before accepting it'
|
||||||
|
redirect_to edit_admin_conference_program_track_path(@conference.short_title, @track)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def confirm
|
||||||
|
update_state(:confirm, "Track #{@track.name} confirmed!")
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_reject
|
||||||
|
update_state(:to_reject, "Track #{@track.name} marked as a possible rejection!")
|
||||||
|
end
|
||||||
|
|
||||||
|
def reject
|
||||||
|
update_state(:reject, "Track #{@track.name} rejected!")
|
||||||
|
end
|
||||||
|
|
||||||
|
def cancel
|
||||||
|
update_state(:cancel, "Track #{@track.name} canceled!")
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_selected_schedule
|
||||||
|
if @track.update_attributes(params.require(:track).permit(:selected_schedule_id))
|
||||||
|
respond_to do |format|
|
||||||
|
format.js { render json: {} }
|
||||||
|
end
|
||||||
|
else
|
||||||
|
respond_to do |format|
|
||||||
|
format.js { render json: { errors: "The selected schedule couldn't be updated #{@track.errors.to_a.join('. ')}" }, status: 422 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def track_params
|
def track_params
|
||||||
params.require(:track).permit(:name, :description, :color)
|
params.require(:track).permit(:name, :description, :color, :short_name, :cfp_active, :start_date, :end_date, :room_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_state(transition, notice)
|
||||||
|
errors = @track.update_state(transition)
|
||||||
|
|
||||||
|
if errors.blank?
|
||||||
|
flash[:notice] = notice
|
||||||
|
else
|
||||||
|
flash[:error] = errors
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_back_or_to(admin_conference_program_tracks_path(conference_id: @conference.short_title))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,17 @@ module Admin
|
||||||
@user = User.new
|
@user = User.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@user = User.new(user_params)
|
||||||
|
@user.skip_confirmation!
|
||||||
|
if @user.save
|
||||||
|
redirect_to admin_users_path, notice: 'User successfully created.'
|
||||||
|
else
|
||||||
|
flash.now[:error] = "Creating User failed: #{@user.errors.full_messages.join('. ')}."
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@users = User.all
|
@users = User.all
|
||||||
end
|
end
|
||||||
|
|
@ -50,8 +61,9 @@ module Admin
|
||||||
private
|
private
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
params.require(:user).permit(:email, :name, :email_public, :biography, :nickname, :affiliation, :is_admin, :username, :login, :is_disabled,
|
params.require(:user).permit(:email, :name, :email_public, :biography, :nickname, :affiliation, :is_admin,
|
||||||
:tshirt, :mobile, :volunteer_experience, :languages, :to_confirm, role_ids: [])
|
:username, :login, :is_disabled, :tshirt, :mobile, :volunteer_experience,
|
||||||
|
:languages, :to_confirm, :password, role_ids: [])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ module Admin
|
||||||
redirect_to admin_conference_venue_path(conference_id: @conference.short_title),
|
redirect_to admin_conference_venue_path(conference_id: @conference.short_title),
|
||||||
notice: 'Venue was successfully updated.'
|
notice: 'Venue was successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Update venue failed: #{@venue.errors.full_messages.join('. ')}."
|
flash.now[:error] = "Update venue failed: #{@venue.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,21 @@
|
||||||
module Admin
|
module Admin
|
||||||
class VersionsController < Admin::BaseController
|
class VersionsController < Admin::BaseController
|
||||||
skip_authorization_check
|
load_resource :conference, find_by: :short_title, only: :index
|
||||||
|
load_and_authorize_resource class: PaperTrail::Version
|
||||||
|
|
||||||
def index
|
def index
|
||||||
authorize! :index, PaperTrail::Version.new(item_type: 'User')
|
@conferences_with_role = current_user.is_admin? ? Conference.pluck(:short_title) : Conference.with_role([:organizer, :cfp, :info_desk], current_user).pluck(:short_title)
|
||||||
conf_ids_for_organizer = current_user.is_admin? ? Conference.pluck(:id) : Conference.with_role(:organizer, current_user).pluck(:id)
|
|
||||||
@versions = PaperTrail::Version.where(["conference_id IN (?) OR item_type = 'User'", conf_ids_for_organizer])
|
if current_user.has_role? :organization_admin, :any
|
||||||
|
@conferences_with_role = Organization.with_role('organization_admin', current_user).map { |org| org.conferences.pluck :short_title }.flatten
|
||||||
|
end
|
||||||
|
@conferences_with_role.uniq!
|
||||||
|
|
||||||
|
return if @conference.blank?
|
||||||
|
@versions = PaperTrail::Version.where(conference_id: @conference.id).accessible_by(current_ability)
|
||||||
end
|
end
|
||||||
|
|
||||||
def revert_attribute
|
def revert_attribute
|
||||||
@version = PaperTrail::Version.find(params[:id])
|
|
||||||
authorize! :revert_attribute, @version
|
|
||||||
|
|
||||||
if params[:attribute] && @version.changeset.reject{ |_, values| values[0].blank? && values[1].blank? }.keys.include?(params[:attribute])
|
if params[:attribute] && @version.changeset.reject{ |_, values| values[0].blank? && values[1].blank? }.keys.include?(params[:attribute])
|
||||||
if @version.item[params[:attribute]] == @version.changeset[params[:attribute]][0]
|
if @version.item[params[:attribute]] == @version.changeset[params[:attribute]][0]
|
||||||
flash[:error] = 'The item is already in the state that you are trying to revert it back to'
|
flash[:error] = 'The item is already in the state that you are trying to revert it back to'
|
||||||
|
|
@ -33,9 +37,6 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def revert_object
|
def revert_object
|
||||||
@version = PaperTrail::Version.find(params[:id])
|
|
||||||
authorize! :revert_object, @version
|
|
||||||
|
|
||||||
if @version.event != 'create'
|
if @version.event != 'create'
|
||||||
if @version.reify.save
|
if @version.reify.save
|
||||||
flash[:notice] = 'The selected change was successfully reverted'
|
flash[:notice] = 'The selected change was successfully reverted'
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
module Admin
|
module Admin
|
||||||
class VolunteersController < Admin::BaseController
|
class VolunteersController < Admin::BaseController
|
||||||
|
include VolunteersHelper
|
||||||
load_and_authorize_resource :conference, find_by: :short_title
|
load_and_authorize_resource :conference, find_by: :short_title
|
||||||
|
|
||||||
def index
|
def index
|
||||||
if can_manage_volunteers(@conference)
|
if can_manage_volunteers?(@conference)
|
||||||
render :index
|
render :index
|
||||||
else
|
else
|
||||||
authorize! :index, :volunteer
|
authorize! :index, :volunteer
|
||||||
|
|
@ -11,11 +12,11 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
if can_manage_volunteers(@conference)
|
if can_manage_volunteers?(@conference)
|
||||||
if @conference.use_vpositions
|
@volunteers = if @conference.use_vpositions
|
||||||
@volunteers = @conference.registrations.joins(:vchoices).uniq
|
@conference.registrations.joins(:vchoices).uniq
|
||||||
else
|
else
|
||||||
@volunteers = @conference.registrations.where(volunteer: true)
|
@conference.registrations.where(volunteer: true)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
authorize! :index, :volunteer
|
authorize! :index, :volunteer
|
||||||
|
|
|
||||||
97
app/controllers/booths_controller.rb
Normal file
97
app/controllers/booths_controller.rb
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
class BoothsController < ApplicationController
|
||||||
|
before_action :authenticate_user!
|
||||||
|
load_resource :conference, find_by: :short_title
|
||||||
|
load_and_authorize_resource through: :conference
|
||||||
|
skip_authorize_resource only: [:withdraw, :confirm, :restart]
|
||||||
|
|
||||||
|
def index
|
||||||
|
@booths = current_user.booths.where(conference_id: @conference.id).uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
def show; end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@url = conference_booths_path(@conference.short_title)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@url = conference_booths_path(@conference.short_title)
|
||||||
|
|
||||||
|
@booth.submitter = current_user
|
||||||
|
|
||||||
|
if @booth.save
|
||||||
|
redirect_to conference_booths_path,
|
||||||
|
notice: 'Booth successfully created.'
|
||||||
|
else
|
||||||
|
flash.now[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}."
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
@url = conference_booth_path(@conference.short_title, @booth.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@url = conference_booth_path(@conference.short_title, @booth.id)
|
||||||
|
@booth.update_attributes(booth_params)
|
||||||
|
|
||||||
|
if @booth.save
|
||||||
|
redirect_to conference_booths_path,
|
||||||
|
notice: 'Booth successfully updated!'
|
||||||
|
else
|
||||||
|
flash.now[:error] = "Booth could not be updated. #{@booth.errors.full_messages.to_sentence}."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy; end
|
||||||
|
|
||||||
|
def withdraw
|
||||||
|
authorize! :update, @booth
|
||||||
|
@url = conference_booth_path(@conference.short_title, @booth.id)
|
||||||
|
|
||||||
|
@booth.withdraw!
|
||||||
|
|
||||||
|
if @booth.save
|
||||||
|
redirect_to conference_booths_path,
|
||||||
|
notice: 'Booth successfully withdrawn'
|
||||||
|
else
|
||||||
|
flash.now[:error] = "Booth could not be withdrawn. #{@booth.errors.full_messages.to_sentence}."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def confirm
|
||||||
|
authorize! :update, @booth
|
||||||
|
@url = conference_booth_path(@conference.short_title, @booth.id)
|
||||||
|
|
||||||
|
@booth.confirm!
|
||||||
|
|
||||||
|
if @booth.save
|
||||||
|
redirect_to conference_booths_path,
|
||||||
|
notice: 'Booth successfully confirmed'
|
||||||
|
else
|
||||||
|
flash.now[:error] = "Booth could not be confirmed. #{@booth.errors.full_messages.to_sentence}."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def restart
|
||||||
|
authorize! :update, @booth
|
||||||
|
@url = conference_booth_path(@conference.short_title, @booth.id)
|
||||||
|
|
||||||
|
@booth.restart!
|
||||||
|
|
||||||
|
if @booth.save
|
||||||
|
redirect_to conference_booths_path,
|
||||||
|
notice: 'Booth successfully re-submitted'
|
||||||
|
else
|
||||||
|
flash.now[:error] = "Booth could not be re-submitted. #{@booth.errors.full_messages.to_sentence}."
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def booth_params
|
||||||
|
params.require(:booth).permit(:title, :description, :reasoning, :state, :picture, :conference_id,
|
||||||
|
:created_at, :updated_at, :submitter_relationship, :website_url, responsible_ids: [])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -38,11 +38,11 @@ class ConferenceRegistrationsController < ApplicationController
|
||||||
def create
|
def create
|
||||||
@registration = @conference.registrations.new(registration_params)
|
@registration = @conference.registrations.new(registration_params)
|
||||||
|
|
||||||
if current_user.nil?
|
@user = if current_user.nil?
|
||||||
# @user variable needs to be set so that _sign_up_form_embedded works properly
|
# @user variable needs to be set so that _sign_up_form_embedded works properly
|
||||||
@user = @registration.build_user(user_params)
|
@registration.build_user(user_params)
|
||||||
else
|
else
|
||||||
@user = current_user
|
current_user
|
||||||
end
|
end
|
||||||
|
|
||||||
@registration.user = @user
|
@registration.user = @user
|
||||||
|
|
@ -65,7 +65,7 @@ class ConferenceRegistrationsController < ApplicationController
|
||||||
notice: 'You are now registered and will be receiving E-Mail notifications.'
|
notice: 'You are now registered and will be receiving E-Mail notifications.'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
flash[:error] = "Could not create your registration for #{@conference.title}: "\
|
flash.now[:error] = "Could not create your registration for #{@conference.title}: "\
|
||||||
"#{@registration.errors.full_messages.join('. ')}."
|
"#{@registration.errors.full_messages.join('. ')}."
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
|
|
@ -76,7 +76,7 @@ class ConferenceRegistrationsController < ApplicationController
|
||||||
redirect_to conference_conference_registration_path(@conference.short_title),
|
redirect_to conference_conference_registration_path(@conference.short_title),
|
||||||
notice: 'Registration was successfully updated.'
|
notice: 'Registration was successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Could not update your registration for #{@conference.title}: "\
|
flash.now[:error] = "Could not update your registration for #{@conference.title}: "\
|
||||||
"#{@registration.errors.full_messages.join('. ')}."
|
"#{@registration.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
|
|
@ -108,8 +108,8 @@ class ConferenceRegistrationsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def registration_params
|
def registration_params
|
||||||
params.require(:registration).
|
params.require(:registration)
|
||||||
permit(
|
.permit(
|
||||||
:conference_id, :arrival, :departure,
|
:conference_id, :arrival, :departure,
|
||||||
:volunteer,
|
:volunteer,
|
||||||
vchoice_ids: [], qanswer_ids: [],
|
vchoice_ids: [], qanswer_ids: [],
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,29 @@
|
||||||
class ConferencesController < ApplicationController
|
class ConferencesController < ApplicationController
|
||||||
protect_from_forgery with: :null_session
|
protect_from_forgery with: :null_session
|
||||||
before_action :respond_to_options
|
before_action :respond_to_options
|
||||||
load_and_authorize_resource find_by: :short_title
|
load_and_authorize_resource find_by: :short_title, except: :show
|
||||||
load_resource :program, through: :conference, singleton: true, except: :index
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@current = Conference.where('end_date >= ?', Date.current).reorder(start_date: :asc)
|
@current = Conference.where('end_date >= ?', Date.current).reorder(start_date: :asc)
|
||||||
@antiquated = @conferences - @current
|
@antiquated = @conferences - @current
|
||||||
end
|
end
|
||||||
|
|
||||||
def show; end
|
def show
|
||||||
|
@conference = if params[:id]
|
||||||
|
Conference.find_by_short_title(params[:id])
|
||||||
|
else
|
||||||
|
load_conference_by_domain
|
||||||
|
end
|
||||||
|
authorize! :show, @conference
|
||||||
|
@program = @conference.program
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def load_conference_by_domain
|
||||||
|
Conference.find_by(custom_domain: request.domain)
|
||||||
|
end
|
||||||
|
|
||||||
def respond_to_options
|
def respond_to_options
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { head :ok }
|
format.html { head :ok }
|
||||||
|
|
|
||||||
9
app/controllers/openids_controller.rb
Normal file
9
app/controllers/openids_controller.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
class OpenidsController < ApplicationController
|
||||||
|
load_and_authorize_resource :user
|
||||||
|
load_and_authorize_resource through: :user
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
@openid.destroy
|
||||||
|
redirect_to :back
|
||||||
|
end
|
||||||
|
end
|
||||||
7
app/controllers/organizations_controller.rb
Normal file
7
app/controllers/organizations_controller.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
class OrganizationsController < ApplicationController
|
||||||
|
load_and_authorize_resource :organization
|
||||||
|
|
||||||
|
def index
|
||||||
|
@organizations = Organization.all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -10,6 +10,9 @@ class PaymentsController < ApplicationController
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false)
|
@total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false)
|
||||||
|
if @total_amount_to_pay.zero?
|
||||||
|
raise CanCan::AccessDenied.new('Nothing to pay for!', :new, Payment)
|
||||||
|
end
|
||||||
@unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference)
|
@unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -18,12 +21,12 @@ class PaymentsController < ApplicationController
|
||||||
|
|
||||||
if @payment.purchase && @payment.save
|
if @payment.purchase && @payment.save
|
||||||
update_purchased_ticket_purchases
|
update_purchased_ticket_purchases
|
||||||
redirect_to conference_conference_registration_path(@conference.short_title),
|
redirect_to conference_physical_tickets_path,
|
||||||
notice: 'Thanks! Your ticket is booked successfully.'
|
notice: 'Thanks! Your ticket is booked successfully.'
|
||||||
else
|
else
|
||||||
@total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false)
|
@total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false)
|
||||||
@unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference)
|
@unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference)
|
||||||
flash[:error] = @payment.errors.full_messages.to_sentence + ' Please try again with correct credentials.'
|
flash.now[:error] = @payment.errors.full_messages.to_sentence + ' Please try again with correct credentials.'
|
||||||
render :new
|
render :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -38,6 +41,8 @@ class PaymentsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_purchased_ticket_purchases
|
def update_purchased_ticket_purchases
|
||||||
current_user.ticket_purchases.by_conference(@conference).unpaid.update_all(paid: true, payment_id: @payment.id)
|
current_user.ticket_purchases.by_conference(@conference).unpaid.each do |ticket_purchase|
|
||||||
|
ticket_purchase.pay(@payment)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
28
app/controllers/physical_tickets_controller.rb
Normal file
28
app/controllers/physical_tickets_controller.rb
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
class PhysicalTicketsController < ApplicationController
|
||||||
|
before_action :authenticate_user!
|
||||||
|
load_resource :conference, find_by: :short_title
|
||||||
|
load_and_authorize_resource find_by: :token
|
||||||
|
authorize_resource :conference_registrations, class: Registration
|
||||||
|
|
||||||
|
def index
|
||||||
|
@physical_tickets = current_user.physical_tickets.by_conference(@conference)
|
||||||
|
@unpaid_ticket_purchases = current_user.ticket_purchases.by_conference(@conference).unpaid
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@file_name = "ticket_for_#{@conference.short_title}"
|
||||||
|
@user = @physical_ticket.user
|
||||||
|
@ticket_layout = @conference.ticket_layout.to_sym
|
||||||
|
@qrcode_image = RQRCode::QRCode.new(@physical_ticket.token).as_png(size: 180, border_modules: 0)
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.pdf do
|
||||||
|
pdf = TicketPdf.new(@conference, @user, @physical_ticket, @ticket_layout, @file_name)
|
||||||
|
send_data pdf.render,
|
||||||
|
filename: @file_name,
|
||||||
|
type: 'application/pdf',
|
||||||
|
disposition: 'attachment'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -13,9 +13,8 @@ class ProposalsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
# FIXME: We should show more than the first speaker
|
|
||||||
@speaker = @event.speakers.first || @event.submitter
|
|
||||||
@event_schedule = @event.event_schedules.find_by(schedule_id: @program.selected_schedule_id)
|
@event_schedule = @event.event_schedules.find_by(schedule_id: @program.selected_schedule_id)
|
||||||
|
@speakers_ordered = @event.speakers_ordered
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
|
|
@ -40,7 +39,7 @@ class ProposalsController < ApplicationController
|
||||||
if @user.save
|
if @user.save
|
||||||
sign_in(@user)
|
sign_in(@user)
|
||||||
else
|
else
|
||||||
flash[:error] = "Could not save user: #{@user.errors.full_messages.join(', ')}"
|
flash.now[:error] = "Could not save user: #{@user.errors.full_messages.join(', ')}"
|
||||||
render action: 'new'
|
render action: 'new'
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
@ -48,16 +47,21 @@ class ProposalsController < ApplicationController
|
||||||
|
|
||||||
# User which creates the proposal is both `submitter` and `speaker` of proposal
|
# User which creates the proposal is both `submitter` and `speaker` of proposal
|
||||||
# by default.
|
# by default.
|
||||||
# TODO: Allow submitter to add speakers to proposals
|
@event.speakers = [current_user]
|
||||||
@event.event_users.new(user: current_user,
|
@event.submitter = current_user
|
||||||
event_role: 'submitter')
|
|
||||||
@event.event_users.new(user: current_user,
|
track = Track.find_by(id: params[:event][:track_id])
|
||||||
event_role: 'speaker')
|
if track && !track.cfp_active
|
||||||
|
flash.now[:error] = 'You have selected a track that doesn\'t accept proposals'
|
||||||
|
render action: 'new'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if @event.save
|
if @event.save
|
||||||
ahoy.track 'Event submission', title: 'New submission'
|
ahoy.track 'Event submission', title: 'New submission'
|
||||||
redirect_to conference_program_proposals_path(@conference.short_title), notice: 'Proposal was successfully submitted.'
|
redirect_to conference_program_proposals_path(@conference.short_title), notice: 'Proposal was successfully submitted.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Could not submit proposal: #{@event.errors.full_messages.join(', ')}"
|
flash.now[:error] = "Could not submit proposal: #{@event.errors.full_messages.join(', ')}"
|
||||||
render action: 'new'
|
render action: 'new'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -65,11 +69,18 @@ class ProposalsController < ApplicationController
|
||||||
def update
|
def update
|
||||||
@url = conference_program_proposal_path(@conference.short_title, params[:id])
|
@url = conference_program_proposal_path(@conference.short_title, params[:id])
|
||||||
|
|
||||||
|
track = Track.find_by(id: params[:event][:track_id])
|
||||||
|
if track && !track.cfp_active
|
||||||
|
flash.now[:error] = 'You have selected a track that doesn\'t accept proposals'
|
||||||
|
render action: 'edit'
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if @event.update(event_params)
|
if @event.update(event_params)
|
||||||
redirect_to conference_program_proposals_path(conference_id: @conference.short_title),
|
redirect_to conference_program_proposals_path(conference_id: @conference.short_title),
|
||||||
notice: 'Proposal was successfully updated.'
|
notice: 'Proposal was successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "Could not update proposal: #{@event.errors.full_messages.join(', ')}"
|
flash.now[:error] = "Could not update proposal: #{@event.errors.full_messages.join(', ')}"
|
||||||
render action: 'edit'
|
render action: 'edit'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -147,7 +158,9 @@ class ProposalsController < ApplicationController
|
||||||
def event_params
|
def event_params
|
||||||
params.require(:event).permit(:event_type_id, :track_id, :difficulty_level_id,
|
params.require(:event).permit(:event_type_id, :track_id, :difficulty_level_id,
|
||||||
:title, :subtitle, :abstract, :description,
|
:title, :subtitle, :abstract, :description,
|
||||||
:require_registration, :max_attendees, :language)
|
:require_registration, :max_attendees, :language,
|
||||||
|
speaker_ids: []
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@ class RegistrationsController < Devise::RegistrationsController
|
||||||
|
|
||||||
def configure_permitted_parameters
|
def configure_permitted_parameters
|
||||||
devise_parameter_sanitizer.permit(:account_update) do |u|
|
devise_parameter_sanitizer.permit(:account_update) do |u|
|
||||||
u.
|
u
|
||||||
permit(:email, :password, :password_confirmation, :current_password, :username, :email_public)
|
.permit(:email, :password, :password_confirmation, :current_password, :username, :email_public)
|
||||||
end
|
end
|
||||||
devise_parameter_sanitizer.permit(:sign_up) do |u|
|
devise_parameter_sanitizer.permit(:sign_up) do |u|
|
||||||
u.
|
u
|
||||||
permit(:email, :password, :password_confirmation, :name, :username)
|
.permit(:email, :password, :password_confirmation, :name, :username)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
class SchedulesController < ApplicationController
|
class SchedulesController < ApplicationController
|
||||||
|
load_and_authorize_resource
|
||||||
protect_from_forgery with: :null_session
|
protect_from_forgery with: :null_session
|
||||||
before_action :respond_to_options
|
before_action :respond_to_options
|
||||||
load_and_authorize_resource :conference, find_by: :short_title
|
load_resource :conference, find_by: :short_title
|
||||||
load_resource :program, through: :conference, singleton: true, except: :index
|
load_resource :program, through: :conference, singleton: true, except: :index
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
|
@ -13,17 +14,24 @@ class SchedulesController < ApplicationController
|
||||||
|
|
||||||
@events_xml = schedules.map(&:event).group_by{ |event| event.time.to_date } if schedules
|
@events_xml = schedules.map(&:event).group_by{ |event| event.time.to_date } if schedules
|
||||||
@dates = @conference.start_date..@conference.end_date
|
@dates = @conference.start_date..@conference.end_date
|
||||||
@step_minutes = EventType::LENGTH_STEP.minutes
|
@step_minutes = @program.schedule_interval.minutes
|
||||||
@conf_start = @conference.start_hour
|
@conf_start = @conference.start_hour
|
||||||
@conf_period = @conference.end_hour - @conf_start
|
@conf_period = @conference.end_hour - @conf_start
|
||||||
|
|
||||||
# the schedule takes you to today if it is a date of the schedule
|
# the schedule takes you to today if it is a date of the schedule
|
||||||
@current_day = @conference.current_conference_day
|
@current_day = @conference.current_conference_day
|
||||||
@day = @current_day.present? ? @current_day : @dates.first
|
@day = @current_day.present? ? @current_day : @dates.first
|
||||||
return unless @current_day
|
unless @current_day
|
||||||
# the schedule takes you to the current time if it is beetween the start and the end time.
|
# the schedule takes you to the current time if it is beetween the start and the end time.
|
||||||
@hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour)
|
@hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour)
|
||||||
end
|
end
|
||||||
|
# Ids of the schedules of confrmed self_organized tracks along with the selected_schedule_id
|
||||||
|
@selected_schedules_ids = [@conference.program.selected_schedule_id]
|
||||||
|
@conference.program.tracks.self_organized.confirmed.each do |track|
|
||||||
|
@selected_schedules_ids << track.selected_schedule_id
|
||||||
|
end
|
||||||
|
@selected_schedules_ids.compact!
|
||||||
|
end
|
||||||
|
|
||||||
def events
|
def events
|
||||||
@dates = @conference.start_date..@conference.end_date
|
@dates = @conference.start_date..@conference.end_date
|
||||||
|
|
@ -31,11 +39,7 @@ class SchedulesController < ApplicationController
|
||||||
@events_schedules = @program.selected_event_schedules
|
@events_schedules = @program.selected_event_schedules
|
||||||
@events_schedules = [] unless @events_schedules
|
@events_schedules = [] unless @events_schedules
|
||||||
|
|
||||||
@unscheduled_events = if @program.selected_schedule
|
@unscheduled_events = @program.events.confirmed - @events_schedules.map(&:event)
|
||||||
@program.events.confirmed - @program.selected_schedule.events
|
|
||||||
else
|
|
||||||
@program.events.confirmed
|
|
||||||
end
|
|
||||||
|
|
||||||
day = @conference.current_conference_day
|
day = @conference.current_conference_day
|
||||||
@tag = day.strftime('%Y-%m-%d') if day
|
@tag = day.strftime('%Y-%m-%d') if day
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,19 @@ class SubscriptionsController < ApplicationController
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@subscription = current_user.subscriptions.build(conference_id: @conference.id)
|
@subscription = current_user.subscriptions.build(conference_id: @conference.id)
|
||||||
if @subscription.save!
|
if @subscription.save
|
||||||
redirect_to root_path, notice: "You have been subscribed to receive email notifications for #{@conference.short_title}."
|
redirect_to root_path, notice: "You have subscribed to receive email notifications for #{@conference.title}."
|
||||||
else
|
else
|
||||||
redirect_to root_path, error: subscription.errors.full_messages.to_sentence
|
redirect_to root_path, error: @subscription.errors.full_messages.to_sentence
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@subscription = current_user.subscriptions.find_by(conference_id: @conference.id)
|
@subscription = current_user.subscriptions.find_by(conference_id: @conference.id)
|
||||||
|
|
||||||
|
redirect_to(root_path, error: "You are not subscribed to #{@conference.title}.") && return unless @subscription
|
||||||
if @subscription.destroy
|
if @subscription.destroy
|
||||||
redirect_to root_path, notice: "You have been unsubscribed and now you will not be receiving email notifications for #{@conference.short_title}."
|
redirect_to root_path, notice: "You have unsubscribed and you will not be receiving email notifications for #{@conference.title}."
|
||||||
else
|
else
|
||||||
redirect_to root_path, error: @subscription.errors.full_messages.to_sentence
|
redirect_to root_path, error: @subscription.errors.full_messages.to_sentence
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ class TicketPurchasesController < ApplicationController
|
||||||
before_filter :authenticate_user!
|
before_filter :authenticate_user!
|
||||||
load_resource :conference, find_by: :short_title
|
load_resource :conference, find_by: :short_title
|
||||||
authorize_resource :conference_registrations, class: Registration
|
authorize_resource :conference_registrations, class: Registration
|
||||||
|
authorize_resource
|
||||||
|
|
||||||
def create
|
def create
|
||||||
current_user.ticket_purchases.by_conference(@conference).unpaid.destroy_all
|
current_user.ticket_purchases.by_conference(@conference).unpaid.destroy_all
|
||||||
|
|
@ -11,18 +12,22 @@ class TicketPurchasesController < ApplicationController
|
||||||
redirect_to new_conference_payment_path,
|
redirect_to new_conference_payment_path,
|
||||||
notice: 'Please pay here to get tickets.'
|
notice: 'Please pay here to get tickets.'
|
||||||
elsif current_user.ticket_purchases.by_conference(@conference).paid.any?
|
elsif current_user.ticket_purchases.by_conference(@conference).paid.any?
|
||||||
redirect_to conference_conference_registration_path(@conference.short_title),
|
redirect_to conference_physical_tickets_path,
|
||||||
notice: 'You have free tickets for the conference.'
|
notice: 'You have free tickets for the conference.'
|
||||||
else
|
else
|
||||||
redirect_to conference_tickets_path(@conference.short_title),
|
redirect_to conference_tickets_path(@conference.short_title),
|
||||||
error: 'Please get at least one ticket to continue.'
|
error: 'Please get at least one ticket to continue.'
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
redirect_to conference_conference_registration_path(@conference.short_title),
|
redirect_to conference_tickets_path(@conference.short_title),
|
||||||
error: "Oops, something went wrong with your purchase! #{message}"
|
error: "Oops, something went wrong with your purchase! #{message}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def index
|
||||||
|
@unpaid_ticket_purchases = current_user.ticket_purchases.by_conference(@conference).unpaid
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def ticket_purchase_params
|
def ticket_purchase_params
|
||||||
|
|
|
||||||
70
app/controllers/tracks_controller.rb
Normal file
70
app/controllers/tracks_controller.rb
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
class TracksController < ApplicationController
|
||||||
|
load_resource :conference, find_by: :short_title
|
||||||
|
load_resource :program, through: :conference, singleton: true
|
||||||
|
load_and_authorize_resource through: :program, find_by: :short_name
|
||||||
|
|
||||||
|
def index
|
||||||
|
@tracks = @tracks.where(submitter: current_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show; end
|
||||||
|
|
||||||
|
def new
|
||||||
|
@track = @program.tracks.new(color: @conference.next_color_for_collection(:tracks))
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit; end
|
||||||
|
|
||||||
|
def create
|
||||||
|
@track = @program.tracks.new(track_params)
|
||||||
|
@track.submitter = current_user
|
||||||
|
@track.cfp_active = false
|
||||||
|
if @track.save
|
||||||
|
redirect_to conference_program_tracks_path(conference_id: @conference.short_title),
|
||||||
|
notice: 'Track request successfully created.'
|
||||||
|
else
|
||||||
|
flash.now[:error] = "Creating Track request failed: #{@track.errors.full_messages.join('. ')}."
|
||||||
|
render :new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
if @track.update_attributes(track_params)
|
||||||
|
redirect_to conference_program_tracks_path(conference_id: @conference.short_title),
|
||||||
|
notice: 'Track request successfully updated.'
|
||||||
|
else
|
||||||
|
flash.now[:error] = "Track request update failed: #{@track.errors.full_messages.join('. ')}."
|
||||||
|
render :edit
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def restart
|
||||||
|
update_state(:restart, "Track #{@track.name} re-submitted.")
|
||||||
|
end
|
||||||
|
|
||||||
|
def confirm
|
||||||
|
update_state(:confirm, "Track #{@track.name} confirmed.")
|
||||||
|
end
|
||||||
|
|
||||||
|
def withdraw
|
||||||
|
update_state(:withdraw, "Track #{@track.name} withdrawn.")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def track_params
|
||||||
|
params.require(:track).permit(:name, :description, :color, :short_name, :start_date, :end_date, :relevance)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_state(transition, notice)
|
||||||
|
errors = @track.update_state(transition)
|
||||||
|
|
||||||
|
if errors.blank?
|
||||||
|
flash[:notice] = notice
|
||||||
|
else
|
||||||
|
flash[:error] = errors
|
||||||
|
end
|
||||||
|
|
||||||
|
redirect_back_or_to(conference_program_tracks_path(conference_id: @conference.short_title))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -11,13 +11,13 @@ module Users
|
||||||
|
|
||||||
def handle(provider)
|
def handle(provider)
|
||||||
auth_hash = request.env['omniauth.auth']
|
auth_hash = request.env['omniauth.auth']
|
||||||
uid = auth_hash[:uid]
|
username = auth_hash.info.email.split('@')[0]
|
||||||
openid = Openid.find_for_oauth(auth_hash) # Get or create openid
|
openid = Openid.find_for_oauth(auth_hash) # Get or create openid
|
||||||
# If openid exists and is associated with a user, sign in with associated user,
|
# If openid exists and is associated with a user, sign in with associated user,
|
||||||
# even if the email of the associated user and the email of the provided openid are different
|
# even if the email of the associated user and the email of the provided openid are different
|
||||||
unless (user = openid.user)
|
unless (user = openid.user)
|
||||||
user = User.find_for_auth(auth_hash, current_user) # Get or create users
|
user = User.find_for_auth(auth_hash, current_user) # Get or create users
|
||||||
user.username = "#{uid}@#{provider}" if user.username.blank?
|
user.username = "#{username}@#{provider}" if user.username.blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ class UsersController < ApplicationController
|
||||||
if @user.update(user_params)
|
if @user.update(user_params)
|
||||||
redirect_to @user, notice: 'User was successfully updated.'
|
redirect_to @user, notice: 'User was successfully updated.'
|
||||||
else
|
else
|
||||||
flash[:error] = "An error prohibited your Profile from being saved: #{@user.errors.full_messages.join('. ')}."
|
flash.now[:error] = "An error prohibited your Profile from being saved: #{@user.errors.full_messages.join('. ')}."
|
||||||
render :edit
|
render :edit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
7
app/helpers/admin/volunteers_helper.rb
Normal file
7
app/helpers/admin/volunteers_helper.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
module Admin
|
||||||
|
module VolunteersHelper
|
||||||
|
def can_manage_volunteers?(conference)
|
||||||
|
current_user.has_role?(:organizer, conference) || current_user.has_role?(:volunteers_coordinator, conference)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
module ApplicationHelper
|
module ApplicationHelper
|
||||||
##
|
|
||||||
# Returns a string build from the start and end date of the given conference.
|
# Returns a string build from the start and end date of the given conference.
|
||||||
#
|
#
|
||||||
# If the conference is only one day long
|
# If the conference is only one day long
|
||||||
|
|
@ -34,43 +33,9 @@ module ApplicationHelper
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
# Returns time with conference timezone
|
||||||
# Checks if the voting has already started, or if it has already ended
|
def time_with_timezone(time)
|
||||||
#
|
time.strftime('%F %R') + ' ' + @conference.timezone.to_s
|
||||||
def voting_open_or_close(program)
|
|
||||||
return if program.voting_period?
|
|
||||||
if program.voting_start_date > Time.current
|
|
||||||
return 'Voting period has not started yet!'
|
|
||||||
else # voting_end_date > Date.today because voting_start_date < voting_end_date
|
|
||||||
return 'Voting period is over!'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Gets an EventType object, and returns its length in timestamp format (HH:MM)
|
|
||||||
# ====Gets
|
|
||||||
# * +Integer+ -> 30
|
|
||||||
# ====Returns
|
|
||||||
# * +String+ -> "00:30"
|
|
||||||
def length_timestamp(length)
|
|
||||||
[length / 60, length % 60].map { |t| t.to_s.rjust(2, '0') }.join(':')
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# Gets a datetime object
|
|
||||||
# ====Returns
|
|
||||||
# * +String+ -> formated datetime object
|
|
||||||
def format_datetime(obj)
|
|
||||||
return unless obj
|
|
||||||
obj.strftime('%Y-%m-%d %H:%M')
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# ====Returns
|
|
||||||
# * +String+ -> number of registrations / max allowed registrations
|
|
||||||
def registered_text(event)
|
|
||||||
return "Registered: #{event.registrations.count}/#{event.max_attendees}" if event.max_attendees
|
|
||||||
"Registered: #{event.registrations.count}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set resource_name for devise so that we can call the devise help links (views/devise/shared/_links) from anywhere (eg sign_up form in proposals#new)
|
# Set resource_name for devise so that we can call the devise help links (views/devise/shared/_links) from anywhere (eg sign_up form in proposals#new)
|
||||||
|
|
@ -78,141 +43,6 @@ module ApplicationHelper
|
||||||
:user
|
:user
|
||||||
end
|
end
|
||||||
|
|
||||||
# Set devise_mapping for devise so that we can call the devise help links (views/devise/shared/_links) from anywhere (eg sign_up form in proposals#new)
|
|
||||||
def devise_mapping
|
|
||||||
@devise_mapping ||= Devise.mappings[:user]
|
|
||||||
end
|
|
||||||
|
|
||||||
def event_status_icon(event)
|
|
||||||
case event.state
|
|
||||||
when 'new'
|
|
||||||
'fa-eye'
|
|
||||||
when 'unconfirmed'
|
|
||||||
'fa-check text-muted'
|
|
||||||
when 'confirmed'
|
|
||||||
'fa-check text-success'
|
|
||||||
when 'rejected', 'withdrawn', 'canceled'
|
|
||||||
'fa-ban'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def event_progress_color(progress)
|
|
||||||
progress = progress.to_i
|
|
||||||
if progress == 100
|
|
||||||
'progress-bar-success'
|
|
||||||
elsif progress >= 85
|
|
||||||
'progress-bar-info'
|
|
||||||
elsif progress >= 71
|
|
||||||
'progress-bar-warning'
|
|
||||||
else
|
|
||||||
'progress-bar-danger'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def target_progress_color(progress)
|
|
||||||
progress = progress.to_i
|
|
||||||
result =
|
|
||||||
case
|
|
||||||
when progress >= 90 then 'green'
|
|
||||||
when progress < 90 && progress >= 80 then 'orange'
|
|
||||||
else 'red'
|
|
||||||
end
|
|
||||||
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def days_left_color(days_left)
|
|
||||||
days_left = days_left.to_i
|
|
||||||
if days_left > 30
|
|
||||||
result = 'green'
|
|
||||||
elsif days_left < 30 && days_left > 10
|
|
||||||
result = 'orange'
|
|
||||||
else
|
|
||||||
result = 'red'
|
|
||||||
end
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def bootstrap_class_for(flash_type)
|
|
||||||
case flash_type
|
|
||||||
when 'success'
|
|
||||||
'alert-success'
|
|
||||||
when 'error'
|
|
||||||
'alert-danger'
|
|
||||||
when 'alert'
|
|
||||||
'alert-warning'
|
|
||||||
when 'notice'
|
|
||||||
'alert-info'
|
|
||||||
else
|
|
||||||
'alert-warning'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def label_for(event_state)
|
|
||||||
result = ''
|
|
||||||
case event_state
|
|
||||||
when 'new'
|
|
||||||
result = 'label label-primary'
|
|
||||||
when 'withdrawn'
|
|
||||||
result = 'label label-danger'
|
|
||||||
when 'unconfirmed'
|
|
||||||
result = 'label label-success'
|
|
||||||
when 'confirmed'
|
|
||||||
result = 'label label-success'
|
|
||||||
when 'rejected'
|
|
||||||
result = 'label label-warning'
|
|
||||||
when 'canceled'
|
|
||||||
result = 'label label-danger'
|
|
||||||
end
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
def icon_for_todo(bool)
|
|
||||||
if bool
|
|
||||||
return 'fa fa-check'
|
|
||||||
else
|
|
||||||
return 'fa fa-times'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def class_for_todo(bool)
|
|
||||||
if bool
|
|
||||||
return 'todolist-ok'
|
|
||||||
else
|
|
||||||
return 'todolist-missing'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def normalize_array_length(hashmap, length)
|
|
||||||
hashmap.each do |_, value|
|
|
||||||
if value.length < length
|
|
||||||
value.fill(value[-1], value.length...length)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def active_nav_li(link)
|
|
||||||
if current_page?(link)
|
|
||||||
return 'active'
|
|
||||||
else
|
|
||||||
return ''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def show_time(length)
|
|
||||||
return '0 h 0 min' if length.blank?
|
|
||||||
|
|
||||||
h, min = length.divmod(60)
|
|
||||||
|
|
||||||
if h == 0
|
|
||||||
"#{min.round} min"
|
|
||||||
elsif min == 0
|
|
||||||
"#{h} h"
|
|
||||||
else
|
|
||||||
"#{h} h #{min.round} min"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_association_link(association_name, form_builder, div_class, html_options = {})
|
def add_association_link(association_name, form_builder, div_class, html_options = {})
|
||||||
link_to_add_association 'Add ' + association_name.to_s.singularize, form_builder, div_class, html_options.merge(class: 'assoc btn btn-success')
|
link_to_add_association 'Add ' + association_name.to_s.singularize, form_builder, div_class, html_options.merge(class: 'assoc btn btn-success')
|
||||||
end
|
end
|
||||||
|
|
@ -225,31 +55,8 @@ module ApplicationHelper
|
||||||
render 'shared/dynamic_association', association_name: association_name, title: title, f: form_builder, hint: options[:hint]
|
render 'shared/dynamic_association', association_name: association_name, title: title, f: form_builder, hint: options[:hint]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Same as redirect_to(:back) if there is a valid HTTP referer, otherwise redirect_to()
|
|
||||||
def redirect_back_or_to(options = {}, response_status = {})
|
|
||||||
if request.env['HTTP_REFERER']
|
|
||||||
redirect_to :back
|
|
||||||
else
|
|
||||||
redirect_to options, response_status
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def event_types(conference)
|
|
||||||
all = conference.program.event_types.map { |et | et.title.pluralize }
|
|
||||||
first = all[0...-1]
|
|
||||||
last = all[-1]
|
|
||||||
ets = ''
|
|
||||||
if all.length > 1
|
|
||||||
ets << first.join(', ')
|
|
||||||
ets << " and #{last}"
|
|
||||||
else
|
|
||||||
ets = all.join
|
|
||||||
end
|
|
||||||
return ets
|
|
||||||
end
|
|
||||||
|
|
||||||
def tracks(conference)
|
def tracks(conference)
|
||||||
all = conference.program.tracks.map {|t| t.name}
|
all = conference.program.tracks.confirmed.cfp_active.pluck(:name)
|
||||||
first = all[0...-1]
|
first = all[0...-1]
|
||||||
last = all[-1]
|
last = all[-1]
|
||||||
ts = ''
|
ts = ''
|
||||||
|
|
@ -276,309 +83,41 @@ module ApplicationHelper
|
||||||
return ts
|
return ts
|
||||||
end
|
end
|
||||||
|
|
||||||
# rubocop:disable Lint/EndAlignment
|
|
||||||
def word_pluralize(count, singular, plural = nil)
|
|
||||||
word = if (count == 1 || count =~ /^1(\.0+)?$/)
|
|
||||||
singular
|
|
||||||
else
|
|
||||||
plural || singular.pluralize
|
|
||||||
end
|
|
||||||
|
|
||||||
"#{word}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def markdown(text)
|
|
||||||
return '' if text.nil?
|
|
||||||
|
|
||||||
options = {
|
|
||||||
autolink: true,
|
|
||||||
space_after_headers: true,
|
|
||||||
no_intra_emphasis: true
|
|
||||||
}
|
|
||||||
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(escape_html: true), options)
|
|
||||||
markdown.render(text).html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
def markdown_hint(text='')
|
|
||||||
markdown("#{text}\n\nPlease look at [**Markdown Syntax**](https://daringfireball.net/projects/markdown/syntax) to format your text")
|
|
||||||
end
|
|
||||||
|
|
||||||
def omniauth_configured
|
|
||||||
providers = []
|
|
||||||
Devise.omniauth_providers.each do |provider|
|
|
||||||
provider_key = "#{provider}_key"
|
|
||||||
provider_secret = "#{provider}_secret"
|
|
||||||
unless Rails.application.secrets.send(provider_key).blank? || Rails.application.secrets.send(provider_secret).blank?
|
|
||||||
providers << provider
|
|
||||||
end
|
|
||||||
providers << provider if !ENV["OSEM_#{provider.upcase}_KEY"].blank? && !ENV["OSEM_#{provider.upcase}_SECRET"].blank?
|
|
||||||
end
|
|
||||||
|
|
||||||
return providers.uniq
|
|
||||||
end
|
|
||||||
|
|
||||||
# Receives a hash, generated from User model, function get_roles
|
|
||||||
# Outputs the roles of a user, including the conferences for which the user has the roles
|
|
||||||
# Eg. organizer(oSC13, oSC14), cfp(oSC12, oSC13)
|
|
||||||
def show_roles(roles)
|
|
||||||
roles.map{ |x| x[0].titleize + ' (' + x[1].join(', ') + ')' }.join ', '
|
|
||||||
end
|
|
||||||
|
|
||||||
def can_manage_volunteers(conference)
|
|
||||||
if (current_user.has_role? :organizer, conference) || (current_user.has_role? :volunteers_coordinator, conference)
|
|
||||||
true
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def sign_in_path
|
|
||||||
if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
|
|
||||||
new_user_ichain_session_path
|
|
||||||
else
|
|
||||||
new_user_session_path
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def unread_notifications(user)
|
def unread_notifications(user)
|
||||||
Comment.accessible_by(current_ability).find_since_last_login(user)
|
Comment.accessible_by(current_ability).find_since_last_login(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns black or white deppending on what of them contrast more with the
|
|
||||||
# given color. Useful to print text in a coloured background.
|
|
||||||
# hexcolor is a hex color of 7 characters, being the first one '#'.
|
|
||||||
# Reference: https://24ways.org/2010/calculating-color-contrast
|
|
||||||
def contrast_color(hexcolor)
|
|
||||||
r = hexcolor[1..2].to_i(16)
|
|
||||||
g = hexcolor[3..4].to_i(16)
|
|
||||||
b = hexcolor[5..6].to_i(16)
|
|
||||||
yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000
|
|
||||||
(yiq >= 128) ? 'black' : 'white'
|
|
||||||
end
|
|
||||||
|
|
||||||
def td_height(rooms)
|
|
||||||
td_height = 500 / rooms.length
|
|
||||||
# we want all least 3 lines in events and td padding = 3px, speaker picture height >= 25px
|
|
||||||
# and line-height = 17px => (17 * 3) + 6 + 25 = 82
|
|
||||||
td_height < 82 ? 82 : td_height
|
|
||||||
end
|
|
||||||
|
|
||||||
def room_height(rooms)
|
|
||||||
room_lines(rooms) * 17
|
|
||||||
end
|
|
||||||
|
|
||||||
def room_lines(rooms)
|
|
||||||
# line-height = 17px, td padding = 3px
|
|
||||||
(td_height(rooms) - 6) / 17
|
|
||||||
end
|
|
||||||
|
|
||||||
def event_height(rooms)
|
|
||||||
event_lines(rooms) * 17
|
|
||||||
end
|
|
||||||
|
|
||||||
def event_lines(rooms)
|
|
||||||
# line-height = 17px, td padding = 3px, speaker picture height >= 25px
|
|
||||||
(td_height(rooms) - 31) / 17
|
|
||||||
end
|
|
||||||
|
|
||||||
def speaker_height(rooms)
|
|
||||||
# td padding = 3px
|
|
||||||
speaker_height = td_height(rooms) - 6 - event_height(rooms)
|
|
||||||
# The speaker picture is a circle and the width must be <= 37 to avoid making the cell widther
|
|
||||||
speaker_height >= 37 ? 37 : speaker_height
|
|
||||||
end
|
|
||||||
|
|
||||||
def speaker_width(rooms)
|
|
||||||
# speaker picture padding: 4px 2px; and we want the picture to be a circle
|
|
||||||
speaker_height(rooms) - 4
|
|
||||||
end
|
|
||||||
|
|
||||||
def carousel_item_class(number, carousel_number, num_cols, col)
|
|
||||||
item_class = 'item'
|
|
||||||
item_class += ' first' if number == 0
|
|
||||||
item_class += ' last' if number == (carousel_number - 1)
|
|
||||||
if (col && ((col / num_cols) == number)) || (!col && number == 0)
|
|
||||||
item_class += ' active'
|
|
||||||
end
|
|
||||||
item_class
|
|
||||||
end
|
|
||||||
|
|
||||||
def selected_scheduled?(schedule)
|
|
||||||
(schedule == @selected_schedule) ? 'Yes' : 'No'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Recieves a PaperTrail::Version object
|
# Recieves a PaperTrail::Version object
|
||||||
# Outputs the list of attributes that were changed in the version (ignoring changes from one blank value to another)
|
# Outputs the list of attributes that were changed in the version (ignoring changes from one blank value to another)
|
||||||
# Eg: If version.changeset = '{"title"=>[nil, "Premium"], "description"=>[nil, "Premium = Super cool"], "conference_id"=>[nil, 3]}'
|
# Eg: If version.changeset = '{"title"=>[nil, "Premium"], "description"=>[nil, "Premium = Super cool"], "conference_id"=>[nil, 3]}'
|
||||||
# Output will be 'title, description and conference'
|
# Output will be 'title, description and conference'
|
||||||
def updated_attributes(version)
|
def updated_attributes(version)
|
||||||
version.changeset.
|
version.changeset
|
||||||
reject{ |_, values| values[0].blank? && values[1].blank? }.
|
.reject{ |_, values| values[0].blank? && values[1].blank? }
|
||||||
keys.map{ |key| key.gsub('_id', '').tr('_', ' ')}.join(', ').
|
.keys.map{ |key| key.gsub('_id', '').tr('_', ' ')}.join(', ')
|
||||||
reverse.sub(',', ' dna ').reverse
|
.reverse.sub(',', ' dna ').reverse
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to_user(user_id)
|
def normalize_array_length(hashmap, length)
|
||||||
user = User.find_by(id: user_id)
|
hashmap.each do |_, value|
|
||||||
if user
|
if value.length < length
|
||||||
link_to user.name, admin_user_path(id: user_id)
|
value.fill(value[-1], value.length...length)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Same as redirect_to(:back) if there is a valid HTTP referer, otherwise redirect_to()
|
||||||
|
def redirect_back_or_to(options = {}, response_status = {})
|
||||||
|
if request.env['HTTP_REFERER']
|
||||||
|
redirect_to :back
|
||||||
else
|
else
|
||||||
'Someone (probably via the console)'
|
redirect_to options, response_status
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Recieves a model_name and id
|
|
||||||
# Returns nil if model_name is invalid
|
|
||||||
# Returns object in its current state if its alive
|
|
||||||
# Otherwise Returns object state just before deletion
|
|
||||||
def current_or_last_object_state(model_name, id)
|
|
||||||
return nil unless id.present? && model_name.present?
|
|
||||||
begin
|
|
||||||
object = model_name.constantize.find_by(id: id)
|
|
||||||
rescue NameError
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if object.nil?
|
|
||||||
object_last_version = PaperTrail::Version.where(item_type: model_name, item_id: id).last
|
|
||||||
object = object_last_version.reify if object_last_version
|
|
||||||
end
|
|
||||||
object
|
|
||||||
end
|
|
||||||
|
|
||||||
def event_change_description(version)
|
|
||||||
case
|
|
||||||
when version.event == 'create' then 'submitted new'
|
|
||||||
|
|
||||||
when version.changeset['state']
|
|
||||||
case version.changeset['state'][1]
|
|
||||||
when 'unconfirmed' then 'accepted'
|
|
||||||
when 'withdrawn' then 'withdrew'
|
|
||||||
when 'canceled', 'rejected', 'confirmed' then version.changeset['state'][1]
|
|
||||||
when 'new' then 'resubmitted'
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
"updated #{updated_attributes(version)} of"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def users_role_change_description(version)
|
|
||||||
version.event == 'create' ? 'added' : 'removed'
|
|
||||||
end
|
|
||||||
|
|
||||||
def subscription_change_description(version)
|
|
||||||
user = current_or_last_object_state(version.item_type, version.item_id).user
|
|
||||||
user_name = user.name unless user.id.to_s == version.whodunnit
|
|
||||||
version.event == 'create' ? "subscribed #{user_name} to" : "unsubscribed #{user_name} from"
|
|
||||||
end
|
|
||||||
|
|
||||||
def registration_change_description(version)
|
|
||||||
if version.item_type == 'Registration'
|
|
||||||
user = current_or_last_object_state(version.item_type, version.item_id).user
|
|
||||||
elsif version.item_type == 'EventsRegistration'
|
|
||||||
registration_id = current_or_last_object_state(version.item_type, version.item_id).registration_id
|
|
||||||
user = current_or_last_object_state('Registration', registration_id).user
|
|
||||||
end
|
|
||||||
|
|
||||||
if user.id.to_s == version.whodunnit
|
|
||||||
case version.event
|
|
||||||
when 'create' then 'registered to'
|
|
||||||
when 'update' then "updated #{updated_attributes(version)} of the registration for"
|
|
||||||
when 'destroy' then 'unregistered from'
|
|
||||||
end
|
|
||||||
else
|
|
||||||
case version.event
|
|
||||||
when 'create' then "registered #{user.name} to"
|
|
||||||
when 'update' then "updated #{updated_attributes(version)} of #{user.name}'s registration for"
|
|
||||||
when 'destroy' then "unregistered #{user.name} from"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def comment_change_description(version)
|
|
||||||
user = current_or_last_object_state(version.item_type, version.item_id).user
|
|
||||||
if version.event == 'create'
|
|
||||||
version.previous.nil? ? 'commented on' : "re-added #{user.name}'s comment on"
|
|
||||||
else
|
|
||||||
"deleted #{user.name}'s comment on"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def vote_change_description(version)
|
|
||||||
user = current_or_last_object_state(version.item_type, version.item_id).user
|
|
||||||
if version.event == 'create'
|
|
||||||
version.previous.nil? ? 'voted on' : "re-added #{user.name}'s vote on"
|
|
||||||
elsif version.event == 'update'
|
|
||||||
"updated #{user.name}'s vote on"
|
|
||||||
else
|
|
||||||
"deleted #{user.name}'s vote on"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def user_change_description(version)
|
|
||||||
if version.event == 'create'
|
|
||||||
link_to_user(version.item_id) + ' signed up'
|
|
||||||
elsif version.event == 'update'
|
|
||||||
if version.changeset.keys.include?('reset_password_sent_at')
|
|
||||||
'Someone requested password reset of'
|
|
||||||
elsif version.changeset.keys.include?('confirmed_at') && version.changeset['confirmed_at'][0].nil?
|
|
||||||
(version.whodunnit.nil? ? link_to_user(version.item_id) : link_to_user(version.whodunnit)) + ' confirmed account of'
|
|
||||||
elsif version.changeset.keys.include?('confirmed_at') && version.changeset['confirmed_at'][1].nil?
|
|
||||||
link_to_user(version.whodunnit) + ' unconfirmed account of'
|
|
||||||
else
|
|
||||||
link_to_user(version.whodunnit) + " updated #{updated_attributes(version)} of"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def event_schedule_change_description(version)
|
|
||||||
case version.event
|
|
||||||
when 'create' then 'scheduled'
|
|
||||||
when 'update' then 'rescheduled'
|
|
||||||
when 'destroy' then 'unscheduled'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def general_change_description(version)
|
|
||||||
if version.event == 'create'
|
|
||||||
'created new'
|
|
||||||
elsif version.event == 'update'
|
|
||||||
"updated #{updated_attributes(version)} of"
|
|
||||||
else
|
|
||||||
'deleted'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def link_if_alive(version, link_text, link_url)
|
|
||||||
version.item ? link_to(link_text, link_url) : link_text
|
|
||||||
end
|
|
||||||
|
|
||||||
def canceled_replacement_event_label(event, event_schedule, *label_classes)
|
|
||||||
if event.state == 'canceled' || event.state == 'withdrawn'
|
|
||||||
content_tag :span, 'CANCELED', class: (['label', 'label-danger'] + label_classes)
|
|
||||||
elsif event_schedule.present? && event_schedule.replacement?
|
|
||||||
content_tag :span, 'REPLACEMENT', class: (['label', 'label-info'] + label_classes)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def replacement_event_notice(event_schedule)
|
|
||||||
if event_schedule.present? && event_schedule.replacement?
|
|
||||||
replaced_event = (event_schedule.intersecting_event_schedules.withdrawn.first || event_schedule.intersecting_event_schedules.canceled.first).event
|
|
||||||
content_tag :span do
|
|
||||||
concat content_tag :span, 'Please note that this talk replaces '
|
|
||||||
concat link_to replaced_event.title, conference_program_proposal_path(@conference.short_title, replaced_event.id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def quantity_left_of(resource)
|
|
||||||
"#{resource.quantity - resource.used}/#{resource.quantity}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def concurrent_events(event)
|
def concurrent_events(event)
|
||||||
return nil unless event.scheduled? && event.program.selected_event_schedules
|
return nil unless event.scheduled? && event.program.selected_event_schedules
|
||||||
event_schedule = event.program.selected_event_schedules.find_by(event: event)
|
event_schedule = event.program.selected_event_schedules.find { |es| es.event == event }
|
||||||
other_event_schedules = event.program.selected_event_schedules.reject { |other_event_schedule| other_event_schedule == event_schedule }
|
other_event_schedules = event.program.selected_event_schedules.reject { |other_event_schedule| other_event_schedule == event_schedule }
|
||||||
concurrent_events = []
|
concurrent_events = []
|
||||||
|
|
||||||
|
|
@ -592,4 +131,44 @@ module ApplicationHelper
|
||||||
end
|
end
|
||||||
concurrent_events
|
concurrent_events
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def speaker_links(event)
|
||||||
|
safe_join(event.speakers.map{ |speaker| link_to speaker.name, admin_user_path(speaker) }, ',')
|
||||||
|
end
|
||||||
|
|
||||||
|
def speaker_selector_input(form)
|
||||||
|
users = User.active.pluck(:id, :name, :username, :email).map { |user| [user[0], user[1].blank? ? user[2] : user[1], user[2], user[3]] }.sort_by { |user| user[1].downcase }
|
||||||
|
form.input :speakers, as: :select,
|
||||||
|
collection: options_for_select(users.map {|user| ["#{user[1]} (#{user[2]}) #{user[3]}", user[0]]}, @event.speakers.map(&:id)),
|
||||||
|
include_blank: false, label: 'Speakers', input_html: { class: 'select-help-toggle', multiple: 'true' }
|
||||||
|
end
|
||||||
|
|
||||||
|
def responsibles_selector_input(form)
|
||||||
|
users = User.active.pluck(:id, :name, :username, :email).map { |user| [user[0], user[1].blank? ? user[2] : user[1], user[2], user[3]] }.sort_by { |user| user[1].downcase }
|
||||||
|
form.input :responsibles, as: :select,
|
||||||
|
collection: options_for_select(users.map {|user| ["#{user[1]} (#{user[2]}) #{user[3]}", user[0]]}, @booth.responsibles.map(&:id)),
|
||||||
|
include_blank: false, label: 'Responsibles', input_html: { class: 'select-help-toggle', multiple: 'true' },
|
||||||
|
hint: 'The people responsible for the booth. You can only select existing users.'
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_types(conference)
|
||||||
|
conference.program.event_types.map { |et| et.title.pluralize }.to_sentence
|
||||||
|
end
|
||||||
|
|
||||||
|
def sign_in_path
|
||||||
|
if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
|
||||||
|
new_user_ichain_session_path
|
||||||
|
else
|
||||||
|
new_user_session_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# ====Gets
|
||||||
|
# a conference object
|
||||||
|
# ==== Returns
|
||||||
|
# class hidden if conference is over
|
||||||
|
def hidden_if_conference_over(conference)
|
||||||
|
'hidden' if Date.today > conference.end_date
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
37
app/helpers/date_time_helper.rb
Normal file
37
app/helpers/date_time_helper.rb
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
module DateTimeHelper
|
||||||
|
##
|
||||||
|
# Includes functions related to date or time manipulations
|
||||||
|
##
|
||||||
|
##
|
||||||
|
# Gets an EventType object, and returns its length in timestamp format (HH:MM)
|
||||||
|
# ====Gets
|
||||||
|
# * +Integer+ -> 30
|
||||||
|
# ====Returns
|
||||||
|
# * +String+ -> "00:30"
|
||||||
|
def length_timestamp(length)
|
||||||
|
[length / 60, length % 60].map { |t| t.to_s.rjust(2, '0') }.join(':')
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Gets a datetime object
|
||||||
|
# ====Returns
|
||||||
|
# * +String+ -> formated datetime object
|
||||||
|
def format_datetime(obj)
|
||||||
|
return unless obj
|
||||||
|
obj.strftime('%Y-%m-%d %H:%M')
|
||||||
|
end
|
||||||
|
|
||||||
|
def show_time(length)
|
||||||
|
return '0 h 0 min' if length.blank?
|
||||||
|
|
||||||
|
h, min = length.divmod(60)
|
||||||
|
|
||||||
|
if h == 0
|
||||||
|
"#{min.round} min"
|
||||||
|
elsif min == 0
|
||||||
|
"#{h} h"
|
||||||
|
else
|
||||||
|
"#{h} h #{min.round} min"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
50
app/helpers/events_helper.rb
Normal file
50
app/helpers/events_helper.rb
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
module EventsHelper
|
||||||
|
##
|
||||||
|
# Includes functions related to events
|
||||||
|
##
|
||||||
|
##
|
||||||
|
# ====Returns
|
||||||
|
# * +String+ -> number of registrations / max allowed registrations
|
||||||
|
def registered_text(event)
|
||||||
|
return "Registered: #{event.registrations.count}/#{event.max_attendees}" if event.max_attendees
|
||||||
|
"Registered: #{event.registrations.count}"
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Checks if the voting has already started, or if it has already ended
|
||||||
|
#
|
||||||
|
def voting_open_or_close(program)
|
||||||
|
return if program.voting_period?
|
||||||
|
if program.voting_start_date > Time.current
|
||||||
|
return 'Voting period has not started yet!'
|
||||||
|
else # voting_end_date > Date.today because voting_start_date < voting_end_date
|
||||||
|
return 'Voting period is over!'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def replacement_event_notice(event_schedule)
|
||||||
|
if event_schedule.present? && event_schedule.replacement?
|
||||||
|
replaced_event = (event_schedule.intersecting_event_schedules.withdrawn.first || event_schedule.intersecting_event_schedules.canceled.first).event
|
||||||
|
content_tag :span do
|
||||||
|
concat content_tag :span, 'Please note that this talk replaces '
|
||||||
|
concat link_to replaced_event.title, conference_program_proposal_path(@conference.short_title, replaced_event.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def canceled_replacement_event_label(event, event_schedule, *label_classes)
|
||||||
|
if event.state == 'canceled' || event.state == 'withdrawn'
|
||||||
|
content_tag :span, 'CANCELED', class: (['label', 'label-danger'] + label_classes)
|
||||||
|
elsif event_schedule.present? && event_schedule.replacement?
|
||||||
|
content_tag :span, 'REPLACEMENT', class: (['label', 'label-info'] + label_classes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def track_selector_input(form)
|
||||||
|
if @program.tracks.confirmed.cfp_active.any?
|
||||||
|
form.input :track_id, as: :select,
|
||||||
|
collection: @program.tracks.confirmed.cfp_active.pluck(:name, :id),
|
||||||
|
include_blank: '(Please select)'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
211
app/helpers/format_helper.rb
Normal file
211
app/helpers/format_helper.rb
Normal file
|
|
@ -0,0 +1,211 @@
|
||||||
|
module FormatHelper
|
||||||
|
##
|
||||||
|
# Includes functions related to formatting (like adding classes, colors)
|
||||||
|
##
|
||||||
|
def event_status_icon(event)
|
||||||
|
case event.state
|
||||||
|
when 'new'
|
||||||
|
'fa-eye'
|
||||||
|
when 'unconfirmed'
|
||||||
|
'fa-check text-muted'
|
||||||
|
when 'confirmed'
|
||||||
|
'fa-check text-success'
|
||||||
|
when 'rejected', 'withdrawn', 'canceled'
|
||||||
|
'fa-ban'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def booth_status_icon(booth)
|
||||||
|
case booth.state
|
||||||
|
when 'new', 'to_reject', 'to_accept'
|
||||||
|
'fa-eye'
|
||||||
|
when 'accepted'
|
||||||
|
'fa-check text-muted'
|
||||||
|
when 'confirmed'
|
||||||
|
'fa-check text-success'
|
||||||
|
when 'rejected', 'withdrawn', 'canceled'
|
||||||
|
'fa-ban'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_progress_color(progress)
|
||||||
|
progress = progress.to_i
|
||||||
|
if progress == 100
|
||||||
|
'progress-bar-success'
|
||||||
|
elsif progress >= 85
|
||||||
|
'progress-bar-info'
|
||||||
|
elsif progress >= 71
|
||||||
|
'progress-bar-warning'
|
||||||
|
else
|
||||||
|
'progress-bar-danger'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def target_progress_color(progress)
|
||||||
|
progress = progress.to_i
|
||||||
|
result =
|
||||||
|
case
|
||||||
|
when progress >= 90 then 'green'
|
||||||
|
when progress < 90 && progress >= 80 then 'orange'
|
||||||
|
else 'red'
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def days_left_color(days_left)
|
||||||
|
days_left = days_left.to_i
|
||||||
|
if days_left > 30
|
||||||
|
result = 'green'
|
||||||
|
elsif days_left < 30 && days_left > 10
|
||||||
|
result = 'orange'
|
||||||
|
else
|
||||||
|
result = 'red'
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def bootstrap_class_for(flash_type)
|
||||||
|
case flash_type
|
||||||
|
when 'success'
|
||||||
|
'alert-success'
|
||||||
|
when 'error'
|
||||||
|
'alert-danger'
|
||||||
|
when 'alert'
|
||||||
|
'alert-warning'
|
||||||
|
when 'notice'
|
||||||
|
'alert-info'
|
||||||
|
else
|
||||||
|
'alert-warning'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def label_for(event_state)
|
||||||
|
result = ''
|
||||||
|
case event_state
|
||||||
|
when 'new'
|
||||||
|
result = 'label label-primary'
|
||||||
|
when 'withdrawn'
|
||||||
|
result = 'label label-danger'
|
||||||
|
when 'unconfirmed'
|
||||||
|
result = 'label label-success'
|
||||||
|
when 'confirmed'
|
||||||
|
result = 'label label-success'
|
||||||
|
when 'rejected'
|
||||||
|
result = 'label label-warning'
|
||||||
|
when 'canceled'
|
||||||
|
result = 'label label-danger'
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def icon_for_todo(bool)
|
||||||
|
if bool
|
||||||
|
return 'fa fa-check'
|
||||||
|
else
|
||||||
|
return 'fa fa-times'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def class_for_todo(bool)
|
||||||
|
if bool
|
||||||
|
return 'todolist-ok'
|
||||||
|
else
|
||||||
|
return 'todolist-missing'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def word_pluralize(count, singular, plural = nil)
|
||||||
|
word = if (count == 1 || count =~ /^1(\.0+)?$/)
|
||||||
|
singular
|
||||||
|
else
|
||||||
|
plural || singular.pluralize
|
||||||
|
end
|
||||||
|
|
||||||
|
"#{word}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns black or white deppending on what of them contrast more with the
|
||||||
|
# given color. Useful to print text in a coloured background.
|
||||||
|
# hexcolor is a hex color of 7 characters, being the first one '#'.
|
||||||
|
# Reference: https://24ways.org/2010/calculating-color-contrast
|
||||||
|
def contrast_color(hexcolor)
|
||||||
|
r = hexcolor[1..2].to_i(16)
|
||||||
|
g = hexcolor[3..4].to_i(16)
|
||||||
|
b = hexcolor[5..6].to_i(16)
|
||||||
|
yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000
|
||||||
|
(yiq >= 128) ? 'black' : 'white'
|
||||||
|
end
|
||||||
|
|
||||||
|
def td_height(rooms)
|
||||||
|
td_height = 500 / rooms.length
|
||||||
|
# we want all least 3 lines in events and td padding = 3px, speaker picture height >= 25px
|
||||||
|
# and line-height = 17px => (17 * 3) + 6 + 25 = 82
|
||||||
|
td_height < 82 ? 82 : td_height
|
||||||
|
end
|
||||||
|
|
||||||
|
def room_height(rooms)
|
||||||
|
room_lines(rooms) * 17
|
||||||
|
end
|
||||||
|
|
||||||
|
def room_lines(rooms)
|
||||||
|
# line-height = 17px, td padding = 3px
|
||||||
|
(td_height(rooms) - 6) / 17
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_height(rooms)
|
||||||
|
event_lines(rooms) * 17
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_lines(rooms)
|
||||||
|
# line-height = 17px, td padding = 3px, speaker picture height >= 25px
|
||||||
|
(td_height(rooms) - 31) / 17
|
||||||
|
end
|
||||||
|
|
||||||
|
def speaker_height(rooms)
|
||||||
|
# td padding = 3px
|
||||||
|
speaker_height = td_height(rooms) - 6 - event_height(rooms)
|
||||||
|
# The speaker picture is a circle and the width must be <= 37 to avoid making the cell widther
|
||||||
|
speaker_height >= 37 ? 37 : speaker_height
|
||||||
|
end
|
||||||
|
|
||||||
|
def speaker_width(rooms)
|
||||||
|
# speaker picture padding: 4px 2px; and we want the picture to be a circle
|
||||||
|
speaker_height(rooms) - 4
|
||||||
|
end
|
||||||
|
|
||||||
|
def carousel_item_class(number, carousel_number, num_cols, col)
|
||||||
|
item_class = 'item'
|
||||||
|
item_class += ' first' if number == 0
|
||||||
|
item_class += ' last' if number == (carousel_number - 1)
|
||||||
|
if (col && ((col / num_cols) == number)) || (!col && number == 0)
|
||||||
|
item_class += ' active'
|
||||||
|
end
|
||||||
|
item_class
|
||||||
|
end
|
||||||
|
|
||||||
|
def selected_scheduled?(schedule)
|
||||||
|
(schedule == @selected_schedule) ? 'Yes' : 'No'
|
||||||
|
end
|
||||||
|
|
||||||
|
def markdown(text, escape_html=true)
|
||||||
|
return '' if text.nil?
|
||||||
|
|
||||||
|
options = {
|
||||||
|
autolink: true,
|
||||||
|
space_after_headers: true,
|
||||||
|
no_intra_emphasis: true
|
||||||
|
}
|
||||||
|
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(escape_html: escape_html), options)
|
||||||
|
markdown.render(text).html_safe
|
||||||
|
end
|
||||||
|
|
||||||
|
def markdown_hint(text='')
|
||||||
|
markdown("#{text} Please look at #{link_to '**Markdown Syntax**', 'https://daringfireball.net/projects/markdown/syntax', target: '_blank'} to format your text", false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def quantity_left_of(resource)
|
||||||
|
return '-/-' if resource.quantity.blank?
|
||||||
|
"#{resource.quantity - resource.used}/#{resource.quantity}"
|
||||||
|
end
|
||||||
|
end
|
||||||
13
app/helpers/paths_helper.rb
Normal file
13
app/helpers/paths_helper.rb
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
module PathsHelper
|
||||||
|
##
|
||||||
|
# Includes functions related to links or redirects
|
||||||
|
##
|
||||||
|
|
||||||
|
def active_nav_li(link)
|
||||||
|
if current_page?(link)
|
||||||
|
return 'active'
|
||||||
|
else
|
||||||
|
return ''
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
30
app/helpers/users_helper.rb
Normal file
30
app/helpers/users_helper.rb
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
module UsersHelper
|
||||||
|
##
|
||||||
|
# Includes functions related to users
|
||||||
|
##
|
||||||
|
# Set devise_mapping for devise so that we can call the devise help links (views/devise/shared/_links) from anywhere (eg sign_up form in proposals#new)
|
||||||
|
def devise_mapping
|
||||||
|
@devise_mapping ||= Devise.mappings[:user]
|
||||||
|
end
|
||||||
|
|
||||||
|
def omniauth_configured
|
||||||
|
providers = []
|
||||||
|
Devise.omniauth_providers.each do |provider|
|
||||||
|
provider_key = "#{provider}_key"
|
||||||
|
provider_secret = "#{provider}_secret"
|
||||||
|
unless Rails.application.secrets.send(provider_key).blank? || Rails.application.secrets.send(provider_secret).blank?
|
||||||
|
providers << provider
|
||||||
|
end
|
||||||
|
providers << provider if !ENV["OSEM_#{provider.upcase}_KEY"].blank? && !ENV["OSEM_#{provider.upcase}_SECRET"].blank?
|
||||||
|
end
|
||||||
|
|
||||||
|
return providers.uniq
|
||||||
|
end
|
||||||
|
|
||||||
|
# Receives a hash, generated from User model, function get_roles
|
||||||
|
# Outputs the roles of a user, including the conferences for which the user has the roles
|
||||||
|
# Eg. organizer(oSC13, oSC14), cfp(oSC12, oSC13)
|
||||||
|
def show_roles(roles)
|
||||||
|
roles.map{ |x| x[0].titleize + ' (' + x[1].join(', ') + ')' }.join ', '
|
||||||
|
end
|
||||||
|
end
|
||||||
165
app/helpers/versions_helper.rb
Normal file
165
app/helpers/versions_helper.rb
Normal file
|
|
@ -0,0 +1,165 @@
|
||||||
|
module VersionsHelper
|
||||||
|
##
|
||||||
|
# Groups functions related to change description
|
||||||
|
##
|
||||||
|
def link_if_alive(version, link_text, link_url, conference)
|
||||||
|
version.item && conference ? link_to(link_text, link_url) : "#{link_text} with ID #{version.item_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def link_to_organization(organization_id)
|
||||||
|
return 'deleted organization' unless organization_id
|
||||||
|
|
||||||
|
org = Organization.find_by(id: organization_id)
|
||||||
|
return current_or_last_object_state('Organization', organization_id).try(:name) unless org
|
||||||
|
org.name.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def link_to_conference(conference_id)
|
||||||
|
return 'deleted conference' if conference_id.nil?
|
||||||
|
|
||||||
|
conference = Conference.find_by(id: conference_id)
|
||||||
|
if conference
|
||||||
|
link_to conference.short_title,
|
||||||
|
edit_admin_conference_path(conference.short_title)
|
||||||
|
else
|
||||||
|
short_title = current_or_last_object_state('Conference', conference_id).try(:short_title) || ''
|
||||||
|
" #{short_title} with ID #{conference_id}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def link_to_user(user_id)
|
||||||
|
return 'Someone (probably via the console)' unless user_id
|
||||||
|
|
||||||
|
user = User.find_by(id: user_id)
|
||||||
|
if user
|
||||||
|
link_to user.name, admin_user_path(id: user_id)
|
||||||
|
else
|
||||||
|
name = current_or_last_object_state('User', user_id).try(:name) || PaperTrail::Version.where(item_type: 'User', item_id: user_id).last.changeset['name'].second if PaperTrail::Version.where(item_type: 'User', item_id: user_id).any?
|
||||||
|
"#{name ? name : 'Unknown user'} with ID #{user_id}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Receives a model_name and id
|
||||||
|
# Returns nil if model_name is invalid
|
||||||
|
# Returns object in its current state if its alive
|
||||||
|
# Otherwise Returns object state just before deletion
|
||||||
|
def current_or_last_object_state(model_name, id)
|
||||||
|
return nil unless id.present? && model_name.present?
|
||||||
|
begin
|
||||||
|
object = model_name.constantize.find_by(id: id)
|
||||||
|
rescue NameError
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if object.nil?
|
||||||
|
object_last_version = PaperTrail::Version.where(item_type: model_name, item_id: id).last
|
||||||
|
object = object_last_version.reify if object_last_version
|
||||||
|
end
|
||||||
|
object
|
||||||
|
end
|
||||||
|
|
||||||
|
def subscription_change_description(version)
|
||||||
|
user_id = current_or_last_object_state(version.item_type, version.item_id).user_id
|
||||||
|
user_name = User.find_by(id: user_id).try(:name) || current_or_last_object_state('User', user_id).try(:name) || PaperTrail::Version.where(item_type: 'User', item_id: user_id).last.changeset[:name].second unless user_id.to_s == version.whodunnit
|
||||||
|
version.event == 'create' ? "subscribed #{user_name} to" : "unsubscribed #{user_name} from"
|
||||||
|
end
|
||||||
|
|
||||||
|
def registration_change_description(version)
|
||||||
|
if version.item_type == 'Registration'
|
||||||
|
user_id = current_or_last_object_state(version.item_type, version.item_id).user_id
|
||||||
|
elsif version.item_type == 'EventsRegistration'
|
||||||
|
registration_id = current_or_last_object_state(version.item_type, version.item_id).registration_id
|
||||||
|
user_id = current_or_last_object_state('Registration', registration_id).user_id
|
||||||
|
end
|
||||||
|
user_name = User.find_by(id: user_id).try(:name) || current_or_last_object_state('User', user_id).try(:name) || PaperTrail::Version.where(item_type: 'User', item_id: user_id).last.changeset[:name].second
|
||||||
|
|
||||||
|
if user_id.to_s == version.whodunnit
|
||||||
|
case version.event
|
||||||
|
when 'create' then 'registered to'
|
||||||
|
when 'update' then "updated #{updated_attributes(version)} of the registration for"
|
||||||
|
when 'destroy' then 'unregistered from'
|
||||||
|
end
|
||||||
|
else
|
||||||
|
case version.event
|
||||||
|
when 'create' then "registered #{user_name} to"
|
||||||
|
when 'update' then "updated #{updated_attributes(version)} of #{user_name}'s registration for"
|
||||||
|
when 'destroy' then "unregistered #{user_name} from"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def comment_change_description(version)
|
||||||
|
user = current_or_last_object_state(version.item_type, version.item_id).user
|
||||||
|
if version.event == 'create'
|
||||||
|
version.previous.nil? ? 'commented on' : "re-added #{user.name}'s comment on"
|
||||||
|
else
|
||||||
|
"deleted #{user.name}'s comment on"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def vote_change_description(version)
|
||||||
|
user = current_or_last_object_state(version.item_type, version.item_id).user
|
||||||
|
if version.event == 'create'
|
||||||
|
version.previous.nil? ? 'voted on' : "re-added #{user.name}'s vote on"
|
||||||
|
elsif version.event == 'update'
|
||||||
|
"updated #{user.name}'s vote on"
|
||||||
|
else
|
||||||
|
"deleted #{user.name}'s vote on"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def general_change_description(version)
|
||||||
|
if version.event == 'create'
|
||||||
|
'created new'
|
||||||
|
elsif version.event == 'update'
|
||||||
|
"updated #{updated_attributes(version)} of"
|
||||||
|
else
|
||||||
|
'deleted'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_change_description(version)
|
||||||
|
case
|
||||||
|
when version.event == 'create' then 'submitted new'
|
||||||
|
|
||||||
|
when version.changeset['state']
|
||||||
|
case version.changeset['state'][1]
|
||||||
|
when 'unconfirmed' then 'accepted'
|
||||||
|
when 'withdrawn' then 'withdrew'
|
||||||
|
when 'canceled', 'rejected', 'confirmed' then version.changeset['state'][1]
|
||||||
|
when 'new' then 'resubmitted'
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
"updated #{updated_attributes(version)} of"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def event_schedule_change_description(version)
|
||||||
|
case version.event
|
||||||
|
when 'create' then 'scheduled'
|
||||||
|
when 'update' then 'rescheduled'
|
||||||
|
when 'destroy' then 'unscheduled'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def user_change_description(version)
|
||||||
|
if version.event == 'create'
|
||||||
|
link_to_user(version.item_id) + ' signed up'
|
||||||
|
elsif version.event == 'update'
|
||||||
|
if version.changeset.keys.include?('reset_password_sent_at')
|
||||||
|
'Someone requested password reset of'
|
||||||
|
elsif version.changeset.keys.include?('confirmed_at') && version.changeset['confirmed_at'][0].nil?
|
||||||
|
(version.whodunnit.nil? ? link_to_user(version.item_id) : link_to_user(version.whodunnit)) + ' confirmed account of'
|
||||||
|
elsif version.changeset.keys.include?('confirmed_at') && version.changeset['confirmed_at'][1].nil?
|
||||||
|
link_to_user(version.whodunnit) + ' unconfirmed account of'
|
||||||
|
else
|
||||||
|
link_to_user(version.whodunnit) + " updated #{updated_attributes(version)} of"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def users_role_change_description(version)
|
||||||
|
version.event == 'create' ? 'added' : 'removed'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -8,6 +8,22 @@ class Mailbot < ActionMailer::Base
|
||||||
conference.email_settings.registration_body))
|
conference.email_settings.registration_body))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ticket_confirmation_mail(ticket_purchase)
|
||||||
|
@ticket_purchase = ticket_purchase
|
||||||
|
@conference = ticket_purchase.conference
|
||||||
|
@user = ticket_purchase.user
|
||||||
|
|
||||||
|
PhysicalTicket.last(ticket_purchase.quantity).each do |physical_ticket|
|
||||||
|
pdf = TicketPdf.new(@conference, @user, physical_ticket, @conference.ticket_layout.to_sym, "ticket_for_#{@conference.short_title}_#{physical_ticket.id}")
|
||||||
|
attachments["ticket_for_#{@conference.short_title}_#{physical_ticket.id}.pdf"] = pdf.render
|
||||||
|
end
|
||||||
|
|
||||||
|
mail(to: @user.email,
|
||||||
|
from: @conference.contact.email,
|
||||||
|
template_name: 'ticket_confirmation_template',
|
||||||
|
subject: "#{@conference.title} | Ticket Confirmation and PDF!")
|
||||||
|
end
|
||||||
|
|
||||||
def acceptance_mail(event)
|
def acceptance_mail(event)
|
||||||
conference = event.program.conference
|
conference = event.program.conference
|
||||||
|
|
||||||
|
|
@ -81,6 +97,24 @@ class Mailbot < ActionMailer::Base
|
||||||
conference.email_settings.cfp_dates_updated_body))
|
conference.email_settings.cfp_dates_updated_body))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def conference_booths_acceptance_mail(booth)
|
||||||
|
conference = booth.conference
|
||||||
|
|
||||||
|
mail(to: booth.submitter.email,
|
||||||
|
from: conference.contact.email,
|
||||||
|
subject: conference.email_settings.booths_acceptance_subject,
|
||||||
|
body: conference.email_settings.generate_booth_mail(booth, conference.email_settings.booths_acceptance_body))
|
||||||
|
end
|
||||||
|
|
||||||
|
def conference_booths_rejection_mail(booth)
|
||||||
|
conference = booth.conference
|
||||||
|
|
||||||
|
mail(to: booth.submitter.email,
|
||||||
|
from: conference.contact.email,
|
||||||
|
subject: conference.email_settings.booths_rejection_subject,
|
||||||
|
body: conference.email_settings.generate_booth_mail(booth, conference.email_settings.booths_rejection_body))
|
||||||
|
end
|
||||||
|
|
||||||
def event_comment_mail(comment, user)
|
def event_comment_mail(comment, user)
|
||||||
@comment = comment
|
@comment = comment
|
||||||
@event = @comment.commentable
|
@event = @comment.commentable
|
||||||
|
|
|
||||||
|
|
@ -3,32 +3,19 @@ class Ability
|
||||||
|
|
||||||
# Initializes the ability class
|
# Initializes the ability class
|
||||||
def initialize(user)
|
def initialize(user)
|
||||||
# Order Abilities
|
|
||||||
# (Check https://github.com/CanCanCommunity/cancancan/wiki/Ability-Precedence)
|
|
||||||
# Check roles of user, using rolify. Role name is *case sensitive*
|
|
||||||
# user.is_organizer? or user.has_role? :organizer
|
|
||||||
# user.is_cfp_of? Conference or user.has_role? :cfp, Conference
|
|
||||||
# user.is_info_desk_of? Conference
|
|
||||||
# user.is_volunteers_coordinator_of? Conference
|
|
||||||
# user.is_attendee_of? Conference
|
|
||||||
# The following is wrong because a user will only have 'cfp' role for a specific conference
|
|
||||||
# user.is_cfp? # This is always false
|
|
||||||
|
|
||||||
user ||= User.new
|
user ||= User.new
|
||||||
|
|
||||||
# This is what sets up the different abilities
|
|
||||||
if user.new_record?
|
if user.new_record?
|
||||||
not_signed_in
|
not_signed_in
|
||||||
# Checks if the user does not have any role and is not an admin
|
|
||||||
elsif user.roles.any? || user.is_admin
|
|
||||||
signed_in_with_roles(user)
|
|
||||||
else
|
else
|
||||||
signed_in(user)
|
signed_in(user)
|
||||||
|
common_abilities_for_admins(user) if user.roles.any? || user.is_admin?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Abilities for not signed in users (guests)
|
# Abilities for not signed in users (guests)
|
||||||
def not_signed_in
|
def not_signed_in
|
||||||
|
can [:index], Organization
|
||||||
can [:index], Conference
|
can [:index], Conference
|
||||||
can [:show], Conference do |conference|
|
can [:show], Conference do |conference|
|
||||||
conference.splashpage && conference.splashpage.public == true
|
conference.splashpage && conference.splashpage.public == true
|
||||||
|
|
@ -62,6 +49,10 @@ class Ability
|
||||||
can [:new, :create], Event do |event|
|
can [:new, :create], Event do |event|
|
||||||
event.program.cfp_open? && event.new_record?
|
event.program.cfp_open? && event.new_record?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
can [:show, :events], Schedule do |schedule|
|
||||||
|
schedule.program.schedule_public
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -69,19 +60,28 @@ class Ability
|
||||||
def signed_in(user)
|
def signed_in(user)
|
||||||
# Abilities from not_signed_in user are also inherited
|
# Abilities from not_signed_in user are also inherited
|
||||||
not_signed_in
|
not_signed_in
|
||||||
|
|
||||||
can :manage, User, id: user.id
|
can :manage, User, id: user.id
|
||||||
|
|
||||||
can :manage, Registration, user_id: user.id
|
can :manage, Registration, user_id: user.id
|
||||||
|
|
||||||
can [:new, :create], Registration do |registration|
|
can [:new, :create], Registration do |registration|
|
||||||
conference = registration.conference
|
conference = registration.conference
|
||||||
conference.registration_open? && !conference.registration_limit_exceeded?
|
conference.registration_open? && !conference.registration_limit_exceeded? || conference.program.speakers.confirmed.include?(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
can :index, Organization
|
||||||
can :index, Ticket
|
can :index, Ticket
|
||||||
can :manage, TicketPurchase, user_id: user.id
|
can :manage, TicketPurchase, user_id: user.id
|
||||||
can [:new, :create], Payment, user_id: user.id
|
can [:new, :create], Payment, user_id: user.id
|
||||||
|
can [:index, :show], PhysicalTicket, user: user
|
||||||
|
|
||||||
|
can [:new, :create], Booth do |booth|
|
||||||
|
booth.new_record? && booth.conference.program.cfps.for_booths.try(:open?)
|
||||||
|
end
|
||||||
|
|
||||||
|
can [:edit, :update, :index, :show], Booth do |booth|
|
||||||
|
booth.users.include?(user)
|
||||||
|
end
|
||||||
|
|
||||||
can [:create, :destroy], Subscription, user_id: user.id
|
can [:create, :destroy], Subscription, user_id: user.id
|
||||||
|
|
||||||
|
|
@ -89,177 +89,58 @@ class Ability
|
||||||
event.program.cfp_open? && event.new_record?
|
event.program.cfp_open? && event.new_record?
|
||||||
end
|
end
|
||||||
|
|
||||||
can [:update, :show, :delete, :index], Event do |event|
|
can [:update, :show, :index], Event do |event|
|
||||||
event.users.include?(user)
|
event.users.include?(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
# can manage the commercials of their own events
|
# can manage the commercials of their own events
|
||||||
can :manage, Commercial, commercialable_type: 'Event', commercialable_id: user.events.pluck(:id)
|
can :manage, Commercial, commercialable_type: 'Event', commercialable_id: user.events.pluck(:id)
|
||||||
|
|
||||||
|
can [:destroy], Openid
|
||||||
|
|
||||||
|
can [:new, :create], Track do |track|
|
||||||
|
track.new_record? && track.program.cfps.for_tracks.try(:open?)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Abilities for signed in users with roles
|
can [:index, :show, :restart, :confirm, :withdraw], Track, submitter_id: user.id
|
||||||
def signed_in_with_roles(user)
|
|
||||||
# Abilities from not_signed_in and signed_in are also inherited
|
|
||||||
signed_in(user)
|
|
||||||
|
|
||||||
signed_in_with_organizer_role(user) if user.has_role? :organizer, :any
|
can [:edit, :update], Track do |track|
|
||||||
signed_in_with_cfp_role(user) if user.has_role? :cfp, :any
|
user == track.submitter && !(track.accepted? || track.confirmed?)
|
||||||
signed_in_with_info_desk_role(user) if user.has_role? :info_desk, :any
|
end
|
||||||
signed_in_with_volunteers_coordinator_role(user) if user.has_role? :volunteers_coordinator, :any
|
end
|
||||||
|
|
||||||
# for users with any role
|
# Abilities for users with roles wandering around in non-admin views.
|
||||||
|
def common_abilities_for_admins(user)
|
||||||
can :access, Admin
|
can :access, Admin
|
||||||
can [:show], Conference
|
can :manage, :all if user.is_admin?
|
||||||
can :index, Commercial, commercialable_type: 'Conference'
|
|
||||||
cannot [:edit, :update, :destroy], Question, global: true
|
|
||||||
# for admins
|
|
||||||
can :manage, :all if user.is_admin
|
|
||||||
|
|
||||||
cannot :revert_object, PaperTrail::Version do |version|
|
|
||||||
(version.event == 'create' && %w(Conference User Event).include?(version.item_type))
|
|
||||||
end
|
|
||||||
|
|
||||||
cannot :revert_attribute, PaperTrail::Version do |version|
|
|
||||||
version.event != 'update' || version.item.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
cannot :destroy, Program
|
|
||||||
# Do not delete venue, when there are rooms being used
|
|
||||||
cannot :destroy, Venue do |venue|
|
|
||||||
venue.conference.program.events.where.not(room_id: nil).any?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def signed_in_with_organizer_role(user)
|
|
||||||
# ids of all the conferences for which the user has the 'organizer' role
|
|
||||||
conf_ids_for_organizer = Conference.with_role(:organizer, user).pluck(:id)
|
conf_ids_for_organizer = Conference.with_role(:organizer, user).pluck(:id)
|
||||||
|
|
||||||
can :manage, Resource, conference_id: conf_ids_for_organizer
|
|
||||||
can [:new, :create], Conference if user.has_role?(:organizer, :any)
|
|
||||||
can :manage, Conference, id: conf_ids_for_organizer
|
|
||||||
can :manage, Splashpage, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Contact, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, EmailSettings, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Campaign, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Target, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Commercial, commercialable_type: 'Conference',
|
|
||||||
commercialable_id: conf_ids_for_organizer
|
|
||||||
can :manage, Registration, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, RegistrationPeriod, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Question, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Question do |question|
|
|
||||||
!(question.conferences.pluck(:id) & conf_ids_for_organizer).empty?
|
|
||||||
end
|
|
||||||
can :manage, Vposition, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Vday, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Program, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Schedule, program: { conference_id: conf_ids_for_organizer }
|
|
||||||
can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids_for_organizer } }
|
|
||||||
can :manage, Cfp, program: { conference_id: conf_ids_for_organizer}
|
|
||||||
can :manage, Event, program: { conference_id: conf_ids_for_organizer}
|
|
||||||
can :manage, EventType, program: { conference_id: conf_ids_for_organizer}
|
|
||||||
can :manage, Track, program: { conference_id: conf_ids_for_organizer}
|
|
||||||
can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_organizer}
|
|
||||||
can :manage, Commercial, commercialable_type: 'Event',
|
|
||||||
commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id)
|
|
||||||
can :manage, Venue, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Commercial, commercialable_type: 'Venue',
|
|
||||||
commercialable_id: Venue.where(conference_id: conf_ids_for_organizer).pluck(:id)
|
|
||||||
can :manage, Lodging, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Room, venue: { conference_id: conf_ids_for_organizer}
|
|
||||||
can :manage, Sponsor, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, SponsorshipLevel, conference_id: conf_ids_for_organizer
|
|
||||||
can :manage, Ticket, conference_id: conf_ids_for_organizer
|
|
||||||
can :index, Comment, commentable_type: 'Event',
|
|
||||||
commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id)
|
|
||||||
|
|
||||||
# Abilities for Role (Conference resource)
|
|
||||||
can [:index, :show], Role
|
|
||||||
can [:edit, :update, :toggle_user], Role do |role|
|
|
||||||
role.resource_type == 'Conference' && (conf_ids_for_organizer.include? role.resource_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version|
|
|
||||||
version.item_type == 'User' || (conf_ids_for_organizer.include? version.conference_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def signed_in_with_cfp_role(user)
|
|
||||||
# ids of all the conferences for which the user has the 'cfp' role
|
|
||||||
conf_ids_for_cfp = Conference.with_role(:cfp, user).pluck(:id)
|
conf_ids_for_cfp = Conference.with_role(:cfp, user).pluck(:id)
|
||||||
|
|
||||||
can [:index, :show, :update], Resource, conference_id: conf_ids_for_cfp
|
|
||||||
can :manage, Event, program: { conference_id: conf_ids_for_cfp }
|
|
||||||
can :manage, EventType, program: { conference_id: conf_ids_for_cfp }
|
|
||||||
can :manage, Track, program: { conference_id: conf_ids_for_cfp }
|
|
||||||
can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_cfp }
|
|
||||||
can :manage, EmailSettings, conference_id: conf_ids_for_cfp
|
|
||||||
can :manage, Room, venue: { conference_id: conf_ids_for_cfp }
|
|
||||||
can :show, Venue, conference_id: conf_ids_for_cfp
|
|
||||||
can :show, Commercial, commercialable_type: 'Venue', commercialable_id: Venue.where(conference_id: conf_ids_for_cfp).pluck(:id)
|
|
||||||
can :manage, Cfp, program: { conference_id: conf_ids_for_cfp }
|
|
||||||
can :manage, Program, conference_id: conf_ids_for_cfp
|
|
||||||
can :manage, Commercial, commercialable_type: 'Event',
|
|
||||||
commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id)
|
|
||||||
can :index, Comment, commentable_type: 'Event',
|
|
||||||
commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id)
|
|
||||||
|
|
||||||
# Abilities for Role (Conference resource)
|
|
||||||
can [:index, :show], Role
|
|
||||||
|
|
||||||
# Can add or remove users from role, when user has that same role for the conference
|
|
||||||
# Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP')
|
|
||||||
can :toggle_user, Role do |role|
|
|
||||||
role.resource_type == 'Conference' && role.name == 'cfp' &&
|
|
||||||
(Conference.with_role(:cfp, user).pluck(:id).include? role.resource_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Event', conference_id: conf_ids_for_cfp
|
|
||||||
can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Vote', conference_id: conf_ids_for_cfp
|
|
||||||
can [:index, :revert_object, :revert_attribute], PaperTrail::Version do |version|
|
|
||||||
version.item_type == 'Commercial' && conf_ids_for_cfp.include?(version.conference_id) &&
|
|
||||||
(version.object.to_s.include?('Event') || version.object_changes.to_s.include?('Event'))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def signed_in_with_info_desk_role(user)
|
|
||||||
# ids of all the conferences for which the user has the 'info_desk' role
|
|
||||||
conf_ids_for_info_desk = Conference.with_role(:info_desk, user).pluck(:id)
|
conf_ids_for_info_desk = Conference.with_role(:info_desk, user).pluck(:id)
|
||||||
|
|
||||||
can [:index, :show, :update], Resource, conference_id: conf_ids_for_info_desk
|
if conf_ids_for_organizer
|
||||||
|
# To access splashpage of their conference if it is not public
|
||||||
|
can :show, Conference, id: conf_ids_for_organizer
|
||||||
|
# To access conference/proposals/registrations
|
||||||
|
can :manage, Registration, conference_id: conf_ids_for_organizer
|
||||||
|
# To access conference/proposals
|
||||||
|
can :manage, Event, program: { conference_id: conf_ids_for_organizer }
|
||||||
|
# To access comment link in menu bar
|
||||||
|
can :index, Comment, commentable_type: 'Event',
|
||||||
|
commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_organizer).pluck(:id)).pluck(:id)
|
||||||
|
end
|
||||||
|
|
||||||
|
if conf_ids_for_cfp
|
||||||
|
# To access comment link in menu bar
|
||||||
|
can :index, Comment, commentable_type: 'Event',
|
||||||
|
commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id)
|
||||||
|
# To access conference/proposals
|
||||||
|
can :manage, Event, program: { conference_id: conf_ids_for_cfp }
|
||||||
|
end
|
||||||
|
|
||||||
|
if conf_ids_for_info_desk
|
||||||
|
# To access conference/proposals/registrations
|
||||||
can :manage, Registration, conference_id: conf_ids_for_info_desk
|
can :manage, Registration, conference_id: conf_ids_for_info_desk
|
||||||
can :manage, Question, conference_id: conf_ids_for_info_desk
|
|
||||||
can :manage, Question do |question|
|
|
||||||
!(question.conferences.pluck(:id) & conf_ids_for_info_desk).empty?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Abilities for Role (Conference resource)
|
|
||||||
can [:index, :show], Role
|
|
||||||
|
|
||||||
# Can add or remove users from role, when user has that same role for the conference
|
|
||||||
# Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP')
|
|
||||||
can :toggle_user, Role do |role|
|
|
||||||
role.resource_type == 'Conference' && role.name == 'info_desk' &&
|
|
||||||
(Conference.with_role(:info_desk, user).pluck(:id).include? role.resource_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def signed_in_with_volunteers_coordinator_role(user)
|
|
||||||
# ids of all the conferences for which the user has the 'volunteers_coordinator' role
|
|
||||||
conf_ids_for_volunteers_coordinator = Conference.with_role(:volunteers_coordinator, user).pluck(:id)
|
|
||||||
|
|
||||||
can [:index, :show, :update], Resource, conference_id: conf_ids_for_volunteers_coordinator
|
|
||||||
can :manage, Vposition, conference_id: conf_ids_for_volunteers_coordinator
|
|
||||||
can :manage, Vday, conference_id: conf_ids_for_volunteers_coordinator
|
|
||||||
|
|
||||||
# Abilities for Role (Conference resource)
|
|
||||||
can [:index, :show], Role
|
|
||||||
|
|
||||||
# Can add or remove users from role, when user has that same role for the conference
|
|
||||||
# Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP')
|
|
||||||
can :toggle_user, Role do |role|
|
|
||||||
role.resource_type == 'Conference' && role.name == 'volunteers_coordinator' &&
|
|
||||||
(Conference.with_role(:volunteers_coordinator, user).pluck(:id).include? role.resource_id)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
324
app/models/admin_ability.rb
Normal file
324
app/models/admin_ability.rb
Normal file
|
|
@ -0,0 +1,324 @@
|
||||||
|
class AdminAbility
|
||||||
|
include CanCan::Ability
|
||||||
|
|
||||||
|
def initialize(user)
|
||||||
|
# Order Abilities
|
||||||
|
# (Check https://github.com/CanCanCommunity/cancancan/wiki/Ability-Precedence)
|
||||||
|
# Check roles of user, using rolify. Role name is *case sensitive*
|
||||||
|
# user.is_organizer? or user.has_role? :organizer
|
||||||
|
# user.is_cfp_of? Conference or user.has_role? :cfp, Conference
|
||||||
|
# user.is_info_desk_of? Conference
|
||||||
|
# user.is_volunteers_coordinator_of? Conference
|
||||||
|
# user.is_attendee_of? Conference
|
||||||
|
# The following is wrong because a user will only have 'cfp' role for a specific conference
|
||||||
|
# user.is_cfp? # This is always false
|
||||||
|
|
||||||
|
user ||= User.new
|
||||||
|
signed_in_with_roles(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def common_abilities_for_roles(user)
|
||||||
|
can :manage, Registration, user_id: user.id
|
||||||
|
|
||||||
|
can :index, Conference
|
||||||
|
can :show, Registration, &:new_record?
|
||||||
|
|
||||||
|
can [:new, :create], Registration do |registration|
|
||||||
|
conference = registration.conference
|
||||||
|
conference.registration_open? && !conference.registration_limit_exceeded? || conference.program.speakers.confirmed.include?(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
can [:index, :admins], Organization
|
||||||
|
can :index, Ticket
|
||||||
|
can :manage, TicketPurchase, user_id: user.id
|
||||||
|
can [:new, :create], Payment, user_id: user.id
|
||||||
|
|
||||||
|
can [:create, :destroy], Subscription, user_id: user.id
|
||||||
|
|
||||||
|
can [:new, :create], Event do |event|
|
||||||
|
event.program.cfp_open? && event.new_record?
|
||||||
|
end
|
||||||
|
|
||||||
|
# can manage the commercials of their own events
|
||||||
|
can :manage, Commercial, commercialable_type: 'Event', commercialable_id: user.events.pluck(:id)
|
||||||
|
|
||||||
|
can [:destroy], Openid
|
||||||
|
can :access, Admin
|
||||||
|
can :index, Commercial, commercialable_type: 'Conference'
|
||||||
|
cannot [:edit, :update, :destroy], Question, global: true
|
||||||
|
# for admins
|
||||||
|
can :manage, :all if user.is_admin
|
||||||
|
# even admin cannot create new users with ICHAIN enabled
|
||||||
|
cannot [:new, :create], User if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
|
||||||
|
cannot :revert_object, PaperTrail::Version do |version|
|
||||||
|
(version.event == 'create' && %w[Conference User Event].include?(version.item_type))
|
||||||
|
end
|
||||||
|
cannot :revert_attribute, PaperTrail::Version do |version|
|
||||||
|
version.event != 'update' || version.item.nil?
|
||||||
|
end
|
||||||
|
# Can't create cfp if there are no available cfp types
|
||||||
|
cannot [:new, :create], Cfp do |cfp|
|
||||||
|
cfp.program.remaining_cfp_types.empty?
|
||||||
|
end
|
||||||
|
cannot :destroy, Program
|
||||||
|
# Do not delete venue, when there are rooms being used
|
||||||
|
cannot :destroy, Venue do |venue|
|
||||||
|
venue.conference.program.events.where.not(room_id: nil).any?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Prevent requests for tracks from being destroyed
|
||||||
|
cannot :destroy, Track do |track|
|
||||||
|
track.self_organized?
|
||||||
|
end
|
||||||
|
# Can't accept a booth when booth_limit is reached
|
||||||
|
cannot :accept, Booth do |booth|
|
||||||
|
conference = booth.conference
|
||||||
|
conference.maximum_accepted_booths?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Abilities for signed in users with roles
|
||||||
|
def signed_in_with_roles(user)
|
||||||
|
signed_in_with_organization_admin_role(user) if user.has_role? :organization_admin, :any
|
||||||
|
signed_in_with_organizer_role(user) if user.has_role? :organizer, :any
|
||||||
|
signed_in_with_cfp_role(user) if user.has_role? :cfp, :any
|
||||||
|
signed_in_with_info_desk_role(user) if user.has_role? :info_desk, :any
|
||||||
|
signed_in_with_volunteers_coordinator_role(user) if user.has_role? :volunteers_coordinator, :any
|
||||||
|
signed_in_with_track_organizer_role(user) if user.has_role? :track_organizer, :any
|
||||||
|
common_abilities_for_roles(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
def signed_in_with_organization_admin_role(user)
|
||||||
|
org_ids_for_organization_admin = Organization.with_role(:organization_admin, user).pluck(:id)
|
||||||
|
conf_ids_for_organization_admin = Conference.where(organization_id: org_ids_for_organization_admin).pluck(:id)
|
||||||
|
|
||||||
|
can [:read, :update, :destroy, :assign_org_admins, :unassign_org_admins, :admins], Organization, id: org_ids_for_organization_admin
|
||||||
|
can :new, Conference
|
||||||
|
can :manage, Conference, organization_id: org_ids_for_organization_admin
|
||||||
|
can [:index, :show], Role
|
||||||
|
|
||||||
|
signed_in_with_organizer_role(user, conf_ids_for_organization_admin)
|
||||||
|
end
|
||||||
|
|
||||||
|
def signed_in_with_organizer_role(user, conf_ids_for_organization_admin = [])
|
||||||
|
# ids of all the conferences for which the user has the 'organizer' role and
|
||||||
|
# conferences that belong to organizations for which user is 'organization_admin'
|
||||||
|
conf_ids = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq
|
||||||
|
# ids of all the tracks that belong to the programs of the above conferences
|
||||||
|
track_ids = Track.joins(:program).where('programs.conference_id IN (?)', conf_ids).pluck(:id)
|
||||||
|
|
||||||
|
can :manage, Resource, conference_id: conf_ids
|
||||||
|
can [:read, :update, :destroy], Conference, id: conf_ids
|
||||||
|
can :manage, Splashpage, conference_id: conf_ids
|
||||||
|
can :manage, Contact, conference_id: conf_ids
|
||||||
|
can :manage, EmailSettings, conference_id: conf_ids
|
||||||
|
can :manage, Campaign, conference_id: conf_ids
|
||||||
|
can :manage, Target, conference_id: conf_ids
|
||||||
|
can :manage, Commercial, commercialable_type: 'Conference',
|
||||||
|
commercialable_id: conf_ids
|
||||||
|
can :manage, Registration, conference_id: conf_ids
|
||||||
|
can :manage, RegistrationPeriod do |registration_period|
|
||||||
|
conference = registration_period.conference
|
||||||
|
conf_ids.include?(conference.id) && conference.tickets.for_registration.any?
|
||||||
|
end
|
||||||
|
can :manage, Booth, conference_id: conf_ids
|
||||||
|
can :manage, Question, conference_id: conf_ids
|
||||||
|
can :manage, Question do |question|
|
||||||
|
!(question.conferences.pluck(:id) & conf_ids).empty?
|
||||||
|
end
|
||||||
|
can :manage, Vposition, conference_id: conf_ids
|
||||||
|
can :manage, Vday, conference_id: conf_ids
|
||||||
|
can :manage, Program, conference_id: conf_ids
|
||||||
|
can :manage, Schedule, program: { conference_id: conf_ids }
|
||||||
|
can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids } }
|
||||||
|
can :manage, Cfp, program: { conference_id: conf_ids }
|
||||||
|
can :manage, Event, program: { conference_id: conf_ids }
|
||||||
|
can :manage, EventType, program: { conference_id: conf_ids }
|
||||||
|
can :manage, Track, program: { conference_id: conf_ids }
|
||||||
|
can :manage, DifficultyLevel, program: { conference_id: conf_ids }
|
||||||
|
can :manage, Commercial, commercialable_type: 'Event',
|
||||||
|
commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id)
|
||||||
|
can :manage, Venue, conference_id: conf_ids
|
||||||
|
can :manage, Commercial, commercialable_type: 'Venue',
|
||||||
|
commercialable_id: Venue.where(conference_id: conf_ids).pluck(:id)
|
||||||
|
can :manage, Lodging, conference_id: conf_ids
|
||||||
|
can :manage, Room, venue: { conference_id: conf_ids }
|
||||||
|
can :manage, Sponsor, conference_id: conf_ids
|
||||||
|
can :manage, SponsorshipLevel, conference_id: conf_ids
|
||||||
|
can :manage, Ticket, conference_id: conf_ids
|
||||||
|
can :create, TicketScanning do |ticket_scanning|
|
||||||
|
conf_id = ticket_scanning.physical_ticket.ticket_purchase.conference_id
|
||||||
|
conf_ids.include? conf_id
|
||||||
|
end
|
||||||
|
can :index, Comment, commentable_type: 'Event',
|
||||||
|
commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id)
|
||||||
|
|
||||||
|
# Abilities for Role (Conference resource)
|
||||||
|
can [:index, :show], Role do |role|
|
||||||
|
role.resource_type == 'Conference' || role.resource_type == 'Track'
|
||||||
|
end
|
||||||
|
|
||||||
|
can [:edit, :update, :toggle_user], Role do |role|
|
||||||
|
role.resource_type == 'Conference' && (conf_ids.include? role.resource_id) ||
|
||||||
|
role.resource_type == 'Track' && (track_ids.include? role.resource_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'User'
|
||||||
|
can [:index, :revert_object, :revert_attribute], PaperTrail::Version, conference_id: conf_ids
|
||||||
|
end
|
||||||
|
|
||||||
|
def signed_in_with_cfp_role(user)
|
||||||
|
# ids of all the conferences for which the user has the 'cfp' role
|
||||||
|
conf_ids_for_cfp = Conference.with_role(:cfp, user).pluck(:id)
|
||||||
|
|
||||||
|
can :show, Conference do |conf|
|
||||||
|
conf_ids_for_cfp.include?(conf.id)
|
||||||
|
end
|
||||||
|
can [:index, :show, :update], Resource, conference_id: conf_ids_for_cfp
|
||||||
|
can :manage, Booth, conference_id: conf_ids_for_cfp
|
||||||
|
can :manage, Event, program: { conference_id: conf_ids_for_cfp }
|
||||||
|
can :manage, EventType, program: { conference_id: conf_ids_for_cfp }
|
||||||
|
can :manage, Track, program: { conference_id: conf_ids_for_cfp }
|
||||||
|
can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_cfp }
|
||||||
|
can :manage, EmailSettings, conference_id: conf_ids_for_cfp
|
||||||
|
can :manage, Schedule, program: { conference_id: conf_ids_for_cfp }
|
||||||
|
can :manage, Room, venue: { conference_id: conf_ids_for_cfp }
|
||||||
|
can :show, Venue, conference_id: conf_ids_for_cfp
|
||||||
|
can :show, Commercial, commercialable_type: 'Venue', commercialable_id: Venue.where(conference_id: conf_ids_for_cfp).pluck(:id)
|
||||||
|
can :manage, Cfp, program: { conference_id: conf_ids_for_cfp }
|
||||||
|
can :manage, Program, conference_id: conf_ids_for_cfp
|
||||||
|
can :manage, Commercial, commercialable_type: 'Event',
|
||||||
|
commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id)
|
||||||
|
can :index, Comment, commentable_type: 'Event',
|
||||||
|
commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id)
|
||||||
|
|
||||||
|
# Abilities for Role (Conference resource)
|
||||||
|
can [:index, :show], Role do |role|
|
||||||
|
role.resource_type == 'Conference' || role.resource_type == 'Track'
|
||||||
|
end
|
||||||
|
# Can add or remove users from role, when user has that same role for the conference
|
||||||
|
# Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP')
|
||||||
|
can :toggle_user, Role do |role|
|
||||||
|
role.resource_type == 'Conference' && role.name == 'cfp' &&
|
||||||
|
(Conference.with_role(:cfp, user).pluck(:id).include? role.resource_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
can [:index, :revert_object, :revert_attribute], PaperTrail::Version,
|
||||||
|
item_type: %w[Event EventType Track DifficultyLevel EmailSettings Room Cfp Program Comment], conference_id: conf_ids_for_cfp
|
||||||
|
can [:index, :revert_object, :revert_attribute], PaperTrail::Version,
|
||||||
|
["item_type = 'Commercial' AND conference_id IN (?) AND (object LIKE '%Event%' OR object_changes LIKE '%Event%')", conf_ids_for_cfp] do |version|
|
||||||
|
version.item_type == 'Commercial' && conf_ids_for_cfp.include?(version.conference_id) &&
|
||||||
|
(version.object.to_s.include?('Event') || version.object_changes.to_s.include?('Event'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def signed_in_with_info_desk_role(user)
|
||||||
|
# ids of all the conferences for which the user has the 'info_desk' role
|
||||||
|
conf_ids_for_info_desk = Conference.with_role(:info_desk, user).pluck(:id)
|
||||||
|
|
||||||
|
can :show, Conference do |conf|
|
||||||
|
conf_ids_for_info_desk.include?(conf.id)
|
||||||
|
end
|
||||||
|
can [:index, :show, :update], Resource, conference_id: conf_ids_for_info_desk
|
||||||
|
can :manage, Registration, conference_id: conf_ids_for_info_desk
|
||||||
|
can :manage, Question, conference_id: conf_ids_for_info_desk
|
||||||
|
can :manage, Question do |question|
|
||||||
|
!(question.conferences.pluck(:id) & conf_ids_for_info_desk).empty?
|
||||||
|
end
|
||||||
|
can :create, TicketScanning do |ticket_scanning|
|
||||||
|
conf_id = ticket_scanning.physical_ticket.ticket_purchase.conference_id
|
||||||
|
conf_ids_for_info_desk.include? conf_id
|
||||||
|
end
|
||||||
|
|
||||||
|
# Abilities for Role (Conference resource)
|
||||||
|
can [:index, :show], Role do |role|
|
||||||
|
role.resource_type == 'Conference' || role.resource_type == 'Track'
|
||||||
|
end
|
||||||
|
# Can add or remove users from role, when user has that same role for the conference
|
||||||
|
# Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP')
|
||||||
|
can :toggle_user, Role do |role|
|
||||||
|
role.resource_type == 'Conference' && role.name == 'info_desk' &&
|
||||||
|
(Conference.with_role(:info_desk, user).pluck(:id).include? role.resource_id)
|
||||||
|
end
|
||||||
|
can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Registration', conference_id: conf_ids_for_info_desk
|
||||||
|
end
|
||||||
|
|
||||||
|
def signed_in_with_volunteers_coordinator_role(user)
|
||||||
|
# ids of all the conferences for which the user has the 'volunteers_coordinator' role
|
||||||
|
conf_ids_for_volunteers_coordinator = Conference.with_role(:volunteers_coordinator, user).pluck(:id)
|
||||||
|
|
||||||
|
can :show, Conference do |conf|
|
||||||
|
conf_ids_for_volunteers_coordinator.include?(conf.id)
|
||||||
|
end
|
||||||
|
can [:index, :show, :update], Resource, conference_id: conf_ids_for_volunteers_coordinator
|
||||||
|
can :manage, Vposition, conference_id: conf_ids_for_volunteers_coordinator
|
||||||
|
can :manage, Vday, conference_id: conf_ids_for_volunteers_coordinator
|
||||||
|
|
||||||
|
# Abilities for Role (Conference resource)
|
||||||
|
can [:index, :show], Role do |role|
|
||||||
|
role.resource_type == 'Conference' || role.resource_type == 'Track'
|
||||||
|
end
|
||||||
|
# Can add or remove users from role, when user has that same role for the conference
|
||||||
|
# Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP')
|
||||||
|
can :toggle_user, Role do |role|
|
||||||
|
role.resource_type == 'Conference' && role.name == 'volunteers_coordinator' &&
|
||||||
|
(Conference.with_role(:volunteers_coordinator, user).pluck(:id).include? role.resource_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def signed_in_with_track_organizer_role(user)
|
||||||
|
# ids of all the conferences for which the user has the 'track organizer' role
|
||||||
|
conf_ids_for_track_organizer = Track.with_role(:track_organizer, user).joins(:program).pluck(:conference_id)
|
||||||
|
# ids of all the tracks for which the user has the 'track_organizer' role
|
||||||
|
track_ids_for_track_organizer = Track.with_role(:track_organizer, user).pluck(:id)
|
||||||
|
|
||||||
|
can :show, Conference do |conf|
|
||||||
|
conf_ids_for_track_organizer.include?(conf.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Show Program in the admin sidebar
|
||||||
|
can :show, Program, conference_id: conf_ids_for_track_organizer
|
||||||
|
|
||||||
|
# Show Tracks in the admin sidebar
|
||||||
|
can :update, Track do |track|
|
||||||
|
track.new_record? && conf_ids_for_track_organizer.include?(track.program.conference_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
can :manage, Track, id: track_ids_for_track_organizer
|
||||||
|
|
||||||
|
cannot [:edit, :update], Track do |track|
|
||||||
|
track.self_organized_and_accepted_or_confirmed?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Show Roles in the admin sidebar and allow authorization of the index action
|
||||||
|
can [:index, :show], Role do |role|
|
||||||
|
role.resource_type == 'Conference' || role.resource_type == 'Track'
|
||||||
|
end
|
||||||
|
|
||||||
|
can :toggle_user, Role do |role|
|
||||||
|
role.resource_type == 'Track' && track_ids_for_track_organizer.include?(role.resource_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Show Events in the admin sidebar
|
||||||
|
can :update, Event do |event|
|
||||||
|
event.new_record? && conf_ids_for_track_organizer.include?(event.program.conference_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
can :manage, Event, track_id: track_ids_for_track_organizer
|
||||||
|
can :manage, Commercial, commercialable_type: 'Event',
|
||||||
|
commercialable_id: Event.where(track_id: track_ids_for_track_organizer).pluck(:id)
|
||||||
|
|
||||||
|
# Show Scheduless in the admin sidebar
|
||||||
|
can :update, Schedule do |schedule|
|
||||||
|
schedule.new_record? && conf_ids_for_track_organizer.include?(schedule.program.conference_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Show new track schedule button
|
||||||
|
can :new, Schedule do |schedule|
|
||||||
|
schedule.new_record? && conf_ids_for_track_organizer.include?(schedule.program.conference_id) && schedule.track.try(:new_record?)
|
||||||
|
end
|
||||||
|
|
||||||
|
can :manage, Schedule, track_id: track_ids_for_track_organizer
|
||||||
|
can :manage, EventSchedule, schedule: { track_id: track_ids_for_track_organizer }
|
||||||
|
end
|
||||||
|
end
|
||||||
83
app/models/booth.rb
Normal file
83
app/models/booth.rb
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
class Booth < ActiveRecord::Base
|
||||||
|
include ActiveRecord::Transitions
|
||||||
|
has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||||
|
|
||||||
|
belongs_to :conference
|
||||||
|
has_many :booth_requests, dependent: :destroy
|
||||||
|
has_many :users, through: :booth_requests
|
||||||
|
|
||||||
|
has_one :submitter_booth_user, -> { where(role: 'submitter') }, class_name: 'BoothRequest'
|
||||||
|
has_one :submitter, through: :submitter_booth_user, source: :user
|
||||||
|
|
||||||
|
has_many :responsibles_booth_user, -> { where(role: 'responsible') }, class_name: 'BoothRequest'
|
||||||
|
has_many :responsibles, through: :responsibles_booth_user, source: :user
|
||||||
|
|
||||||
|
validates :title,
|
||||||
|
uniqueness: { case_sensitive: false },
|
||||||
|
presence: true
|
||||||
|
|
||||||
|
validates :description,
|
||||||
|
:reasoning,
|
||||||
|
:state,
|
||||||
|
:responsibles,
|
||||||
|
:conference_id,
|
||||||
|
:website_url,
|
||||||
|
:submitter_relationship,
|
||||||
|
presence: true
|
||||||
|
|
||||||
|
scope :accepted, -> { where(state: 'accepted') }
|
||||||
|
scope :confirmed, -> { where(state: 'confirmed') }
|
||||||
|
|
||||||
|
mount_uploader :picture, PictureUploader, mount_on: :logo_link
|
||||||
|
|
||||||
|
state_machine initial: :new do
|
||||||
|
state :new
|
||||||
|
state :withdrawn
|
||||||
|
state :to_accept
|
||||||
|
state :accepted
|
||||||
|
state :to_reject
|
||||||
|
state :rejected
|
||||||
|
state :canceled
|
||||||
|
state :confirmed
|
||||||
|
|
||||||
|
event :restart do
|
||||||
|
transitions to: :new, from: [:withdrawn, :rejected, :canceled]
|
||||||
|
end
|
||||||
|
event :withdraw do
|
||||||
|
transitions to: :withdrawn, from: [:new, :to_accept, :accepted, :to_reject, :rejected, :confirmed]
|
||||||
|
end
|
||||||
|
event :confirm do
|
||||||
|
transitions to: :confirmed, from: [:accepted]
|
||||||
|
end
|
||||||
|
event :to_accept do
|
||||||
|
transitions to: :to_accept, from: [:new, :to_reject]
|
||||||
|
end
|
||||||
|
event :to_reject do
|
||||||
|
transitions to: :to_reject, from: [:new, :to_accept]
|
||||||
|
end
|
||||||
|
event :accept do
|
||||||
|
transitions to: :accepted, from: [:new, :to_accept]
|
||||||
|
end
|
||||||
|
event :reject do
|
||||||
|
transitions to: :rejected, from: [:new, :to_reject]
|
||||||
|
end
|
||||||
|
event :cancel do
|
||||||
|
transitions to: :canceled, from: [:accepted, :rejected, :to_accept, :to_reject, :confirmed]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def transition_possible?(transition)
|
||||||
|
self.class.state_machine.events_for(current_state).include?(transition)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_state(transition, _notice)
|
||||||
|
alert = ''
|
||||||
|
begin
|
||||||
|
send(transition)
|
||||||
|
save
|
||||||
|
rescue Transitions::InvalidTransition => e
|
||||||
|
alert = "Update state failed. #{e.message}"
|
||||||
|
end
|
||||||
|
alert
|
||||||
|
end
|
||||||
|
end
|
||||||
9
app/models/booth_request.rb
Normal file
9
app/models/booth_request.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
class BoothRequest < ActiveRecord::Base
|
||||||
|
belongs_to :booth
|
||||||
|
belongs_to :user
|
||||||
|
|
||||||
|
validates :role,
|
||||||
|
presence: true
|
||||||
|
|
||||||
|
ROLES = %w[submitter responsible].freeze
|
||||||
|
end
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
# cannot delete program if there are events submitted
|
# cannot delete program if there are events submitted
|
||||||
|
|
||||||
class Cfp < ActiveRecord::Base
|
class Cfp < ActiveRecord::Base
|
||||||
|
TYPES = %w(events booths tracks).freeze
|
||||||
|
|
||||||
has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id }
|
has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||||
belongs_to :program
|
belongs_to :program
|
||||||
|
|
||||||
|
|
@ -8,6 +10,15 @@ class Cfp < ActiveRecord::Base
|
||||||
validates :start_date, :end_date, presence: true
|
validates :start_date, :end_date, presence: true
|
||||||
validate :before_end_of_conference
|
validate :before_end_of_conference
|
||||||
validate :start_after_end_date
|
validate :start_after_end_date
|
||||||
|
validates :cfp_type,
|
||||||
|
presence: true,
|
||||||
|
inclusion: {
|
||||||
|
in: TYPES
|
||||||
|
},
|
||||||
|
uniqueness: {
|
||||||
|
scope: :program,
|
||||||
|
case_sensitive: false
|
||||||
|
}
|
||||||
|
|
||||||
##
|
##
|
||||||
# Checks whether cfp date is updated
|
# Checks whether cfp date is updated
|
||||||
|
|
@ -16,11 +27,11 @@ class Cfp < ActiveRecord::Base
|
||||||
# * +True+ -> If cfp dates is updated and all other parameters are set
|
# * +True+ -> If cfp dates is updated and all other parameters are set
|
||||||
# * +False+ -> Either cfp date is not updated or one or more parameter is not set
|
# * +False+ -> Either cfp date is not updated or one or more parameter is not set
|
||||||
def notify_on_cfp_date_update?
|
def notify_on_cfp_date_update?
|
||||||
!self.end_date.blank? && !self.start_date.blank?\
|
!end_date.blank? && !start_date.blank?\
|
||||||
&& (self.start_date_changed? || self.end_date_changed?)\
|
&& (start_date_changed? || end_date_changed?)\
|
||||||
&& self.program.conference.email_settings.send_on_cfp_dates_updated\
|
&& program.conference.email_settings.send_on_cfp_dates_updated\
|
||||||
&& !self.program.conference.email_settings.cfp_dates_updated_subject.blank?\
|
&& !program.conference.email_settings.cfp_dates_updated_subject.blank?\
|
||||||
&& !self.program.conference.email_settings.cfp_dates_updated_body.blank?
|
&& !program.conference.email_settings.cfp_dates_updated_body.blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
@ -51,23 +62,64 @@ class Cfp < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def remaining_days(date = Date.today)
|
def remaining_days(date = Date.today)
|
||||||
result = (self.end_date - date).to_i
|
result = (end_date - date).to_i
|
||||||
result > 0 ? result : 0
|
result > 0 ? result : 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Checks if the call for papers is currently open
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +false+ -> If the CFP is not set or today isn't in the CFP period.
|
||||||
|
# * +true+ -> If today is in the CFP period.
|
||||||
|
def open?
|
||||||
|
(start_date..end_date).cover?(Date.current)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Finds the cfp for events if it exists
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +Cfp+ -> The cfp with type 'events'
|
||||||
|
def self.for_events
|
||||||
|
find_by(cfp_type: 'events')
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Finds the cfp for tracks if it exists
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +Cfp+ -> The cfp with type 'tracks'
|
||||||
|
def self.for_tracks
|
||||||
|
find_by(cfp_type: 'tracks')
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Finds the cfp for booths if it exists
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +Cfp+ -> The cfp with type 'booths'
|
||||||
|
def self.for_booths
|
||||||
|
find_by(cfp_type: 'booths')
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def before_end_of_conference
|
def before_end_of_conference
|
||||||
errors.
|
if program && program.conference && program.conference.end_date && end_date && (end_date > program.conference.end_date)
|
||||||
add(:end_date, "can't be after the conference end date (#{program.conference.end_date})") if program.conference && program.conference.end_date && end_date && (end_date > program.conference.end_date)
|
errors
|
||||||
|
.add(:end_date, "can't be after the conference end date (#{program.conference.end_date})")
|
||||||
|
end
|
||||||
|
|
||||||
errors.
|
if program && program.conference && program.conference.end_date && start_date && (start_date > program.conference.end_date)
|
||||||
add(:start_date, "can't be after the conference end date (#{program.conference.end_date})") if program.conference && program.conference.end_date && start_date && (start_date > program.conference.end_date)
|
errors
|
||||||
|
.add(:start_date, "can't be after the conference end date (#{program.conference.end_date})")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_after_end_date
|
def start_after_end_date
|
||||||
errors.
|
errors
|
||||||
add(:start_date, "can't be after the end date") if start_date && end_date && start_date > end_date
|
.add(:start_date, "can't be after the end date") if start_date && end_date && start_date > end_date
|
||||||
end
|
end
|
||||||
|
|
||||||
def conference_id
|
def conference_id
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
class Comment < ActiveRecord::Base
|
class Comment < ActiveRecord::Base
|
||||||
acts_as_nested_set scope: [:commentable_id, :commentable_type]
|
acts_as_nested_set scope: %i(commentable_id commentable_type)
|
||||||
validates_presence_of :body
|
validates :body, presence: true
|
||||||
validates_presence_of :user
|
validates :user, presence: true
|
||||||
after_create :send_notification
|
after_create :send_notification
|
||||||
|
|
||||||
# NOTE: install the acts_as_votable plugin if you
|
# NOTE: install the acts_as_votable plugin if you
|
||||||
# want user to vote on the quality of comments.
|
# want user to vote on the quality of comments.
|
||||||
#acts_as_votable
|
#acts_as_votable
|
||||||
|
|
||||||
belongs_to :commentable, polymorphic: true
|
belongs_to :commentable, counter_cache: true, polymorphic: true
|
||||||
|
|
||||||
# NOTE: Comments belong to a user
|
# NOTE: Comments belong to a user
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
||||||
has_paper_trail on: [:create, :destroy], meta: { conference_id: :conference_id }
|
has_paper_trail on: %i(create destroy), meta: { conference_id: :conference_id }
|
||||||
|
|
||||||
# Helper class method that allows you to build a comment
|
# Helper class method that allows you to build a comment
|
||||||
# by passing a commentable object, a user_id, and comment text
|
# by passing a commentable object, a user_id, and comment text
|
||||||
|
|
@ -27,7 +27,7 @@ class Comment < ActiveRecord::Base
|
||||||
|
|
||||||
#helper method to check if a comment has children
|
#helper method to check if a comment has children
|
||||||
def has_children?
|
def has_children?
|
||||||
self.children.any?
|
children.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper class method to lookup all comments assigned
|
# Helper class method to lookup all comments assigned
|
||||||
|
|
|
||||||
11
app/models/concerns/revision_count.rb
Normal file
11
app/models/concerns/revision_count.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
module RevisionCount
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
after_update :increment_revision
|
||||||
|
end
|
||||||
|
|
||||||
|
def increment_revision
|
||||||
|
conference.update_column(:revision, conference.revision + 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
class Conference < ActiveRecord::Base
|
class Conference < ActiveRecord::Base
|
||||||
|
include RevisionCount
|
||||||
require 'uri'
|
require 'uri'
|
||||||
serialize :events_per_week, Hash
|
serialize :events_per_week, Hash
|
||||||
# Needed to call 'Conference.with_role' in /models/ability.rb
|
# Needed to call 'Conference.with_role' in /models/ability.rb
|
||||||
|
|
@ -6,8 +7,12 @@ class Conference < ActiveRecord::Base
|
||||||
resourcify :roles, dependent: :delete_all
|
resourcify :roles, dependent: :delete_all
|
||||||
|
|
||||||
default_scope { order('start_date DESC') }
|
default_scope { order('start_date DESC') }
|
||||||
|
scope :upcoming, (-> { where('end_date >= ?', Date.current) })
|
||||||
|
scope :past, (-> { where('end_date < ?', Date.current) })
|
||||||
|
|
||||||
has_paper_trail ignore: [:updated_at, :guid, :revision, :events_per_week], meta: { conference_id: :id }
|
belongs_to :organization
|
||||||
|
|
||||||
|
has_paper_trail ignore: %i(updated_at guid revision events_per_week), meta: { conference_id: :id }
|
||||||
|
|
||||||
has_and_belongs_to_many :questions
|
has_and_belongs_to_many :questions
|
||||||
|
|
||||||
|
|
@ -17,11 +22,17 @@ class Conference < ActiveRecord::Base
|
||||||
has_one :email_settings, dependent: :destroy
|
has_one :email_settings, dependent: :destroy
|
||||||
has_one :program, dependent: :destroy
|
has_one :program, dependent: :destroy
|
||||||
has_one :venue, dependent: :destroy
|
has_one :venue, dependent: :destroy
|
||||||
|
has_many :physical_tickets, through: :ticket_purchases
|
||||||
has_many :ticket_purchases, dependent: :destroy
|
has_many :ticket_purchases, dependent: :destroy
|
||||||
has_many :payments, dependent: :destroy
|
has_many :payments, dependent: :destroy
|
||||||
has_many :supporters, through: :ticket_purchases, source: :user
|
has_many :supporters, through: :ticket_purchases, source: :user
|
||||||
has_many :tickets, dependent: :destroy
|
has_many :tickets, dependent: :destroy do
|
||||||
|
def for_registration
|
||||||
|
where(registration_ticket: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
has_many :resources, dependent: :destroy
|
has_many :resources, dependent: :destroy
|
||||||
|
has_many :booths, dependent: :destroy
|
||||||
|
|
||||||
has_many :lodgings, dependent: :destroy
|
has_many :lodgings, dependent: :destroy
|
||||||
has_many :registrations, dependent: :destroy
|
has_many :registrations, dependent: :destroy
|
||||||
|
|
@ -48,15 +59,17 @@ class Conference < ActiveRecord::Base
|
||||||
|
|
||||||
mount_uploader :picture, PictureUploader, mount_on: :logo_file_name
|
mount_uploader :picture, PictureUploader, mount_on: :logo_file_name
|
||||||
|
|
||||||
validates_presence_of :title,
|
validates :title,
|
||||||
:short_title,
|
:short_title,
|
||||||
:start_date,
|
:start_date,
|
||||||
:end_date,
|
:end_date,
|
||||||
:start_hour,
|
:start_hour,
|
||||||
:end_hour
|
:end_hour,
|
||||||
|
:ticket_layout,
|
||||||
|
:organization, presence: true
|
||||||
|
|
||||||
validates_uniqueness_of :short_title
|
validates :short_title, uniqueness: true
|
||||||
validates_format_of :short_title, with: /\A[a-zA-Z0-9_-]*\z/
|
validates :short_title, format: { with: /\A[a-zA-Z0-9_-]*\z/ }
|
||||||
validates :registration_limit, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
validates :registration_limit, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
||||||
|
|
||||||
# This validation is needed since a conference with a start date greater than the end date is not possible
|
# This validation is needed since a conference with a start date greater than the end date is not possible
|
||||||
|
|
@ -67,6 +80,9 @@ class Conference < ActiveRecord::Base
|
||||||
before_create :create_email_settings
|
before_create :create_email_settings
|
||||||
|
|
||||||
after_create :create_free_ticket
|
after_create :create_free_ticket
|
||||||
|
after_update :delete_event_schedules
|
||||||
|
|
||||||
|
enum ticket_layout: [:portrait, :landscape]
|
||||||
|
|
||||||
##
|
##
|
||||||
# Checks if the user is registered to the conference
|
# Checks if the user is registered to the conference
|
||||||
|
|
@ -80,6 +96,20 @@ class Conference < ActiveRecord::Base
|
||||||
user.present? && registrations.where(user_id: user.id).count > 0
|
user.present? && registrations.where(user_id: user.id).count > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Delete all EventSchedules that are not in the hours range
|
||||||
|
# After the conference has been successfully updated
|
||||||
|
def delete_event_schedules
|
||||||
|
if start_hour_changed? || end_hour_changed?
|
||||||
|
event_schedules = program.event_schedules.select do |event_schedule|
|
||||||
|
event_schedule.start_time.hour < start_hour ||
|
||||||
|
event_schedule.end_time.hour > end_hour ||
|
||||||
|
(event_schedule.end_time.hour == end_hour && event_schedule.end_time.minute > 0)
|
||||||
|
end
|
||||||
|
event_schedules.each(&:destroy)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Checks if the registration for the conference is currently open
|
# Checks if the registration for the conference is currently open
|
||||||
#
|
#
|
||||||
|
|
@ -113,7 +143,7 @@ class Conference < ActiveRecord::Base
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
if program && program.cfp && program.events
|
if program && program.cfp && program.events
|
||||||
submissions = program.events.group(:week).count
|
submissions = program.events.select(:week).group(:week).order(:week).count
|
||||||
start_week = program.cfp.start_week
|
start_week = program.cfp.start_week
|
||||||
weeks = program.cfp.weeks
|
weeks = program.cfp.weeks
|
||||||
result = calculate_items_per_week(start_week, weeks, submissions)
|
result = calculate_items_per_week(start_week, weeks, submissions)
|
||||||
|
|
@ -161,7 +191,7 @@ class Conference < ActiveRecord::Base
|
||||||
registration_period.start_date &&
|
registration_period.start_date &&
|
||||||
registration_period.end_date
|
registration_period.end_date
|
||||||
|
|
||||||
reg = registrations.group(:week).count
|
reg = registrations.group(:week).order(:week).count
|
||||||
start_week = get_registration_start_week
|
start_week = get_registration_start_week
|
||||||
weeks = registration_weeks
|
weeks = registration_weeks
|
||||||
result = calculate_items_per_week(start_week, weeks, reg)
|
result = calculate_items_per_week(start_week, weeks, reg)
|
||||||
|
|
@ -169,6 +199,59 @@ class Conference < ActiveRecord::Base
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns an array with the summarized ticket sales per week.
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +Array+ -> e.g. [0, 3, 3, 5] -> first week 0, second week 3 tickets sold
|
||||||
|
def get_tickets_sold_per_week
|
||||||
|
result = []
|
||||||
|
|
||||||
|
if tickets && ticket_purchases && registration_period
|
||||||
|
tickets_sold = ticket_purchases.paid.group(:week).sum(:quantity)
|
||||||
|
start_week = get_registration_start_week
|
||||||
|
weeks = registration_weeks
|
||||||
|
result = calculate_items_per_week(start_week, weeks, tickets_sold)
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns an hash with ticket sales by ticket title
|
||||||
|
# per week.
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +Array+ -> e.g. 'Free Access' => [0, 3, 3, 5] -> first week 0 tickets sold, second week 3 tickets sold.
|
||||||
|
def get_tickets_data
|
||||||
|
result = {}
|
||||||
|
if tickets && ticket_purchases && registration_period
|
||||||
|
tickets_per_ticket_id_and_week = ticket_purchases.paid.group(:ticket_id, :week).sum(:quantity)
|
||||||
|
|
||||||
|
start_week = get_registration_start_week
|
||||||
|
weeks = registration_weeks
|
||||||
|
|
||||||
|
tickets_by_id_per_week = {}
|
||||||
|
|
||||||
|
tickets.each do |ticket|
|
||||||
|
tickets_by_id_per_week[ticket.id] = {}
|
||||||
|
(start_week...(start_week + weeks)).each do |week|
|
||||||
|
tickets_by_id_per_week[ticket.id][week] = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tickets_per_ticket_id_and_week.each do |ticket_week, value|
|
||||||
|
tickets_by_id_per_week[ticket_week[0]][ticket_week[1]] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
tickets_by_id_per_week.each do |ticket, values|
|
||||||
|
result[Ticket.find(ticket).title] = pad_array_left_not_kumulative(start_week, values)
|
||||||
|
end
|
||||||
|
|
||||||
|
result['Weeks'] = weeks > 0 ? (1..weeks).to_a : 0
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Calculates how many weeks the registration is.
|
# Calculates how many weeks the registration is.
|
||||||
#
|
#
|
||||||
|
|
@ -180,8 +263,8 @@ class Conference < ActiveRecord::Base
|
||||||
if registration_period &&
|
if registration_period &&
|
||||||
registration_period.start_date &&
|
registration_period.start_date &&
|
||||||
registration_period.end_date
|
registration_period.end_date
|
||||||
weeks = Date.new(registration_period.start_date.year, 12, 31).
|
weeks = Date.new(registration_period.start_date.year, 12, 31)
|
||||||
strftime('%W').to_i
|
.strftime('%W').to_i
|
||||||
|
|
||||||
result = get_registration_end_week - get_registration_start_week + 1
|
result = get_registration_end_week - get_registration_start_week + 1
|
||||||
end
|
end
|
||||||
|
|
@ -266,8 +349,8 @@ class Conference < ActiveRecord::Base
|
||||||
# ====Returns
|
# ====Returns
|
||||||
# * +hash+ -> user: submissions
|
# * +hash+ -> user: submissions
|
||||||
def self.get_top_submitter(limit = 5)
|
def self.get_top_submitter(limit = 5)
|
||||||
submitter = EventUser.where('event_role = ?', 'submitter').limit(limit).group(:user_id)
|
submitter = EventUser.select(:user_id).where('event_role = ?', 'submitter').limit(limit).group(:user_id)
|
||||||
counter = submitter.order('count_all desc').count
|
counter = submitter.order('count_all desc').count(:all)
|
||||||
calculate_user_submission_hash(submitter, counter)
|
calculate_user_submission_hash(submitter, counter)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -277,10 +360,10 @@ class Conference < ActiveRecord::Base
|
||||||
# ====Returns
|
# ====Returns
|
||||||
# * +hash+ -> user: submissions
|
# * +hash+ -> user: submissions
|
||||||
def get_top_submitter(limit = 5)
|
def get_top_submitter(limit = 5)
|
||||||
submitter = EventUser.joins(:event).
|
submitter = EventUser.joins(:event).select(:user_id)
|
||||||
where('event_role = ? and program_id = ?', 'submitter', Conference.find(id).program.id).
|
.where('event_role = ? and program_id = ?', 'submitter', Conference.find(id).program.id)
|
||||||
limit(limit).group(:user_id)
|
.limit(limit).group(:user_id)
|
||||||
counter = submitter.order('count_all desc').count
|
counter = submitter.order('count_all desc').count(:all)
|
||||||
Conference.calculate_user_submission_hash(submitter, counter)
|
Conference.calculate_user_submission_hash(submitter, counter)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -311,9 +394,10 @@ class Conference < ActiveRecord::Base
|
||||||
# ====Returns
|
# ====Returns
|
||||||
# * +hash+ -> hash
|
# * +hash+ -> hash
|
||||||
def scheduled_event_distribution
|
def scheduled_event_distribution
|
||||||
confirmed_events = program.events.where(state: 'confirmed')
|
confirmed_scheduled_events = program.events.confirmed.scheduled(program.selected_schedule.try(:id))
|
||||||
scheduled_value = { 'value' => confirmed_events.where.not(start_time: nil).count, 'color' => 'green' }
|
confirmed_unscheduled_events = program.events.confirmed - confirmed_scheduled_events
|
||||||
unscheduled_value = { 'value' => confirmed_events.where(start_time: nil).count, 'color' => 'red' }
|
scheduled_value = { 'value' => confirmed_scheduled_events.count, 'color' => 'green' }
|
||||||
|
unscheduled_value = { 'value' => confirmed_unscheduled_events.count, 'color' => 'red' }
|
||||||
{ 'Scheduled' => scheduled_value, 'Unscheduled' => unscheduled_value }
|
{ 'Scheduled' => scheduled_value, 'Unscheduled' => unscheduled_value }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -380,6 +464,46 @@ class Conference < ActiveRecord::Base
|
||||||
calculate_user_distribution_hash(active_user, unconfirmed_user, dead_user)
|
calculate_user_distribution_hash(active_user, unconfirmed_user, dead_user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns a hash with per ticket sales => { "Title" => { value: number of tickets sold,
|
||||||
|
# color: generated from the title using a hash function }, ...}
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +hash+ -> hash
|
||||||
|
def tickets_sold_distribution
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
if tickets && ticket_purchases
|
||||||
|
tickets.each do |ticket|
|
||||||
|
result[ticket.title] = {
|
||||||
|
'value' => ApplicationController.helpers.humanized_money(ticket.tickets_sold).delete(',').to_i,
|
||||||
|
'color' => "\##{Digest::MD5.hexdigest(ticket.title)[0..5]}"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Returns a hash with per ticket turnover => { "Title" => { value: ticket turnover,
|
||||||
|
# color: generated from the title using a hash function }, ...}
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +hash+ -> hash
|
||||||
|
def tickets_turnover_distribution
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
if tickets && ticket_purchases
|
||||||
|
tickets.each do |ticket|
|
||||||
|
result[ticket.title] = {
|
||||||
|
'value' => ApplicationController.helpers.humanized_money(ticket.tickets_turnover).delete(',').to_i,
|
||||||
|
'color' => "\##{Digest::MD5.hexdigest(ticket.title)[0..5]}"
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Calculates the overall program minutes
|
# Calculates the overall program minutes
|
||||||
#
|
#
|
||||||
|
|
@ -444,10 +568,10 @@ class Conference < ActiveRecord::Base
|
||||||
# ====Returns
|
# ====Returns
|
||||||
# * +hash+ -> track => {color, value}
|
# * +hash+ -> track => {color, value}
|
||||||
def tracks_distribution(state = nil)
|
def tracks_distribution(state = nil)
|
||||||
if state
|
tracks_grouped = if state
|
||||||
tracks_grouped = program.events.select(:track_id).where('state = ?', state).group(:track_id)
|
program.events.select(:track_id).where('state = ?', state).group(:track_id)
|
||||||
else
|
else
|
||||||
tracks_grouped = program.events.select(:track_id).group(:track_id)
|
program.events.select(:track_id).group(:track_id)
|
||||||
end
|
end
|
||||||
tracks_counted = tracks_grouped.count
|
tracks_counted = tracks_grouped.count
|
||||||
|
|
||||||
|
|
@ -461,13 +585,13 @@ class Conference < ActiveRecord::Base
|
||||||
# ====Returns
|
# ====Returns
|
||||||
# * +ActiveRecord+
|
# * +ActiveRecord+
|
||||||
def self.get_active_conferences_for_dashboard
|
def self.get_active_conferences_for_dashboard
|
||||||
result = Conference.where('start_date > ?', Time.now).
|
result = Conference.where('start_date > ?', Time.now)
|
||||||
select('id, short_title, color, start_date')
|
.select('id, short_title, color, start_date')
|
||||||
|
|
||||||
if result.length == 0
|
if result.empty?
|
||||||
result = Conference.
|
result = Conference
|
||||||
select('id, short_title, color, start_date').limit(2).
|
.select('id, short_title, color, start_date').limit(2)
|
||||||
order(start_date: :desc)
|
.order(start_date: :desc)
|
||||||
end
|
end
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
@ -531,7 +655,7 @@ class Conference < ActiveRecord::Base
|
||||||
def self.write_event_distribution_to_db
|
def self.write_event_distribution_to_db
|
||||||
week = DateTime.now.end_of_week
|
week = DateTime.now.end_of_week
|
||||||
|
|
||||||
Conference.where('end_date > ?', Date.today).each do |conference|
|
Conference.where('end_date > ?', Date.today).find_each do |conference|
|
||||||
result = {}
|
result = {}
|
||||||
Event.state_machine.states.each do |state|
|
Event.state_machine.states.each do |state|
|
||||||
count = conference.program.events.where('state = ?', state.name).count
|
count = conference.program.events.where('state = ?', state.name).count
|
||||||
|
|
@ -555,11 +679,11 @@ class Conference < ActiveRecord::Base
|
||||||
# * +True+ -> If conference is updated and all other parameters are set
|
# * +True+ -> If conference is updated and all other parameters are set
|
||||||
# * +False+ -> Either conference is not updated or one or more parameter is not set
|
# * +False+ -> Either conference is not updated or one or more parameter is not set
|
||||||
def notify_on_dates_changed?
|
def notify_on_dates_changed?
|
||||||
return false unless self.email_settings.send_on_conference_dates_updated
|
return false unless email_settings.send_on_conference_dates_updated
|
||||||
# do not notify unless one of the dates changed
|
# do not notify unless one of the dates changed
|
||||||
return false unless self.start_date_changed? || self.end_date_changed?
|
return false unless start_date_changed? || end_date_changed?
|
||||||
# do not notify unless the mail content is set up
|
# do not notify unless the mail content is set up
|
||||||
(!email_settings.conference_dates_updated_subject.blank? && !email_settings.conference_dates_updated_body.blank?)
|
(email_settings.conference_dates_updated_subject.present? && email_settings.conference_dates_updated_body.present?)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
@ -569,17 +693,24 @@ class Conference < ActiveRecord::Base
|
||||||
# * +True+ -> If registration dates is updated and all other parameters are set
|
# * +True+ -> If registration dates is updated and all other parameters are set
|
||||||
# * +False+ -> Either registration date is not updated or one or more parameter is not set
|
# * +False+ -> Either registration date is not updated or one or more parameter is not set
|
||||||
def notify_on_registration_dates_changed?
|
def notify_on_registration_dates_changed?
|
||||||
return false unless self.email_settings.send_on_conference_registration_dates_updated
|
return false unless email_settings.send_on_conference_registration_dates_updated
|
||||||
# do not notify unless we allow a registration
|
# do not notify unless we allow a registration
|
||||||
return false unless self.registration_period
|
return false unless registration_period
|
||||||
# do not notify unless one of the dates changed
|
# do not notify unless one of the dates changed
|
||||||
return false unless registration_period.start_date_changed? || registration_period.end_date_changed?
|
return false unless registration_period.start_date_changed? || registration_period.end_date_changed?
|
||||||
# do not notify unless the mail content is set up
|
# do not notify unless the mail content is set up
|
||||||
(!email_settings.conference_registration_dates_updated_subject.blank? && !email_settings.conference_registration_dates_updated_body.blank?)
|
(email_settings.conference_registration_dates_updated_subject.present? && email_settings.conference_registration_dates_updated_body.present?)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Checks if the registration limit has been exceeded
|
||||||
|
# Additionally, it takes into account the confirmed speakers that haven't registered yet
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +True+ -> If the registration limit has been reached or exceeded
|
||||||
|
# * +False+ -> If the registration limit hasn't been exceeded
|
||||||
def registration_limit_exceeded?
|
def registration_limit_exceeded?
|
||||||
registration_limit > 0 && registrations.count >= registration_limit
|
registration_limit > 0 && registrations.count + program.speakers.confirmed.count - program.speakers.confirmed.registered(program.conference).count >= registration_limit
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an hexadecimal color given a collection. The returned color changed
|
# Returns an hexadecimal color given a collection. The returned color changed
|
||||||
|
|
@ -611,6 +742,28 @@ class Conference < ActiveRecord::Base
|
||||||
(start_hour..(end_hour - 1)).cover?(current_hour) ? current_hour - start_hour : 0
|
(start_hour..(end_hour - 1)).cover?(current_hour) ? current_hour - start_hour : 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +True+ -> if accepted booths are equal to the booth limit
|
||||||
|
# * +False+ -> Accepted booths have not reached the booth limit
|
||||||
|
def maximum_accepted_booths?
|
||||||
|
booth_limit > 0 && booths.accepted.count + booths.confirmed.count >= booth_limit
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Return the current conference object to be used in RevisionCount
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +ActiveRecord+
|
||||||
|
def conference
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_param
|
||||||
|
short_title
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Returns a different html colour for every i and consecutive colors are
|
# Returns a different html colour for every i and consecutive colors are
|
||||||
|
|
@ -628,8 +781,8 @@ class Conference < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
after_create do
|
after_create do
|
||||||
self.create_contact
|
create_contact
|
||||||
self.create_program
|
create_program
|
||||||
create_roles
|
create_roles
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -699,7 +852,7 @@ class Conference < ActiveRecord::Base
|
||||||
# Completed weeks
|
# Completed weeks
|
||||||
events_per_week.each do |week, values|
|
events_per_week.each do |week, values|
|
||||||
values.each do |state, value|
|
values.each do |state, value|
|
||||||
if [:confirmed, :unconfirmed].include?(state)
|
if %i(confirmed unconfirmed).include?(state)
|
||||||
unless result[state.to_s.capitalize]
|
unless result[state.to_s.capitalize]
|
||||||
result[state.to_s.capitalize] = {}
|
result[state.to_s.capitalize] = {}
|
||||||
end
|
end
|
||||||
|
|
@ -838,7 +991,7 @@ class Conference < ActiveRecord::Base
|
||||||
# * +True+ -> If conference has a venue object.
|
# * +True+ -> If conference has a venue object.
|
||||||
# * +False+ -> IF conference has no venue object.
|
# * +False+ -> IF conference has no venue object.
|
||||||
def venue_set?
|
def venue_set?
|
||||||
!!venue
|
venue.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
@ -848,7 +1001,7 @@ class Conference < ActiveRecord::Base
|
||||||
# * +True+ -> If conference has a cfp object.
|
# * +True+ -> If conference has a cfp object.
|
||||||
# * +False+ -> If conference has no cfp object.
|
# * +False+ -> If conference has no cfp object.
|
||||||
def cfp_set?
|
def cfp_set?
|
||||||
!!program.cfp
|
program.cfp.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
@ -858,7 +1011,7 @@ class Conference < ActiveRecord::Base
|
||||||
# * +True+ -> If conference has a start and a end date.
|
# * +True+ -> If conference has a start and a end date.
|
||||||
# * +False+ -> If conference has no start or end date.
|
# * +False+ -> If conference has no start or end date.
|
||||||
def registration_date_set?
|
def registration_date_set?
|
||||||
!!registration_period && !!registration_period.start_date && !!registration_period.end_date
|
registration_period.present? && registration_period.start_date.present? && registration_period.end_date.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Calculates the distribution from events.
|
# Calculates the distribution from events.
|
||||||
|
|
@ -866,10 +1019,10 @@ class Conference < ActiveRecord::Base
|
||||||
# ====Returns
|
# ====Returns
|
||||||
# * +hash+ -> object_type => {color, value}
|
# * +hash+ -> object_type => {color, value}
|
||||||
def calculate_event_distribution(group_by_id, association_symbol, state = nil)
|
def calculate_event_distribution(group_by_id, association_symbol, state = nil)
|
||||||
if state
|
grouped = if state
|
||||||
grouped = program.events.select(group_by_id).where('state = ?', 'confirmed').group(group_by_id)
|
program.events.select(group_by_id).where('state = ?', 'confirmed').group(group_by_id)
|
||||||
else
|
else
|
||||||
grouped = program.events.select(group_by_id).group(group_by_id)
|
program.events.select(group_by_id).group(group_by_id)
|
||||||
end
|
end
|
||||||
counted = grouped.count
|
counted = grouped.count
|
||||||
|
|
||||||
|
|
@ -981,7 +1134,8 @@ class Conference < ActiveRecord::Base
|
||||||
def self.calculate_user_submission_hash(submitters, counter)
|
def self.calculate_user_submission_hash(submitters, counter)
|
||||||
result = ActiveSupport::OrderedHash.new
|
result = ActiveSupport::OrderedHash.new
|
||||||
counter.each do |key, value|
|
counter.each do |key, value|
|
||||||
submitter = submitters.where(user_id: key).first
|
# make PG happy by including the user_id in ORDER
|
||||||
|
submitter = submitters.where(user_id: key).order(:user_id).first
|
||||||
if submitter
|
if submitter
|
||||||
result[submitter.user] = value
|
result[submitter.user] = value
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ class EmailSettings < ActiveRecord::Base
|
||||||
|
|
||||||
has_paper_trail on: [:update], ignore: [:updated_at], meta: { conference_id: :conference_id }
|
has_paper_trail on: [:update], ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||||
|
|
||||||
def get_values(conference, user, event = nil)
|
def get_values(conference, user, event = nil, booth = nil)
|
||||||
h = {
|
h = {
|
||||||
'email' => user.email,
|
'email' => user.email,
|
||||||
'name' => user.name,
|
'name' => user.name,
|
||||||
|
|
@ -45,6 +45,10 @@ class EmailSettings < ActiveRecord::Base
|
||||||
h['proposalslink'] = Rails.application.routes.url_helpers.conference_program_proposals_url(
|
h['proposalslink'] = Rails.application.routes.url_helpers.conference_program_proposals_url(
|
||||||
conference.short_title, host: (ENV['OSEM_HOSTNAME'] || 'localhost:3000'))
|
conference.short_title, host: (ENV['OSEM_HOSTNAME'] || 'localhost:3000'))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if booth
|
||||||
|
h['booth_title'] = booth.title
|
||||||
|
end
|
||||||
h
|
h
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -58,6 +62,11 @@ class EmailSettings < ActiveRecord::Base
|
||||||
parse_template(conf_update_template, values)
|
parse_template(conf_update_template, values)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def generate_booth_mail(booth, booth_template)
|
||||||
|
values = get_values(booth.conference, booth.submitter, nil, booth)
|
||||||
|
parse_template(booth_template, values)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def parse_template(text, values)
|
def parse_template(text, values)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
class Event < ActiveRecord::Base
|
class Event < ActiveRecord::Base
|
||||||
include ActiveRecord::Transitions
|
include ActiveRecord::Transitions
|
||||||
|
include RevisionCount
|
||||||
has_paper_trail on: [:create, :update], ignore: [:updated_at, :guid, :week], meta: { conference_id: :conference_id }
|
has_paper_trail on: [:create, :update], ignore: [:updated_at, :guid, :week], meta: { conference_id: :conference_id }
|
||||||
|
|
||||||
acts_as_commentable
|
acts_as_commentable
|
||||||
|
|
@ -8,7 +9,13 @@ class Event < ActiveRecord::Base
|
||||||
|
|
||||||
has_many :event_users, dependent: :destroy
|
has_many :event_users, dependent: :destroy
|
||||||
has_many :users, through: :event_users
|
has_many :users, through: :event_users
|
||||||
has_many :speakers, through: :event_users, source: :user
|
|
||||||
|
has_many :speaker_event_users, -> { where(event_role: 'speaker') }, class_name: 'EventUser'
|
||||||
|
has_many :speakers, through: :speaker_event_users, source: :user
|
||||||
|
|
||||||
|
has_one :submitter_event_user, -> { where(event_role: 'submitter') }, class_name: 'EventUser'
|
||||||
|
has_one :submitter, through: :submitter_event_user, source: :user
|
||||||
|
|
||||||
has_many :votes, dependent: :destroy
|
has_many :votes, dependent: :destroy
|
||||||
has_many :voters, through: :votes, source: :user
|
has_many :voters, through: :votes, source: :user
|
||||||
has_many :commercials, as: :commercialable, dependent: :destroy
|
has_many :commercials, as: :commercialable, dependent: :destroy
|
||||||
|
|
@ -23,6 +30,7 @@ class Event < ActiveRecord::Base
|
||||||
belongs_to :program
|
belongs_to :program
|
||||||
|
|
||||||
accepts_nested_attributes_for :event_users, allow_destroy: true
|
accepts_nested_attributes_for :event_users, allow_destroy: true
|
||||||
|
accepts_nested_attributes_for :speakers, allow_destroy: true
|
||||||
accepts_nested_attributes_for :users
|
accepts_nested_attributes_for :users
|
||||||
|
|
||||||
before_create :generate_guid
|
before_create :generate_guid
|
||||||
|
|
@ -33,9 +41,11 @@ class Event < ActiveRecord::Base
|
||||||
validates :abstract, presence: true
|
validates :abstract, presence: true
|
||||||
validates :event_type, presence: true
|
validates :event_type, presence: true
|
||||||
validates :program, presence: true
|
validates :program, presence: true
|
||||||
|
validates :speakers, presence: true
|
||||||
validates :max_attendees, numericality: { only_integer: true, greater_than_or_equal_to: 1, allow_nil: true }
|
validates :max_attendees, numericality: { only_integer: true, greater_than_or_equal_to: 1, allow_nil: true }
|
||||||
|
|
||||||
validate :max_attendees_no_more_than_room_size
|
validate :max_attendees_no_more_than_room_size
|
||||||
|
validate :valid_track
|
||||||
|
|
||||||
scope :confirmed, -> { where(state: 'confirmed') }
|
scope :confirmed, -> { where(state: 'confirmed') }
|
||||||
scope :canceled, -> { where(state: 'canceled') }
|
scope :canceled, -> { where(state: 'canceled') }
|
||||||
|
|
@ -75,7 +85,7 @@ class Event < ActiveRecord::Base
|
||||||
# ====Returns
|
# ====Returns
|
||||||
# * +true+ or +false+
|
# * +true+ or +false+
|
||||||
def scheduled?
|
def scheduled?
|
||||||
event_schedules.find_by(schedule_id: program.selected_schedule_id).present?
|
event_schedules.find_by(schedule_id: selected_schedule_id).present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def registration_possible?
|
def registration_possible?
|
||||||
|
|
@ -107,26 +117,22 @@ class Event < ActiveRecord::Base
|
||||||
def average_rating
|
def average_rating
|
||||||
@total_rating = 0
|
@total_rating = 0
|
||||||
votes.each do |vote|
|
votes.each do |vote|
|
||||||
@total_rating = @total_rating + vote.rating
|
@total_rating += vote.rating
|
||||||
end
|
end
|
||||||
@total = votes.size
|
@total = votes.size
|
||||||
@total_rating > 0 ? number_with_precision(@total_rating / @total.to_f, precision: 2, strip_insignificant_zeros: true) : 0
|
@total_rating > 0 ? number_with_precision(@total_rating / @total.to_f, precision: 2, strip_insignificant_zeros: true) : 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def submitter
|
# get event speakers with the event sumbmitter at the first position
|
||||||
result = event_users.where(event_role: 'submitter').first
|
# if the submitter is also a speaker for this event
|
||||||
if result.nil?
|
def speakers_ordered
|
||||||
user = nil
|
speakers_list = speakers.to_a
|
||||||
# Perhaps the event_users haven't been saved, if this is a new proposal
|
|
||||||
event_users.each do |u|
|
if speakers_list.reject! { |speaker| speaker == submitter }
|
||||||
if u.event_role == 'submitter'
|
speakers_list.unshift(submitter)
|
||||||
user = u.user
|
|
||||||
end
|
|
||||||
end
|
|
||||||
user
|
|
||||||
else
|
|
||||||
result.user
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
speakers_list
|
||||||
end
|
end
|
||||||
|
|
||||||
def transition_possible?(transition)
|
def transition_possible?(transition)
|
||||||
|
|
@ -185,12 +191,12 @@ class Event < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
begin
|
begin
|
||||||
if mail
|
if mail
|
||||||
self.send(transition,
|
send(transition,
|
||||||
send_mail: send_mail_param)
|
send_mail: send_mail_param)
|
||||||
else
|
else
|
||||||
self.send(transition)
|
send(transition)
|
||||||
end
|
end
|
||||||
self.save
|
save
|
||||||
rescue Transitions::InvalidTransition => e
|
rescue Transitions::InvalidTransition => e
|
||||||
alert = "Update state failed. #{e.message}"
|
alert = "Update state failed. #{e.message}"
|
||||||
end
|
end
|
||||||
|
|
@ -210,12 +216,12 @@ class Event < ActiveRecord::Base
|
||||||
# Returns +Hash+
|
# Returns +Hash+
|
||||||
def progress_status
|
def progress_status
|
||||||
{
|
{
|
||||||
registered: self.program.conference.user_registered?(self.submitter),
|
registered: speakers.all? { |speaker| program.conference.user_registered? speaker },
|
||||||
commercials: self.commercials.any?,
|
commercials: commercials.any?,
|
||||||
biography: !self.submitter.biography.blank?,
|
biographies: speakers.all? { |speaker| !speaker.biography.blank? },
|
||||||
subtitle: !self.subtitle.blank?,
|
subtitle: !subtitle.blank?,
|
||||||
track: (!self.track.blank? unless self.program.tracks.empty?),
|
track: (!track.blank? unless program.tracks.empty?),
|
||||||
difficulty_level: !self.difficulty_level.blank?,
|
difficulty_level: !difficulty_level.blank?,
|
||||||
title: true,
|
title: true,
|
||||||
abstract: true
|
abstract: true
|
||||||
}.with_indifferent_access
|
}.with_indifferent_access
|
||||||
|
|
@ -227,7 +233,7 @@ class Event < ActiveRecord::Base
|
||||||
# ====Returns
|
# ====Returns
|
||||||
# * +String+ -> Progress in Percent
|
# * +String+ -> Progress in Percent
|
||||||
def calculate_progress
|
def calculate_progress
|
||||||
result = self.progress_status
|
result = progress_status
|
||||||
(100 * result.values.count(true) / result.values.compact.count).to_s
|
(100 * result.values.count(true) / result.values.compact.count).to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -237,14 +243,22 @@ class Event < ActiveRecord::Base
|
||||||
def room
|
def room
|
||||||
# We use try(:selected_schedule_id) because this function is used for
|
# We use try(:selected_schedule_id) because this function is used for
|
||||||
# validations so program could not be present there
|
# validations so program could not be present there
|
||||||
|
if track.try(:self_organized?)
|
||||||
|
track.room
|
||||||
|
else
|
||||||
event_schedules.find_by(schedule_id: program.try(:selected_schedule_id)).try(:room)
|
event_schedules.find_by(schedule_id: program.try(:selected_schedule_id)).try(:room)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Returns the start time at which this event is scheduled
|
# Returns the start time at which this event is scheduled
|
||||||
#
|
#
|
||||||
def time
|
def time
|
||||||
event_schedules.find_by(schedule_id: program.selected_schedule_id).try(:start_time)
|
event_schedules.find_by(schedule_id: selected_schedule_id).try(:start_time)
|
||||||
|
end
|
||||||
|
|
||||||
|
def conference
|
||||||
|
program.conference
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
@ -280,18 +294,39 @@ class Event < ActiveRecord::Base
|
||||||
|
|
||||||
def set_week
|
def set_week
|
||||||
self.week = created_at.strftime('%W')
|
self.week = created_at.strftime('%W')
|
||||||
self.without_versioning do
|
without_versioning do
|
||||||
self.save!
|
save!
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_end_of_conference
|
def before_end_of_conference
|
||||||
errors.
|
errors
|
||||||
add(:created_at, "can't be after the conference end date!") if program.conference && program.conference.end_date &&
|
.add(:created_at, "can't be after the conference end date!") if program.conference && program.conference.end_date &&
|
||||||
(Date.today > program.conference.end_date)
|
(Date.today > program.conference.end_date)
|
||||||
end
|
end
|
||||||
|
|
||||||
def conference_id
|
def conference_id
|
||||||
program.conference_id
|
program.conference_id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Allow only confirmed tracks that belong to the same program as the event
|
||||||
|
#
|
||||||
|
def valid_track
|
||||||
|
return unless track && track.program && program
|
||||||
|
errors.add(:track, 'is invalid') unless track.confirmed? && track.program == program
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Return the id of the selected schedule
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +Integer+ -> selected_schedule_id of self-organized track or program
|
||||||
|
def selected_schedule_id
|
||||||
|
if track.try(:self_organized?)
|
||||||
|
track.selected_schedule_id
|
||||||
|
else
|
||||||
|
program.selected_schedule_id
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ class EventSchedule < ActiveRecord::Base
|
||||||
validates :room, presence: true
|
validates :room, presence: true
|
||||||
validates :start_time, presence: true
|
validates :start_time, presence: true
|
||||||
validates :event, uniqueness: { scope: :schedule }
|
validates :event, uniqueness: { scope: :schedule }
|
||||||
|
validate :start_after_end_hour
|
||||||
|
validate :start_before_start_hour
|
||||||
|
validate :same_room_as_track
|
||||||
|
validate :during_track
|
||||||
|
validate :valid_schedule
|
||||||
|
|
||||||
scope :confirmed, -> { joins(:event).where('state = ?', 'confirmed') }
|
scope :confirmed, -> { joins(:event).where('state = ?', 'confirmed') }
|
||||||
scope :canceled, -> { joins(:event).where('state = ?', 'canceled') }
|
scope :canceled, -> { joins(:event).where('state = ?', 'canceled') }
|
||||||
|
|
@ -37,7 +42,48 @@ class EventSchedule < ActiveRecord::Base
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def start_after_end_hour
|
||||||
|
return unless event && start_time && event.program && event.program.conference && event.program.conference.end_hour
|
||||||
|
errors.add(:start_time, "can't be after the conference end hour (#{event.program.conference.end_hour})") if start_time.hour >= event.program.conference.end_hour
|
||||||
|
end
|
||||||
|
|
||||||
|
def start_before_start_hour
|
||||||
|
return unless event && start_time && event.program && event.program.conference && event.program.conference.start_hour
|
||||||
|
errors.add(:start_time, "can't be before the conference start hour (#{event.program.conference.start_hour})") if start_time.hour < event.program.conference.start_hour
|
||||||
|
end
|
||||||
|
|
||||||
def conference_id
|
def conference_id
|
||||||
schedule.program.conference_id
|
schedule.program.conference_id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Validates that the event is scheduled in the same room as its track
|
||||||
|
#
|
||||||
|
def same_room_as_track
|
||||||
|
return unless event.try(:track).try(:room)
|
||||||
|
errors.add(:room, "must be the same as the track's room (#{event.track.room.name})") unless event.track.room == room
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Validates that the event is scheduled within its track's time slot
|
||||||
|
#
|
||||||
|
def during_track
|
||||||
|
return unless event.try(:track) && start_time
|
||||||
|
|
||||||
|
if event.track.try(:start_date) && event.track.start_date > start_time
|
||||||
|
errors.add(:start_time, "can't be before the track's start date (#{event.track.start_date})")
|
||||||
|
end
|
||||||
|
|
||||||
|
if event.track.try(:end_date) && event.track.end_date + 1.day < end_time
|
||||||
|
errors.add(:end_time, "can't be after the track's end date (#{event.track.end_date})")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Validates that the event is scheduled in its self-organized tracks's schedules
|
||||||
|
#
|
||||||
|
def valid_schedule
|
||||||
|
return unless event.try(:track).try(:self_organized?) && schedule
|
||||||
|
errors.add(:schedule, "must be one of #{event.track.name} track's schedules") unless event.track.schedules.include?(schedule)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -15,17 +15,13 @@ class EventType < ActiveRecord::Base
|
||||||
|
|
||||||
alias_attribute :name, :title
|
alias_attribute :name, :title
|
||||||
|
|
||||||
# If LENGTH_STEP must be divisor of 60, otherwise the schedule wont be displayed properly
|
|
||||||
|
|
||||||
LENGTH_STEP = defined?(SCHEDULE_CELL_SIZE) ? SCHEDULE_CELL_SIZE : 15
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
##
|
##
|
||||||
# Check if length is multiple of LENGTH_STEP. Used as validation.
|
# Check if length is a divisor of program schedule cell size. Used as validation.
|
||||||
#
|
#
|
||||||
def length_step
|
def length_step
|
||||||
errors.add(:length, "must be multiple of #{LENGTH_STEP}") if length % LENGTH_STEP != 0
|
errors.add(:length, "must be a divisor of #{program.schedule_interval}") if program && length % program.schedule_interval != 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def capitalize_color
|
def capitalize_color
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
class EventUser < ActiveRecord::Base
|
class EventUser < ActiveRecord::Base
|
||||||
# TODO Do we need these roles?
|
# TODO: Do we need these roles?
|
||||||
ROLES = [['Speaker', 'speaker'], ['Submitter', 'submitter'], ['Moderator', 'moderator']]
|
ROLES = [%w[Speaker speaker], %w[Submitter submitter], %w[Moderator moderator]]
|
||||||
|
|
||||||
belongs_to :event
|
belongs_to :event
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
|
|
|
||||||
19
app/models/organization.rb
Normal file
19
app/models/organization.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
class Organization < ActiveRecord::Base
|
||||||
|
resourcify :roles, dependent: :delete_all
|
||||||
|
|
||||||
|
has_paper_trail
|
||||||
|
|
||||||
|
has_many :conferences, dependent: :destroy
|
||||||
|
|
||||||
|
after_create :create_roles
|
||||||
|
|
||||||
|
validates :name, presence: true
|
||||||
|
|
||||||
|
mount_uploader :picture, PictureUploader, mount_on: :picture
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def create_roles
|
||||||
|
roles.where(name: 'organization_admin').first_or_create(description: 'For the administrators of an organization and its conferences')
|
||||||
|
end
|
||||||
|
end
|
||||||
22
app/models/physical_ticket.rb
Normal file
22
app/models/physical_ticket.rb
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
class PhysicalTicket < ActiveRecord::Base
|
||||||
|
belongs_to :ticket_purchase
|
||||||
|
has_one :ticket, through: :ticket_purchase
|
||||||
|
has_one :conference, through: :ticket_purchase
|
||||||
|
has_one :user, through: :ticket_purchase
|
||||||
|
has_many :ticket_scannings
|
||||||
|
|
||||||
|
before_create :set_token
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_token
|
||||||
|
self.token = generate_token
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate_token
|
||||||
|
loop do
|
||||||
|
token = SecureRandom.hex(10)
|
||||||
|
break token unless PhysicalTicket.exists?(token: token)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -5,11 +5,12 @@ class Program < ActiveRecord::Base
|
||||||
|
|
||||||
belongs_to :conference
|
belongs_to :conference
|
||||||
|
|
||||||
has_one :cfp, dependent: :destroy
|
has_many :cfps, dependent: :destroy
|
||||||
has_many :event_types, dependent: :destroy
|
has_many :event_types, dependent: :destroy
|
||||||
has_many :tracks, dependent: :destroy
|
has_many :tracks, dependent: :destroy
|
||||||
has_many :difficulty_levels, dependent: :destroy
|
has_many :difficulty_levels, dependent: :destroy
|
||||||
has_many :schedules, dependent: :destroy
|
has_many :schedules, dependent: :destroy
|
||||||
|
has_many :event_schedules, through: :schedules
|
||||||
belongs_to :selected_schedule, class_name: 'Schedule'
|
belongs_to :selected_schedule, class_name: 'Schedule'
|
||||||
has_many :events, dependent: :destroy do
|
has_many :events, dependent: :destroy do
|
||||||
def require_registration
|
def require_registration
|
||||||
|
|
@ -38,12 +39,17 @@ class Program < ActiveRecord::Base
|
||||||
where(state: :confirmed, is_highlight: true)
|
where(state: :confirmed, is_highlight: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
has_many :event_schedules, through: :events
|
||||||
|
|
||||||
has_many :event_users, through: :events
|
has_many :event_users, through: :events
|
||||||
has_many :speakers, -> { distinct }, through: :event_users, source: :user do
|
has_many :speakers, -> { distinct }, through: :event_users, source: :user do
|
||||||
def confirmed
|
def confirmed
|
||||||
joins(:events).where(events: { state: :confirmed })
|
joins(:events).where(events: { state: :confirmed })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def registered(conference)
|
||||||
|
joins(:registrations).where('registrations.conference_id = ?', conference.id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
accepts_nested_attributes_for :event_types, allow_destroy: true
|
accepts_nested_attributes_for :event_types, allow_destroy: true
|
||||||
|
|
@ -52,16 +58,24 @@ class Program < ActiveRecord::Base
|
||||||
|
|
||||||
# validates :conference_id, presence: true, uniqueness: true
|
# validates :conference_id, presence: true, uniqueness: true
|
||||||
validates :rating, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 10, only_integer: true }
|
validates :rating, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 10, only_integer: true }
|
||||||
|
validates :schedule_interval, numericality: { greater_than_or_equal_to: 5, less_than_or_equal_to: 60 }, presence: true
|
||||||
|
validate :schedule_interval_divisor_60
|
||||||
validate :voting_start_date_before_end_date
|
validate :voting_start_date_before_end_date
|
||||||
validate :voting_dates_exist
|
validate :voting_dates_exist
|
||||||
|
|
||||||
after_create :create_event_types
|
after_create :create_event_types
|
||||||
after_create :create_difficulty_levels
|
after_create :create_difficulty_levels
|
||||||
|
after_save :unschedule_unfit_events, if: :schedule_interval_changed?
|
||||||
|
after_save :normalize_event_types_length, if: :schedule_interval_changed?
|
||||||
validate :check_languages_format
|
validate :check_languages_format
|
||||||
|
|
||||||
# Returns all event_schedules for the selected schedule ordered by start_time
|
# Returns all event_schedules for the selected schedule ordered by start_time
|
||||||
def selected_event_schedules
|
def selected_event_schedules
|
||||||
selected_schedule.event_schedules.order(start_time: :asc) if selected_schedule
|
event_schedules = selected_schedule.event_schedules.order(start_time: :asc) if selected_schedule
|
||||||
|
tracks.self_organized.confirmed.order(start_date: :asc).each do |track|
|
||||||
|
event_schedules += track.selected_schedule.event_schedules.order(start_time: :asc) if track.selected_schedule
|
||||||
|
end
|
||||||
|
event_schedules.sort_by(&:start_time) if event_schedules
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
@ -115,7 +129,7 @@ class Program < ActiveRecord::Base
|
||||||
# * +false+ -> If rating is not enabled
|
# * +false+ -> If rating is not enabled
|
||||||
# * +true+ -> If rating is enabled
|
# * +true+ -> If rating is enabled
|
||||||
def rating_enabled?
|
def rating_enabled?
|
||||||
self.rating && self.rating > 0
|
rating && rating > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
@ -139,7 +153,7 @@ class Program < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def languages_list
|
def languages_list
|
||||||
self.languages.split(',').map {|l| ISO_639.find(l).english_name} if self.languages.present?
|
languages.split(',').map {|l| ISO_639.find(l).english_name} if languages.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
@ -153,6 +167,23 @@ class Program < ActiveRecord::Base
|
||||||
EventSchedule.where(schedule: selected_schedule).where(start_time: parsed_date..(parsed_date + 1)).any?
|
EventSchedule.where(schedule: selected_schedule).where(start_time: parsed_date..(parsed_date + 1)).any?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Provides backwards compatibility for when the program had one cfp
|
||||||
|
#
|
||||||
|
# ====Returns
|
||||||
|
# * +ActiveRecord+ -> The program's cfp with cfp_type == 'events'
|
||||||
|
def cfp
|
||||||
|
return nil if cfps.for_events.blank?
|
||||||
|
cfps.for_events
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# ====Returns
|
||||||
|
# * +Array+ -> The types of cfps for which a cfp doesn't exist yet
|
||||||
|
def remaining_cfp_types
|
||||||
|
Cfp::TYPES - cfps.pluck(:cfp_type)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
@ -161,10 +192,10 @@ class Program < ActiveRecord::Base
|
||||||
def create_event_types
|
def create_event_types
|
||||||
EventType.create(title: 'Talk', length: 30, color: '#FF0000', description: 'Presentation in lecture format',
|
EventType.create(title: 'Talk', length: 30, color: '#FF0000', description: 'Presentation in lecture format',
|
||||||
minimum_abstract_length: 0,
|
minimum_abstract_length: 0,
|
||||||
maximum_abstract_length: 500, program_id: self.id)
|
maximum_abstract_length: 500, program_id: id)
|
||||||
EventType.create(title: 'Workshop', length: 60, color: '#0000FF', description: 'Interactive hands-on practice',
|
EventType.create(title: 'Workshop', length: 60, color: '#0000FF', description: 'Interactive hands-on practice',
|
||||||
minimum_abstract_length: 0,
|
minimum_abstract_length: 0,
|
||||||
maximum_abstract_length: 500, program_id: self.id)
|
maximum_abstract_length: 500, program_id: id)
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -174,13 +205,13 @@ class Program < ActiveRecord::Base
|
||||||
def create_difficulty_levels
|
def create_difficulty_levels
|
||||||
DifficultyLevel.create(title: 'Easy',
|
DifficultyLevel.create(title: 'Easy',
|
||||||
description: 'Events are understandable for everyone without knowledge of the topic.',
|
description: 'Events are understandable for everyone without knowledge of the topic.',
|
||||||
color: '#70EF69', program_id: self.id)
|
color: '#32CB2A', program_id: id)
|
||||||
DifficultyLevel.create(title: 'Medium',
|
DifficultyLevel.create(title: 'Medium',
|
||||||
description: 'Events require a basic understanding of the topic.',
|
description: 'Events require a basic understanding of the topic.',
|
||||||
color: '#EEEF69', program_id: self.id)
|
color: '#E6B65B', program_id: id)
|
||||||
DifficultyLevel.create(title: 'Hard',
|
DifficultyLevel.create(title: 'Hard',
|
||||||
description: 'Events require expert knowledge of the topic.',
|
description: 'Events require expert knowledge of the topic.',
|
||||||
color: '#EF6E69', program_id: self.id)
|
color: '#EF6E69', program_id: id)
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -188,15 +219,42 @@ class Program < ActiveRecord::Base
|
||||||
# Check if languages string has the right format. Used as validation.
|
# Check if languages string has the right format. Used as validation.
|
||||||
#
|
#
|
||||||
def check_languages_format
|
def check_languages_format
|
||||||
return unless self.languages.present?
|
return unless languages.present?
|
||||||
# All white spaces are removed to allow languages to be separated by ',' and ', '. The languages string without spaces is saved
|
# All white spaces are removed to allow languages to be separated by ',' and ', '. The languages string without spaces is saved
|
||||||
self.languages = self.languages.delete(' ').downcase
|
self.languages = languages.delete(' ').downcase
|
||||||
errors.add(:languages, 'must be two letters separated by commas') && return unless
|
errors.add(:languages, 'must be two letters separated by commas') && return unless
|
||||||
self.languages.match(/^$|(\A[a-z][a-z](,[a-z][a-z])*\z)/).present?
|
languages.match(/^$|(\A[a-z][a-z](,[a-z][a-z])*\z)/).present?
|
||||||
languages_array = self.languages.split(',')
|
languages_array = languages.split(',')
|
||||||
# We check that languages are not repeated
|
# We check that languages are not repeated
|
||||||
errors.add(:languages, "can't be repeated") && return unless languages_array.uniq!.nil?
|
errors.add(:languages, "can't be repeated") && return unless languages_array.uniq!.nil?
|
||||||
# We check if every language is a valid ISO 639-1 language
|
# We check if every language is a valid ISO 639-1 language
|
||||||
errors.add(:languages, 'must be ISO 639-1 valid codes') unless languages_array.select{ |x| ISO_639.find(x).nil? }.empty?
|
errors.add(:languages, 'must be ISO 639-1 valid codes') unless languages_array.select{ |x| ISO_639.find(x).nil? }.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Check if schedule_interval is a divisor of 60 minutes
|
||||||
|
#
|
||||||
|
def schedule_interval_divisor_60
|
||||||
|
errors.add(:schedule_interval, 'must be a divisor of 60') if schedule_interval > 0 && 60 % schedule_interval > 0
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Unschedule all the events which don't fit
|
||||||
|
#
|
||||||
|
def unschedule_unfit_events
|
||||||
|
unfit_schedules = event_schedules.select do |event_schedule|
|
||||||
|
event_schedule.start_time.min % schedule_interval > 0
|
||||||
|
end
|
||||||
|
EventSchedule.where(id: unfit_schedules.map(&:id)).destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Change event type length according schedule interval
|
||||||
|
#
|
||||||
|
def normalize_event_types_length
|
||||||
|
event_types.each do |event_type|
|
||||||
|
new_length = event_type.length > schedule_interval ? event_type.length - (event_type.length % schedule_interval) : schedule_interval
|
||||||
|
event_type.update_attributes length: new_length
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,6 @@ class Question < ActiveRecord::Base
|
||||||
private
|
private
|
||||||
|
|
||||||
def existing_answers
|
def existing_answers
|
||||||
errors.add(:base, 'Must have answers') if self.answers.blank?
|
errors.add(:base, 'Must have answers') if answers.blank?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,13 @@ class Registration < ActiveRecord::Base
|
||||||
belongs_to :user
|
belongs_to :user
|
||||||
belongs_to :conference
|
belongs_to :conference
|
||||||
|
|
||||||
has_and_belongs_to_many :events
|
|
||||||
has_and_belongs_to_many :qanswers
|
has_and_belongs_to_many :qanswers
|
||||||
has_and_belongs_to_many :vchoices
|
has_and_belongs_to_many :vchoices
|
||||||
|
|
||||||
has_many :events_registrations
|
has_many :events_registrations
|
||||||
has_many :events, through: :events_registrations, dependent: :destroy
|
has_many :events, through: :events_registrations, dependent: :destroy
|
||||||
|
|
||||||
has_paper_trail ignore: [:updated_at, :week], meta: { conference_id: :conference_id }
|
has_paper_trail ignore: %i(updated_at week), meta: { conference_id: :conference_id }
|
||||||
|
|
||||||
accepts_nested_attributes_for :user
|
accepts_nested_attributes_for :user
|
||||||
accepts_nested_attributes_for :qanswers
|
accepts_nested_attributes_for :qanswers
|
||||||
|
|
@ -24,7 +23,7 @@ class Registration < ActiveRecord::Base
|
||||||
|
|
||||||
validates :user, presence: true
|
validates :user, presence: true
|
||||||
|
|
||||||
validates_uniqueness_of :user_id, scope: :conference_id, message: 'already Registered!'
|
validates :user_id, uniqueness: { scope: :conference_id, message: 'already Registered!' }
|
||||||
validate :registration_limit_not_exceed, on: :create
|
validate :registration_limit_not_exceed, on: :create
|
||||||
validate :registration_to_events_only_if_present
|
validate :registration_to_events_only_if_present
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,15 @@ class RegistrationPeriod < ActiveRecord::Base
|
||||||
private
|
private
|
||||||
|
|
||||||
def before_end_of_conference
|
def before_end_of_conference
|
||||||
errors.
|
errors
|
||||||
add(:start_date, "can't be after the conference end date (#{conference.end_date})") if conference && conference.end_date && start_date && (start_date > conference.end_date)
|
.add(:start_date, "can't be after the conference end date (#{conference.end_date})") if conference && conference.end_date && start_date && (start_date > conference.end_date)
|
||||||
|
|
||||||
errors.
|
errors
|
||||||
add(:end_date, "can't be after the conference end date (#{conference.end_date})") if conference && conference.end_date && end_date && (end_date > conference.end_date)
|
.add(:end_date, "can't be after the conference end date (#{conference.end_date})") if conference && conference.end_date && end_date && (end_date > conference.end_date)
|
||||||
end
|
end
|
||||||
|
|
||||||
def start_date_before_end_date
|
def start_date_before_end_date
|
||||||
errors.
|
errors
|
||||||
add(:start_date, "can't be after the end date") if start_date && end_date && start_date > end_date
|
.add(:start_date, "can't be after the end date") if start_date && end_date && start_date > end_date
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
class Resource < ActiveRecord::Base
|
class Resource < ActiveRecord::Base
|
||||||
belongs_to :conference
|
belongs_to :conference
|
||||||
validate :used_less_than_quantity
|
validates :name, :used, :quantity, presence: true
|
||||||
|
validates :used, :quantity, numericality: { greater_than_or_equal_to: 0, only_integer: true }
|
||||||
|
validate :used_no_more_than_quantity
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def used_less_than_quantity
|
def used_no_more_than_quantity
|
||||||
errors.add(:used, 'can not be higher than total quantity') unless used <= quantity
|
errors.add(:used, 'cannot be higher than total quantity') if used.present? && quantity.present? && used > quantity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue