Merge branch 'master' into responsive_charts
This commit is contained in:
commit
56c8328b2f
273 changed files with 7772 additions and 3171 deletions
2
.dockerignore
Normal file
2
.dockerignore
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Dockerfile
|
||||
docker-compose.*
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -36,3 +36,5 @@ pickle-email-*.html
|
|||
.env.development
|
||||
.env.test
|
||||
.env.local
|
||||
docker-compose.env
|
||||
docker-compose.yml
|
||||
|
|
|
|||
1
.haml-lint.yml
Normal file
1
.haml-lint.yml
Normal file
|
|
@ -0,0 +1 @@
|
|||
inherits_from: .haml-lint_todo.yml
|
||||
436
.haml-lint_todo.yml
Normal file
436
.haml-lint_todo.yml
Normal file
|
|
@ -0,0 +1,436 @@
|
|||
# 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/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/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/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/_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/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"
|
||||
|
||||
# Offense count: 223
|
||||
InstanceVariables:
|
||||
exclude:
|
||||
- "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"
|
||||
|
||||
# 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"
|
||||
|
||||
# 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/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/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/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/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"
|
||||
147
.rubocop.yml
147
.rubocop.yml
|
|
@ -1,131 +1,7 @@
|
|||
Rails:
|
||||
Enabled: true
|
||||
# Inherit style from another configuration
|
||||
inherit_from: .rubocop_todo.yml
|
||||
|
||||
Style/HashSyntax:
|
||||
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
|
||||
|
||||
# Checks for uses of double negation (!!) to convert something to a boolean value.
|
||||
Style/DoubleNegation:
|
||||
Enabled: true
|
||||
|
||||
# Apply rule to all cops
|
||||
AllCops:
|
||||
Include:
|
||||
- '**/Rakefile'
|
||||
|
|
@ -136,3 +12,22 @@ AllCops:
|
|||
- 'bundle/**/*'
|
||||
- 'config/**/*'
|
||||
- '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'
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -24,5 +24,9 @@ before_script:
|
|||
- mysql -u root -e 'create database osem_test;'
|
||||
- RAILS_ENV=test bundle exec rake db:migrate --trace
|
||||
script:
|
||||
- 'bundle exec rubocop -Dc .rubocop.yml'
|
||||
- 'bundle exec rspec --color --format documentation'
|
||||
- "./travis_script.sh $TEST_SUITE"
|
||||
env:
|
||||
- TEST_SUITE=rspec
|
||||
- TEST_SUITE=linters
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ We are using [rubocop](https://github.com/bbatsov/rubocop) as a style checker. I
|
|||
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.
|
||||
|
||||
### Test Suite
|
||||
|
|
@ -169,6 +169,18 @@ config.ichain_force_test_username = "testuser"
|
|||
# set email of 'testuser'
|
||||
config.ichain_force_test_attributes = {:email => "testuser@example.com"}
|
||||
```
|
||||
|
||||
### Using OpenID in developement
|
||||
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.
|
||||
|
||||
e.g.
|
||||
```
|
||||
OSEM_GITHUB_KEY='sample'
|
||||
OSEM_GITHUB_SECRET='sample'
|
||||
```
|
||||
|
||||
If you don't already have a `.env` file you can use the `dotenv.example` as a template.
|
||||
|
||||
## Labels for issues and PRs
|
||||
...and what they mean!
|
||||
|
||||
|
|
@ -204,6 +216,8 @@ config.ichain_force_test_attributes = {:email => "testuser@example.com"}
|
|||
* 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.
|
||||
15. **GSoC**
|
||||
* To group all the issues and PRs related to Google Summer of Code together.
|
||||
|
||||
## 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
|
||||
|
|
|
|||
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"]
|
||||
14
Gemfile
14
Gemfile
|
|
@ -18,10 +18,9 @@ gem 'rails_12factor', group: :production
|
|||
gem 'responders', '~> 2.0'
|
||||
|
||||
# as the database for Active Record
|
||||
# choose only one
|
||||
gem 'mysql2'
|
||||
|
||||
# for observing records
|
||||
gem 'rails-observers'
|
||||
# gem 'pg'
|
||||
|
||||
# for tracking data changes
|
||||
gem 'paper_trail'
|
||||
|
|
@ -126,8 +125,11 @@ gem 'country_select'
|
|||
|
||||
# as PDF generator
|
||||
gem 'prawn_rails'
|
||||
gem 'rqrcode'
|
||||
gem 'prawn-qrcode', '~> 0.2.2.1'
|
||||
|
||||
# to render XLS spreadsheets
|
||||
gem 'axlsx', git: 'https://github.com/randym/axlsx.git'
|
||||
gem 'axlsx_rails'
|
||||
|
||||
# as error catcher
|
||||
|
|
@ -193,13 +195,17 @@ gem 'stripe'
|
|||
# Provides Sprockets implementation for Rails Asset Pipeline
|
||||
gem 'sprockets-rails'
|
||||
|
||||
# for multiple speakers select on proposal/event forms
|
||||
gem 'selectize-rails'
|
||||
|
||||
# Use guard and spring for testing in development
|
||||
group :development do
|
||||
# to launch specs when files are modified
|
||||
gem 'guard-rspec', '~> 4.2.8'
|
||||
gem 'spring-commands-rspec'
|
||||
gem 'haml_lint', '~> 0.24.0'
|
||||
# for static code analisys
|
||||
gem 'rubocop', require: false
|
||||
gem 'rubocop', '~> 0.49.0', require: false
|
||||
# as database
|
||||
gem 'sqlite3'
|
||||
# to open mails
|
||||
|
|
|
|||
90
Gemfile.lock
90
Gemfile.lock
|
|
@ -1,3 +1,13 @@
|
|||
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
|
||||
remote: https://rubygems.org/
|
||||
remote: https://rails-assets.org/
|
||||
|
|
@ -58,17 +68,13 @@ GEM
|
|||
user_agent_parser
|
||||
uuidtools
|
||||
arel (6.0.3)
|
||||
ast (2.2.0)
|
||||
ast (2.3.0)
|
||||
autoprefixer-rails (5.1.9)
|
||||
execjs
|
||||
json
|
||||
awesome_nested_set (3.0.0.rc.5)
|
||||
activerecord (>= 4.0.0, < 5)
|
||||
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 (>= 2.0.1)
|
||||
rails (>= 3.1)
|
||||
|
|
@ -83,9 +89,7 @@ GEM
|
|||
momentjs-rails (>= 2.8.1)
|
||||
browser (0.6.0)
|
||||
builder (3.2.2)
|
||||
byebug (3.1.2)
|
||||
columnize (~> 0.8)
|
||||
debugger-linecache (~> 1.2)
|
||||
byebug (9.0.6)
|
||||
cancancan (1.13.1)
|
||||
capybara (2.6.2)
|
||||
addressable
|
||||
|
|
@ -111,6 +115,7 @@ GEM
|
|||
chart-js-rails (0.0.6)
|
||||
railties (> 3.1)
|
||||
chronic (0.10.2)
|
||||
chunky_png (1.3.8)
|
||||
cliver (0.3.2)
|
||||
cloudinary (1.1.6)
|
||||
aws_cf_signer
|
||||
|
|
@ -124,7 +129,6 @@ GEM
|
|||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.10.0)
|
||||
columnize (0.8.9)
|
||||
countable-rails (0.0.1)
|
||||
railties (>= 3.1)
|
||||
countries (1.2.5)
|
||||
|
|
@ -146,7 +150,6 @@ GEM
|
|||
dante (0.2.0)
|
||||
database_cleaner (1.3.0)
|
||||
debug_inspector (0.0.2)
|
||||
debugger-linecache (1.2.0)
|
||||
delayed_job (4.1.1)
|
||||
activesupport (>= 3.0, < 5.0)
|
||||
delayed_job_active_record (4.1.0)
|
||||
|
|
@ -209,6 +212,12 @@ GEM
|
|||
activesupport (>= 4.0.1)
|
||||
haml (>= 3.1, < 5.0)
|
||||
railties (>= 4.0.1)
|
||||
haml_lint (0.24.0)
|
||||
haml (>= 4.0, < 5.1)
|
||||
rainbow
|
||||
rake (>= 10, < 13)
|
||||
rubocop (>= 0.47.0)
|
||||
sysexits (~> 1.1)
|
||||
hashie (2.1.1)
|
||||
hike (1.2.3)
|
||||
hoptoad_notifier (2.4.11)
|
||||
|
|
@ -230,7 +239,7 @@ GEM
|
|||
thor (>= 0.14, < 2.0)
|
||||
jquery-ui-rails (4.2.1)
|
||||
railties (>= 3.2.16)
|
||||
json (1.8.3)
|
||||
json (1.8.6)
|
||||
json-schema (2.5.0)
|
||||
addressable (~> 2.3)
|
||||
jwt (1.0.0)
|
||||
|
|
@ -256,12 +265,13 @@ GEM
|
|||
mime-types (>= 1.16, < 3)
|
||||
method_source (0.8.2)
|
||||
mime-types (2.99.1)
|
||||
mimemagic (0.3.2)
|
||||
mina (0.3.8)
|
||||
open4 (~> 1.3.4)
|
||||
rake
|
||||
mini_magick (4.5.1)
|
||||
mini_portile2 (2.1.0)
|
||||
minitest (5.9.0)
|
||||
mini_portile2 (2.2.0)
|
||||
minitest (5.10.1)
|
||||
momentjs-rails (2.8.1)
|
||||
railties (>= 3.1)
|
||||
monetize (1.4.0)
|
||||
|
|
@ -280,9 +290,8 @@ GEM
|
|||
mysql2 (0.4.2)
|
||||
netrc (0.11.0)
|
||||
nio4r (1.2.1)
|
||||
nokogiri (1.6.8)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
pkg-config (~> 1.1.7)
|
||||
nokogiri (1.8.0)
|
||||
mini_portile2 (~> 2.2.0)
|
||||
oauth2 (0.9.4)
|
||||
faraday (>= 0.8, < 0.10)
|
||||
jwt (~> 1.0)
|
||||
|
|
@ -310,11 +319,12 @@ GEM
|
|||
rack-openid (~> 1.3.1)
|
||||
open4 (1.3.4)
|
||||
orm_adapter (0.5.0)
|
||||
paper_trail (5.0.1)
|
||||
paper_trail (5.2.1)
|
||||
activerecord (>= 3.0, < 6.0)
|
||||
activesupport (>= 3.0, < 6.0)
|
||||
request_store (~> 1.1)
|
||||
parser (2.3.0.3)
|
||||
parallel (1.11.2)
|
||||
parser (2.4.0.0)
|
||||
ast (~> 2.2)
|
||||
pdf-core (0.2.5)
|
||||
phantomjs (2.1.1.0)
|
||||
|
|
@ -322,7 +332,6 @@ GEM
|
|||
actionpack
|
||||
activesupport
|
||||
rails (>= 3.0.0)
|
||||
pkg-config (1.1.7)
|
||||
poltergeist (1.9.0)
|
||||
capybara (~> 2.1)
|
||||
cliver (~> 0.3.1)
|
||||
|
|
@ -332,6 +341,9 @@ GEM
|
|||
prawn (1.0.0)
|
||||
pdf-core (~> 0.2.2)
|
||||
ttfunk (~> 1.1.1)
|
||||
prawn-qrcode (0.2.2.1)
|
||||
prawn (>= 0.11.1)
|
||||
rqrcode (>= 0.4.1)
|
||||
prawn_rails (0.0.11)
|
||||
prawn (>= 0.11.1)
|
||||
railties (>= 3.0.0)
|
||||
|
|
@ -375,17 +387,15 @@ GEM
|
|||
rails-assets-waypoints (4.0.0)
|
||||
rails-deprecated_sanitizer (1.0.3)
|
||||
activesupport (>= 4.2.0.alpha)
|
||||
rails-dom-testing (1.0.7)
|
||||
rails-dom-testing (1.0.8)
|
||||
activesupport (>= 4.2.0.beta, < 5.0)
|
||||
nokogiri (~> 1.6.0)
|
||||
nokogiri (~> 1.6)
|
||||
rails-deprecated_sanitizer (>= 1.0.1)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
loofah (~> 2.0)
|
||||
rails-i18n (4.0.8)
|
||||
i18n (~> 0.7)
|
||||
railties (~> 4.0)
|
||||
rails-observers (0.1.2)
|
||||
activemodel (~> 4.0)
|
||||
rails_12factor (0.0.3)
|
||||
rails_serve_static_assets
|
||||
rails_stdout_logging
|
||||
|
|
@ -396,7 +406,8 @@ GEM
|
|||
activesupport (= 4.2.7.1)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rainbow (2.1.0)
|
||||
rainbow (2.2.2)
|
||||
rake
|
||||
rake (10.5.0)
|
||||
rb-fsevent (0.9.4)
|
||||
rb-inotify (0.9.4)
|
||||
|
|
@ -418,6 +429,8 @@ GEM
|
|||
mime-types (>= 1.16, < 3.0)
|
||||
netrc (~> 0.7)
|
||||
rolify (5.1.0)
|
||||
rqrcode (0.10.1)
|
||||
chunky_png (~> 1.0)
|
||||
rspec (3.0.0)
|
||||
rspec-core (~> 3.0.0)
|
||||
rspec-expectations (~> 3.0.0)
|
||||
|
|
@ -442,15 +455,16 @@ GEM
|
|||
rspec-mocks (~> 3.0.0)
|
||||
rspec-support (~> 3.0.0)
|
||||
rspec-support (3.0.2)
|
||||
rubocop (0.37.0)
|
||||
parser (>= 2.3.0.2, < 3.0)
|
||||
rubocop (0.49.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.3.3.1, < 3.0)
|
||||
powerpack (~> 0.1)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (~> 0.3)
|
||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||
ruby-oembed (0.8.14)
|
||||
ruby-openid (2.5.0)
|
||||
ruby-progressbar (1.7.5)
|
||||
ruby-progressbar (1.8.1)
|
||||
rubyzip (1.2.1)
|
||||
safe_yaml (1.0.4)
|
||||
sass (3.2.19)
|
||||
|
|
@ -459,7 +473,8 @@ GEM
|
|||
sass (~> 3.2.2)
|
||||
sprockets (~> 2.8, < 2.12)
|
||||
sprockets-rails (~> 2.0)
|
||||
shoulda-matchers (2.6.1)
|
||||
selectize-rails (0.12.4)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
simplecov (0.11.2)
|
||||
docile (~> 1.1.0)
|
||||
|
|
@ -489,10 +504,11 @@ GEM
|
|||
dante (>= 0.2.0)
|
||||
multi_json (>= 1.0.0)
|
||||
stripe (>= 1.31.0, <= 1.43)
|
||||
sysexits (1.2.0)
|
||||
term-ansicolor (1.3.2)
|
||||
tins (~> 1.0)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.5)
|
||||
thread_safe (0.3.6)
|
||||
tilt (1.4.1)
|
||||
timecop (0.7.1)
|
||||
timers (1.1.0)
|
||||
|
|
@ -501,14 +517,14 @@ GEM
|
|||
ttfunk (1.1.1)
|
||||
turbolinks (2.5.3)
|
||||
coffee-rails
|
||||
tzinfo (1.2.2)
|
||||
tzinfo (1.2.3)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (3.0.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.2)
|
||||
unicode-display_width (0.3.1)
|
||||
unicode-display_width (1.3.0)
|
||||
unicode_utils (1.4.0)
|
||||
unobtrusive_flash (3.1.0)
|
||||
railties
|
||||
|
|
@ -545,6 +561,7 @@ DEPENDENCIES
|
|||
ahoy_matey
|
||||
autoprefixer-rails
|
||||
awesome_nested_set (~> 3.0.0.rc.5)
|
||||
axlsx!
|
||||
axlsx_rails
|
||||
bootstrap-sass (~> 3.3.4.1)
|
||||
bootstrap-switch-rails (~> 3.0.0)
|
||||
|
|
@ -574,6 +591,7 @@ DEPENDENCIES
|
|||
gravtastic
|
||||
guard-rspec (~> 4.2.8)
|
||||
haml-rails
|
||||
haml_lint (~> 0.24.0)
|
||||
hoptoad_notifier (~> 2.3)
|
||||
iso-639
|
||||
jquery-datatables-rails (~> 2.2.1)
|
||||
|
|
@ -596,6 +614,7 @@ DEPENDENCIES
|
|||
phantomjs
|
||||
piwik_analytics (~> 1.0.1)
|
||||
poltergeist
|
||||
prawn-qrcode (~> 0.2.2.1)
|
||||
prawn_rails
|
||||
rails (~> 4.2)
|
||||
rails-assets-bootstrap-markdown!
|
||||
|
|
@ -610,17 +629,18 @@ DEPENDENCIES
|
|||
rails-assets-trianglify!
|
||||
rails-assets-waypoints!
|
||||
rails-i18n (~> 4.0.0)
|
||||
rails-observers
|
||||
rails_12factor
|
||||
rdoc-generator-fivefish
|
||||
redcarpet
|
||||
responders (~> 2.0)
|
||||
rolify
|
||||
rqrcode
|
||||
rspec-activemodel-mocks
|
||||
rspec-rails
|
||||
rubocop
|
||||
rubocop (~> 0.49.0)
|
||||
ruby-oembed
|
||||
sass-rails (>= 4.0.2)
|
||||
selectize-rails
|
||||
shoulda-matchers
|
||||
spring-commands-rspec
|
||||
sprockets-rails
|
||||
|
|
@ -637,4 +657,4 @@ DEPENDENCIES
|
|||
whenever
|
||||
|
||||
BUNDLED WITH
|
||||
1.14.3
|
||||
1.15.1
|
||||
|
|
|
|||
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
|
||||
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
|
||||
|
||||
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
|
||||
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">
|
||||
</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
|
||||
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_GITHUB_KEY | *string* | OMNIAUTH Developer Key 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_PORT | *int* | The port on the smtp server
|
||||
| OSEM_SMTP_USERNAME | *string* | The user for the smtp server
|
||||
|
|
@ -70,7 +122,7 @@ $ bundle exec rake logo:reprocess
|
|||
```
|
||||
|
||||
### 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
|
||||
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
|
||||
# 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
|
||||
# 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",
|
||||
"required": false
|
||||
},
|
||||
"OSEM_SCHEDULE_CELL_SIZE": {
|
||||
"description": "Schedule timeslot size in minutes",
|
||||
"required": false
|
||||
},
|
||||
"RACK_ENV": {
|
||||
"required": false
|
||||
},
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
//= require unobtrusive_flash
|
||||
//= require unobtrusive_flash_bootstrap
|
||||
//= require countable
|
||||
//= require selectize
|
||||
|
||||
$(document).ready(function() {
|
||||
$('a[disabled=disabled]').click(function(event){
|
||||
|
|
|
|||
|
|
@ -16,4 +16,6 @@
|
|||
*= require bootstrap3-switch
|
||||
*= require osem-payments
|
||||
*= require osem-navbar
|
||||
*= require selectize
|
||||
*= require selectize.bootstrap3
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -106,7 +106,11 @@ background-image: -webkit-gradient(
|
|||
}
|
||||
|
||||
.speakerinfo {
|
||||
margin-top: 20px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.speakerbio {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.schedule-title, .schedule-subtitle, .schedule-speaker, .schedule-track {
|
||||
|
|
|
|||
|
|
@ -2,15 +2,22 @@ module Admin
|
|||
class BaseController < ApplicationController
|
||||
before_filter :verify_user_admin
|
||||
|
||||
private
|
||||
|
||||
def current_ability
|
||||
@current_ability ||= AdminAbility.new(current_user)
|
||||
end
|
||||
|
||||
def verify_user_admin
|
||||
if (current_user.nil?)
|
||||
redirect_to sign_in_path
|
||||
return false
|
||||
end
|
||||
unless (current_user.has_role? :organizer, :any) || (current_user.has_role? :cfp, :any) ||
|
||||
(current_user.has_role? :info_desk, :any) ||
|
||||
(current_user.has_role? :volunteers_coordinator, :any) || current_user.is_admin
|
||||
raise CanCan::AccessDenied.new('You are not authorized to access this area!')
|
||||
(current_user.has_role? :info_desk, :any) || (current_user.has_role? :organization_admin, :any) ||
|
||||
(current_user.has_role? :volunteers_coordinator, :any) ||
|
||||
(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
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ module Admin
|
|||
redirect_to admin_conference_campaigns_path(conference_id: @conference.short_title),
|
||||
notice: 'Campaign successfully created.'
|
||||
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'
|
||||
end
|
||||
end
|
||||
|
|
@ -29,7 +29,7 @@ module Admin
|
|||
redirect_to admin_conference_campaigns_path(conference_id: @conference.short_title),
|
||||
notice: "Campaign '#{@campaign.name}' successfully updated."
|
||||
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'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,51 +2,52 @@ module Admin
|
|||
class CfpsController < Admin::BaseController
|
||||
load_and_authorize_resource :conference, find_by: :short_title
|
||||
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 new
|
||||
@cfp = @program.build_cfp
|
||||
@cfp = @program.cfps.new
|
||||
end
|
||||
|
||||
def edit; end
|
||||
|
||||
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?
|
||||
|
||||
if @cfp.save
|
||||
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.'
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@cfp = @program.cfp
|
||||
@cfp.assign_attributes(cfp_params)
|
||||
|
||||
send_mail_on_cfp_dates_updates = @cfp.notify_on_cfp_date_update?
|
||||
|
||||
if @cfp.update_attributes(cfp_params)
|
||||
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.'
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
def 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
|
||||
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('. ')}."
|
||||
end
|
||||
end
|
||||
|
|
@ -54,7 +55,7 @@ module Admin
|
|||
private
|
||||
|
||||
def cfp_params
|
||||
params.require(:cfp).permit(:start_date, :end_date)
|
||||
params.require(:cfp).permit(:start_date, :end_date, :cfp_type)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ module Admin
|
|||
@commercials = @conference.commercials
|
||||
|
||||
@commercial = @conference.commercials.build
|
||||
authorize! :create, @conference.commercials.new
|
||||
end
|
||||
|
||||
def create
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ module Admin
|
|||
@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
|
||||
@deactive_conferences = Conference.
|
||||
get_conferences_without_active_for_dashboard(@active_conferences) # conferences without active
|
||||
@deactive_conferences = Conference
|
||||
.get_conferences_without_active_for_dashboard(@active_conferences) # conferences without active
|
||||
@conferences = @active_conferences + @deactive_conferences
|
||||
|
||||
@recent_users = User.limit(5).order(created_at: :desc)
|
||||
|
|
@ -37,6 +37,9 @@ module Admin
|
|||
@registrations = {}
|
||||
@registration_weeks = [0]
|
||||
|
||||
@tickets = {}
|
||||
@ticket_weeks = [0]
|
||||
|
||||
@conferences.each do |c|
|
||||
# Event submissions over time chart
|
||||
@submissions[c.short_title] = c.get_submissions_per_week
|
||||
|
|
@ -45,6 +48,10 @@ module Admin
|
|||
# Conference registrations over time chart
|
||||
@registrations[c.short_title] = c.get_registrations_per_week
|
||||
@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
|
||||
|
||||
@cfp_weeks = @cfp_weeks.max
|
||||
|
|
@ -55,6 +62,10 @@ module Admin
|
|||
@registrations = normalize_array_length(@registrations, @registration_weeks)
|
||||
@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
|
||||
@user_distribution = Conference.user_distribution
|
||||
end
|
||||
|
|
@ -65,7 +76,7 @@ module Admin
|
|||
|
||||
def create
|
||||
@conference = Conference.new(conference_params)
|
||||
|
||||
@conference.organization = Organization.find_or_create_by(name: 'organization')
|
||||
if @conference.save
|
||||
# user that creates the conference becomes organizer of that conference
|
||||
current_user.add_role :organizer, @conference
|
||||
|
|
@ -73,7 +84,7 @@ module Admin
|
|||
redirect_to admin_conference_path(id: @conference.short_title),
|
||||
notice: 'Conference was successfully created.'
|
||||
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'
|
||||
end
|
||||
end
|
||||
|
|
@ -82,7 +93,6 @@ module Admin
|
|||
short_title = @conference.short_title
|
||||
@conference.assign_attributes(conference_params)
|
||||
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)
|
||||
ConferenceDateUpdateMailJob.perform_later(@conference) if send_mail_on_conf_update
|
||||
|
|
@ -106,8 +116,8 @@ module Admin
|
|||
@new_reg = @conference.registrations.where('created_at > ?', current_user.last_sign_in_at).count
|
||||
|
||||
@total_submissions = @program.events.count
|
||||
@new_submissions = @program.events.
|
||||
where('created_at > ?', current_user.last_sign_in_at).count
|
||||
@new_submissions = @program.events
|
||||
.where('created_at > ?', current_user.last_sign_in_at).count
|
||||
|
||||
@program_length = @conference.current_program_hours
|
||||
@new_program_length = @conference.new_program_hours(current_user.last_sign_in_at)
|
||||
|
|
@ -134,13 +144,27 @@ module Admin
|
|||
@submissions_data = @submissions_data.except('Weeks')
|
||||
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
|
||||
@event_type_distribution = @conference.event_type_distribution
|
||||
@event_type_distribution_confirmed = @conference.event_type_distribution(:confirmed)
|
||||
|
||||
@difficulty_levels_distribution = @conference.difficulty_levels_distribution
|
||||
@difficulty_levels_distribution_confirmed = @conference.
|
||||
difficulty_levels_distribution(:confirmed)
|
||||
@difficulty_levels_distribution_confirmed = @conference
|
||||
.difficulty_levels_distribution(:confirmed)
|
||||
|
||||
@tracks_distribution = @conference.tracks_distribution
|
||||
@tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed)
|
||||
|
|
@ -187,16 +211,7 @@ module Admin
|
|||
:vpositions_attributes, :use_volunteers, :color,
|
||||
:sponsorship_levels_attributes, :sponsors_attributes,
|
||||
:targets, :targets_attributes,
|
||||
:campaigns, :campaigns_attributes, :registration_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)
|
||||
:campaigns, :campaigns_attributes, :registration_limit, :organization_id, :ticket_layout)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ module Admin
|
|||
redirect_to admin_conference_program_difficulty_levels_path(conference_id: @conference.short_title),
|
||||
notice: 'Difficulty level successfully created.'
|
||||
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
|
||||
end
|
||||
end
|
||||
|
|
@ -30,7 +30,7 @@ module Admin
|
|||
redirect_to admin_conference_program_difficulty_levels_path(conference_id: @conference.short_title),
|
||||
notice: 'Difficulty level successfully updated.'
|
||||
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
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ module Admin
|
|||
redirect_to admin_conference_program_event_types_path(conference_id: @conference.short_title),
|
||||
notice: 'Event type successfully created.'
|
||||
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
|
||||
end
|
||||
end
|
||||
|
|
@ -28,7 +28,7 @@ module Admin
|
|||
redirect_to admin_conference_program_event_types_path(conference_id: @conference.short_title),
|
||||
notice: 'Event type successfully updated.'
|
||||
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
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module Admin
|
|||
load_and_authorize_resource :event, through: :program
|
||||
load_and_authorize_resource :events_registration, only: :toggle_attendance
|
||||
|
||||
before_action :get_event, except: [:index, :create]
|
||||
before_action :get_event, except: [:index, :create, :new]
|
||||
|
||||
# FIXME: The timezome should only be applied on output, otherwise
|
||||
# you get lost in timezone conversions...
|
||||
|
|
@ -50,8 +50,8 @@ module Admin
|
|||
@ratings = @event.votes.includes(:user)
|
||||
@difficulty_levels = @program.difficulty_levels
|
||||
@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_changes(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 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 LIKE ?', "%\nevent_id: #{@event.id}\n%")
|
||||
end
|
||||
|
|
@ -79,6 +79,7 @@ module Admin
|
|||
end
|
||||
|
||||
def update
|
||||
@languages = @program.languages_list
|
||||
if @event.update_attributes(event_params)
|
||||
|
||||
if request.xhr?
|
||||
|
|
@ -89,12 +90,29 @@ module Admin
|
|||
end
|
||||
else
|
||||
@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
|
||||
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[: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
|
||||
send_mail = @event.program.conference.email_settings.send_on_accepted
|
||||
|
|
@ -161,7 +179,8 @@ module Admin
|
|||
# Set only in admin/events controller
|
||||
:track_id, :state, :language, :is_highlight, :max_attendees,
|
||||
# Not used anymore?
|
||||
:proposal_additional_speakers, :user, :users_attributes)
|
||||
:proposal_additional_speakers, :user, :users_attributes,
|
||||
speaker_ids: [])
|
||||
end
|
||||
|
||||
def comment_params
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ module Admin
|
|||
redirect_to admin_conference_lodgings_path(conference_id: @conference.short_title),
|
||||
notice: 'Lodging successfully created.'
|
||||
else
|
||||
flash[:error] = "Creating Lodging failed: #{@lodging.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Creating Lodging failed: #{@lodging.errors.full_messages.join('. ')}."
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
|
@ -28,7 +28,7 @@ module Admin
|
|||
redirect_to admin_conference_lodgings_path(conference_id: @conference.short_title),
|
||||
notice: 'Lodging successfully updated.'
|
||||
else
|
||||
flash[:error] = "Update Lodging failed: #{@lodging.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Update Lodging failed: #{@lodging.errors.full_messages.join('. ')}."
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
|
|
|||
52
app/controllers/admin/organizations_controller.rb
Normal file
52
app/controllers/admin/organizations_controller.rb
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
module Admin
|
||||
class OrganizationsController < Admin::BaseController
|
||||
load_and_authorize_resource :organization
|
||||
|
||||
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
|
||||
|
||||
private
|
||||
|
||||
def organization_params
|
||||
params.require(:organization).permit(:name, :description, :picture)
|
||||
end
|
||||
end
|
||||
end
|
||||
14
app/controllers/admin/physical_ticket_controller.rb
Normal file
14
app/controllers/admin/physical_ticket_controller.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
module Admin
|
||||
class PhysicalTicketController < 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,20 +12,22 @@ module Admin
|
|||
@program = @conference.program
|
||||
@program.assign_attributes(program_params)
|
||||
send_mail_on_schedule_public = @program.notify_on_schedule_public?
|
||||
event_schedules_count_was = @program.event_schedules.count
|
||||
|
||||
if @program.update_attributes(program_params)
|
||||
ConferenceScheduleUpdateMailJob.perform_later(@conference) if send_mail_on_schedule_public
|
||||
respond_to do |format|
|
||||
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
|
||||
format.js { render json: {} }
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
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
|
||||
end
|
||||
format.js { render json: { errors: "The selected schedule couldn't been updated #{@program.errors.to_a.join('. ')}" }, status: 422 }
|
||||
|
|
@ -36,7 +38,7 @@ module Admin
|
|||
private
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
module Admin
|
||||
class RegistrationPeriodsController < ApplicationController
|
||||
class RegistrationPeriodsController < Admin::BaseController
|
||||
load_and_authorize_resource :conference, find_by: :short_title
|
||||
load_and_authorize_resource through: :conference, singleton: true
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ module Admin
|
|||
redirect_to admin_conference_registration_period_path(@conference.short_title),
|
||||
notice: 'Registration Period successfully updated.'
|
||||
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
|
||||
end
|
||||
end
|
||||
|
|
@ -36,7 +36,7 @@ module Admin
|
|||
redirect_to admin_conference_registration_period_path(@conference.short_title),
|
||||
notice: 'Registration Period successfully updated.'
|
||||
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('. ')}."
|
||||
render :edit
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ module Admin
|
|||
redirect_to admin_conference_registrations_path(@conference.short_title),
|
||||
notice: "Successfully updated registration for #{@registration.user.email}!"
|
||||
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('. ')}."
|
||||
render :edit
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ module Admin
|
|||
@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)
|
||||
@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
|
||||
class ResourcesController < ApplicationController
|
||||
class ResourcesController < Admin::BaseController
|
||||
load_and_authorize_resource :conference, find_by: :short_title
|
||||
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),
|
||||
notice: 'Resource successfully created.'
|
||||
else
|
||||
flash[:error] = "Creating resource failed: #{@resource.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Creating resource failed: #{@resource.errors.full_messages.join('. ')}."
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
|
@ -27,7 +27,7 @@ module Admin
|
|||
redirect_to admin_conference_resources_path(conference_id: @conference.short_title),
|
||||
notice: 'Resource successfully updated.'
|
||||
else
|
||||
flash[:error] = "Resource update failed: #{@resource.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Resource update failed: #{@resource.errors.full_messages.join('. ')}."
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,14 +8,26 @@ module Admin
|
|||
|
||||
def index
|
||||
@roles = Role.where(resource: @conference)
|
||||
tracks = @conference.program.tracks.where.not(submitter: nil)
|
||||
@roles += Role.where(resource: tracks)
|
||||
authorize! :index, @role
|
||||
end
|
||||
|
||||
def show
|
||||
@url = if @track
|
||||
toggle_user_track_admin_conference_role_path(@conference.short_title, @role.name, @track)
|
||||
else
|
||||
toggle_user_admin_conference_role_path(@conference.short_title, @role.name)
|
||||
end
|
||||
@users = @role.users
|
||||
end
|
||||
|
||||
def edit
|
||||
@url = if @track
|
||||
track_admin_conference_role_path(@conference.short_title, @role.name, @track)
|
||||
else
|
||||
admin_conference_role_path(@conference.short_title, @role.name)
|
||||
end
|
||||
@users = @role.users
|
||||
end
|
||||
|
||||
|
|
@ -23,11 +35,17 @@ module Admin
|
|||
role_name = @role.name
|
||||
|
||||
if @role.update_attributes(role_params)
|
||||
redirect_to admin_conference_role_path(@conference.short_title, @role.name),
|
||||
url = if @track
|
||||
track_admin_conference_role_path(@conference.short_title, @role.name, @track)
|
||||
else
|
||||
admin_conference_role_path(@conference.short_title, @role.name)
|
||||
end
|
||||
|
||||
redirect_to url,
|
||||
notice: 'Successfully updated role ' + @role.name
|
||||
else
|
||||
@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
|
||||
end
|
||||
end
|
||||
|
|
@ -36,8 +54,14 @@ module Admin
|
|||
user = User.find_by(email: user_params[:email])
|
||||
state = user_params[:state]
|
||||
|
||||
url = if @track
|
||||
track_admin_conference_role_path(@conference.short_title, @role.name, @track)
|
||||
else
|
||||
admin_conference_role_path(@conference.short_title, @role.name)
|
||||
end
|
||||
|
||||
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!'
|
||||
return
|
||||
end
|
||||
|
|
@ -49,17 +73,23 @@ module Admin
|
|||
return
|
||||
end
|
||||
|
||||
if @role.resource_type == 'Conference'
|
||||
role_resource = @conference
|
||||
elsif @role.resource_type == 'Track'
|
||||
role_resource = @track
|
||||
end
|
||||
|
||||
# Remove user
|
||||
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}"
|
||||
else
|
||||
flash[:error] = "Could not remove role #{@role.name} from user #{user.email}"
|
||||
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}"
|
||||
# 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}"
|
||||
else
|
||||
flash[:error] = "Coud not add role #{@role.name} to #{user.email}"
|
||||
|
|
@ -67,7 +97,7 @@ module Admin
|
|||
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.html { redirect_to admin_conference_role_path(@conference.short_title, @role.name) }
|
||||
format.html { redirect_to url }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -77,8 +107,13 @@ module Admin
|
|||
# Set 'organizer' as default role, when there is no other selection
|
||||
@selection = params[:id] ? params[:id].parameterize.underscore : 'organizer'
|
||||
|
||||
if @selection == 'track_organizer'
|
||||
@track = @conference.program.tracks.find_by(short_name: params[:track_name])
|
||||
@role = Role.find_by(name: @selection, resource: @track)
|
||||
else
|
||||
@role = Role.find_by(name: @selection, resource: @conference)
|
||||
end
|
||||
end
|
||||
|
||||
def role_params
|
||||
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),
|
||||
notice: 'Room successfully created.'
|
||||
else
|
||||
flash[:error] = "Creating Room failed: #{@room.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Creating Room failed: #{@room.errors.full_messages.join('. ')}."
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
|
@ -28,7 +28,7 @@ module Admin
|
|||
redirect_to admin_conference_venue_rooms_path(conference_id: @conference.short_title),
|
||||
notice: 'Room successfully updated.'
|
||||
else
|
||||
flash[:error] = "Update Room failed: #{@room.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Update Room failed: #{@room.errors.full_messages.join('. ')}."
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ module Admin
|
|||
redirect_to admin_conference_sponsors_path(conference_id: @conference.short_title),
|
||||
notice: 'Sponsor successfully created.'
|
||||
else
|
||||
flash[:error] = "Creating sponsor failed: #{@sponsor.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Creating sponsor failed: #{@sponsor.errors.full_messages.join('. ')}."
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
|
@ -31,7 +31,7 @@ module Admin
|
|||
conference_id: @conference.short_title),
|
||||
notice: 'Sponsor successfully updated.'
|
||||
else
|
||||
flash[:error] = "Update sponsor failed: #{@sponsor.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Update sponsor failed: #{@sponsor.errors.full_messages.join('. ')}."
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ module Admin
|
|||
redirect_to admin_conference_sponsorship_levels_path(conference_id: @conference.short_title),
|
||||
notice: 'Sponsorship level successfully created.'
|
||||
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
|
||||
end
|
||||
end
|
||||
|
|
@ -30,7 +30,7 @@ module Admin
|
|||
conference_id: @conference.short_title),
|
||||
notice: 'Sponsorship level successfully updated.'
|
||||
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
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ module Admin
|
|||
redirect_to admin_conference_targets_path(conference_id: @conference.short_title),
|
||||
notice: 'Target successfully created.'
|
||||
else
|
||||
flash[:error] = "Creating target failed: #{@target.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Creating target failed: #{@target.errors.full_messages.join('. ')}."
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
|
@ -27,7 +27,7 @@ module Admin
|
|||
redirect_to admin_conference_targets_path(conference_id: @conference.short_title),
|
||||
notice: 'Target successfully updated.'
|
||||
else
|
||||
flash[:error] = "Target update failed: #{@target.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Target update failed: #{@target.errors.full_messages.join('. ')}."
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ module Admin
|
|||
|
||||
def index
|
||||
authorize! :update, Ticket.new(conference_id: @conference.id)
|
||||
@tickets_sold_distribution = @conference.tickets_sold_distribution
|
||||
@tickets_turnover_distribution = @conference.tickets_turnover_distribution
|
||||
end
|
||||
|
||||
def new
|
||||
|
|
@ -17,7 +19,7 @@ module Admin
|
|||
redirect_to admin_conference_tickets_path(conference_id: @conference.short_title),
|
||||
notice: 'Ticket successfully created.'
|
||||
else
|
||||
flash[:error] = "Creating Ticket failed: #{@ticket.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Creating Ticket failed: #{@ticket.errors.full_messages.join('. ')}."
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
|
@ -29,7 +31,7 @@ module Admin
|
|||
redirect_to admin_conference_tickets_path(conference_id: @conference.short_title),
|
||||
notice: 'Ticket successfully updated.'
|
||||
else
|
||||
flash[:error] = "Ticket update failed: #{@ticket.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Ticket update failed: #{@ticket.errors.full_messages.join('. ')}."
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ module Admin
|
|||
class TracksController < Admin::BaseController
|
||||
load_and_authorize_resource :conference, find_by: :short_title
|
||||
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
|
||||
|
||||
def index; end
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ module Admin
|
|||
redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title),
|
||||
notice: 'Track successfully created.'
|
||||
else
|
||||
flash[:error] = "Creating Track failed: #{@track.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Creating Track failed: #{@track.errors.full_messages.join('. ')}."
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
|
@ -35,7 +35,7 @@ module Admin
|
|||
redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title),
|
||||
notice: 'Track successfully updated.'
|
||||
else
|
||||
flash[:error] = "Track update failed: #{@track.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Track update failed: #{@track.errors.full_messages.join('. ')}."
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
|
@ -50,10 +50,19 @@ module Admin
|
|||
end
|
||||
end
|
||||
|
||||
def toggle_cfp_inclusion
|
||||
@track.cfp_active = !@track.cfp_active
|
||||
if @track.save
|
||||
head :ok
|
||||
else
|
||||
head :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def track_params
|
||||
params.require(:track).permit(:name, :description, :color)
|
||||
params.require(:track).permit(:name, :description, :color, :short_name, :cfp_active)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,6 +6,17 @@ module Admin
|
|||
@user = User.new
|
||||
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
|
||||
@users = User.all
|
||||
end
|
||||
|
|
@ -50,8 +61,9 @@ module Admin
|
|||
private
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:email, :name, :email_public, :biography, :nickname, :affiliation, :is_admin, :username, :login, :is_disabled,
|
||||
:tshirt, :mobile, :volunteer_experience, :languages, :to_confirm, role_ids: [])
|
||||
params.require(:user).permit(:email, :name, :email_public, :biography, :nickname, :affiliation, :is_admin,
|
||||
:username, :login, :is_disabled, :tshirt, :mobile, :volunteer_experience,
|
||||
:languages, :to_confirm, :password, role_ids: [])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ module Admin
|
|||
redirect_to admin_conference_venue_path(conference_id: @conference.short_title),
|
||||
notice: 'Venue was successfully updated.'
|
||||
else
|
||||
flash[:error] = "Update venue failed: #{@venue.errors.full_messages.join('. ')}."
|
||||
flash.now[:error] = "Update venue failed: #{@venue.errors.full_messages.join('. ')}."
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
module Admin
|
||||
class VolunteersController < Admin::BaseController
|
||||
include VolunteersHelper
|
||||
load_and_authorize_resource :conference, find_by: :short_title
|
||||
|
||||
def index
|
||||
if can_manage_volunteers(@conference)
|
||||
if can_manage_volunteers?(@conference)
|
||||
render :index
|
||||
else
|
||||
authorize! :index, :volunteer
|
||||
|
|
@ -11,11 +12,11 @@ module Admin
|
|||
end
|
||||
|
||||
def show
|
||||
if can_manage_volunteers(@conference)
|
||||
if @conference.use_vpositions
|
||||
@volunteers = @conference.registrations.joins(:vchoices).uniq
|
||||
if can_manage_volunteers?(@conference)
|
||||
@volunteers = if @conference.use_vpositions
|
||||
@conference.registrations.joins(:vchoices).uniq
|
||||
else
|
||||
@volunteers = @conference.registrations.where(volunteer: true)
|
||||
@conference.registrations.where(volunteer: true)
|
||||
end
|
||||
else
|
||||
authorize! :index, :volunteer
|
||||
|
|
|
|||
|
|
@ -38,11 +38,11 @@ class ConferenceRegistrationsController < ApplicationController
|
|||
def create
|
||||
@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 = @registration.build_user(user_params)
|
||||
@registration.build_user(user_params)
|
||||
else
|
||||
@user = current_user
|
||||
current_user
|
||||
end
|
||||
|
||||
@registration.user = @user
|
||||
|
|
@ -65,7 +65,7 @@ class ConferenceRegistrationsController < ApplicationController
|
|||
notice: 'You are now registered and will be receiving E-Mail notifications.'
|
||||
end
|
||||
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('. ')}."
|
||||
render :new
|
||||
end
|
||||
|
|
@ -76,7 +76,7 @@ class ConferenceRegistrationsController < ApplicationController
|
|||
redirect_to conference_conference_registration_path(@conference.short_title),
|
||||
notice: 'Registration was successfully updated.'
|
||||
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('. ')}."
|
||||
render :edit
|
||||
end
|
||||
|
|
@ -108,8 +108,8 @@ class ConferenceRegistrationsController < ApplicationController
|
|||
end
|
||||
|
||||
def registration_params
|
||||
params.require(:registration).
|
||||
permit(
|
||||
params.require(:registration)
|
||||
.permit(
|
||||
:conference_id, :arrival, :departure,
|
||||
:volunteer,
|
||||
vchoice_ids: [], qanswer_ids: [],
|
||||
|
|
|
|||
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
|
||||
|
|
@ -18,12 +18,12 @@ class PaymentsController < ApplicationController
|
|||
|
||||
if @payment.purchase && @payment.save
|
||||
update_purchased_ticket_purchases
|
||||
redirect_to conference_conference_registration_path(@conference.short_title),
|
||||
redirect_to conference_physical_ticket_index_path,
|
||||
notice: 'Thanks! Your ticket is booked successfully.'
|
||||
else
|
||||
@total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false)
|
||||
@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
|
||||
end
|
||||
end
|
||||
|
|
@ -38,6 +38,8 @@ class PaymentsController < ApplicationController
|
|||
end
|
||||
|
||||
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
|
||||
|
|
|
|||
17
app/controllers/physical_ticket_controller.rb
Normal file
17
app/controllers/physical_ticket_controller.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
class PhysicalTicketController < ApplicationController
|
||||
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 = 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
|
||||
end
|
||||
end
|
||||
|
|
@ -13,9 +13,8 @@ class ProposalsController < ApplicationController
|
|||
end
|
||||
|
||||
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)
|
||||
@speakers_ordered = @event.speakers_ordered
|
||||
end
|
||||
|
||||
def new
|
||||
|
|
@ -40,7 +39,7 @@ class ProposalsController < ApplicationController
|
|||
if @user.save
|
||||
sign_in(@user)
|
||||
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'
|
||||
return
|
||||
end
|
||||
|
|
@ -48,16 +47,13 @@ class ProposalsController < ApplicationController
|
|||
|
||||
# User which creates the proposal is both `submitter` and `speaker` of proposal
|
||||
# by default.
|
||||
# TODO: Allow submitter to add speakers to proposals
|
||||
@event.event_users.new(user: current_user,
|
||||
event_role: 'submitter')
|
||||
@event.event_users.new(user: current_user,
|
||||
event_role: 'speaker')
|
||||
@event.speakers = [current_user]
|
||||
@event.submitter = current_user
|
||||
if @event.save
|
||||
ahoy.track 'Event submission', title: 'New submission'
|
||||
redirect_to conference_program_proposals_path(@conference.short_title), notice: 'Proposal was successfully submitted.'
|
||||
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'
|
||||
end
|
||||
end
|
||||
|
|
@ -69,7 +65,7 @@ class ProposalsController < ApplicationController
|
|||
redirect_to conference_program_proposals_path(conference_id: @conference.short_title),
|
||||
notice: 'Proposal was successfully updated.'
|
||||
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'
|
||||
end
|
||||
end
|
||||
|
|
@ -147,7 +143,9 @@ class ProposalsController < ApplicationController
|
|||
def event_params
|
||||
params.require(:event).permit(:event_type_id, :track_id, :difficulty_level_id,
|
||||
:title, :subtitle, :abstract, :description,
|
||||
:require_registration, :max_attendees, :language)
|
||||
:require_registration, :max_attendees, :language,
|
||||
speaker_ids: []
|
||||
)
|
||||
end
|
||||
|
||||
def user_params
|
||||
|
|
|
|||
|
|
@ -23,12 +23,12 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
|
||||
def configure_permitted_parameters
|
||||
devise_parameter_sanitizer.permit(:account_update) do |u|
|
||||
u.
|
||||
permit(:email, :password, :password_confirmation, :current_password, :username, :email_public)
|
||||
u
|
||||
.permit(:email, :password, :password_confirmation, :current_password, :username, :email_public)
|
||||
end
|
||||
devise_parameter_sanitizer.permit(:sign_up) do |u|
|
||||
u.
|
||||
permit(:email, :password, :password_confirmation, :name, :username)
|
||||
u
|
||||
.permit(:email, :password, :password_confirmation, :name, :username)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
class SchedulesController < ApplicationController
|
||||
load_and_authorize_resource
|
||||
protect_from_forgery with: :null_session
|
||||
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
|
||||
|
||||
def show
|
||||
|
|
@ -13,7 +14,7 @@ class SchedulesController < ApplicationController
|
|||
|
||||
@events_xml = schedules.map(&:event).group_by{ |event| event.time.to_date } if schedules
|
||||
@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_period = @conference.end_hour - @conf_start
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class TicketPurchasesController < ApplicationController
|
|||
redirect_to new_conference_payment_path,
|
||||
notice: 'Please pay here to get tickets.'
|
||||
elsif current_user.ticket_purchases.by_conference(@conference).paid.any?
|
||||
redirect_to conference_conference_registration_path(@conference.short_title),
|
||||
redirect_to conference_physical_ticket_index_path,
|
||||
notice: 'You have free tickets for the conference.'
|
||||
else
|
||||
redirect_to conference_tickets_path(@conference.short_title),
|
||||
|
|
@ -23,6 +23,10 @@ class TicketPurchasesController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def index
|
||||
@unpaid_ticket_purchases = current_user.ticket_purchases.by_conference(@conference).unpaid
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_purchase_params
|
||||
|
|
|
|||
47
app/controllers/tracks_controller.rb
Normal file
47
app/controllers/tracks_controller.rb
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
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 = current_user.tracks.where(program: @program)
|
||||
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.state = 'new'
|
||||
@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
|
||||
|
||||
private
|
||||
|
||||
def track_params
|
||||
params.require(:track).permit(:name, :description, :color, :short_name)
|
||||
end
|
||||
end
|
||||
|
|
@ -15,7 +15,7 @@ class UsersController < ApplicationController
|
|||
if @user.update(user_params)
|
||||
redirect_to @user, notice: 'User was successfully updated.'
|
||||
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
|
||||
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
|
||||
##
|
||||
# Returns a string build from the start and end date of the given conference.
|
||||
#
|
||||
# If the conference is only one day long
|
||||
|
|
@ -34,43 +33,9 @@ module ApplicationHelper
|
|||
result
|
||||
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
|
||||
|
||||
##
|
||||
# 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}"
|
||||
# Returns time with conference timezone
|
||||
def time_with_timezone(time)
|
||||
time.strftime('%F %R') + ' ' + @conference.timezone.to_s
|
||||
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)
|
||||
|
|
@ -78,141 +43,6 @@ module ApplicationHelper
|
|||
:user
|
||||
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 = {})
|
||||
link_to_add_association 'Add ' + association_name.to_s.singularize, form_builder, div_class, html_options.merge(class: 'assoc btn btn-success')
|
||||
end
|
||||
|
|
@ -225,29 +55,6 @@ module ApplicationHelper
|
|||
render 'shared/dynamic_association', association_name: association_name, title: title, f: form_builder, hint: options[:hint]
|
||||
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)
|
||||
all = conference.program.tracks.map {|t| t.name}
|
||||
first = all[0...-1]
|
||||
|
|
@ -276,155 +83,19 @@ module ApplicationHelper
|
|||
return ts
|
||||
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)
|
||||
Comment.accessible_by(current_ability).find_since_last_login(user)
|
||||
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
|
||||
# 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]}'
|
||||
# Output will be 'title, description and conference'
|
||||
def updated_attributes(version)
|
||||
version.changeset.
|
||||
reject{ |_, values| values[0].blank? && values[1].blank? }.
|
||||
keys.map{ |key| key.gsub('_id', '').tr('_', ' ')}.join(', ').
|
||||
reverse.sub(',', ' dna ').reverse
|
||||
end
|
||||
|
||||
def link_to_user(user_id)
|
||||
user = User.find_by(id: user_id)
|
||||
if user
|
||||
link_to user.name, admin_user_path(id: user_id)
|
||||
else
|
||||
'Someone (probably via the console)'
|
||||
end
|
||||
version.changeset
|
||||
.reject{ |_, values| values[0].blank? && values[1].blank? }
|
||||
.keys.map{ |key| key.gsub('_id', '').tr('_', ' ')}.join(', ')
|
||||
.reverse.sub(',', ' dna ').reverse
|
||||
end
|
||||
|
||||
# Recieves a model_name and id
|
||||
|
|
@ -446,136 +117,23 @@ module ApplicationHelper
|
|||
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'
|
||||
def normalize_array_length(hashmap, length)
|
||||
hashmap.each do |_, value|
|
||||
if value.length < length
|
||||
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
|
||||
"updated #{updated_attributes(version)} of"
|
||||
redirect_to options, response_status
|
||||
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)
|
||||
return nil unless event.scheduled? && event.program.selected_event_schedules
|
||||
event_schedule = event.program.selected_event_schedules.find_by(event: event)
|
||||
|
|
@ -592,4 +150,36 @@ module ApplicationHelper
|
|||
end
|
||||
concurrent_events
|
||||
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 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
|
||||
|
|
|
|||
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
|
||||
42
app/helpers/events_helper.rb
Normal file
42
app/helpers/events_helper.rb
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
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
|
||||
end
|
||||
198
app/helpers/format_helper.rb
Normal file
198
app/helpers/format_helper.rb
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
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 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
|
||||
21
app/helpers/paths_helper.rb
Normal file
21
app/helpers/paths_helper.rb
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
module PathsHelper
|
||||
##
|
||||
# Includes functions related to links or redirects
|
||||
##
|
||||
def link_to_user(user_id)
|
||||
user = User.find_by(id: user_id)
|
||||
if user
|
||||
link_to user.name, admin_user_path(id: user_id)
|
||||
else
|
||||
'Someone (probably via the console)'
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
112
app/helpers/versions_helper.rb
Normal file
112
app/helpers/versions_helper.rb
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
module VersionsHelper
|
||||
##
|
||||
# Groups functions related to change description
|
||||
##
|
||||
def link_if_alive(version, link_text, link_url)
|
||||
version.item ? link_to(link_text, link_url) : link_text
|
||||
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 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
|
||||
|
|
@ -3,32 +3,19 @@ class Ability
|
|||
|
||||
# Initializes the ability class
|
||||
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
|
||||
|
||||
# This is what sets up the different abilities
|
||||
if user.new_record?
|
||||
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
|
||||
signed_in(user)
|
||||
common_abilities_for_admins(user) if user.roles.any? || user.is_admin?
|
||||
end
|
||||
end
|
||||
|
||||
# Abilities for not signed in users (guests)
|
||||
def not_signed_in
|
||||
can [:index], Organization
|
||||
can [:index], Conference
|
||||
can [:show], Conference do |conference|
|
||||
conference.splashpage && conference.splashpage.public == true
|
||||
|
|
@ -62,6 +49,10 @@ class Ability
|
|||
can [:new, :create], Event do |event|
|
||||
event.program.cfp_open? && event.new_record?
|
||||
end
|
||||
|
||||
can [:show, :events], Schedule do |schedule|
|
||||
schedule.program.schedule_public
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -69,19 +60,20 @@ class Ability
|
|||
def signed_in(user)
|
||||
# Abilities from not_signed_in user are also inherited
|
||||
not_signed_in
|
||||
|
||||
can :manage, User, id: user.id
|
||||
|
||||
can :manage, Registration, user_id: user.id
|
||||
|
||||
can [:new, :create], Registration do |registration|
|
||||
conference = registration.conference
|
||||
conference.registration_open? && !conference.registration_limit_exceeded?
|
||||
conference.registration_open? && !conference.registration_limit_exceeded? || conference.program.speakers.confirmed.include?(user)
|
||||
end
|
||||
|
||||
can :index, Organization
|
||||
can :index, Ticket
|
||||
can :manage, TicketPurchase, user_id: user.id
|
||||
can [:new, :create], Payment, user_id: user.id
|
||||
can [:index, :show], PhysicalTicket, user: user
|
||||
|
||||
can [:create, :destroy], Subscription, user_id: user.id
|
||||
|
||||
|
|
@ -95,171 +87,42 @@ class Ability
|
|||
|
||||
# can manage the commercials of their own events
|
||||
can :manage, Commercial, commercialable_type: 'Event', commercialable_id: user.events.pluck(:id)
|
||||
|
||||
can [:destroy], Openid
|
||||
end
|
||||
|
||||
# Abilities for signed in users with roles
|
||||
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
|
||||
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
|
||||
|
||||
# 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 [:show], Conference
|
||||
can :index, Commercial, commercialable_type: 'Conference'
|
||||
cannot [:edit, :update, :destroy], Question, global: true
|
||||
# for admins
|
||||
can :manage, :all if user.is_admin
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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, 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
|
||||
|
|
|
|||
286
app/models/admin_ability.rb
Normal file
286
app/models/admin_ability.rb
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
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, User, id: user.id
|
||||
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, 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 [:update, :show, :delete, :index], Event do |event|
|
||||
event.users.include?(user)
|
||||
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
|
||||
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], Organization, id: org_ids_for_organization_admin
|
||||
can :new, Conference
|
||||
can :manage, Conference, organization_id: org_ids_for_organization_admin
|
||||
can [:index, :show], Role
|
||||
can [:edit, :update], Role do |role|
|
||||
role.resource_type == 'Organization' && (org_ids_for_organization_admin.include? role.resource_id)
|
||||
end
|
||||
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, 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 :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 do |version|
|
||||
version.item_type == 'User' || (conf_ids.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)
|
||||
|
||||
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, 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: '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)
|
||||
|
||||
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
|
||||
|
||||
# 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
|
||||
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
|
||||
|
||||
# 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
|
||||
end
|
||||
end
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
# cannot delete program if there are events submitted
|
||||
|
||||
class Cfp < ActiveRecord::Base
|
||||
TYPES = %w(events booths).freeze
|
||||
|
||||
scope :for_events, (-> { find_by(cfp_type: 'events') })
|
||||
|
||||
has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||
belongs_to :program
|
||||
|
||||
|
|
@ -8,6 +12,15 @@ class Cfp < ActiveRecord::Base
|
|||
validates :start_date, :end_date, presence: true
|
||||
validate :before_end_of_conference
|
||||
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
|
||||
|
|
@ -16,11 +29,11 @@ class Cfp < ActiveRecord::Base
|
|||
# * +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
|
||||
def notify_on_cfp_date_update?
|
||||
!self.end_date.blank? && !self.start_date.blank?\
|
||||
&& (self.start_date_changed? || self.end_date_changed?)\
|
||||
&& self.program.conference.email_settings.send_on_cfp_dates_updated\
|
||||
&& !self.program.conference.email_settings.cfp_dates_updated_subject.blank?\
|
||||
&& !self.program.conference.email_settings.cfp_dates_updated_body.blank?
|
||||
!end_date.blank? && !start_date.blank?\
|
||||
&& (start_date_changed? || end_date_changed?)\
|
||||
&& program.conference.email_settings.send_on_cfp_dates_updated\
|
||||
&& !program.conference.email_settings.cfp_dates_updated_subject.blank?\
|
||||
&& !program.conference.email_settings.cfp_dates_updated_body.blank?
|
||||
end
|
||||
|
||||
##
|
||||
|
|
@ -51,23 +64,37 @@ class Cfp < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def remaining_days(date = Date.today)
|
||||
result = (self.end_date - date).to_i
|
||||
result = (end_date - date).to_i
|
||||
result > 0 ? result : 0
|
||||
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
|
||||
|
||||
private
|
||||
|
||||
def before_end_of_conference
|
||||
errors.
|
||||
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)
|
||||
if program && 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.
|
||||
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)
|
||||
if program && 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
|
||||
|
||||
def start_after_end_date
|
||||
errors.
|
||||
add(:start_date, "can't be after the end date") if start_date && end_date && start_date > end_date
|
||||
errors
|
||||
.add(:start_date, "can't be after the end date") if start_date && end_date && start_date > end_date
|
||||
end
|
||||
|
||||
def conference_id
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
class Comment < ActiveRecord::Base
|
||||
acts_as_nested_set scope: [:commentable_id, :commentable_type]
|
||||
validates_presence_of :body
|
||||
validates_presence_of :user
|
||||
acts_as_nested_set scope: %i(commentable_id commentable_type)
|
||||
validates :body, presence: true
|
||||
validates :user, presence: true
|
||||
after_create :send_notification
|
||||
|
||||
# NOTE: install the acts_as_votable plugin if you
|
||||
# want user to vote on the quality of comments.
|
||||
#acts_as_votable
|
||||
|
||||
belongs_to :commentable, polymorphic: true
|
||||
belongs_to :commentable, counter_cache: true, polymorphic: true
|
||||
|
||||
# NOTE: Comments belong to a 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
|
||||
# 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
|
||||
def has_children?
|
||||
self.children.any?
|
||||
children.any?
|
||||
end
|
||||
|
||||
# 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
|
||||
include RevisionCount
|
||||
require 'uri'
|
||||
serialize :events_per_week, Hash
|
||||
# Needed to call 'Conference.with_role' in /models/ability.rb
|
||||
|
|
@ -6,8 +7,12 @@ class Conference < ActiveRecord::Base
|
|||
resourcify :roles, dependent: :delete_all
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -17,6 +22,7 @@ class Conference < ActiveRecord::Base
|
|||
has_one :email_settings, dependent: :destroy
|
||||
has_one :program, dependent: :destroy
|
||||
has_one :venue, dependent: :destroy
|
||||
has_many :physical_tickets, through: :ticket_purchases
|
||||
has_many :ticket_purchases, dependent: :destroy
|
||||
has_many :payments, dependent: :destroy
|
||||
has_many :supporters, through: :ticket_purchases, source: :user
|
||||
|
|
@ -48,15 +54,17 @@ class Conference < ActiveRecord::Base
|
|||
|
||||
mount_uploader :picture, PictureUploader, mount_on: :logo_file_name
|
||||
|
||||
validates_presence_of :title,
|
||||
validates :title,
|
||||
:short_title,
|
||||
:start_date,
|
||||
:end_date,
|
||||
:start_hour,
|
||||
:end_hour
|
||||
:end_hour,
|
||||
:ticket_layout,
|
||||
:organization, presence: true
|
||||
|
||||
validates_uniqueness_of :short_title
|
||||
validates_format_of :short_title, with: /\A[a-zA-Z0-9_-]*\z/
|
||||
validates :short_title, uniqueness: true
|
||||
validates :short_title, format: { with: /\A[a-zA-Z0-9_-]*\z/ }
|
||||
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
|
||||
|
|
@ -67,6 +75,9 @@ class Conference < ActiveRecord::Base
|
|||
before_create :create_email_settings
|
||||
|
||||
after_create :create_free_ticket
|
||||
after_update :delete_event_schedules
|
||||
|
||||
enum ticket_layout: [:portrait, :landscape]
|
||||
|
||||
##
|
||||
# Checks if the user is registered to the conference
|
||||
|
|
@ -80,6 +91,20 @@ class Conference < ActiveRecord::Base
|
|||
user.present? && registrations.where(user_id: user.id).count > 0
|
||||
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
|
||||
#
|
||||
|
|
@ -113,7 +138,7 @@ class Conference < ActiveRecord::Base
|
|||
result = []
|
||||
|
||||
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
|
||||
weeks = program.cfp.weeks
|
||||
result = calculate_items_per_week(start_week, weeks, submissions)
|
||||
|
|
@ -161,7 +186,7 @@ class Conference < ActiveRecord::Base
|
|||
registration_period.start_date &&
|
||||
registration_period.end_date
|
||||
|
||||
reg = registrations.group(:week).count
|
||||
reg = registrations.group(:week).order(:week).count
|
||||
start_week = get_registration_start_week
|
||||
weeks = registration_weeks
|
||||
result = calculate_items_per_week(start_week, weeks, reg)
|
||||
|
|
@ -169,6 +194,59 @@ class Conference < ActiveRecord::Base
|
|||
result
|
||||
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.
|
||||
#
|
||||
|
|
@ -180,8 +258,8 @@ class Conference < ActiveRecord::Base
|
|||
if registration_period &&
|
||||
registration_period.start_date &&
|
||||
registration_period.end_date
|
||||
weeks = Date.new(registration_period.start_date.year, 12, 31).
|
||||
strftime('%W').to_i
|
||||
weeks = Date.new(registration_period.start_date.year, 12, 31)
|
||||
.strftime('%W').to_i
|
||||
|
||||
result = get_registration_end_week - get_registration_start_week + 1
|
||||
end
|
||||
|
|
@ -266,8 +344,8 @@ class Conference < ActiveRecord::Base
|
|||
# ====Returns
|
||||
# * +hash+ -> user: submissions
|
||||
def self.get_top_submitter(limit = 5)
|
||||
submitter = EventUser.where('event_role = ?', 'submitter').limit(limit).group(:user_id)
|
||||
counter = submitter.order('count_all desc').count
|
||||
submitter = EventUser.select(:user_id).where('event_role = ?', 'submitter').limit(limit).group(:user_id)
|
||||
counter = submitter.order('count_all desc').count(:all)
|
||||
calculate_user_submission_hash(submitter, counter)
|
||||
end
|
||||
|
||||
|
|
@ -277,10 +355,10 @@ class Conference < ActiveRecord::Base
|
|||
# ====Returns
|
||||
# * +hash+ -> user: submissions
|
||||
def get_top_submitter(limit = 5)
|
||||
submitter = EventUser.joins(:event).
|
||||
where('event_role = ? and program_id = ?', 'submitter', Conference.find(id).program.id).
|
||||
limit(limit).group(:user_id)
|
||||
counter = submitter.order('count_all desc').count
|
||||
submitter = EventUser.joins(:event).select(:user_id)
|
||||
.where('event_role = ? and program_id = ?', 'submitter', Conference.find(id).program.id)
|
||||
.limit(limit).group(:user_id)
|
||||
counter = submitter.order('count_all desc').count(:all)
|
||||
Conference.calculate_user_submission_hash(submitter, counter)
|
||||
end
|
||||
|
||||
|
|
@ -311,9 +389,10 @@ class Conference < ActiveRecord::Base
|
|||
# ====Returns
|
||||
# * +hash+ -> hash
|
||||
def scheduled_event_distribution
|
||||
confirmed_events = program.events.where(state: 'confirmed')
|
||||
scheduled_value = { 'value' => confirmed_events.where.not(start_time: nil).count, 'color' => 'green' }
|
||||
unscheduled_value = { 'value' => confirmed_events.where(start_time: nil).count, 'color' => 'red' }
|
||||
confirmed_scheduled_events = program.events.confirmed.scheduled(program.selected_schedule.try(:id))
|
||||
confirmed_unscheduled_events = program.events.confirmed - confirmed_scheduled_events
|
||||
scheduled_value = { 'value' => confirmed_scheduled_events.count, 'color' => 'green' }
|
||||
unscheduled_value = { 'value' => confirmed_unscheduled_events.count, 'color' => 'red' }
|
||||
{ 'Scheduled' => scheduled_value, 'Unscheduled' => unscheduled_value }
|
||||
end
|
||||
|
||||
|
|
@ -380,6 +459,46 @@ class Conference < ActiveRecord::Base
|
|||
calculate_user_distribution_hash(active_user, unconfirmed_user, dead_user)
|
||||
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
|
||||
#
|
||||
|
|
@ -444,10 +563,10 @@ class Conference < ActiveRecord::Base
|
|||
# ====Returns
|
||||
# * +hash+ -> track => {color, value}
|
||||
def tracks_distribution(state = nil)
|
||||
if state
|
||||
tracks_grouped = program.events.select(:track_id).where('state = ?', state).group(:track_id)
|
||||
tracks_grouped = if state
|
||||
program.events.select(:track_id).where('state = ?', state).group(:track_id)
|
||||
else
|
||||
tracks_grouped = program.events.select(:track_id).group(:track_id)
|
||||
program.events.select(:track_id).group(:track_id)
|
||||
end
|
||||
tracks_counted = tracks_grouped.count
|
||||
|
||||
|
|
@ -461,13 +580,13 @@ class Conference < ActiveRecord::Base
|
|||
# ====Returns
|
||||
# * +ActiveRecord+
|
||||
def self.get_active_conferences_for_dashboard
|
||||
result = Conference.where('start_date > ?', Time.now).
|
||||
select('id, short_title, color, start_date')
|
||||
result = Conference.where('start_date > ?', Time.now)
|
||||
.select('id, short_title, color, start_date')
|
||||
|
||||
if result.length == 0
|
||||
result = Conference.
|
||||
select('id, short_title, color, start_date').limit(2).
|
||||
order(start_date: :desc)
|
||||
if result.empty?
|
||||
result = Conference
|
||||
.select('id, short_title, color, start_date').limit(2)
|
||||
.order(start_date: :desc)
|
||||
end
|
||||
result
|
||||
end
|
||||
|
|
@ -531,7 +650,7 @@ class Conference < ActiveRecord::Base
|
|||
def self.write_event_distribution_to_db
|
||||
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 = {}
|
||||
Event.state_machine.states.each do |state|
|
||||
count = conference.program.events.where('state = ?', state.name).count
|
||||
|
|
@ -555,11 +674,11 @@ class Conference < ActiveRecord::Base
|
|||
# * +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
|
||||
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
|
||||
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
|
||||
(!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
|
||||
|
||||
##
|
||||
|
|
@ -569,17 +688,24 @@ class Conference < ActiveRecord::Base
|
|||
# * +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
|
||||
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
|
||||
return false unless self.registration_period
|
||||
return false unless registration_period
|
||||
# do not notify unless one of the dates changed
|
||||
return false unless registration_period.start_date_changed? || registration_period.end_date_changed?
|
||||
# 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
|
||||
|
||||
##
|
||||
# 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?
|
||||
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
|
||||
|
||||
# Returns an hexadecimal color given a collection. The returned color changed
|
||||
|
|
@ -611,6 +737,15 @@ class Conference < ActiveRecord::Base
|
|||
(start_hour..(end_hour - 1)).cover?(current_hour) ? current_hour - start_hour : 0
|
||||
end
|
||||
|
||||
##
|
||||
# Return the current conference object to be used in RevisionCount
|
||||
#
|
||||
# ====Returns
|
||||
# * +ActiveRecord+
|
||||
def conference
|
||||
self
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns a different html colour for every i and consecutive colors are
|
||||
|
|
@ -628,8 +763,8 @@ class Conference < ActiveRecord::Base
|
|||
end
|
||||
|
||||
after_create do
|
||||
self.create_contact
|
||||
self.create_program
|
||||
create_contact
|
||||
create_program
|
||||
create_roles
|
||||
end
|
||||
|
||||
|
|
@ -699,7 +834,7 @@ class Conference < ActiveRecord::Base
|
|||
# Completed weeks
|
||||
events_per_week.each do |week, values|
|
||||
values.each do |state, value|
|
||||
if [:confirmed, :unconfirmed].include?(state)
|
||||
if %i(confirmed unconfirmed).include?(state)
|
||||
unless result[state.to_s.capitalize]
|
||||
result[state.to_s.capitalize] = {}
|
||||
end
|
||||
|
|
@ -866,10 +1001,10 @@ class Conference < ActiveRecord::Base
|
|||
# ====Returns
|
||||
# * +hash+ -> object_type => {color, value}
|
||||
def calculate_event_distribution(group_by_id, association_symbol, state = nil)
|
||||
if state
|
||||
grouped = program.events.select(group_by_id).where('state = ?', 'confirmed').group(group_by_id)
|
||||
grouped = if state
|
||||
program.events.select(group_by_id).where('state = ?', 'confirmed').group(group_by_id)
|
||||
else
|
||||
grouped = program.events.select(group_by_id).group(group_by_id)
|
||||
program.events.select(group_by_id).group(group_by_id)
|
||||
end
|
||||
counted = grouped.count
|
||||
|
||||
|
|
@ -981,7 +1116,8 @@ class Conference < ActiveRecord::Base
|
|||
def self.calculate_user_submission_hash(submitters, counter)
|
||||
result = ActiveSupport::OrderedHash.new
|
||||
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
|
||||
result[submitter.user] = value
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
class Event < ActiveRecord::Base
|
||||
include ActiveRecord::Transitions
|
||||
include RevisionCount
|
||||
has_paper_trail on: [:create, :update], ignore: [:updated_at, :guid, :week], meta: { conference_id: :conference_id }
|
||||
|
||||
acts_as_commentable
|
||||
|
|
@ -8,7 +9,13 @@ class Event < ActiveRecord::Base
|
|||
|
||||
has_many :event_users, dependent: :destroy
|
||||
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 :voters, through: :votes, source: :user
|
||||
has_many :commercials, as: :commercialable, dependent: :destroy
|
||||
|
|
@ -23,6 +30,7 @@ class Event < ActiveRecord::Base
|
|||
belongs_to :program
|
||||
|
||||
accepts_nested_attributes_for :event_users, allow_destroy: true
|
||||
accepts_nested_attributes_for :speakers, allow_destroy: true
|
||||
accepts_nested_attributes_for :users
|
||||
|
||||
before_create :generate_guid
|
||||
|
|
@ -33,6 +41,7 @@ class Event < ActiveRecord::Base
|
|||
validates :abstract, presence: true
|
||||
validates :event_type, 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 }
|
||||
|
||||
validate :max_attendees_no_more_than_room_size
|
||||
|
|
@ -107,26 +116,22 @@ class Event < ActiveRecord::Base
|
|||
def average_rating
|
||||
@total_rating = 0
|
||||
votes.each do |vote|
|
||||
@total_rating = @total_rating + vote.rating
|
||||
@total_rating += vote.rating
|
||||
end
|
||||
@total = votes.size
|
||||
@total_rating > 0 ? number_with_precision(@total_rating / @total.to_f, precision: 2, strip_insignificant_zeros: true) : 0
|
||||
end
|
||||
|
||||
def submitter
|
||||
result = event_users.where(event_role: 'submitter').first
|
||||
if result.nil?
|
||||
user = nil
|
||||
# Perhaps the event_users haven't been saved, if this is a new proposal
|
||||
event_users.each do |u|
|
||||
if u.event_role == 'submitter'
|
||||
user = u.user
|
||||
end
|
||||
end
|
||||
user
|
||||
else
|
||||
result.user
|
||||
# get event speakers with the event sumbmitter at the first position
|
||||
# if the submitter is also a speaker for this event
|
||||
def speakers_ordered
|
||||
speakers_list = speakers.to_a
|
||||
|
||||
if speakers_list.reject! { |speaker| speaker == submitter }
|
||||
speakers_list.unshift(submitter)
|
||||
end
|
||||
|
||||
speakers_list
|
||||
end
|
||||
|
||||
def transition_possible?(transition)
|
||||
|
|
@ -185,12 +190,12 @@ class Event < ActiveRecord::Base
|
|||
end
|
||||
begin
|
||||
if mail
|
||||
self.send(transition,
|
||||
send(transition,
|
||||
send_mail: send_mail_param)
|
||||
else
|
||||
self.send(transition)
|
||||
send(transition)
|
||||
end
|
||||
self.save
|
||||
save
|
||||
rescue Transitions::InvalidTransition => e
|
||||
alert = "Update state failed. #{e.message}"
|
||||
end
|
||||
|
|
@ -210,12 +215,12 @@ class Event < ActiveRecord::Base
|
|||
# Returns +Hash+
|
||||
def progress_status
|
||||
{
|
||||
registered: self.program.conference.user_registered?(self.submitter),
|
||||
commercials: self.commercials.any?,
|
||||
biography: !self.submitter.biography.blank?,
|
||||
subtitle: !self.subtitle.blank?,
|
||||
track: (!self.track.blank? unless self.program.tracks.empty?),
|
||||
difficulty_level: !self.difficulty_level.blank?,
|
||||
registered: speakers.all? { |speaker| program.conference.user_registered? speaker },
|
||||
commercials: commercials.any?,
|
||||
biographies: speakers.all? { |speaker| !speaker.biography.blank? },
|
||||
subtitle: !subtitle.blank?,
|
||||
track: (!track.blank? unless program.tracks.empty?),
|
||||
difficulty_level: !difficulty_level.blank?,
|
||||
title: true,
|
||||
abstract: true
|
||||
}.with_indifferent_access
|
||||
|
|
@ -227,7 +232,7 @@ class Event < ActiveRecord::Base
|
|||
# ====Returns
|
||||
# * +String+ -> Progress in Percent
|
||||
def calculate_progress
|
||||
result = self.progress_status
|
||||
result = progress_status
|
||||
(100 * result.values.count(true) / result.values.compact.count).to_s
|
||||
end
|
||||
|
||||
|
|
@ -247,6 +252,10 @@ class Event < ActiveRecord::Base
|
|||
event_schedules.find_by(schedule_id: program.selected_schedule_id).try(:start_time)
|
||||
end
|
||||
|
||||
def conference
|
||||
program.conference
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
##
|
||||
|
|
@ -280,14 +289,14 @@ class Event < ActiveRecord::Base
|
|||
|
||||
def set_week
|
||||
self.week = created_at.strftime('%W')
|
||||
self.without_versioning do
|
||||
self.save!
|
||||
without_versioning do
|
||||
save!
|
||||
end
|
||||
end
|
||||
|
||||
def before_end_of_conference
|
||||
errors.
|
||||
add(:created_at, "can't be after the conference end date!") if program.conference && program.conference.end_date &&
|
||||
errors
|
||||
.add(:created_at, "can't be after the conference end date!") if program.conference && program.conference.end_date &&
|
||||
(Date.today > program.conference.end_date)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ class EventSchedule < ActiveRecord::Base
|
|||
validates :room, presence: true
|
||||
validates :start_time, presence: true
|
||||
validates :event, uniqueness: { scope: :schedule }
|
||||
validate :start_after_end_hour
|
||||
validate :start_before_start_hour
|
||||
|
||||
scope :confirmed, -> { joins(:event).where('state = ?', 'confirmed') }
|
||||
scope :canceled, -> { joins(:event).where('state = ?', 'canceled') }
|
||||
|
|
@ -37,6 +39,16 @@ class EventSchedule < ActiveRecord::Base
|
|||
|
||||
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
|
||||
schedule.program.conference_id
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,17 +15,13 @@ class EventType < ActiveRecord::Base
|
|||
|
||||
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
|
||||
|
||||
##
|
||||
# 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
|
||||
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
|
||||
|
||||
def capitalize_color
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
class EventUser < ActiveRecord::Base
|
||||
# TODO Do we need these roles?
|
||||
ROLES = [['Speaker', 'speaker'], ['Submitter', 'submitter'], ['Moderator', 'moderator']]
|
||||
# TODO: Do we need these roles?
|
||||
ROLES = [%w[Speaker speaker], %w[Submitter submitter], %w[Moderator moderator]]
|
||||
|
||||
belongs_to :event
|
||||
belongs_to :user
|
||||
|
|
|
|||
17
app/models/organization.rb
Normal file
17
app/models/organization.rb
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
class Organization < ActiveRecord::Base
|
||||
resourcify :roles, dependent: :delete_all
|
||||
|
||||
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
|
||||
7
app/models/physical_ticket.rb
Normal file
7
app/models/physical_ticket.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
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
|
||||
end
|
||||
|
|
@ -5,11 +5,12 @@ class Program < ActiveRecord::Base
|
|||
|
||||
belongs_to :conference
|
||||
|
||||
has_one :cfp, dependent: :destroy
|
||||
has_many :cfps, dependent: :destroy
|
||||
has_many :event_types, dependent: :destroy
|
||||
has_many :tracks, dependent: :destroy
|
||||
has_many :difficulty_levels, dependent: :destroy
|
||||
has_many :schedules, dependent: :destroy
|
||||
has_many :event_schedules, through: :schedules
|
||||
belongs_to :selected_schedule, class_name: 'Schedule'
|
||||
has_many :events, dependent: :destroy do
|
||||
def require_registration
|
||||
|
|
@ -38,12 +39,17 @@ class Program < ActiveRecord::Base
|
|||
where(state: :confirmed, is_highlight: true)
|
||||
end
|
||||
end
|
||||
has_many :event_schedules, through: :events
|
||||
|
||||
has_many :event_users, through: :events
|
||||
has_many :speakers, -> { distinct }, through: :event_users, source: :user do
|
||||
def confirmed
|
||||
joins(:events).where(events: { state: :confirmed })
|
||||
end
|
||||
|
||||
def registered(conference)
|
||||
joins(:registrations).where('registrations.conference_id = ?', conference.id)
|
||||
end
|
||||
end
|
||||
|
||||
accepts_nested_attributes_for :event_types, allow_destroy: true
|
||||
|
|
@ -52,11 +58,15 @@ class Program < ActiveRecord::Base
|
|||
|
||||
# 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 :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_dates_exist
|
||||
|
||||
after_create :create_event_types
|
||||
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
|
||||
|
||||
# Returns all event_schedules for the selected schedule ordered by start_time
|
||||
|
|
@ -115,7 +125,7 @@ class Program < ActiveRecord::Base
|
|||
# * +false+ -> If rating is not enabled
|
||||
# * +true+ -> If rating is enabled
|
||||
def rating_enabled?
|
||||
self.rating && self.rating > 0
|
||||
rating && rating > 0
|
||||
end
|
||||
|
||||
##
|
||||
|
|
@ -139,7 +149,7 @@ class Program < ActiveRecord::Base
|
|||
end
|
||||
|
||||
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
|
||||
|
||||
##
|
||||
|
|
@ -153,6 +163,23 @@ class Program < ActiveRecord::Base
|
|||
EventSchedule.where(schedule: selected_schedule).where(start_time: parsed_date..(parsed_date + 1)).any?
|
||||
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
|
||||
|
||||
##
|
||||
|
|
@ -161,10 +188,10 @@ class Program < ActiveRecord::Base
|
|||
def create_event_types
|
||||
EventType.create(title: 'Talk', length: 30, color: '#FF0000', description: 'Presentation in lecture format',
|
||||
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',
|
||||
minimum_abstract_length: 0,
|
||||
maximum_abstract_length: 500, program_id: self.id)
|
||||
maximum_abstract_length: 500, program_id: id)
|
||||
true
|
||||
end
|
||||
|
||||
|
|
@ -174,13 +201,13 @@ class Program < ActiveRecord::Base
|
|||
def create_difficulty_levels
|
||||
DifficultyLevel.create(title: 'Easy',
|
||||
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',
|
||||
description: 'Events require a basic understanding of the topic.',
|
||||
color: '#EEEF69', program_id: self.id)
|
||||
color: '#E6B65B', program_id: id)
|
||||
DifficultyLevel.create(title: 'Hard',
|
||||
description: 'Events require expert knowledge of the topic.',
|
||||
color: '#EF6E69', program_id: self.id)
|
||||
color: '#EF6E69', program_id: id)
|
||||
true
|
||||
end
|
||||
|
||||
|
|
@ -188,15 +215,42 @@ class Program < ActiveRecord::Base
|
|||
# Check if languages string has the right format. Used as validation.
|
||||
#
|
||||
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
|
||||
self.languages = self.languages.delete(' ').downcase
|
||||
self.languages = languages.delete(' ').downcase
|
||||
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_array = self.languages.split(',')
|
||||
languages.match(/^$|(\A[a-z][a-z](,[a-z][a-z])*\z)/).present?
|
||||
languages_array = languages.split(',')
|
||||
# We check that languages are not repeated
|
||||
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
|
||||
errors.add(:languages, 'must be ISO 639-1 valid codes') unless languages_array.select{ |x| ISO_639.find(x).nil? }.empty?
|
||||
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
|
||||
|
|
|
|||
|
|
@ -12,6 +12,6 @@ class Question < ActiveRecord::Base
|
|||
private
|
||||
|
||||
def existing_answers
|
||||
errors.add(:base, 'Must have answers') if self.answers.blank?
|
||||
errors.add(:base, 'Must have answers') if answers.blank?
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,14 +2,13 @@ class Registration < ActiveRecord::Base
|
|||
belongs_to :user
|
||||
belongs_to :conference
|
||||
|
||||
has_and_belongs_to_many :events
|
||||
has_and_belongs_to_many :qanswers
|
||||
has_and_belongs_to_many :vchoices
|
||||
|
||||
has_many :events_registrations
|
||||
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 :qanswers
|
||||
|
|
@ -24,7 +23,7 @@ class Registration < ActiveRecord::Base
|
|||
|
||||
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_to_events_only_if_present
|
||||
|
||||
|
|
|
|||
|
|
@ -10,15 +10,15 @@ class RegistrationPeriod < ActiveRecord::Base
|
|||
private
|
||||
|
||||
def before_end_of_conference
|
||||
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)
|
||||
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)
|
||||
|
||||
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)
|
||||
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)
|
||||
end
|
||||
|
||||
def start_date_before_end_date
|
||||
errors.
|
||||
add(:start_date, "can't be after the end date") if start_date && end_date && start_date > end_date
|
||||
errors
|
||||
.add(:start_date, "can't be after the end date") if start_date && end_date && start_date > end_date
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
class Resource < ActiveRecord::Base
|
||||
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
|
||||
|
||||
def used_less_than_quantity
|
||||
errors.add(:used, 'can not be higher than total quantity') unless used <= quantity
|
||||
def used_no_more_than_quantity
|
||||
errors.add(:used, 'cannot be higher than total quantity') if used.present? && quantity.present? && used > quantity
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
#
|
||||
# suseconferenceclient relies on a 'revision' attribute for caching and
|
||||
# doing some calculations.
|
||||
#
|
||||
# It should be incremented after any change in the conference or in any
|
||||
# associated models
|
||||
#
|
||||
# This observer updates the revision column in a non-intrusive way,
|
||||
# preventing validations, callbacks or exceptions to be triggered
|
||||
#
|
||||
# Relying on paper_trail could also be an option, but a 'revision' column
|
||||
# in table 'conferences' looks like a more simple and straightforward solution
|
||||
#
|
||||
class RevisionObserver < ActiveRecord::Observer
|
||||
observe :conference, :event, :room, :track
|
||||
|
||||
def after_save(model)
|
||||
begin
|
||||
conference = model.kind_of?(Conference) ? model : model.conference
|
||||
conference.reload.increment(:revision)
|
||||
conference.update_column(:revision, conference.revision)
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
class Room < ActiveRecord::Base
|
||||
include RevisionCount
|
||||
belongs_to :venue
|
||||
has_many :event_schedules, dependent: :destroy
|
||||
|
||||
|
|
@ -10,6 +11,10 @@ class Room < ActiveRecord::Base
|
|||
|
||||
validates :size, numericality: { only_integer: true, greater_than: 0 }, allow_nil: true
|
||||
|
||||
def conference
|
||||
venue.conference
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_guid
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ class Sponsor < ActiveRecord::Base
|
|||
|
||||
mount_uploader :picture, PictureUploader, mount_on: :logo_file_name
|
||||
|
||||
validates_presence_of :name, :website_url, :sponsorship_level
|
||||
validates :name, :website_url, :sponsorship_level, presence: true
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
class SponsorshipLevel < ActiveRecord::Base
|
||||
validates_presence_of :title
|
||||
validates :title, presence: true
|
||||
belongs_to :conference
|
||||
acts_as_list scope: :conference
|
||||
has_many :sponsors
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
class Subscription < ActiveRecord::Base
|
||||
validates_uniqueness_of :user_id, scope: [:conference_id]
|
||||
validates :user_id, uniqueness: { scope: [:conference_id] }
|
||||
belongs_to :conference
|
||||
belongs_to :user
|
||||
|
||||
has_paper_trail on: [:create, :destroy], ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||
has_paper_trail on: %i(create destroy), ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||
|
||||
validates_uniqueness_of :user_id, scope: :conference_id, message: 'already subscribed!'
|
||||
validates :user_id, uniqueness: { scope: :conference_id, message: 'already subscribed!' }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class Ticket < ActiveRecord::Base
|
|||
|
||||
validates :price_cents, :price_currency, :title, presence: true
|
||||
|
||||
validates_numericality_of :price_cents, greater_than_or_equal_to: 0
|
||||
validates :price_cents, numericality: { greater_than_or_equal_to: 0 }
|
||||
|
||||
def bought?(user)
|
||||
buyers.include?(user)
|
||||
|
|
@ -56,7 +56,7 @@ class Ticket < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def tickets_sold
|
||||
ticket_purchases.sum(:quantity)
|
||||
ticket_purchases.paid.sum(:quantity)
|
||||
end
|
||||
|
||||
def tickets_turnover
|
||||
|
|
@ -66,7 +66,7 @@ class Ticket < ActiveRecord::Base
|
|||
private
|
||||
|
||||
def tickets_of_conference_have_same_currency
|
||||
unless Ticket.where(conference_id: conference_id).all?{|t| t.price_currency == self.price_currency }
|
||||
unless Ticket.where(conference_id: conference_id).all?{|t| t.price_currency == price_currency }
|
||||
errors.add(:price_currency, 'is different from the existing tickets of this conference.')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ class TicketPurchase < ActiveRecord::Base
|
|||
belongs_to :ticket
|
||||
belongs_to :user
|
||||
belongs_to :conference
|
||||
belongs_to :payment
|
||||
|
||||
validates :ticket_id, :user_id, :conference_id, :quantity, presence: true
|
||||
|
||||
validates_numericality_of :quantity, greater_than: 0
|
||||
validates :quantity, numericality: { greater_than: 0 }
|
||||
|
||||
delegate :title, to: :ticket
|
||||
delegate :description, to: :ticket
|
||||
|
|
@ -13,21 +14,25 @@ class TicketPurchase < ActiveRecord::Base
|
|||
delegate :price_cents, to: :ticket
|
||||
delegate :price_currency, to: :ticket
|
||||
|
||||
has_many :physical_tickets
|
||||
|
||||
scope :paid, -> { where(paid: true) }
|
||||
scope :unpaid, -> { where(paid: false) }
|
||||
scope :by_conference, ->(conference) { where(conference_id: conference.id) }
|
||||
scope :by_user, ->(user) { where(user_id: user.id) }
|
||||
|
||||
after_create :set_week
|
||||
|
||||
def self.purchase(conference, user, purchases)
|
||||
errors = []
|
||||
ActiveRecord::Base.transaction do
|
||||
conference.tickets.each do |ticket|
|
||||
quantity = purchases[ticket.id.to_s].to_i
|
||||
# if the user bought the ticket and is still unpaid, just update the quantity
|
||||
if ticket.bought?(user) && ticket.unpaid?(user)
|
||||
purchase = update_quantity(conference, quantity, ticket, user)
|
||||
purchase = if ticket.bought?(user) && ticket.unpaid?(user)
|
||||
update_quantity(conference, quantity, ticket, user)
|
||||
else
|
||||
purchase = purchase_ticket(conference, quantity, ticket, user)
|
||||
purchase_ticket(conference, quantity, ticket, user)
|
||||
end
|
||||
|
||||
if purchase && !purchase.save
|
||||
|
|
@ -43,8 +48,8 @@ class TicketPurchase < ActiveRecord::Base
|
|||
purchase = new(ticket_id: ticket.id,
|
||||
conference_id: conference.id,
|
||||
user_id: user.id,
|
||||
quantity: quantity,
|
||||
paid: ticket.price_cents.zero?)
|
||||
quantity: quantity)
|
||||
purchase.pay(nil) if ticket.price_cents.zero?
|
||||
end
|
||||
purchase
|
||||
end
|
||||
|
|
@ -58,4 +63,18 @@ class TicketPurchase < ActiveRecord::Base
|
|||
purchase.quantity = quantity if quantity > 0
|
||||
purchase
|
||||
end
|
||||
|
||||
def pay(payment)
|
||||
update_attributes(paid: true, payment: payment)
|
||||
PhysicalTicket.transaction do
|
||||
quantity.times { physical_tickets.create }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_week
|
||||
self.week = created_at.strftime('%W')
|
||||
save!
|
||||
end
|
||||
|
|
|
|||
3
app/models/ticket_scanning.rb
Normal file
3
app/models/ticket_scanning.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
class TicketScanning < ActiveRecord::Base
|
||||
belongs_to :physical_ticket
|
||||
end
|
||||
|
|
@ -1,5 +1,10 @@
|
|||
class Track < ActiveRecord::Base
|
||||
include RevisionCount
|
||||
|
||||
resourcify :roles, dependent: :delete_all
|
||||
|
||||
belongs_to :program
|
||||
belongs_to :submitter, class_name: 'User'
|
||||
has_many :events, dependent: :nullify
|
||||
|
||||
has_paper_trail only: [:name, :description, :color], meta: { conference_id: :conference_id }
|
||||
|
|
@ -7,9 +12,37 @@ class Track < ActiveRecord::Base
|
|||
before_create :generate_guid
|
||||
validates :name, presence: true
|
||||
validates :color, format: /\A#[0-9A-F]{6}\z/
|
||||
validates :short_name,
|
||||
presence: true,
|
||||
format: /\A[a-zA-Z0-9_-]*\z/,
|
||||
uniqueness: {
|
||||
scope: :program
|
||||
}
|
||||
validates :state, presence: true, if: :self_organized?
|
||||
validates :cfp_active, inclusion: { in: [true, false] }, if: :self_organized?
|
||||
|
||||
before_validation :capitalize_color
|
||||
|
||||
after_create :create_organizer_role, if: :self_organized?
|
||||
|
||||
def conference
|
||||
program.conference
|
||||
end
|
||||
|
||||
##
|
||||
# Checks if the track is self-organized
|
||||
# ====Returns
|
||||
# * +true+ -> If the track has a submitter
|
||||
# * +false+ -> if the track doesn't have a submitter
|
||||
def self_organized?
|
||||
return true if submitter
|
||||
false
|
||||
end
|
||||
|
||||
def to_param
|
||||
short_name
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_guid
|
||||
|
|
@ -27,4 +60,10 @@ class Track < ActiveRecord::Base
|
|||
def conference_id
|
||||
program.conference_id
|
||||
end
|
||||
|
||||
##
|
||||
# Creates the role of the track organizer
|
||||
def create_organizer_role
|
||||
Role.where(name: 'track_organizer', resource: self).first_or_create(description: 'For the organizers of the Track')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ end
|
|||
|
||||
class User < ActiveRecord::Base
|
||||
rolify
|
||||
has_many :physical_tickets, through: :ticket_purchases do
|
||||
def by_conference(conference)
|
||||
where('ticket_purchases.conference_id = ?', conference)
|
||||
end
|
||||
end
|
||||
has_many :users_roles
|
||||
has_many :roles, through: :users_roles, dependent: :destroy
|
||||
|
||||
|
|
@ -25,10 +30,10 @@ class User < ActiveRecord::Base
|
|||
# :lockable, :timeoutable and :omniauthable
|
||||
devise_modules = []
|
||||
|
||||
if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
|
||||
devise_modules += [ :ichain_authenticatable, :ichain_registerable, :omniauthable, omniauth_providers: [] ]
|
||||
devise_modules += if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
|
||||
[:ichain_authenticatable, :ichain_registerable, :omniauthable, omniauth_providers: []]
|
||||
else
|
||||
devise_modules += [:database_authenticatable, :registerable,
|
||||
[:database_authenticatable, :registerable,
|
||||
:recoverable, :rememberable, :trackable, :validatable, :confirmable,
|
||||
:omniauthable, omniauth_providers: [:suse, :google, :facebook, :github]]
|
||||
end
|
||||
|
|
@ -41,6 +46,7 @@ class User < ActiveRecord::Base
|
|||
|
||||
has_many :event_users, dependent: :destroy
|
||||
has_many :events, -> { uniq }, through: :event_users
|
||||
has_many :presented_events, -> { joins(:event_users).where(event_users: {event_role: 'speaker'}).uniq }, through: :event_users, source: :event
|
||||
has_many :registrations, dependent: :destroy
|
||||
has_many :events_registrations, through: :registrations
|
||||
has_many :ticket_purchases, dependent: :destroy
|
||||
|
|
@ -49,9 +55,11 @@ class User < ActiveRecord::Base
|
|||
has_many :votes, dependent: :destroy
|
||||
has_many :voted_events, through: :votes, source: :events
|
||||
has_many :subscriptions, dependent: :destroy
|
||||
has_many :tracks, foreign_key: 'submitter_id'
|
||||
accepts_nested_attributes_for :roles
|
||||
|
||||
scope :admin, -> { where(is_admin: true) }
|
||||
scope :active, -> { where(is_disabled: false) }
|
||||
|
||||
validates :email, presence: true
|
||||
|
||||
|
|
@ -72,7 +80,7 @@ class User < ActiveRecord::Base
|
|||
# * +true+ if the user attended the event
|
||||
# * +false+ if the user did not attend the event
|
||||
def attended_event? event
|
||||
event_registration = event.events_registrations.find_by(registration: self.registrations)
|
||||
event_registration = event.events_registrations.find_by(registration: registrations)
|
||||
|
||||
return false unless event_registration.present?
|
||||
event_registration.attended
|
||||
|
|
@ -91,7 +99,7 @@ class User < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def subscribed? conference
|
||||
self.subscriptions.find_by(conference_id: conference.id).present?
|
||||
subscriptions.find_by(conference_id: conference.id).present?
|
||||
end
|
||||
|
||||
def supports? conference
|
||||
|
|
@ -206,8 +214,8 @@ class User < ActiveRecord::Base
|
|||
# Check if biography has an allowed number of words. Used as validation.
|
||||
#
|
||||
def biography_limit
|
||||
if self.biography.present?
|
||||
errors.add(:biography, 'is limited to 150 words.') if self.biography.split.length > 150
|
||||
if biography.present?
|
||||
errors.add(:biography, 'is limited to 150 words.') if biography.split.length > 150
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class Venue < ActiveRecord::Base
|
|||
def notify_on_venue_changed?
|
||||
return false unless conference.try(:email_settings).try(:send_on_venue_updated)
|
||||
# do not notify unless the address changed
|
||||
return false unless self.name_changed? || self.street_changed? || self.city_changed? || self.country_changed?
|
||||
return false unless name_changed? || street_changed? || city_changed? || country_changed?
|
||||
# do not notify unless the mail content is set up
|
||||
(!conference.email_settings.venue_updated_subject.blank? && !conference.email_settings.venue_updated_body.blank?)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@ class Vposition < ActiveRecord::Base
|
|||
has_many :vchoices
|
||||
has_many :vdays, through: :vchoices
|
||||
|
||||
validates_presence_of :title, :vdays
|
||||
validates :title, :vdays, presence: true
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,6 +26,6 @@ class EventSerializer < ActiveModel::Serializer
|
|||
end
|
||||
|
||||
def length
|
||||
object.event_type.try(:length) || EventType::LENGTH_STEP
|
||||
object.event_type.try(:length) || object.event_type.program.schedule_interval
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,5 @@ class SpeakerSerializer < ActiveModel::Serializer
|
|||
|
||||
attributes :name, :affiliation, :biography
|
||||
|
||||
def name
|
||||
object.name
|
||||
end
|
||||
delegate :name, to: :object
|
||||
end
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ class PictureUploader < CarrierWave::Uploader::Base
|
|||
"system/#{object_class_name}/#{mounted_as}/#{model.id}"
|
||||
end
|
||||
|
||||
def image
|
||||
@image ||= MiniMagick::Image.open(file.file)
|
||||
end
|
||||
|
||||
# Create different versions of your uploaded files:
|
||||
version :large do
|
||||
process resize_to_fit: [300, 300]
|
||||
|
|
|
|||
12
app/views/admin/cfps/_booths_cfp.html.haml
Normal file
12
app/views/admin/cfps/_booths_cfp.html.haml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
%dt
|
||||
Start Date
|
||||
%dd
|
||||
= @cfp.start_date.strftime('%A, %B %e. %Y')
|
||||
%dt
|
||||
End Date
|
||||
%dd
|
||||
= @cfp.end_date.strftime('%A, %B %e. %Y')
|
||||
%dt
|
||||
Days Left
|
||||
%dd
|
||||
= pluralize(@cfp.remaining_days, 'day')
|
||||
38
app/views/admin/cfps/_events_cfp.html.haml
Normal file
38
app/views/admin/cfps/_events_cfp.html.haml
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
%dt
|
||||
Start Date:
|
||||
%dd#start_date
|
||||
= @cfp.start_date.strftime('%A, %B %-d. %Y')
|
||||
%dt
|
||||
End Date:
|
||||
%dd#end_date
|
||||
= @cfp.end_date.strftime('%A, %B %-d. %Y')
|
||||
%dt
|
||||
Days Left:
|
||||
%dd
|
||||
= pluralize(@cfp.remaining_days, 'day')
|
||||
%dt
|
||||
Event types:
|
||||
%dd
|
||||
= event_types(@conference)
|
||||
%dt
|
||||
Tracks:
|
||||
%dd
|
||||
= tracks(@conference)
|
||||
%dt
|
||||
Public Schedule
|
||||
%dd#schedule_public
|
||||
- if @program.schedule_public
|
||||
Yes
|
||||
- else
|
||||
No
|
||||
%dt
|
||||
Schedule changeable?
|
||||
%dd#schedule_changes
|
||||
- if @program.schedule_fluid
|
||||
Yes
|
||||
- else
|
||||
No
|
||||
%dt
|
||||
Rating Levels
|
||||
%dd#rating
|
||||
= @program.rating
|
||||
|
|
@ -4,8 +4,9 @@
|
|||
%h1 Call for Papers
|
||||
.row
|
||||
.col-md-8
|
||||
= semantic_form_for(@cfp, url: admin_conference_program_cfp_path(@conference.short_title), html: {multipart: true}) do |f|
|
||||
= semantic_form_for(@cfp, url: (@cfp.new_record? ? admin_conference_program_cfps_path : admin_conference_program_cfp_path(@conference.short_title, @cfp)), html: {multipart: true}) do |f|
|
||||
= f.input :start_date, as: :string, input_html: { id: 'registration-period-start-datepicker', start_date: @conference.start_date, end_date: @conference.end_date, readonly: 'readonly' }
|
||||
= f.input :end_date, as: :string, input_html: { id: 'registration-period-end-datepicker', readonly: 'readonly' }
|
||||
= f.input :cfp_type, as: :select, collection: (@cfp.new_record? ? @program.remaining_cfp_types : [@cfp.cfp_type] + @program.remaining_cfp_types).map {|type| ["#{type.capitalize}", type]}, include_blank: false, label: 'Type', input_html: { class: 'select-help-toggle' }
|
||||
%p.text-right
|
||||
= f.action :submit, as: :button, button_html: { class: 'btn btn-primary' }
|
||||
|
|
|
|||
36
app/views/admin/cfps/index.html.haml
Normal file
36
app/views/admin/cfps/index.html.haml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
.row
|
||||
.col-md-12
|
||||
.page-header
|
||||
%h1 Call for Papers
|
||||
%p.text-muted
|
||||
Call for people to submit events to your conference
|
||||
- if @program.cfps
|
||||
.row
|
||||
.col-md-12
|
||||
%table.table.table-hover.datatable#tickets
|
||||
%thead
|
||||
%th Type
|
||||
%th Start Date
|
||||
%th End Date
|
||||
%th Days Left
|
||||
%th Actions
|
||||
%tbody
|
||||
- @program.cfps.each do |cfp|
|
||||
%tr
|
||||
%td
|
||||
= link_to(admin_conference_program_cfp_path(@conference.short_title, cfp.id)) do
|
||||
= cfp.cfp_type.capitalize
|
||||
%td
|
||||
= cfp.start_date.strftime('%A, %B %-d. %Y')
|
||||
%td
|
||||
= cfp.end_date.strftime('%A, %B %-d. %Y')
|
||||
%td
|
||||
= pluralize(cfp.remaining_days, 'day')
|
||||
%td
|
||||
.btn-group
|
||||
= link_to 'Edit', edit_admin_conference_program_cfp_path(@conference.short_title, cfp.id), method: :get, class: 'btn btn-primary'
|
||||
= link_to 'Delete', admin_conference_program_cfp_path(@conference.short_title, cfp.id), method: 'delete', class: 'btn btn-danger', data: { confirm: 'Are you sure you want to delete the CfP?' }
|
||||
- if can? :new, @program.cfps.new
|
||||
.row
|
||||
.col-md-12.text-right
|
||||
= link_to 'Create Call for Papers', new_admin_conference_program_cfp_path(@conference.short_title), class: 'btn btn-primary'
|
||||
|
|
@ -4,55 +4,13 @@
|
|||
%h1 Call for Papers
|
||||
%p.text-muted
|
||||
Call for people to submit events to your conference
|
||||
- if @cfp
|
||||
.row
|
||||
.col-md-8
|
||||
%dl.dl-horizontal
|
||||
%dt
|
||||
Start Date:
|
||||
%dd#start_date
|
||||
= @cfp.start_date.strftime('%A, %B %-d. %Y')
|
||||
%dt
|
||||
End Date:
|
||||
%dd#end_date
|
||||
= @cfp.end_date.strftime('%A, %B %-d. %Y')
|
||||
%dt
|
||||
Days Left:
|
||||
%dd
|
||||
= pluralize(@cfp.remaining_days, 'day')
|
||||
%dt
|
||||
Event types:
|
||||
%dd
|
||||
= event_types(@conference)
|
||||
%dt
|
||||
Tracks:
|
||||
%dd
|
||||
= tracks(@conference)
|
||||
%dt
|
||||
Public Schedule
|
||||
%dd#schedule_public
|
||||
- if @program.schedule_public
|
||||
Yes
|
||||
- else
|
||||
No
|
||||
%dt
|
||||
Schedule changeable?
|
||||
%dd#schedule_changes
|
||||
- if @program.schedule_fluid
|
||||
Yes
|
||||
- else
|
||||
No
|
||||
%dt
|
||||
Rating Levels
|
||||
%dd#rating
|
||||
= @program.rating
|
||||
= render "#{@cfp.cfp_type}_cfp"
|
||||
.row
|
||||
.col-md-12.text-right
|
||||
= link_to(edit_admin_conference_program_cfp_path(@conference.short_title), class: 'btn btn-primary') do
|
||||
= link_to(edit_admin_conference_program_cfp_path(@conference.short_title, @cfp.id), class: 'btn btn-primary') do
|
||||
Edit
|
||||
= link_to(admin_conference_program_cfp_path(@conference.short_title), method: 'delete', class: 'btn btn-danger', data: { confirm: 'Are you sure you want to delete the CfP?' }) do
|
||||
= link_to(admin_conference_program_cfp_path(@conference.short_title, @cfp.id), method: 'delete', class: 'btn btn-danger', data: { confirm: 'Are you sure you want to delete the CfP?' }) do
|
||||
Delete
|
||||
- else
|
||||
.row
|
||||
.col-md-12.text-right
|
||||
= link_to 'Create Call for Papers', new_admin_conference_program_cfp_path(@conference.short_title), class: 'btn btn-primary'
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
.list-group
|
||||
%li.list-group-item
|
||||
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)}" }
|
||||
%h4
|
||||
Conference progress
|
||||
.progress
|
||||
.progress-bar{ 'role' => 'progressbar', 'aria-valuenow' => "#{conference_progress['process']}", 'aria-valuemin' => '0',
|
||||
'aria-valuemax' => '100', 'style' => "width: #{conference_progress['process']}%;" }
|
||||
= conference_progress['process'] + '%'
|
||||
%li{ 'class' => "list-group-item #{class_for_todo(conference_progress['registration'])}" }
|
||||
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['registration'])}" }
|
||||
%span{ 'class' => icon_for_todo(conference_progress['registration']) }
|
||||
- if can? :update, @conference
|
||||
- if conference.registration_period
|
||||
|
|
@ -15,46 +15,48 @@
|
|||
= link_to 'Set up registration period', new_admin_conference_registration_period_path(conference_progress['short_title'])
|
||||
- else
|
||||
Set up registration period
|
||||
%li{ 'class' => "list-group-item #{class_for_todo(conference_progress['cfp'])}" }
|
||||
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['cfp'])}" }
|
||||
%span{ 'class' => icon_for_todo(conference_progress['cfp']) }
|
||||
- if can? :update, Cfp.new(program_id: @program.id)
|
||||
= link_to 'Set up call for papers', admin_conference_program_cfp_path(conference_progress['short_title'])
|
||||
= link_to 'Set up call for papers', admin_conference_program_cfps_path(conference_progress['short_title'])
|
||||
- else
|
||||
Set up call for papers
|
||||
%li{ 'class' => "list-group-item #{class_for_todo(conference_progress['venue'])}" }
|
||||
%li{'class'=>"list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['venue'])}"}
|
||||
%span{'class'=>icon_for_todo(conference_progress['venue'])}
|
||||
- if can? :update, @conference.venue
|
||||
- if can? :update, Venue.new(conference: @conference)
|
||||
- @conference.reload
|
||||
- if conference.venue
|
||||
= link_to 'Add venue', edit_admin_conference_venue_path(conference_progress['short_title'])
|
||||
- else
|
||||
= link_to 'Add venue', new_admin_conference_venue_path(conference_progress['short_title'])
|
||||
- else
|
||||
- @conference.reload
|
||||
Add venue
|
||||
%li{ 'class' => "list-group-item #{class_for_todo(conference_progress['rooms'])}" }
|
||||
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['rooms'])}" }
|
||||
%span{ 'class' => icon_for_todo(conference_progress['rooms']) }
|
||||
- if @conference.venue && (can? :update, @conference.venue.rooms.build)
|
||||
= link_to 'Add rooms', admin_conference_venue_rooms_path(conference_progress['short_title'])
|
||||
- else
|
||||
Add rooms
|
||||
%li{ 'class' => "list-group-item #{class_for_todo(conference_progress['tracks'])}" }
|
||||
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['tracks'])}" }
|
||||
%span{ 'class' => icon_for_todo(conference_progress['tracks']) }
|
||||
- if can? :update, @conference.program.tracks.build
|
||||
= link_to 'Add tracks', admin_conference_program_tracks_path(conference_progress['short_title'])
|
||||
- else
|
||||
Add tracks
|
||||
%li{ 'class' => "list-group-item #{class_for_todo(conference_progress['event_types'])}" }
|
||||
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['event_types'])}" }
|
||||
%span{ 'class' => icon_for_todo(conference_progress['event_types']) }
|
||||
- if can? :update, @conference.program.event_types.build
|
||||
= link_to 'Add event types', admin_conference_program_event_types_path(conference_progress['short_title'])
|
||||
- else
|
||||
Add event types
|
||||
%li{ 'class' => "list-group-item #{class_for_todo(conference_progress['difficulty_levels'])}" }
|
||||
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['difficulty_levels'])}" }
|
||||
%span{ 'class' => icon_for_todo(conference_progress['difficulty_levels']) }
|
||||
- if can? :update, @conference.program.difficulty_levels.build
|
||||
= link_to 'Add difficulty levels', admin_conference_program_difficulty_levels_path(conference_progress['short_title'])
|
||||
- else
|
||||
Add difficulty levels
|
||||
%li{ class: "list-group-item #{class_for_todo(conference_progress['splashpage'])}" }
|
||||
%li{ class: "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['splashpage'])}" }
|
||||
%span{ 'class' => icon_for_todo(conference_progress['splashpage']) }
|
||||
- if can? :update, @conference
|
||||
= link_to 'Set up a Splashpage', admin_conference_splashpage_path(conference_progress['short_title'])
|
||||
|
|
|
|||
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