Merge branch 'master' into master
This commit is contained in:
commit
7048a37eb6
294 changed files with 10474 additions and 3147 deletions
2
.dockerignore
Normal file
2
.dockerignore
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Dockerfile
|
||||
docker-compose.*
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -36,3 +36,7 @@ pickle-email-*.html
|
|||
.env.development
|
||||
.env.test
|
||||
.env.local
|
||||
docker-compose.env
|
||||
docker-compose.yml
|
||||
.DS_Store
|
||||
.byebug_history
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# This configuration was generated by
|
||||
# `haml-lint --auto-gen-config`
|
||||
# on 2017-04-25 04:36:49 +0530 using Haml-Lint version 0.24.0.
|
||||
# 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
|
||||
|
|
@ -8,9 +8,13 @@
|
|||
|
||||
linters:
|
||||
|
||||
# Offense count: 952
|
||||
# Offense count: 945
|
||||
LineLength:
|
||||
exclude:
|
||||
- "app/views/admin/booths/_change_state_dropdown.html.haml"
|
||||
- "app/views/admin/booths/_form.html.haml"
|
||||
- "app/views/admin/booths/index.html.haml"
|
||||
- "app/views/admin/booths/show.html.haml"
|
||||
- "app/views/admin/campaigns/_form.html.haml"
|
||||
- "app/views/admin/campaigns/index.html.haml"
|
||||
- "app/views/admin/cfps/_form.html.haml"
|
||||
|
|
@ -49,10 +53,11 @@ linters:
|
|||
- "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/reports.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"
|
||||
|
|
@ -73,6 +78,7 @@ linters:
|
|||
- "app/views/admin/resources/show.html.haml"
|
||||
- "app/views/admin/roles/_form.html.haml"
|
||||
- "app/views/admin/roles/_users.html.haml"
|
||||
- "app/views/admin/roles/_users_with_org_admin_role.haml"
|
||||
- "app/views/admin/roles/index.html.haml"
|
||||
- "app/views/admin/roles/show.html.haml"
|
||||
- "app/views/admin/rooms/_form.html.haml"
|
||||
|
|
@ -105,6 +111,9 @@ linters:
|
|||
- "app/views/admin/versions/_object_desc_and_link.html.haml"
|
||||
- "app/views/admin/versions/index.html.haml"
|
||||
- "app/views/admin/volunteers/index.html.haml"
|
||||
- "app/views/booths/_form.html.haml"
|
||||
- "app/views/booths/index.html.haml"
|
||||
- "app/views/booths/show.html.haml"
|
||||
- "app/views/commercials/edit.html.haml"
|
||||
- "app/views/commercials/new.html.haml"
|
||||
- "app/views/conference_registrations/_form.html.haml"
|
||||
|
|
@ -112,6 +121,7 @@ linters:
|
|||
- "app/views/conference_registrations/_registration_info.html.haml"
|
||||
- "app/views/conference_registrations/_volunteer.html.haml"
|
||||
- "app/views/conference_registrations/show.html.haml"
|
||||
- "app/views/conferences/_booths.html.haml"
|
||||
- "app/views/conferences/_call_for_paper.html.haml"
|
||||
- "app/views/conferences/_conference_details.html.haml"
|
||||
- "app/views/conferences/_gallery.html.haml"
|
||||
|
|
@ -143,7 +153,9 @@ linters:
|
|||
- "app/views/layouts/_admin_sidebar_index.html.haml"
|
||||
- "app/views/layouts/_messages.html.haml"
|
||||
- "app/views/layouts/_navigation.html.haml"
|
||||
- "app/views/layouts/_user_menu.html.haml"
|
||||
- "app/views/layouts/application.html.haml"
|
||||
- "app/views/organizations/index.html.haml"
|
||||
- "app/views/payments/_payment.html.haml"
|
||||
- "app/views/proposals/_form.html.haml"
|
||||
- "app/views/proposals/_proposal_form.html.haml"
|
||||
|
|
@ -169,11 +181,21 @@ linters:
|
|||
- "app/views/tickets/index.html.haml"
|
||||
- "app/views/users/edit.html.haml"
|
||||
- "app/views/users/show.html.haml"
|
||||
- "app/views/admin/cfps/index.html.haml"
|
||||
- "app/views/tracks/_form.html.haml"
|
||||
- "app/views/tracks/index.html.haml"
|
||||
- "app/views/tracks/show.html.haml"
|
||||
- "app/views/conferences/_call_for_tracks.html.haml"
|
||||
- "app/views/admin/tracks/_change_state_dropdown.html.haml"
|
||||
- "app/views/proposals/_encouragement_text.html.haml"
|
||||
- "app/views/admin/schedules/_form.html.haml"
|
||||
|
||||
# Offense count: 222
|
||||
# Offense count: 223
|
||||
InstanceVariables:
|
||||
exclude:
|
||||
- "app/views/admin/booths/_change_state_dropdown.html.haml"
|
||||
- "app/views/admin/campaigns/_form.html.haml"
|
||||
- "app/views/admin/cfps/_booths_cfp.html.haml"
|
||||
- "app/views/admin/cfps/_form.html.haml"
|
||||
- "app/views/admin/conferences/_todo_list.html.haml"
|
||||
- "app/views/admin/difficulty_levels/_form.html.haml"
|
||||
|
|
@ -184,6 +206,7 @@ linters:
|
|||
- "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"
|
||||
|
|
@ -226,6 +249,12 @@ linters:
|
|||
- "app/views/schedules/_schedule.html.haml"
|
||||
- "app/views/schedules/_schedule_item.html.haml"
|
||||
- "app/views/schedules/_schedule_tabs.html.haml"
|
||||
- "app/views/admin/cfps/_events_cfp.html.haml"
|
||||
- "app/views/tracks/_form.html.haml"
|
||||
- "app/views/admin/cfps/_tracks_cfp.html.haml"
|
||||
- "app/views/conferences/_call_for_tracks.html.haml"
|
||||
- "app/views/admin/tracks/_change_state_dropdown.html.haml"
|
||||
- "app/views/admin/schedules/_form.html.haml"
|
||||
|
||||
# Offense count: 32
|
||||
IdNames:
|
||||
|
|
@ -244,15 +273,14 @@ linters:
|
|||
- "app/views/admin/users/_event_registrations.html.haml"
|
||||
- "app/views/admin/users/show.html.haml"
|
||||
- "app/views/users/edit.html.haml"
|
||||
- "app/views/admin/cfps/_events_cfp.html.haml"
|
||||
- "app/views/admin/cfps/_tracks_cfp.html.haml"
|
||||
|
||||
# Offense count: 8
|
||||
# Offense count: 4
|
||||
UnnecessaryInterpolation:
|
||||
exclude:
|
||||
- "app/views/admin/conferences/_doughnut_chart.html.haml"
|
||||
- "app/views/admin/conferences/_recent_submissions.html.haml"
|
||||
- "app/views/admin/events/reports.html.haml"
|
||||
- "app/views/admin/reports/_events_with_requirements.html.haml"
|
||||
- "app/views/admin/reports/_events_without_commercials.html.haml"
|
||||
- "app/views/proposals/_proposal_form.html.haml"
|
||||
- "app/views/proposals/new.html.haml"
|
||||
|
||||
|
|
@ -282,6 +310,7 @@ linters:
|
|||
SpaceInsideHashAttributes:
|
||||
exclude:
|
||||
- "app/views/admin/conferences/_todo_list.html.haml"
|
||||
- "app/views/admin/emails/index.html.haml"
|
||||
- "app/views/admin/questions/_form.html.haml"
|
||||
- "app/views/admin/questions/index.html.haml"
|
||||
- "app/views/admin/registrations/index.html.haml"
|
||||
|
|
@ -327,12 +356,13 @@ linters:
|
|||
- "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: 27
|
||||
# Offense count: 23
|
||||
ClassesBeforeIds:
|
||||
exclude:
|
||||
- "app/views/admin/emails/index.html.haml"
|
||||
- "app/views/admin/events/reports.html.haml"
|
||||
- "app/views/admin/events/show.html.haml"
|
||||
- "app/views/admin/reports/index.html.haml"
|
||||
- "app/views/admin/users/show.html.haml"
|
||||
|
|
@ -356,6 +386,7 @@ linters:
|
|||
- "app/views/admin/tracks/show.html.haml"
|
||||
- "app/views/admin/venues/show.html.haml"
|
||||
- "app/views/admin/versions/index.html.haml"
|
||||
- "app/views/booths/index.html.haml"
|
||||
- "app/views/conference_registrations/_form.html.haml"
|
||||
- "app/views/conference_registrations/_ticket.html.haml"
|
||||
- "app/views/conference_registrations/show.html.haml"
|
||||
|
|
@ -380,12 +411,27 @@ linters:
|
|||
# Offense count: 14
|
||||
ConsecutiveSilentScripts:
|
||||
exclude:
|
||||
- "app/views/admin/booths/_change_state_dropdown.html.haml"
|
||||
- "app/views/admin/events/index.html.haml"
|
||||
- "app/views/admin/schedules/_day_tab.html.haml"
|
||||
- "app/views/admin/schedules/_event.html.haml"
|
||||
- "app/views/admin/versions/_object_desc_and_link.html.haml"
|
||||
- "app/views/booths/index.html.haml"
|
||||
- "app/views/schedules/_carousel.html.haml"
|
||||
|
||||
# Offense count: 29
|
||||
TrailingWhitespace:
|
||||
exclude:
|
||||
- "app/views/admin/organizations/_form.html.haml"
|
||||
- "app/views/admin/users/index.html.haml"
|
||||
- "app/views/admin/users/show.html.haml"
|
||||
- "app/views/admin/volunteers/index.html.haml"
|
||||
- "app/views/admin/volunteers/show.html.haml"
|
||||
- "app/views/conference_registrations/_volunteer.html.haml"
|
||||
- "app/views/devise/passwords/new.html.haml"
|
||||
- "app/views/payments/new.html.haml"
|
||||
- "app/views/tickets/index.html.haml"
|
||||
|
||||
# Offense count: 2
|
||||
FinalNewline:
|
||||
exclude:
|
||||
|
|
@ -406,19 +452,6 @@ linters:
|
|||
- "app/views/schedules/_event.html.haml"
|
||||
- "app/views/schedules/_schedule_item.html.haml"
|
||||
|
||||
# Offense count: 38
|
||||
TrailingWhitespace:
|
||||
exclude:
|
||||
- "app/views/admin/users/_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: 7
|
||||
ClassAttributeWithStaticValue:
|
||||
exclude:
|
||||
|
|
|
|||
171
.rubocop.yml
171
.rubocop.yml
|
|
@ -13,100 +13,6 @@ AllCops:
|
|||
- 'config/**/*'
|
||||
- 'bin/*'
|
||||
|
||||
#################### Style ###############################
|
||||
|
||||
# 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 redundunt curly braces when it is obvious that hash is used
|
||||
Style/BracesAroundHashParameters:
|
||||
Enabled: true
|
||||
|
||||
# Avoid the use of the case equality operator `===`
|
||||
Style/CaseEquality:
|
||||
Enabled: true
|
||||
|
||||
# Use nested module/class definitions instead of compact style
|
||||
Style/ClassAndModuleChildren:
|
||||
Enabled: true
|
||||
|
||||
# Checks the . position in multi-line method calls.
|
||||
Style/DotPosition:
|
||||
Enabled: true
|
||||
|
||||
# Checks for uses of double negation (!!) to convert something to a boolean value.
|
||||
Style/DoubleNegation:
|
||||
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
|
||||
|
||||
# Use the new Ruby 1.9 hash syntax
|
||||
Style/HashSyntax:
|
||||
Enabled: true
|
||||
EnforcedStyle: ruby19
|
||||
|
||||
# Checks for uses of if with negated condition. Use unless instead
|
||||
Style/NegatedIf:
|
||||
Enabled: true
|
||||
|
||||
# Do not compare with nil. Use .nil? instead
|
||||
Style/NilComparison:
|
||||
Enabled: true
|
||||
|
||||
# Checks for redundant uses of self.
|
||||
Style/RedundantSelf:
|
||||
Enabled: true
|
||||
|
||||
# Checks that operators have space around them, except for ** which should not have surrounding space.
|
||||
Style/SpaceAroundOperators:
|
||||
Enabled: true
|
||||
|
||||
# Use single quotes unless there's string interpolation
|
||||
Style/StringLiterals:
|
||||
Enabled: true
|
||||
|
||||
# This cop checks for tabs where spaces should be used.
|
||||
Style/Tab:
|
||||
Enabled: true
|
||||
|
||||
# Avoid trailing blank lines
|
||||
Style/TrailingBlankLines:
|
||||
Enabled: true
|
||||
|
||||
# Avoid trailing whitespace
|
||||
Style/TrailingWhitespace:
|
||||
Enabled: true
|
||||
|
||||
# This cop checks for numeric comparisons that can be replaced by a predicate method.
|
||||
Style/ZeroLengthPredicate:
|
||||
Enabled: true
|
||||
|
||||
#################### Metrics ###############################
|
||||
|
||||
|
|
@ -123,77 +29,6 @@ Metrics/ClassLength:
|
|||
Metrics/BlockLength:
|
||||
Exclude:
|
||||
- 'spec/models/conference_spec.rb'
|
||||
|
||||
#################### Lint ###############################
|
||||
|
||||
# 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
|
||||
|
||||
# Things deprecated in current ruby API
|
||||
Lint/DeprecatedClassMethods:
|
||||
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
|
||||
|
||||
# Do not use duplicated keys in hash literals.
|
||||
Lint/DuplicatedKey:
|
||||
Enabled: true
|
||||
|
||||
#################### Rails ###############################
|
||||
|
||||
# Enforce Rails specific style
|
||||
Rails:
|
||||
Enabled: true
|
||||
|
||||
# Avoid use of old-style attribute validation
|
||||
Rails/Validation:
|
||||
Enabled: true
|
||||
|
||||
# Looks for delegations, that could have been created automatically with delegate method
|
||||
Rails/Delegate:
|
||||
Enabled: true
|
||||
|
||||
#################### Performance ###############################
|
||||
|
||||
# Identifies places where gsub can be replaced by tr or delete.
|
||||
Performance/StringReplacement:
|
||||
Enabled: true
|
||||
- 'spec/features/ability_spec.rb'
|
||||
- 'spec/models/ability_spec.rb'
|
||||
- 'spec/models/admin_ability_spec.rb'
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
13
.travis.yml
13
.travis.yml
|
|
@ -3,12 +3,12 @@ dist: trusty
|
|||
language: ruby
|
||||
cache: bundler
|
||||
rvm:
|
||||
- 2.2.3
|
||||
- 2.4.0
|
||||
before_install:
|
||||
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
||||
- "echo `phantomjs -v`"
|
||||
addons:
|
||||
mariadb: '10.1'
|
||||
mariadb: '10.2'
|
||||
notifications:
|
||||
email:
|
||||
on_success: change
|
||||
|
|
@ -24,6 +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 haml-lint app/views'
|
||||
- 'bundle exec rspec --color --format documentation'
|
||||
- "./travis_script.sh $TEST_SUITE"
|
||||
env:
|
||||
- TEST_SUITE=rspec
|
||||
- TEST_SUITE=linters
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
|
|
|||
1
CODE_OF_CONDUCT.md
Normal file
1
CODE_OF_CONDUCT.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
OSEM is part of the openSUSE project. We follow all the [openSUSE Guiding Principles!](http://en.opensuse.org/openSUSE:Guiding_principles) If you think someone doesn't do that, please let us know at maintainers@osem.io
|
||||
101
CONTRIBUTING.md
101
CONTRIBUTING.md
|
|
@ -71,59 +71,6 @@ You can access the app [localhost:3000](http://localhost:3000). Whatever you cha
|
|||
* If you are already a contributor and you get a positive review, you can merge your pull-request yourself
|
||||
* If you are not already a contributor please request a merge via the pull-request comments
|
||||
|
||||
### Getting Started
|
||||
|
||||
* When you get involved with OSEM for the first time, you can choose issues labeled as [Junior]( https://github.com/openSUSE/osem/issues?q=is%3Aissue+is%3Aopen+label%3AJunior)
|
||||
* Leave a comment on the issue that you want to work on it
|
||||
* We expect you to work on it and show progress by either opening a PR or commenting on the issue
|
||||
* If you change your mind, and do not want to work on the issue any more, please be fair to others and leave a comment to let us know
|
||||
* Do **not** work on issues that are assigned to others. If you are uncertain, ask and wait for a **contributor** to reply
|
||||
* Avoid working on issues that have no label
|
||||
* If you have opened a new issue, please wait for a contributor to add relevant labels
|
||||
* If an issue is a feature, we should first have a rough idea on how we want to implement it
|
||||
* If there is already such a discussion on the issue, you can go ahead and pick this up
|
||||
* If not, please first leave a comment on how you want to implement it and wait for contributors' feedback
|
||||
|
||||
### Commits
|
||||
* Commit title should be short and descriptive
|
||||
* title (or summary line) is the first line of the commit message
|
||||
* that says what the commit is doing
|
||||
* in no more than 50 characters
|
||||
* starting with a word like 'Fix' or 'Add' or 'Change'
|
||||
* **without** a period (.) at the end
|
||||
* followed by a blank line
|
||||
* Commit messages are
|
||||
* up to 72 characters
|
||||
* with break lines
|
||||
* Reference the issue(s) the commit closes
|
||||
* https://help.github.com/articles/closing-issues-via-commit-messages
|
||||
* If you haven't done so since the beginning, you should reference the issue when you squash your commits
|
||||
|
||||
### Pull Requests workflow
|
||||
Please open a pull request (PR) only when you have finished coding, and your changes are ready to be reviewed for merging.
|
||||
|
||||
* Title
|
||||
* Include a comprehensive title about what this PR is doing
|
||||
* Referencing the issue number on the PR title is not giving any information about what this PR is about
|
||||
* The title should be short (50 characters maximum); you can add more information in the description
|
||||
* Description
|
||||
* Add a couple of lines about what is the problem you are trying to solve and how you have addressed it
|
||||
* Add bullet points about the new things you are introducing, if applicable
|
||||
* Reference the issue(s) you are solving
|
||||
* Add a screenshot of your change, if you are working on something that changes how the app looks like
|
||||
* Automated checks
|
||||
* We automatically run the [test suite](https://github.com/openSUSE/osem/blob/master/CONTRIBUTING.md#test-suite) and security checks on every PR
|
||||
* Check back later to see if all checks were successful, if not, address them or leave a comment to ask for help
|
||||
* Pushing new changes to your PR
|
||||
* Always add **new** commits; this tremendously helps reviewers
|
||||
* Do not squash commits, unless explicitly requested by the reviewer
|
||||
* Take care of your PR
|
||||
* Make sure you check the status of your PR regularly
|
||||
* Address your reviews, make the necessary changes, ask if something is not clear to you
|
||||
* Rebase against newest changes, when needed; we cannot properly review PRs that are not rebased
|
||||
|
||||
Reviewing your PR might take some time, as we are all volunteers. Please be responsive and respectful.
|
||||
|
||||
### Coding Style
|
||||
We are using [rubocop](https://github.com/bbatsov/rubocop) as a style checker. It is checking code style each time the test suite runs. You can run it locally with
|
||||
|
||||
|
|
@ -141,16 +88,6 @@ We are using [rspec](http://rspec.info/)+[capybara](http://jnicklas.github.io/ca
|
|||
vagrant exec bundle exec rspec
|
||||
```
|
||||
|
||||
### Review App of your PR
|
||||
|
||||
OSEM uses [Review Apps](https://devcenter.heroku.com/articles/github-integration-review-apps) on Heroku.
|
||||
|
||||
* The review app can be manually created by a maintainer, and when that happens you will see a relevant message in the PR
|
||||
|
||||
* Please help reviewers by adding the necessary data relevant to your PR,
|
||||
eg. if your PR is doing something related to conference registrations, go to the review app and make sure there is a conference with registrations.
|
||||
|
||||
|
||||
### Email Notifications
|
||||
**Note**: We use [letter_opener](https://github.com/ryanb/letter_opener) in development environment. You can check out your mails by visiting [localhost:3000/letter_opener](http://localhost:3000/letter_opener).
|
||||
|
||||
|
|
@ -181,44 +118,6 @@ 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!
|
||||
|
||||
1. **Bug**
|
||||
* A bug in the application, something is wrong and needs to be fixed!
|
||||
* Ideally the issue includes details on how to reproduce the bug
|
||||
* Reproduce the bug in master branch, and send a PR that solves it
|
||||
2. **Design**
|
||||
* Related to the looks and/or usability of the application; needs attention from someone who understands front-end and UX
|
||||
* If you are good with graphics and design, give it a shot!
|
||||
3. **Documentation**
|
||||
* Related to the documentation of our application, eg our INSTALL.md file or a wiki page with instructions on how to use the app, or part of it.
|
||||
* If you are working on a documentation issue, make sure you are covering all cases.
|
||||
4. **Epic**
|
||||
* We may, or may not, solve this, thus it is epic. It's bigger than a feature request, because it fundamentally changes or affects the app, or a significant part of it.
|
||||
* Do **not** work on this without prior discussion with the maintainers, it's called epic for a reason!
|
||||
5. **Feature**
|
||||
* This is a new feature for something new in the app!
|
||||
* If an issue is labeled *Feature*, don't work on the issue, unless the maintainers have decided on how to proceed
|
||||
* Ideally, leave a comment with your proposed solution in the issue and wait for feedback
|
||||
6. **Grooming**
|
||||
* This is working, but could look better, thus needs some attention and grooming.
|
||||
7. **Hacktoberfest**
|
||||
* This is for the issues included in the coding event of Hacktoberfest. You can ignore it, when the event is not on
|
||||
8. **in progress**
|
||||
9. **Junior**
|
||||
* For new comers! RoR beginners or people unfamiliar with the application. Where you must start if you are interested in a mentoring program we participate in.
|
||||
10. **need feedback**
|
||||
* Maintainers' attention is needed to decide if this is something we want in the app, and/or how it should be implemented
|
||||
11. **Operation**
|
||||
12. **ready**
|
||||
13. **Refactorization**
|
||||
* Our code needs to be re-written; to avoid code duplication, or make the code more readable, or do things in a simpler way!
|
||||
14. **Research**
|
||||
* Ideas to explore; and think if there is anything we want to include in our app.
|
||||
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"]
|
||||
25
Gemfile
25
Gemfile
|
|
@ -6,7 +6,7 @@ if Gem::Version.new(Bundler::VERSION) < Gem::Version.new('1.8.4')
|
|||
end
|
||||
|
||||
# as web framework
|
||||
gem 'rails', '~> 4.2'
|
||||
gem 'rails', '~> 4.2.8'
|
||||
|
||||
# enables serving assets in production and setting your logger to standard out
|
||||
# both of which are required to run an application on a twelve-factor provider
|
||||
|
|
@ -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'
|
||||
|
|
@ -58,7 +57,7 @@ gem 'unobtrusive_flash', '>=3'
|
|||
gem 'transitions', :require => %w( transitions active_record/transitions )
|
||||
|
||||
# for comments
|
||||
gem 'awesome_nested_set', '~> 3.0.0.rc.5'
|
||||
gem 'awesome_nested_set', '~> 3.1.3'
|
||||
gem 'acts_as_commentable_with_threading'
|
||||
|
||||
# as templating language
|
||||
|
|
@ -84,6 +83,8 @@ gem 'jquery-ui-rails', '~> 4.2.1'
|
|||
# for languages validation
|
||||
gem 'iso-639'
|
||||
|
||||
gem 'thor', '0.19.1'
|
||||
|
||||
# frontend javascripts
|
||||
source 'https://rails-assets.org' do
|
||||
# for placeholder images
|
||||
|
|
@ -126,8 +127,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
|
||||
|
|
@ -196,14 +200,19 @@ gem 'sprockets-rails'
|
|||
# for multiple speakers select on proposal/event forms
|
||||
gem 'selectize-rails'
|
||||
|
||||
# Nokogiri < 1.8.1 is subject to:
|
||||
# CVE-2017-0663, CVE-2017-7375, CVE-2017-7376, CVE-2017-9047, CVE-2017-9048,
|
||||
# CVE-2017-9049, CVE-2017-9050
|
||||
gem 'nokogiri', '>= 1.8.1'
|
||||
|
||||
# Use guard and spring for testing in development
|
||||
group :development do
|
||||
# to launch specs when files are modified
|
||||
gem 'guard-rspec', '~> 4.2.8'
|
||||
gem 'guard-rspec'
|
||||
gem 'spring-commands-rspec'
|
||||
gem 'haml_lint', '~> 0.24.0'
|
||||
# for static code analisys
|
||||
gem 'rubocop', '~> 0.48.1', require: false
|
||||
gem 'rubocop', '~> 0.49.0', require: false
|
||||
# as database
|
||||
gem 'sqlite3'
|
||||
# to open mails
|
||||
|
|
@ -218,7 +227,7 @@ end
|
|||
|
||||
group :test do
|
||||
# as test framework
|
||||
gem 'rspec-rails'
|
||||
gem 'rspec-rails', '~> 3.5', '>= 3.5.2'
|
||||
gem 'database_cleaner'
|
||||
gem 'capybara'
|
||||
gem 'poltergeist'
|
||||
|
|
|
|||
354
Gemfile.lock
354
Gemfile.lock
|
|
@ -1,41 +1,50 @@
|
|||
GIT
|
||||
remote: https://github.com/randym/axlsx.git
|
||||
revision: c8ac844572b25fda358cc01d2104720c4c42f450
|
||||
specs:
|
||||
axlsx (2.1.0.pre)
|
||||
htmlentities (~> 4.3.4)
|
||||
mimemagic (~> 0.3)
|
||||
nokogiri (>= 1.6.6)
|
||||
rubyzip (>= 1.2.1)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
remote: https://rails-assets.org/
|
||||
specs:
|
||||
actionmailer (4.2.7.1)
|
||||
actionpack (= 4.2.7.1)
|
||||
actionview (= 4.2.7.1)
|
||||
activejob (= 4.2.7.1)
|
||||
actionmailer (4.2.9)
|
||||
actionpack (= 4.2.9)
|
||||
actionview (= 4.2.9)
|
||||
activejob (= 4.2.9)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
actionpack (4.2.7.1)
|
||||
actionview (= 4.2.7.1)
|
||||
activesupport (= 4.2.7.1)
|
||||
actionpack (4.2.9)
|
||||
actionview (= 4.2.9)
|
||||
activesupport (= 4.2.9)
|
||||
rack (~> 1.6)
|
||||
rack-test (~> 0.6.2)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
actionview (4.2.7.1)
|
||||
activesupport (= 4.2.7.1)
|
||||
actionview (4.2.9)
|
||||
activesupport (= 4.2.9)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
rails-dom-testing (~> 1.0, >= 1.0.5)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
||||
active_model_serializers (0.9.4)
|
||||
activemodel (>= 3.2)
|
||||
activejob (4.2.7.1)
|
||||
activesupport (= 4.2.7.1)
|
||||
activejob (4.2.9)
|
||||
activesupport (= 4.2.9)
|
||||
globalid (>= 0.3.0)
|
||||
activemodel (4.2.7.1)
|
||||
activesupport (= 4.2.7.1)
|
||||
activemodel (4.2.9)
|
||||
activesupport (= 4.2.9)
|
||||
builder (~> 3.1)
|
||||
activerecord (4.2.7.1)
|
||||
activemodel (= 4.2.7.1)
|
||||
activesupport (= 4.2.7.1)
|
||||
activerecord (4.2.9)
|
||||
activemodel (= 4.2.9)
|
||||
activesupport (= 4.2.9)
|
||||
arel (~> 6.0)
|
||||
activesupport (4.2.7.1)
|
||||
activesupport (4.2.9)
|
||||
i18n (~> 0.7)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
thread_safe (~> 0.3, >= 0.3.4)
|
||||
tzinfo (~> 1.1)
|
||||
|
|
@ -48,7 +57,8 @@ GEM
|
|||
awesome_nested_set (>= 2.0)
|
||||
acts_as_list (0.4.0)
|
||||
activerecord (>= 3.0)
|
||||
addressable (2.3.6)
|
||||
addressable (2.5.1)
|
||||
public_suffix (~> 2.0, >= 2.0.2)
|
||||
ahoy_matey (1.0.0)
|
||||
addressable
|
||||
browser (>= 0.4.0)
|
||||
|
|
@ -57,18 +67,13 @@ GEM
|
|||
request_store
|
||||
user_agent_parser
|
||||
uuidtools
|
||||
arel (6.0.3)
|
||||
arel (6.0.4)
|
||||
ast (2.3.0)
|
||||
autoprefixer-rails (5.1.9)
|
||||
autoprefixer-rails (7.1.1)
|
||||
execjs
|
||||
json
|
||||
awesome_nested_set (3.0.0.rc.5)
|
||||
activerecord (>= 4.0.0, < 5)
|
||||
awesome_nested_set (3.1.3)
|
||||
activerecord (>= 4.0.0, < 5.2)
|
||||
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)
|
||||
|
|
@ -82,10 +87,8 @@ GEM
|
|||
bootstrap3-datetimepicker-rails (3.0.3)
|
||||
momentjs-rails (>= 2.8.1)
|
||||
browser (0.6.0)
|
||||
builder (3.2.2)
|
||||
byebug (3.1.2)
|
||||
columnize (~> 0.8)
|
||||
debugger-linecache (~> 1.2)
|
||||
builder (3.2.3)
|
||||
byebug (9.0.6)
|
||||
cancancan (1.13.1)
|
||||
capybara (2.6.2)
|
||||
addressable
|
||||
|
|
@ -103,28 +106,24 @@ GEM
|
|||
activesupport (>= 3.2.0)
|
||||
carrierwave
|
||||
fastimage
|
||||
celluloid (0.15.2)
|
||||
timers (~> 1.1.0)
|
||||
celluloid-io (0.15.0)
|
||||
celluloid (>= 0.15.0)
|
||||
nio4r (>= 0.5.0)
|
||||
chart-js-rails (0.0.6)
|
||||
railties (> 3.1)
|
||||
chronic (0.10.2)
|
||||
chunky_png (1.3.8)
|
||||
cliver (0.3.2)
|
||||
cloudinary (1.1.6)
|
||||
aws_cf_signer
|
||||
rest-client
|
||||
cocoon (1.2.6)
|
||||
coderay (1.1.0)
|
||||
coffee-rails (4.1.1)
|
||||
coderay (1.1.1)
|
||||
coffee-rails (4.2.2)
|
||||
coffee-script (>= 2.2.0)
|
||||
railties (>= 4.0.0, < 5.1.x)
|
||||
railties (>= 4.0.0)
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.10.0)
|
||||
columnize (0.8.9)
|
||||
coffee-script-source (1.12.2)
|
||||
concurrent-ruby (1.0.5)
|
||||
countable-rails (0.0.1)
|
||||
railties (>= 3.1)
|
||||
countries (1.2.5)
|
||||
|
|
@ -139,18 +138,17 @@ GEM
|
|||
term-ansicolor (~> 1.3)
|
||||
thor (~> 0.19.1)
|
||||
tins (~> 1.6.0)
|
||||
crack (0.4.2)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
currencies (0.4.2)
|
||||
daemons (1.1.9)
|
||||
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)
|
||||
activerecord (>= 3.0, < 5)
|
||||
delayed_job (4.1.3)
|
||||
activesupport (>= 3.0, < 5.2)
|
||||
delayed_job_active_record (4.1.2)
|
||||
activerecord (>= 3.0, < 5.2)
|
||||
delayed_job (>= 3.0, < 5)
|
||||
devise (4.2.0)
|
||||
bcrypt (~> 3.0)
|
||||
|
|
@ -160,14 +158,14 @@ GEM
|
|||
warden (~> 1.2.3)
|
||||
devise_ichain_authenticatable (0.3.1)
|
||||
devise (>= 2.2)
|
||||
diff-lcs (1.2.5)
|
||||
diff-lcs (1.3)
|
||||
docile (1.1.5)
|
||||
domain_name (0.5.20160310)
|
||||
unf (>= 0.0.5, < 1.0.0)
|
||||
dotenv (2.1.1)
|
||||
dotenv-rails (2.1.1)
|
||||
dotenv (= 2.1.1)
|
||||
railties (>= 4.0, < 5.1)
|
||||
dotenv (2.2.1)
|
||||
dotenv-rails (2.2.1)
|
||||
dotenv (= 2.2.1)
|
||||
railties (>= 3.2, < 5.2)
|
||||
erubis (2.7.0)
|
||||
execjs (2.6.0)
|
||||
factory_girl (4.5.0)
|
||||
|
|
@ -181,27 +179,32 @@ GEM
|
|||
multipart-post (>= 1.2, < 3)
|
||||
fastimage (2.0.0)
|
||||
addressable (~> 2)
|
||||
ffi (1.9.3)
|
||||
font-awesome-rails (4.1.0.0)
|
||||
railties (>= 3.2, < 5.0)
|
||||
formatador (0.2.4)
|
||||
ffi (1.9.18)
|
||||
font-awesome-rails (4.7.0.2)
|
||||
railties (>= 3.2, < 5.2)
|
||||
formatador (0.2.5)
|
||||
formtastic (3.1.3)
|
||||
actionpack (>= 3.2.13)
|
||||
formtastic-bootstrap (3.1.1)
|
||||
formtastic (>= 3.0)
|
||||
geocoder (1.2.2)
|
||||
globalid (0.3.6)
|
||||
activesupport (>= 4.1.0)
|
||||
globalid (0.4.0)
|
||||
activesupport (>= 4.2.0)
|
||||
gravtastic (3.2.6)
|
||||
guard (2.6.0)
|
||||
guard (2.14.1)
|
||||
formatador (>= 0.2.4)
|
||||
listen (~> 2.7)
|
||||
listen (>= 2.7, < 4.0)
|
||||
lumberjack (~> 1.0)
|
||||
nenv (~> 0.1)
|
||||
notiffany (~> 0.0)
|
||||
pry (>= 0.9.12)
|
||||
shellany (~> 0.0)
|
||||
thor (>= 0.18.1)
|
||||
guard-rspec (4.2.8)
|
||||
guard-compat (1.2.1)
|
||||
guard-rspec (4.7.3)
|
||||
guard (~> 2.1)
|
||||
rspec (>= 2.14, < 4.0)
|
||||
guard-compat (~> 1.1)
|
||||
rspec (>= 2.99.0, < 4.0)
|
||||
haml (4.0.5)
|
||||
tilt
|
||||
haml-rails (0.5.3)
|
||||
|
|
@ -215,8 +218,8 @@ GEM
|
|||
rake (>= 10, < 13)
|
||||
rubocop (>= 0.47.0)
|
||||
sysexits (~> 1.1)
|
||||
hashie (2.1.1)
|
||||
hike (1.2.3)
|
||||
hashdiff (0.3.4)
|
||||
hashie (3.5.5)
|
||||
hoptoad_notifier (2.4.11)
|
||||
activesupport
|
||||
builder
|
||||
|
|
@ -225,14 +228,15 @@ GEM
|
|||
domain_name (~> 0.5)
|
||||
i18n (0.7.0)
|
||||
i18n_data (0.7.0)
|
||||
inversion (0.12.3)
|
||||
loggability (~> 0.4)
|
||||
inversion (1.0.0)
|
||||
loggability (~> 0.12)
|
||||
iso-639 (0.2.5)
|
||||
jquery-datatables-rails (2.2.3)
|
||||
jquery-rails
|
||||
sass-rails
|
||||
jquery-rails (3.1.4)
|
||||
railties (>= 3.0, < 5.0)
|
||||
jquery-rails (4.3.1)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-ui-rails (4.2.1)
|
||||
railties (>= 3.2.16)
|
||||
|
|
@ -249,25 +253,25 @@ GEM
|
|||
actionmailer (>= 3.2)
|
||||
letter_opener (~> 1.0)
|
||||
railties (>= 3.2)
|
||||
listen (2.7.2)
|
||||
celluloid (>= 0.15.2)
|
||||
celluloid-io (>= 0.15.0)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
loggability (0.11.0)
|
||||
listen (3.1.5)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
ruby_dep (~> 1.2)
|
||||
loggability (0.14.0)
|
||||
loofah (2.0.3)
|
||||
nokogiri (>= 1.5.9)
|
||||
lumberjack (1.0.5)
|
||||
mail (2.6.3)
|
||||
mime-types (>= 1.16, < 3)
|
||||
lumberjack (1.0.12)
|
||||
mail (2.6.6)
|
||||
mime-types (>= 1.16, < 4)
|
||||
method_source (0.8.2)
|
||||
mime-types (2.99.1)
|
||||
mime-types (2.99.3)
|
||||
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.10.1)
|
||||
mini_portile2 (2.3.0)
|
||||
minitest (5.10.2)
|
||||
momentjs-rails (2.8.1)
|
||||
railties (>= 3.1)
|
||||
monetize (1.4.0)
|
||||
|
|
@ -280,23 +284,26 @@ GEM
|
|||
monetize (~> 1.4.0)
|
||||
money (~> 6.7)
|
||||
railties (>= 3.0)
|
||||
multi_json (1.11.2)
|
||||
multi_json (1.12.1)
|
||||
multi_xml (0.5.5)
|
||||
multipart-post (2.0.0)
|
||||
mysql2 (0.4.2)
|
||||
mysql2 (0.4.9)
|
||||
nenv (0.3.0)
|
||||
netrc (0.11.0)
|
||||
nio4r (1.2.1)
|
||||
nokogiri (1.7.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
oauth2 (0.9.4)
|
||||
faraday (>= 0.8, < 0.10)
|
||||
nokogiri (1.8.1)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
notiffany (0.1.1)
|
||||
nenv (~> 0.1)
|
||||
shellany (~> 0.0)
|
||||
oauth2 (1.3.1)
|
||||
faraday (>= 0.8, < 0.12)
|
||||
jwt (~> 1.0)
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
rack (~> 1.2)
|
||||
omniauth (1.2.1)
|
||||
hashie (>= 1.2, < 3)
|
||||
rack (~> 1.0)
|
||||
rack (>= 1.2, < 3)
|
||||
omniauth (1.6.1)
|
||||
hashie (>= 3.4.6, < 3.6.0)
|
||||
rack (>= 1.6.2, < 3)
|
||||
omniauth-facebook (1.6.0)
|
||||
omniauth-oauth2 (~> 1.1)
|
||||
omniauth-github (1.1.2)
|
||||
|
|
@ -305,20 +312,19 @@ GEM
|
|||
omniauth-google-oauth2 (0.2.4)
|
||||
omniauth (~> 1.0)
|
||||
omniauth-oauth2 (~> 1.1)
|
||||
omniauth-oauth2 (1.1.2)
|
||||
faraday (>= 0.8, < 0.10)
|
||||
multi_json (~> 1.3)
|
||||
oauth2 (~> 0.9.3)
|
||||
omniauth-oauth2 (1.4.0)
|
||||
oauth2 (~> 1.0)
|
||||
omniauth (~> 1.2)
|
||||
omniauth-openid (1.0.1)
|
||||
omniauth (~> 1.0)
|
||||
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)
|
||||
parallel (1.11.2)
|
||||
parser (2.4.0.0)
|
||||
ast (~> 2.2)
|
||||
pdf-core (0.2.5)
|
||||
|
|
@ -336,29 +342,33 @@ 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)
|
||||
pry (0.9.12.6)
|
||||
coderay (~> 1.0)
|
||||
method_source (~> 0.8)
|
||||
pry (0.10.4)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
rack (1.6.4)
|
||||
public_suffix (2.0.5)
|
||||
rack (1.6.8)
|
||||
rack-openid (1.3.1)
|
||||
rack (>= 1.1.0)
|
||||
ruby-openid (>= 2.1.8)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (4.2.7.1)
|
||||
actionmailer (= 4.2.7.1)
|
||||
actionpack (= 4.2.7.1)
|
||||
actionview (= 4.2.7.1)
|
||||
activejob (= 4.2.7.1)
|
||||
activemodel (= 4.2.7.1)
|
||||
activerecord (= 4.2.7.1)
|
||||
activesupport (= 4.2.7.1)
|
||||
rails (4.2.9)
|
||||
actionmailer (= 4.2.9)
|
||||
actionpack (= 4.2.9)
|
||||
actionview (= 4.2.9)
|
||||
activejob (= 4.2.9)
|
||||
activemodel (= 4.2.9)
|
||||
activerecord (= 4.2.9)
|
||||
activesupport (= 4.2.9)
|
||||
bundler (>= 1.3.0, < 2.0)
|
||||
railties (= 4.2.7.1)
|
||||
railties (= 4.2.9)
|
||||
sprockets-rails
|
||||
rails-assets-bootstrap (3.3.6)
|
||||
rails-assets-jquery (>= 1.9.1, < 3)
|
||||
|
|
@ -388,65 +398,68 @@ GEM
|
|||
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
|
||||
rails_serve_static_assets (0.0.4)
|
||||
rails_stdout_logging (0.0.3)
|
||||
railties (4.2.7.1)
|
||||
actionpack (= 4.2.7.1)
|
||||
activesupport (= 4.2.7.1)
|
||||
railties (4.2.9)
|
||||
actionpack (= 4.2.9)
|
||||
activesupport (= 4.2.9)
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rainbow (2.2.1)
|
||||
rake (10.5.0)
|
||||
rb-fsevent (0.9.4)
|
||||
rb-inotify (0.9.4)
|
||||
ffi (>= 0.5.0)
|
||||
rdoc (4.1.1)
|
||||
json (~> 1.4)
|
||||
rdoc-generator-fivefish (0.1.0)
|
||||
inversion (~> 0.12)
|
||||
loggability (~> 0.6)
|
||||
rdoc (~> 4.0)
|
||||
yajl-ruby (~> 1.1)
|
||||
rainbow (2.2.2)
|
||||
rake
|
||||
rake (12.0.0)
|
||||
rb-fsevent (0.10.2)
|
||||
rb-inotify (0.9.10)
|
||||
ffi (>= 0.5.0, < 2)
|
||||
rdoc (5.1.0)
|
||||
rdoc-generator-fivefish (0.3.0)
|
||||
inversion (~> 1.0)
|
||||
loggability (~> 0.12)
|
||||
rdoc (~> 5.0)
|
||||
yajl-ruby (~> 1.3)
|
||||
redcarpet (3.2.3)
|
||||
referer-parser (0.2.1)
|
||||
request_store (1.1.0)
|
||||
responders (2.1.1)
|
||||
railties (>= 4.2.0, < 5.1)
|
||||
responders (2.4.0)
|
||||
actionpack (>= 4.2.0, < 5.3)
|
||||
railties (>= 4.2.0, < 5.3)
|
||||
rest-client (1.8.0)
|
||||
http-cookie (>= 1.0.2, < 2.0)
|
||||
mime-types (>= 1.16, < 3.0)
|
||||
netrc (~> 0.7)
|
||||
rolify (5.1.0)
|
||||
rspec (3.0.0)
|
||||
rspec-core (~> 3.0.0)
|
||||
rspec-expectations (~> 3.0.0)
|
||||
rspec-mocks (~> 3.0.0)
|
||||
rqrcode (0.10.1)
|
||||
chunky_png (~> 1.0)
|
||||
rspec (3.6.0)
|
||||
rspec-core (~> 3.6.0)
|
||||
rspec-expectations (~> 3.6.0)
|
||||
rspec-mocks (~> 3.6.0)
|
||||
rspec-activemodel-mocks (1.0.1)
|
||||
activemodel (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
rspec-mocks (>= 2.99, < 4.0)
|
||||
rspec-core (3.0.2)
|
||||
rspec-support (~> 3.0.0)
|
||||
rspec-expectations (3.0.2)
|
||||
rspec-core (3.6.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-expectations (3.6.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.0.0)
|
||||
rspec-mocks (3.0.2)
|
||||
rspec-support (~> 3.0.0)
|
||||
rspec-rails (3.0.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-mocks (3.6.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-rails (3.6.0)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec-core (~> 3.0.0)
|
||||
rspec-expectations (~> 3.0.0)
|
||||
rspec-mocks (~> 3.0.0)
|
||||
rspec-support (~> 3.0.0)
|
||||
rspec-support (3.0.2)
|
||||
rubocop (0.48.1)
|
||||
rspec-core (~> 3.6.0)
|
||||
rspec-expectations (~> 3.6.0)
|
||||
rspec-mocks (~> 3.6.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-support (3.6.0)
|
||||
rubocop (0.49.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.3.3.1, < 3.0)
|
||||
powerpack (~> 0.1)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
|
|
@ -455,16 +468,19 @@ GEM
|
|||
ruby-oembed (0.8.14)
|
||||
ruby-openid (2.5.0)
|
||||
ruby-progressbar (1.8.1)
|
||||
ruby_dep (1.5.0)
|
||||
rubyzip (1.2.1)
|
||||
safe_yaml (1.0.4)
|
||||
sass (3.2.19)
|
||||
sass-rails (4.0.4)
|
||||
railties (>= 4.0.0, < 5.0)
|
||||
sass (~> 3.2.2)
|
||||
sprockets (~> 2.8, < 2.12)
|
||||
sprockets-rails (~> 2.0)
|
||||
sass-rails (5.0.6)
|
||||
railties (>= 4.0.0, < 6)
|
||||
sass (~> 3.1)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
tilt (>= 1.1, < 3)
|
||||
selectize-rails (0.12.4)
|
||||
shoulda-matchers (2.6.1)
|
||||
shellany (0.0.1)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
simplecov (0.11.2)
|
||||
docile (~> 1.1.0)
|
||||
|
|
@ -478,11 +494,9 @@ GEM
|
|||
spring (1.6.3)
|
||||
spring-commands-rspec (1.0.4)
|
||||
spring (>= 0.9.1)
|
||||
sprockets (2.11.3)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sprockets (3.7.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (2.3.3)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
|
|
@ -501,7 +515,6 @@ GEM
|
|||
thread_safe (0.3.6)
|
||||
tilt (1.4.1)
|
||||
timecop (0.7.1)
|
||||
timers (1.1.0)
|
||||
tins (1.6.0)
|
||||
transitions (0.1.12)
|
||||
ttfunk (1.1.1)
|
||||
|
|
@ -514,7 +527,7 @@ GEM
|
|||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.2)
|
||||
unicode-display_width (1.2.1)
|
||||
unicode-display_width (1.3.0)
|
||||
unicode_utils (1.4.0)
|
||||
unobtrusive_flash (3.1.0)
|
||||
railties
|
||||
|
|
@ -527,9 +540,10 @@ GEM
|
|||
binding_of_caller (>= 0.7.2)
|
||||
railties (>= 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
webmock (1.20.4)
|
||||
webmock (3.0.1)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff
|
||||
websocket-driver (0.6.3)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.2)
|
||||
|
|
@ -550,7 +564,8 @@ DEPENDENCIES
|
|||
acts_as_list
|
||||
ahoy_matey
|
||||
autoprefixer-rails
|
||||
awesome_nested_set (~> 3.0.0.rc.5)
|
||||
awesome_nested_set (~> 3.1.3)
|
||||
axlsx!
|
||||
axlsx_rails
|
||||
bootstrap-sass (~> 3.3.4.1)
|
||||
bootstrap-switch-rails (~> 3.0.0)
|
||||
|
|
@ -578,7 +593,7 @@ DEPENDENCIES
|
|||
formtastic (~> 3.1.1)
|
||||
formtastic-bootstrap
|
||||
gravtastic
|
||||
guard-rspec (~> 4.2.8)
|
||||
guard-rspec
|
||||
haml-rails
|
||||
haml_lint (~> 0.24.0)
|
||||
hoptoad_notifier (~> 2.3)
|
||||
|
|
@ -594,6 +609,7 @@ DEPENDENCIES
|
|||
mini_magick
|
||||
money-rails
|
||||
mysql2
|
||||
nokogiri (>= 1.8.1)
|
||||
omniauth
|
||||
omniauth-facebook
|
||||
omniauth-github
|
||||
|
|
@ -603,8 +619,9 @@ DEPENDENCIES
|
|||
phantomjs
|
||||
piwik_analytics (~> 1.0.1)
|
||||
poltergeist
|
||||
prawn-qrcode (~> 0.2.2.1)
|
||||
prawn_rails
|
||||
rails (~> 4.2)
|
||||
rails (~> 4.2.8)
|
||||
rails-assets-bootstrap-markdown!
|
||||
rails-assets-date.format!
|
||||
rails-assets-holderjs!
|
||||
|
|
@ -617,15 +634,15 @@ 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 (~> 0.48.1)
|
||||
rspec-rails (~> 3.5, >= 3.5.2)
|
||||
rubocop (~> 0.49.0)
|
||||
ruby-oembed
|
||||
sass-rails (>= 4.0.2)
|
||||
selectize-rails
|
||||
|
|
@ -635,6 +652,7 @@ DEPENDENCIES
|
|||
sqlite3
|
||||
stripe
|
||||
stripe-ruby-mock
|
||||
thor (= 0.19.1)
|
||||
timecop
|
||||
transitions
|
||||
turbolinks
|
||||
|
|
@ -645,4 +663,4 @@ DEPENDENCIES
|
|||
whenever
|
||||
|
||||
BUNDLED WITH
|
||||
1.14.5
|
||||
1.15.4
|
||||
|
|
|
|||
51
INSTALL.md
51
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.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Translation
|
||||
We are using [Transifex] (https://www.transifex.com/opensuse-community/osem/) to manage our translations.
|
||||
We are using [Transifex](https://www.transifex.com/opensuse-community/osem/) to manage our translations.
|
||||
|
||||
We are also using the _Live_ feature of Transifex. That means that all strings from OSEM instances are automatically collected and are available for translating.
|
||||
>Automated collection only works if you use the API key (See at the end of this file)
|
||||
|
|
@ -7,7 +7,7 @@ We are also using the _Live_ feature of Transifex. That means that all strings f
|
|||
## 1. Translate
|
||||
* Start translating:
|
||||
|
||||
1. Navigate to the [project's page] (https://www.transifex.com/opensuse-community/osem)
|
||||
1. Navigate to the [project's page](https://www.transifex.com/opensuse-community/osem)
|
||||
2. Click **translation** button
|
||||
3. Select **language**
|
||||
4. Select **resource** (events.opensuse.org)
|
||||
|
|
@ -27,7 +27,7 @@ Eg. Assuming you have signed up yourself as a translator for OSEM, to translate
|
|||
|
||||
* How to request to publish translated strings
|
||||
|
||||
After you make sure that you have properly reviewed the newly translated strings (they need to be marked as **reviewed** otherwise they won't go live), you can open a [new issue] (https://github.com/openSUSE/osem/issues/new) with the following information:
|
||||
After you make sure that you have properly reviewed the newly translated strings (they need to be marked as **reviewed** otherwise they won't go live), you can open a [new issue](https://github.com/openSUSE/osem/issues/new) with the following information:
|
||||
|
||||
Title: [Transifex] Publish translation for EN
|
||||
|
||||
|
|
|
|||
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
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@ $(function() {
|
|||
}
|
||||
|
||||
function draw_line_chart(animation, $canvas){
|
||||
var options = get_animation({}, animation);
|
||||
var chart_data = create_dataset($canvas);
|
||||
var weeks = $canvas.parent().data('weeks');
|
||||
var data = {
|
||||
|
|
@ -63,10 +62,27 @@ $(function() {
|
|||
datasets : chart_data
|
||||
}
|
||||
|
||||
var options = get_animation(wholeNumberAxisFix(data), animation);
|
||||
var ctx = $canvas.get(0).getContext("2d");
|
||||
new Chart(ctx).Line(data, options);
|
||||
}
|
||||
|
||||
function wholeNumberAxisFix(data){
|
||||
var maxValue = false;
|
||||
for(datasetIndex = 0; datasetIndex < data.datasets.length; ++datasetIndex){
|
||||
var setMax = Math.max.apply(null, data.datasets[datasetIndex].data);
|
||||
if (maxValue === false || setMax > maxValue) maxValue = setMax;
|
||||
}
|
||||
|
||||
var steps = maxValue;
|
||||
var stepWidth = 1;
|
||||
if (maxValue > 10) {
|
||||
stepWidth = Math.floor(maxValue / 10);
|
||||
steps = Math.ceil(maxValue / stepWidth);
|
||||
}
|
||||
return { scaleOverride: true, scaleSteps: steps, scaleStepWidth: stepWidth, scaleStartValue: 0 };
|
||||
}
|
||||
|
||||
function create_dataset($canvas){
|
||||
var selected = getSelectedConferences($canvas);
|
||||
var chart_data = $canvas.parent().data('chart');
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
$(function () {
|
||||
$(document).ready(function() {
|
||||
$('.datatable').DataTable({
|
||||
// ajax: ...,
|
||||
stateSave: true,
|
||||
autoWidth: false,
|
||||
pagingType: 'full_numbers',
|
||||
"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
|
||||
});
|
||||
$('.datatable').DataTable({
|
||||
// ajax: ...,
|
||||
stateSave: true,
|
||||
autoWidth: false,
|
||||
pagingType: 'full_numbers',
|
||||
"lengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]],
|
||||
});
|
||||
|
||||
$('#versionstable').DataTable({
|
||||
pagingType: 'full_numbers',
|
||||
order: [[ 0, 'desc' ]]
|
||||
});
|
||||
$('#versionstable').DataTable({
|
||||
pagingType: 'full_numbers',
|
||||
order: [[ 0, 'desc' ]]
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -78,11 +78,12 @@ var Schedule = {
|
|||
};
|
||||
|
||||
$(document).ready( function() {
|
||||
// hide the remove button for unscheduled events
|
||||
// hide the remove button for unscheduled and non schedulable events
|
||||
$('.unscheduled-events .schedule-event-delete-button').hide();
|
||||
$('.non_schedulable .schedule-event-delete-button').hide();
|
||||
|
||||
// set events as draggable
|
||||
$('.schedule-event').draggable({
|
||||
$('.schedule-event').not('.non_schedulable').draggable({
|
||||
snap: '.schedule-room-slot',
|
||||
revertDuration: 200,
|
||||
revert: function (event, ui) {
|
||||
|
|
@ -99,7 +100,7 @@ $(document).ready( function() {
|
|||
});
|
||||
|
||||
// set room cells as droppable
|
||||
$('.schedule-room-slot').droppable({
|
||||
$('.schedule-room-slot').not('.non_schedulable .schedule-room-slot').droppable({
|
||||
accept: '.schedule-event',
|
||||
tolerance: "pointer",
|
||||
drop: function(event, ui) {
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ function update_price($this){
|
|||
// Calculate price for row
|
||||
var value = $this.val();
|
||||
var price = $('#price_' + id).text();
|
||||
$('#total_row_' + id).text(value * price);
|
||||
$('#total_row_' + id).text((value * price).toFixed(2));
|
||||
|
||||
// Calculate total price
|
||||
var total = 0;
|
||||
$('.total_row').each(function( index ) {
|
||||
total += parseInt($(this).text());
|
||||
total += parseFloat($(this).text());
|
||||
});
|
||||
$('#total_price').text(total);
|
||||
$('#total_price').text(total.toFixed(2));
|
||||
}
|
||||
|
||||
$( document ).ready(function() {
|
||||
|
|
|
|||
|
|
@ -20,14 +20,6 @@
|
|||
color: black;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
input[type=text],
|
||||
input[type=password] {
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
display: block;
|
||||
margin: auto;
|
||||
width: 255px;
|
||||
}
|
||||
.btn-group {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
|
|
@ -37,7 +29,7 @@
|
|||
}
|
||||
}
|
||||
.dropdown-menu {
|
||||
padding: 17px 17px 0px 17px;
|
||||
padding: 17px;
|
||||
min-width: 225px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -267,6 +267,10 @@ td.no-padding{
|
|||
font-size: 7px;
|
||||
}
|
||||
|
||||
.non_schedulable{
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* Small devices (tablets, 768px and up) */
|
||||
@media (min-width: 768px) {
|
||||
.room, .event-title{
|
||||
|
|
|
|||
|
|
@ -90,3 +90,17 @@ p.comment-body {
|
|||
.changeset{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.box{
|
||||
height: 230px;
|
||||
}
|
||||
|
||||
/* sidebar hamburger btn */
|
||||
.side-nav-btn{
|
||||
margin-left: 10px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.qr-image{
|
||||
margin-left: 120px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,22 @@ module Admin
|
|||
class BaseController < ApplicationController
|
||||
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
|
||||
|
|
|
|||
116
app/controllers/admin/booths_controller.rb
Normal file
116
app/controllers/admin/booths_controller.rb
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
module Admin
|
||||
class BoothsController < Admin::BaseController
|
||||
load_and_authorize_resource :conference, find_by: :short_title
|
||||
load_and_authorize_resource through: :conference
|
||||
|
||||
def index; end
|
||||
|
||||
def show; end
|
||||
|
||||
def new
|
||||
@url = admin_conference_booths_path(@conference.short_title)
|
||||
end
|
||||
|
||||
def create
|
||||
@url = admin_conference_booths_path(@conference.short_title)
|
||||
|
||||
@booth = @conference.booths.new(booth_params)
|
||||
|
||||
@booth.submitter = current_user
|
||||
|
||||
if @booth.save
|
||||
redirect_to admin_conference_booths_path,
|
||||
notice: 'Booth successfully created.'
|
||||
else
|
||||
flash.now[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}."
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@url = admin_conference_booth_path(@conference.short_title, @booth.id)
|
||||
end
|
||||
|
||||
def update
|
||||
@url = admin_conference_booth_path(@conference.short_title, @booth.id)
|
||||
|
||||
@booth.update_attributes(booth_params)
|
||||
|
||||
if @booth.save
|
||||
redirect_to admin_conference_booths_path,
|
||||
notice: "Successfully updated booth for #{@booth.title}."
|
||||
else
|
||||
flash.now[:error] = "An error prohibited the Booth for #{@booth.title} "\
|
||||
"#{@booth.errors.full_messages.join('. ')}."
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def accept
|
||||
@booth.accept!
|
||||
|
||||
if @booth.save
|
||||
if @conference.email_settings.send_on_booths_acceptance
|
||||
Mailbot.conference_booths_acceptance_mail(@booth).deliver
|
||||
end
|
||||
redirect_to admin_conference_booths_path(conference_id: @conference.short_title),
|
||||
notice: 'Booth successfully accepted!'
|
||||
else
|
||||
redirect_to admin_conference_booths_path(conference_id: @conference.short_title)
|
||||
flash[:error] = "Booth could not be accepted. #{@booth.errors.full_messages.to_sentence}."
|
||||
end
|
||||
end
|
||||
|
||||
def to_accept
|
||||
update_state(:to_accept, 'Booth to accept')
|
||||
end
|
||||
|
||||
def to_reject
|
||||
update_state(:to_reject, 'Booth to reject')
|
||||
end
|
||||
|
||||
def reject
|
||||
@booth.reject!
|
||||
|
||||
if @booth.save
|
||||
Mailbot.conference_booths_rejection_mail(@booth).deliver
|
||||
redirect_to admin_conference_booths_path(conference_id: @conference.short_title),
|
||||
notice: 'Booth successfully rejected.'
|
||||
else
|
||||
redirect_to admin_conference_booths_path(conference_id: @conference.short_title)
|
||||
flash[:error] = "Booth could not be rejected. #{@booth.errors.full_messages.to_sentence}."
|
||||
end
|
||||
end
|
||||
|
||||
def restart
|
||||
update_state(:restart, 'Booth is submitted')
|
||||
end
|
||||
|
||||
def cancel
|
||||
update_state(:cancel, 'Booth is canceled')
|
||||
end
|
||||
|
||||
def confirm
|
||||
update_state(:confirm, 'Booth successfully confirmed')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_state(transition, notice)
|
||||
alert = @booth.update_state(transition, notice)
|
||||
|
||||
if alert.blank?
|
||||
flash[:notice] = notice
|
||||
redirect_back_or_to(admin_conference_booths_path(conference_id: @conference.short_title)) && return
|
||||
else
|
||||
flash[:error] = alert
|
||||
return redirect_back_or_to(admin_conference_booths_path(conference_id: @conference.short_title)) && return
|
||||
end
|
||||
end
|
||||
|
||||
def booth_params
|
||||
params.require(:booth).permit(:title, :description, :reasoning, :state, :picture, :conference_id,
|
||||
:created_at, :updated_at, :submitter_relationship, :website_url, responsible_ids: [])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -2,23 +2,25 @@ 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.now[:error] = "Creating the call for papers failed. #{@cfp.errors.full_messages.join('. ')}."
|
||||
|
|
@ -27,14 +29,13 @@ module Admin
|
|||
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.now[:error] = "Updating call for papers failed. #{@cfp.errors.to_a.join('. ')}."
|
||||
|
|
@ -44,9 +45,9 @@ module Admin
|
|||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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,12 +62,17 @@ 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
|
||||
|
||||
def new
|
||||
@conference = Conference.new
|
||||
@organizations = Organization.accessible_by(current_ability, :update).pluck(:name, :id)
|
||||
end
|
||||
|
||||
def create
|
||||
|
|
@ -133,6 +145,20 @@ 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)
|
||||
|
|
@ -186,7 +212,7 @@ module Admin
|
|||
:vpositions_attributes, :use_volunteers, :color,
|
||||
:sponsorship_levels_attributes, :sponsors_attributes,
|
||||
:targets, :targets_attributes,
|
||||
:campaigns, :campaigns_attributes, :registration_limit)
|
||||
:campaigns, :campaigns_attributes, :registration_limit, :organization_id, :ticket_layout, :booth_limit)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ module Admin
|
|||
:send_on_conference_registration_dates_updated, :conference_registration_dates_updated_subject, :conference_registration_dates_updated_body,
|
||||
:send_on_venue_updated, :venue_updated_subject, :venue_updated_body,
|
||||
:send_on_cfp_dates_updated, :cfp_dates_updated_subject, :cfp_dates_updated_body,
|
||||
:send_on_program_schedule_public, :program_schedule_public_subject, :program_schedule_public_body)
|
||||
:send_on_program_schedule_public, :program_schedule_public_subject, :program_schedule_public_body,
|
||||
:send_on_booths_acceptance, :booths_acceptance_subject, :booths_acceptance_body,
|
||||
:send_on_booths_rejection, :booths_rejection_subject, :booths_rejection_body)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@ module Admin
|
|||
load_and_authorize_resource :program, through: :conference, singleton: true
|
||||
load_and_authorize_resource :event, through: :program
|
||||
load_and_authorize_resource :events_registration, only: :toggle_attendance
|
||||
# For some reason this doesn't work, so a workaround is used
|
||||
# load_and_authorize_resource :track, through: :program, only: [:index, :show, :edit]
|
||||
|
||||
before_action :get_event, except: [:index, :create, :new]
|
||||
before_action :get_tracks, only: [:index, :show, :edit]
|
||||
|
||||
# FIXME: The timezome should only be applied on output, otherwise
|
||||
# you get lost in timezone conversions...
|
||||
|
|
@ -16,8 +18,6 @@ module Admin
|
|||
end
|
||||
|
||||
def index
|
||||
@events = @program.events
|
||||
@tracks = @program.tracks
|
||||
@difficulty_levels = @program.difficulty_levels
|
||||
@event_types = @program.event_types
|
||||
@tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed)
|
||||
|
|
@ -43,7 +43,6 @@ module Admin
|
|||
end
|
||||
|
||||
def show
|
||||
@tracks = @program.tracks
|
||||
@event_types = @program.event_types
|
||||
@comments = @event.root_comments
|
||||
@comment_count = @event.comment_threads.count
|
||||
|
|
@ -58,7 +57,6 @@ module Admin
|
|||
|
||||
def edit
|
||||
@event_types = @program.event_types
|
||||
@tracks = Track.all
|
||||
@comments = @event.root_comments
|
||||
@comment_count = @event.comment_threads.count
|
||||
@user = @event.submitter
|
||||
|
|
@ -104,7 +102,7 @@ module Admin
|
|||
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(', ')}"
|
||||
flash.now[:error] = "Could not submit proposal: #{@event.errors.full_messages.join(', ')}"
|
||||
render action: 'new'
|
||||
end
|
||||
end
|
||||
|
|
@ -187,16 +185,6 @@ module Admin
|
|||
params.require(:comment).permit(:commentable, :body, :user_id)
|
||||
end
|
||||
|
||||
def get_event
|
||||
@event = @conference.program.events.find(params[:id])
|
||||
unless @event
|
||||
redirect_to admin_conference_program_events_path(conference_id: @conference.short_title),
|
||||
error: 'Error! Could not find event!'
|
||||
return
|
||||
end
|
||||
@event
|
||||
end
|
||||
|
||||
def update_state(transition, notice, mail = false, subject = false, send_mail = false)
|
||||
alert = @event.update_state(transition, mail, subject, send_mail, params[:send_mail].blank?)
|
||||
|
||||
|
|
@ -208,5 +196,9 @@ module Admin
|
|||
return redirect_back_or_to(admin_conference_program_events_path(conference_id: @conference.short_title)) && return
|
||||
end
|
||||
end
|
||||
|
||||
def get_tracks
|
||||
@tracks = Track.accessible_by(current_ability).where(program: @program).confirmed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
94
app/controllers/admin/organizations_controller.rb
Normal file
94
app/controllers/admin/organizations_controller.rb
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
module Admin
|
||||
class OrganizationsController < Admin::BaseController
|
||||
load_and_authorize_resource :organization
|
||||
before_action :verify_user, only: [:assign_org_admins, :unassign_org_admins]
|
||||
|
||||
def index
|
||||
@organizations = Organization.all
|
||||
end
|
||||
|
||||
def create
|
||||
@organization = Organization.new(organization_params)
|
||||
if @organization.save
|
||||
redirect_to admin_organizations_path,
|
||||
notice: 'Organization successfully created'
|
||||
else
|
||||
redirect_to new_admin_organization_path,
|
||||
error: @organization.errors.full_messages.join(', ')
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@organization = Organization.new
|
||||
end
|
||||
|
||||
def edit; end
|
||||
|
||||
def update
|
||||
if @organization.update_attributes(organization_params)
|
||||
redirect_to admin_organizations_path,
|
||||
notice: 'Organization successfully updated'
|
||||
else
|
||||
redirect_to edit_admin_organization_path(@organization),
|
||||
error: @organization.errors.full_messages.join(', ')
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @organization.destroy
|
||||
redirect_to admin_organizations_path,
|
||||
notice: 'Organization successfully destroyed'
|
||||
else
|
||||
redirect_to admin_organizations_path,
|
||||
error: 'Organization cannot be destroyed'
|
||||
end
|
||||
end
|
||||
|
||||
def assign_org_admins
|
||||
if @user.has_role? 'organization_admin', @organization
|
||||
flash[:error] = "User #{@user.email} already has the role organization admin"
|
||||
elsif @user.add_role 'organization_admin', @organization
|
||||
flash[:notice] = "Successfully added role organization admin to user #{@user.email}"
|
||||
else
|
||||
flash[:error] = "Coud not add role organization admin to #{@user.email}"
|
||||
end
|
||||
|
||||
redirect_to admins_admin_organization_path(@organization)
|
||||
end
|
||||
|
||||
def unassign_org_admins
|
||||
if @user.remove_role 'organization_admin', @organization
|
||||
flash[:notice] = "Successfully removed role organization admin from user #{@user.email}"
|
||||
else
|
||||
flash[:error] = "Could not remove role organization admin from user #{@user.email}"
|
||||
end
|
||||
|
||||
redirect_to admins_admin_organization_path(@organization)
|
||||
end
|
||||
|
||||
def admins
|
||||
@role = @organization.roles.first
|
||||
@users = @role.users
|
||||
render 'show_org_admins'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:email)
|
||||
end
|
||||
|
||||
def verify_user
|
||||
@user = User.find_by(email: user_params[:email])
|
||||
unless @user
|
||||
redirect_to admins_admin_organization_path(@organization),
|
||||
error: 'Could not find user. Please provide a valid email!'
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
def organization_params
|
||||
params.require(:organization).permit(:name, :description, :picture)
|
||||
end
|
||||
end
|
||||
end
|
||||
14
app/controllers/admin/physical_tickets_controller.rb
Normal file
14
app/controllers/admin/physical_tickets_controller.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
module Admin
|
||||
class PhysicalTicketsController < Admin::BaseController
|
||||
before_action :authenticate_user!
|
||||
load_resource :conference, find_by: :short_title
|
||||
load_and_authorize_resource
|
||||
authorize_resource :conference_registrations, class: Registration
|
||||
|
||||
def index
|
||||
@physical_tickets = @conference.physical_tickets
|
||||
@tickets_sold_distribution = @conference.tickets_sold_distribution
|
||||
@tickets_turnover_distribution = @conference.tickets_turnover_distribution
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -30,7 +30,7 @@ module Admin
|
|||
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 }
|
||||
format.js { render json: { errors: "The selected schedule couldn't be updated #{@program.errors.to_a.join('. ')}" }, status: 422 }
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@ module Admin
|
|||
class ReportsController < Admin::BaseController
|
||||
load_and_authorize_resource :conference, find_by: :short_title
|
||||
load_and_authorize_resource :program, through: :conference, singleton: true
|
||||
# For some reason this doesn't work, so a workaround is used
|
||||
# load_and_authorize_resource :event, through: :program
|
||||
|
||||
def index
|
||||
@events = @program.events
|
||||
@events = Event.accessible_by(current_ability).where(program: @program)
|
||||
@events_commercials = Commercial.where(commercialable_type: 'Event', commercialable_id: @events.pluck(:id))
|
||||
@events_missing_commercial = @events.where.not(id: @events_commercials.pluck(:commercialable_id))
|
||||
@events_with_requirements = @events.where.not(description: ['', nil])
|
||||
|
|
|
|||
|
|
@ -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_admin_conference_program_track_role_path(@conference.short_title, @track, @role.name)
|
||||
else
|
||||
toggle_user_admin_conference_role_path(@conference.short_title, @role.name)
|
||||
end
|
||||
@users = @role.users
|
||||
end
|
||||
|
||||
def edit
|
||||
@url = if @track
|
||||
admin_conference_program_track_role_path(@conference.short_title, @track, @role.name)
|
||||
else
|
||||
admin_conference_role_path(@conference.short_title, @role.name)
|
||||
end
|
||||
@users = @role.users
|
||||
end
|
||||
|
||||
|
|
@ -23,7 +35,13 @@ 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
|
||||
admin_conference_program_track_role_path(@conference.short_title, @track, @role.name)
|
||||
else
|
||||
admin_conference_role_path(@conference.short_title, @role.name)
|
||||
end
|
||||
|
||||
redirect_to url,
|
||||
notice: 'Successfully updated role ' + @role.name
|
||||
else
|
||||
@role.name = role_name
|
||||
|
|
@ -36,8 +54,14 @@ module Admin
|
|||
user = User.find_by(email: user_params[:email])
|
||||
state = user_params[:state]
|
||||
|
||||
url = if @track
|
||||
admin_conference_program_track_role_path(@conference.short_title, @track, @role.name)
|
||||
else
|
||||
admin_conference_role_path(@conference.short_title, @role.name)
|
||||
end
|
||||
|
||||
unless user
|
||||
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,7 +107,12 @@ module Admin
|
|||
# Set 'organizer' as default role, when there is no other selection
|
||||
@selection = params[:id] ? params[:id].parameterize.underscore : 'organizer'
|
||||
|
||||
@role = Role.find_by(name: @selection, resource: @conference)
|
||||
if @selection == 'track_organizer'
|
||||
@track = @conference.program.tracks.find_by(short_name: params[:track_id])
|
||||
@role = Role.find_by(name: @selection, resource: @track)
|
||||
else
|
||||
@role = Role.find_by(name: @selection, resource: @conference)
|
||||
end
|
||||
end
|
||||
|
||||
def role_params
|
||||
|
|
|
|||
|
|
@ -4,14 +4,21 @@ module Admin
|
|||
# the schedule of a conference, which should not be accessed in the first place
|
||||
load_and_authorize_resource :conference, find_by: :short_title
|
||||
load_and_authorize_resource :program, through: :conference, singleton: true
|
||||
load_and_authorize_resource :schedule, through: :program
|
||||
load_and_authorize_resource :schedule, through: :program, except: [:new, :create]
|
||||
load_resource :event_schedules, through: :schedule
|
||||
load_resource :selected_schedule, through: :program, singleton: true
|
||||
load_resource :venue, through: :conference, singleton: true
|
||||
|
||||
def index; end
|
||||
|
||||
def new
|
||||
@schedule = @program.schedules.build(track: @program.tracks.new)
|
||||
authorize! :new, @schedule
|
||||
end
|
||||
|
||||
def create
|
||||
@schedule = @program.schedules.new(schedule_params)
|
||||
authorize! :create, @schedule
|
||||
if @schedule.save
|
||||
redirect_to admin_conference_schedule_path(@conference.short_title, @schedule.id),
|
||||
notice: 'Schedule was successfully created.'
|
||||
|
|
@ -23,9 +30,24 @@ module Admin
|
|||
|
||||
def show
|
||||
@event_schedules = @schedule.event_schedules
|
||||
@unscheduled_events = @program.events.confirmed - @schedule.events
|
||||
@dates = @conference.start_date..@conference.end_date
|
||||
@rooms = @conference.venue.rooms if @conference.venue
|
||||
|
||||
if @schedule.track
|
||||
track = @schedule.track
|
||||
@unscheduled_events = track.events.confirmed - @schedule.events
|
||||
@dates = track.start_date..track.end_date
|
||||
@rooms = [track.room]
|
||||
else
|
||||
@program.tracks.self_organized.confirmed.each do |t|
|
||||
@event_schedules += t.selected_schedule.event_schedules if t.selected_schedule
|
||||
end
|
||||
self_organized_tracks_events = @program.tracks.self_organized.confirmed.map do |t|
|
||||
t.events.confirmed
|
||||
end
|
||||
self_organized_tracks_events.flatten.compact!
|
||||
@unscheduled_events = @program.events.confirmed - @schedule.events - self_organized_tracks_events
|
||||
@dates = @conference.start_date..@conference.end_date
|
||||
@rooms = @conference.venue.rooms if @conference.venue
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
|
@ -37,5 +59,11 @@ module Admin
|
|||
error: "Schedule couldn't be deleted. #{@schedule.errors.full_messages.join('. ')}."
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def schedule_params
|
||||
params.require(:schedule).permit(:track_id) if params[:schedule]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ module Admin
|
|||
:include_tracks, :include_program, :include_cfp,
|
||||
:include_venue, :include_registrations,
|
||||
:include_tickets, :include_lodgings,
|
||||
:include_sponsors, :include_social_media)
|
||||
:include_sponsors, :include_social_media,
|
||||
:include_booths)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
16
app/controllers/admin/ticket_scannings_controller.rb
Normal file
16
app/controllers/admin/ticket_scannings_controller.rb
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
module Admin
|
||||
class TicketScanningsController < Admin::BaseController
|
||||
before_action :authenticate_user!
|
||||
load_resource :physical_ticket, find_by: :token
|
||||
# We authorize manually in these actions
|
||||
skip_authorize_resource only: [:create]
|
||||
|
||||
def create
|
||||
@ticket_scanning = TicketScanning.new(physical_ticket: @physical_ticket)
|
||||
authorize! :create, @ticket_scanning
|
||||
@ticket_scanning.save
|
||||
redirect_to conferences_path,
|
||||
notice: "Ticket with token #{@physical_ticket.token} successfully scanned."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,6 +5,8 @@ module Admin
|
|||
|
||||
def index
|
||||
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
|
||||
|
|
@ -48,7 +50,7 @@ module Admin
|
|||
private
|
||||
|
||||
def ticket_params
|
||||
params.require(:ticket).permit(:conference, :title, :url, :description, :conference_id, :price_cents, :price_currency, :price)
|
||||
params.require(:ticket).permit(:conference, :title, :url, :description, :conference_id, :price_cents, :price_currency, :price, :registration_ticket)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,10 @@ 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
|
||||
|
||||
# Show flash message with ajax calls
|
||||
after_action :prepare_unobtrusive_flash, only: :toggle_cfp_inclusion
|
||||
|
||||
def index; end
|
||||
|
||||
|
|
@ -19,6 +22,8 @@ module Admin
|
|||
|
||||
def create
|
||||
@track = @program.tracks.new(track_params)
|
||||
@track.state = 'confirmed'
|
||||
@track.cfp_active = true
|
||||
if @track.save
|
||||
redirect_to admin_conference_program_tracks_path(conference_id: @conference.short_title),
|
||||
notice: 'Track successfully created.'
|
||||
|
|
@ -50,10 +55,80 @@ module Admin
|
|||
end
|
||||
end
|
||||
|
||||
def toggle_cfp_inclusion
|
||||
@track.cfp_active = !@track.cfp_active
|
||||
if @track.save
|
||||
flash[:notice] = "Successfully changed cfp inclusion of #{@track.name} to #{@track.cfp_active}"
|
||||
else
|
||||
flash[:error] = "Failed to toggle cfp inclusion of #{@track.name} to #{@track.cfp_active}"
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
def restart
|
||||
update_state(:restart, "Review for #{@track.name} started!")
|
||||
end
|
||||
|
||||
def to_accept
|
||||
update_state(:to_accept, "Track #{@track.name} marked as a possible acceptance!")
|
||||
end
|
||||
|
||||
def accept
|
||||
if @track.room && @track.start_date && @track.end_date
|
||||
update_state(:accept, "Track #{@track.name} accepted!")
|
||||
else
|
||||
flash[:alert] = 'Please make sure that the track has a room and start/end dates before accepting it'
|
||||
redirect_to edit_admin_conference_program_track_path(@conference.short_title, @track)
|
||||
end
|
||||
end
|
||||
|
||||
def confirm
|
||||
update_state(:confirm, "Track #{@track.name} confirmed!")
|
||||
end
|
||||
|
||||
def to_reject
|
||||
update_state(:to_reject, "Track #{@track.name} marked as a possible rejection!")
|
||||
end
|
||||
|
||||
def reject
|
||||
update_state(:reject, "Track #{@track.name} rejected!")
|
||||
end
|
||||
|
||||
def cancel
|
||||
update_state(:cancel, "Track #{@track.name} canceled!")
|
||||
end
|
||||
|
||||
def update_selected_schedule
|
||||
if @track.update_attributes(params.require(:track).permit(:selected_schedule_id))
|
||||
respond_to do |format|
|
||||
format.js { render json: {} }
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
format.js { render json: { errors: "The selected schedule couldn't be updated #{@track.errors.to_a.join('. ')}" }, status: 422 }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def track_params
|
||||
params.require(:track).permit(:name, :description, :color)
|
||||
params.require(:track).permit(:name, :description, :color, :short_name, :cfp_active, :start_date, :end_date, :room_id)
|
||||
end
|
||||
|
||||
def update_state(transition, notice)
|
||||
errors = @track.update_state(transition)
|
||||
|
||||
if errors.blank?
|
||||
flash[:notice] = notice
|
||||
else
|
||||
flash[:error] = errors
|
||||
end
|
||||
|
||||
redirect_back_or_to(admin_conference_program_tracks_path(conference_id: @conference.short_title))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,17 +1,21 @@
|
|||
module Admin
|
||||
class VersionsController < Admin::BaseController
|
||||
skip_authorization_check
|
||||
load_resource :conference, find_by: :short_title, only: :index
|
||||
load_and_authorize_resource class: PaperTrail::Version
|
||||
|
||||
def index
|
||||
authorize! :index, PaperTrail::Version.new(item_type: 'User')
|
||||
conf_ids_for_organizer = current_user.is_admin? ? Conference.pluck(:id) : Conference.with_role(:organizer, current_user).pluck(:id)
|
||||
@versions = PaperTrail::Version.where(["conference_id IN (?) OR item_type = 'User'", conf_ids_for_organizer])
|
||||
@conferences_with_role = current_user.is_admin? ? Conference.pluck(:short_title) : Conference.with_role([:organizer, :cfp, :info_desk], current_user).pluck(:short_title)
|
||||
|
||||
if current_user.has_role? :organization_admin, :any
|
||||
@conferences_with_role = Organization.with_role('organization_admin', current_user).map { |org| org.conferences.pluck :short_title }.flatten
|
||||
end
|
||||
@conferences_with_role.uniq!
|
||||
|
||||
return if @conference.blank?
|
||||
@versions = PaperTrail::Version.where(conference_id: @conference.id).accessible_by(current_ability)
|
||||
end
|
||||
|
||||
def revert_attribute
|
||||
@version = PaperTrail::Version.find(params[:id])
|
||||
authorize! :revert_attribute, @version
|
||||
|
||||
if params[:attribute] && @version.changeset.reject{ |_, values| values[0].blank? && values[1].blank? }.keys.include?(params[:attribute])
|
||||
if @version.item[params[:attribute]] == @version.changeset[params[:attribute]][0]
|
||||
flash[:error] = 'The item is already in the state that you are trying to revert it back to'
|
||||
|
|
@ -33,9 +37,6 @@ module Admin
|
|||
end
|
||||
|
||||
def revert_object
|
||||
@version = PaperTrail::Version.find(params[:id])
|
||||
authorize! :revert_object, @version
|
||||
|
||||
if @version.event != 'create'
|
||||
if @version.reify.save
|
||||
flash[:notice] = 'The selected change was successfully reverted'
|
||||
|
|
|
|||
|
|
@ -13,11 +13,11 @@ module Admin
|
|||
|
||||
def show
|
||||
if can_manage_volunteers?(@conference)
|
||||
if @conference.use_vpositions
|
||||
@volunteers = @conference.registrations.joins(:vchoices).uniq
|
||||
else
|
||||
@volunteers = @conference.registrations.where(volunteer: true)
|
||||
end
|
||||
@volunteers = if @conference.use_vpositions
|
||||
@conference.registrations.joins(:vchoices).uniq
|
||||
else
|
||||
@conference.registrations.where(volunteer: true)
|
||||
end
|
||||
else
|
||||
authorize! :index, :volunteer
|
||||
end
|
||||
|
|
|
|||
97
app/controllers/booths_controller.rb
Normal file
97
app/controllers/booths_controller.rb
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
class BoothsController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
load_resource :conference, find_by: :short_title
|
||||
load_and_authorize_resource through: :conference
|
||||
skip_authorize_resource only: [:withdraw, :confirm, :restart]
|
||||
|
||||
def index
|
||||
@booths = current_user.booths.where(conference_id: @conference.id).uniq
|
||||
end
|
||||
|
||||
def show; end
|
||||
|
||||
def new
|
||||
@url = conference_booths_path(@conference.short_title)
|
||||
end
|
||||
|
||||
def create
|
||||
@url = conference_booths_path(@conference.short_title)
|
||||
|
||||
@booth.submitter = current_user
|
||||
|
||||
if @booth.save
|
||||
redirect_to conference_booths_path,
|
||||
notice: 'Booth successfully created.'
|
||||
else
|
||||
flash.now[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}."
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@url = conference_booth_path(@conference.short_title, @booth.id)
|
||||
end
|
||||
|
||||
def update
|
||||
@url = conference_booth_path(@conference.short_title, @booth.id)
|
||||
@booth.update_attributes(booth_params)
|
||||
|
||||
if @booth.save
|
||||
redirect_to conference_booths_path,
|
||||
notice: 'Booth successfully updated!'
|
||||
else
|
||||
flash.now[:error] = "Booth could not be updated. #{@booth.errors.full_messages.to_sentence}."
|
||||
end
|
||||
end
|
||||
|
||||
def destroy; end
|
||||
|
||||
def withdraw
|
||||
authorize! :update, @booth
|
||||
@url = conference_booth_path(@conference.short_title, @booth.id)
|
||||
|
||||
@booth.withdraw!
|
||||
|
||||
if @booth.save
|
||||
redirect_to conference_booths_path,
|
||||
notice: 'Booth successfully withdrawn'
|
||||
else
|
||||
flash.now[:error] = "Booth could not be withdrawn. #{@booth.errors.full_messages.to_sentence}."
|
||||
end
|
||||
end
|
||||
|
||||
def confirm
|
||||
authorize! :update, @booth
|
||||
@url = conference_booth_path(@conference.short_title, @booth.id)
|
||||
|
||||
@booth.confirm!
|
||||
|
||||
if @booth.save
|
||||
redirect_to conference_booths_path,
|
||||
notice: 'Booth successfully confirmed'
|
||||
else
|
||||
flash.now[:error] = "Booth could not be confirmed. #{@booth.errors.full_messages.to_sentence}."
|
||||
end
|
||||
end
|
||||
|
||||
def restart
|
||||
authorize! :update, @booth
|
||||
@url = conference_booth_path(@conference.short_title, @booth.id)
|
||||
|
||||
@booth.restart!
|
||||
|
||||
if @booth.save
|
||||
redirect_to conference_booths_path,
|
||||
notice: 'Booth successfully re-submitted'
|
||||
else
|
||||
flash.now[:error] = "Booth could not be re-submitted. #{@booth.errors.full_messages.to_sentence}."
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def booth_params
|
||||
params.require(:booth).permit(:title, :description, :reasoning, :state, :picture, :conference_id,
|
||||
:created_at, :updated_at, :submitter_relationship, :website_url, responsible_ids: [])
|
||||
end
|
||||
end
|
||||
|
|
@ -27,8 +27,9 @@ class ConferenceRegistrationsController < ApplicationController
|
|||
end
|
||||
|
||||
def show
|
||||
@total_price = Ticket.total_price(@conference, current_user, paid: true)
|
||||
@total_price = Ticket.total_price_user(@conference, current_user, paid: true)
|
||||
@tickets = current_user.ticket_purchases.by_conference(@conference).paid
|
||||
@total_price_per_ticket = @tickets.group(:ticket_id).sum('amount_paid * quantity')
|
||||
@ticket_payments = @tickets.group_by(&:ticket_id)
|
||||
@total_quantity = @tickets.group(:ticket_id).sum(:quantity)
|
||||
end
|
||||
|
|
@ -38,12 +39,12 @@ class ConferenceRegistrationsController < ApplicationController
|
|||
def create
|
||||
@registration = @conference.registrations.new(registration_params)
|
||||
|
||||
if current_user.nil?
|
||||
# @user variable needs to be set so that _sign_up_form_embedded works properly
|
||||
@user = @registration.build_user(user_params)
|
||||
else
|
||||
@user = current_user
|
||||
end
|
||||
@user = if current_user.nil?
|
||||
# @user variable needs to be set so that _sign_up_form_embedded works properly
|
||||
@registration.build_user(user_params)
|
||||
else
|
||||
current_user
|
||||
end
|
||||
|
||||
@registration.user = @user
|
||||
authorize! :create, @registration
|
||||
|
|
|
|||
|
|
@ -1,18 +1,29 @@
|
|||
class ConferencesController < ApplicationController
|
||||
protect_from_forgery with: :null_session
|
||||
before_action :respond_to_options
|
||||
load_and_authorize_resource find_by: :short_title
|
||||
load_resource :program, through: :conference, singleton: true, except: :index
|
||||
load_and_authorize_resource find_by: :short_title, except: :show
|
||||
|
||||
def index
|
||||
@current = Conference.where('end_date >= ?', Date.current).reorder(start_date: :asc)
|
||||
@antiquated = @conferences - @current
|
||||
end
|
||||
|
||||
def show; end
|
||||
def show
|
||||
@conference = if params[:id]
|
||||
Conference.find_by_short_title(params[:id])
|
||||
else
|
||||
load_conference_by_domain
|
||||
end
|
||||
authorize! :show, @conference
|
||||
@program = @conference.program
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_conference_by_domain
|
||||
Conference.find_by(custom_domain: request.domain)
|
||||
end
|
||||
|
||||
def respond_to_options
|
||||
respond_to do |format|
|
||||
format.html { head :ok }
|
||||
|
|
|
|||
9
app/controllers/openids_controller.rb
Normal file
9
app/controllers/openids_controller.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
class OpenidsController < ApplicationController
|
||||
load_and_authorize_resource :user
|
||||
load_and_authorize_resource through: :user
|
||||
|
||||
def destroy
|
||||
@openid.destroy
|
||||
redirect_to :back
|
||||
end
|
||||
end
|
||||
7
app/controllers/organizations_controller.rb
Normal file
7
app/controllers/organizations_controller.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
class OrganizationsController < ApplicationController
|
||||
load_and_authorize_resource :organization
|
||||
|
||||
def index
|
||||
@organizations = Organization.all
|
||||
end
|
||||
end
|
||||
|
|
@ -10,6 +10,9 @@ class PaymentsController < ApplicationController
|
|||
|
||||
def new
|
||||
@total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false)
|
||||
if @total_amount_to_pay.zero?
|
||||
raise CanCan::AccessDenied.new('Nothing to pay for!', :new, Payment)
|
||||
end
|
||||
@unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference)
|
||||
end
|
||||
|
||||
|
|
@ -18,7 +21,7 @@ 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_tickets_path,
|
||||
notice: 'Thanks! Your ticket is booked successfully.'
|
||||
else
|
||||
@total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false)
|
||||
|
|
@ -38,6 +41,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
|
||||
|
|
|
|||
28
app/controllers/physical_tickets_controller.rb
Normal file
28
app/controllers/physical_tickets_controller.rb
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
class PhysicalTicketsController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
load_resource :conference, find_by: :short_title
|
||||
load_and_authorize_resource find_by: :token
|
||||
authorize_resource :conference_registrations, class: Registration
|
||||
|
||||
def index
|
||||
@physical_tickets = current_user.physical_tickets.by_conference(@conference)
|
||||
@unpaid_ticket_purchases = current_user.ticket_purchases.by_conference(@conference).unpaid
|
||||
end
|
||||
|
||||
def show
|
||||
@file_name = "ticket_for_#{@conference.short_title}"
|
||||
@user = @physical_ticket.user
|
||||
@ticket_layout = @conference.ticket_layout.to_sym
|
||||
@qrcode_image = RQRCode::QRCode.new(@physical_ticket.token).as_png(size: 180, border_modules: 0)
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.pdf do
|
||||
pdf = TicketPdf.new(@conference, @user, @physical_ticket, @ticket_layout, @file_name)
|
||||
send_data pdf.render,
|
||||
filename: @file_name,
|
||||
type: 'application/pdf',
|
||||
disposition: 'attachment'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -49,6 +49,14 @@ class ProposalsController < ApplicationController
|
|||
# by default.
|
||||
@event.speakers = [current_user]
|
||||
@event.submitter = current_user
|
||||
|
||||
track = Track.find_by(id: params[:event][:track_id])
|
||||
if track && !track.cfp_active
|
||||
flash.now[:error] = 'You have selected a track that doesn\'t accept proposals'
|
||||
render action: 'new'
|
||||
return
|
||||
end
|
||||
|
||||
if @event.save
|
||||
ahoy.track 'Event submission', title: 'New submission'
|
||||
redirect_to conference_program_proposals_path(@conference.short_title), notice: 'Proposal was successfully submitted.'
|
||||
|
|
@ -61,6 +69,13 @@ class ProposalsController < ApplicationController
|
|||
def update
|
||||
@url = conference_program_proposal_path(@conference.short_title, params[:id])
|
||||
|
||||
track = Track.find_by(id: params[:event][:track_id])
|
||||
if track && !track.cfp_active
|
||||
flash.now[:error] = 'You have selected a track that doesn\'t accept proposals'
|
||||
render action: 'edit'
|
||||
return
|
||||
end
|
||||
|
||||
if @event.update(event_params)
|
||||
redirect_to conference_program_proposals_path(conference_id: @conference.short_title),
|
||||
notice: 'Proposal was successfully updated.'
|
||||
|
|
|
|||
|
|
@ -21,9 +21,16 @@ class SchedulesController < ApplicationController
|
|||
# the schedule takes you to today if it is a date of the schedule
|
||||
@current_day = @conference.current_conference_day
|
||||
@day = @current_day.present? ? @current_day : @dates.first
|
||||
return unless @current_day
|
||||
# the schedule takes you to the current time if it is beetween the start and the end time.
|
||||
@hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour)
|
||||
unless @current_day
|
||||
# the schedule takes you to the current time if it is beetween the start and the end time.
|
||||
@hour_column = @conference.hours_from_start_time(@conf_start, @conference.end_hour)
|
||||
end
|
||||
# Ids of the schedules of confrmed self_organized tracks along with the selected_schedule_id
|
||||
@selected_schedules_ids = [@conference.program.selected_schedule_id]
|
||||
@conference.program.tracks.self_organized.confirmed.each do |track|
|
||||
@selected_schedules_ids << track.selected_schedule_id
|
||||
end
|
||||
@selected_schedules_ids.compact!
|
||||
end
|
||||
|
||||
def events
|
||||
|
|
@ -32,11 +39,7 @@ class SchedulesController < ApplicationController
|
|||
@events_schedules = @program.selected_event_schedules
|
||||
@events_schedules = [] unless @events_schedules
|
||||
|
||||
@unscheduled_events = if @program.selected_schedule
|
||||
@program.events.confirmed - @program.selected_schedule.events
|
||||
else
|
||||
@program.events.confirmed
|
||||
end
|
||||
@unscheduled_events = @program.events.confirmed - @events_schedules.map(&:event)
|
||||
|
||||
day = @conference.current_conference_day
|
||||
@tag = day.strftime('%Y-%m-%d') if day
|
||||
|
|
|
|||
|
|
@ -5,17 +5,19 @@ class SubscriptionsController < ApplicationController
|
|||
|
||||
def create
|
||||
@subscription = current_user.subscriptions.build(conference_id: @conference.id)
|
||||
if @subscription.save!
|
||||
redirect_to root_path, notice: "You have been subscribed to receive email notifications for #{@conference.short_title}."
|
||||
if @subscription.save
|
||||
redirect_to root_path, notice: "You have subscribed to receive email notifications for #{@conference.title}."
|
||||
else
|
||||
redirect_to root_path, error: subscription.errors.full_messages.to_sentence
|
||||
redirect_to root_path, error: @subscription.errors.full_messages.to_sentence
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@subscription = current_user.subscriptions.find_by(conference_id: @conference.id)
|
||||
|
||||
redirect_to(root_path, error: "You are not subscribed to #{@conference.title}.") && return unless @subscription
|
||||
if @subscription.destroy
|
||||
redirect_to root_path, notice: "You have been unsubscribed and now you will not be receiving email notifications for #{@conference.short_title}."
|
||||
redirect_to root_path, notice: "You have unsubscribed and you will not be receiving email notifications for #{@conference.title}."
|
||||
else
|
||||
redirect_to root_path, error: @subscription.errors.full_messages.to_sentence
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ class TicketPurchasesController < ApplicationController
|
|||
before_filter :authenticate_user!
|
||||
load_resource :conference, find_by: :short_title
|
||||
authorize_resource :conference_registrations, class: Registration
|
||||
authorize_resource
|
||||
|
||||
def create
|
||||
current_user.ticket_purchases.by_conference(@conference).unpaid.destroy_all
|
||||
|
|
@ -11,18 +12,22 @@ 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_tickets_path,
|
||||
notice: 'You have free tickets for the conference.'
|
||||
else
|
||||
redirect_to conference_tickets_path(@conference.short_title),
|
||||
error: 'Please get at least one ticket to continue.'
|
||||
end
|
||||
else
|
||||
redirect_to conference_conference_registration_path(@conference.short_title),
|
||||
redirect_to conference_tickets_path(@conference.short_title),
|
||||
error: "Oops, something went wrong with your purchase! #{message}"
|
||||
end
|
||||
end
|
||||
|
||||
def index
|
||||
@unpaid_ticket_purchases = current_user.ticket_purchases.by_conference(@conference).unpaid
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ticket_purchase_params
|
||||
|
|
|
|||
70
app/controllers/tracks_controller.rb
Normal file
70
app/controllers/tracks_controller.rb
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
class TracksController < ApplicationController
|
||||
load_resource :conference, find_by: :short_title
|
||||
load_resource :program, through: :conference, singleton: true
|
||||
load_and_authorize_resource through: :program, find_by: :short_name
|
||||
|
||||
def index
|
||||
@tracks = @tracks.where(submitter: current_user)
|
||||
end
|
||||
|
||||
def show; end
|
||||
|
||||
def new
|
||||
@track = @program.tracks.new(color: @conference.next_color_for_collection(:tracks))
|
||||
end
|
||||
|
||||
def edit; end
|
||||
|
||||
def create
|
||||
@track = @program.tracks.new(track_params)
|
||||
@track.submitter = current_user
|
||||
@track.cfp_active = false
|
||||
if @track.save
|
||||
redirect_to conference_program_tracks_path(conference_id: @conference.short_title),
|
||||
notice: 'Track request successfully created.'
|
||||
else
|
||||
flash.now[:error] = "Creating Track request failed: #{@track.errors.full_messages.join('. ')}."
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
if @track.update_attributes(track_params)
|
||||
redirect_to conference_program_tracks_path(conference_id: @conference.short_title),
|
||||
notice: 'Track request successfully updated.'
|
||||
else
|
||||
flash.now[:error] = "Track request update failed: #{@track.errors.full_messages.join('. ')}."
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def restart
|
||||
update_state(:restart, "Track #{@track.name} re-submitted.")
|
||||
end
|
||||
|
||||
def confirm
|
||||
update_state(:confirm, "Track #{@track.name} confirmed.")
|
||||
end
|
||||
|
||||
def withdraw
|
||||
update_state(:withdraw, "Track #{@track.name} withdrawn.")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def track_params
|
||||
params.require(:track).permit(:name, :description, :color, :short_name, :start_date, :end_date, :relevance)
|
||||
end
|
||||
|
||||
def update_state(transition, notice)
|
||||
errors = @track.update_state(transition)
|
||||
|
||||
if errors.blank?
|
||||
flash[:notice] = notice
|
||||
else
|
||||
flash[:error] = errors
|
||||
end
|
||||
|
||||
redirect_back_or_to(conference_program_tracks_path(conference_id: @conference.short_title))
|
||||
end
|
||||
end
|
||||
|
|
@ -11,13 +11,13 @@ module Users
|
|||
|
||||
def handle(provider)
|
||||
auth_hash = request.env['omniauth.auth']
|
||||
uid = auth_hash[:uid]
|
||||
username = auth_hash.info.email.split('@')[0]
|
||||
openid = Openid.find_for_oauth(auth_hash) # Get or create openid
|
||||
# If openid exists and is associated with a user, sign in with associated user,
|
||||
# even if the email of the associated user and the email of the provided openid are different
|
||||
unless (user = openid.user)
|
||||
user = User.find_for_auth(auth_hash, current_user) # Get or create users
|
||||
user.username = "#{uid}@#{provider}" if user.username.blank?
|
||||
user.username = "#{username}@#{provider}" if user.username.blank?
|
||||
end
|
||||
|
||||
begin
|
||||
|
|
|
|||
|
|
@ -33,6 +33,11 @@ module ApplicationHelper
|
|||
result
|
||||
end
|
||||
|
||||
# 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)
|
||||
def resource_name
|
||||
:user
|
||||
|
|
@ -51,7 +56,7 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def tracks(conference)
|
||||
all = conference.program.tracks.map {|t| t.name}
|
||||
all = conference.program.tracks.confirmed.cfp_active.pluck(:name)
|
||||
first = all[0...-1]
|
||||
last = all[-1]
|
||||
ts = ''
|
||||
|
|
@ -93,25 +98,6 @@ module ApplicationHelper
|
|||
.reverse.sub(',', ' dna ').reverse
|
||||
end
|
||||
|
||||
# Recieves a model_name and id
|
||||
# Returns nil if model_name is invalid
|
||||
# Returns object in its current state if its alive
|
||||
# Otherwise Returns object state just before deletion
|
||||
def current_or_last_object_state(model_name, id)
|
||||
return nil unless id.present? && model_name.present?
|
||||
begin
|
||||
object = model_name.constantize.find_by(id: id)
|
||||
rescue NameError
|
||||
return nil
|
||||
end
|
||||
|
||||
if object.nil?
|
||||
object_last_version = PaperTrail::Version.where(item_type: model_name, item_id: id).last
|
||||
object = object_last_version.reify if object_last_version
|
||||
end
|
||||
object
|
||||
end
|
||||
|
||||
def normalize_array_length(hashmap, length)
|
||||
hashmap.each do |_, value|
|
||||
if value.length < length
|
||||
|
|
@ -131,7 +117,7 @@ module ApplicationHelper
|
|||
|
||||
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)
|
||||
event_schedule = event.program.selected_event_schedules.find { |es| es.event == event }
|
||||
other_event_schedules = event.program.selected_event_schedules.reject { |other_event_schedule| other_event_schedule == event_schedule }
|
||||
concurrent_events = []
|
||||
|
||||
|
|
@ -147,7 +133,7 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def speaker_links(event)
|
||||
event.speakers.map{ |speaker| link_to speaker.name, admin_user_path(speaker) }.join(', ').html_safe
|
||||
safe_join(event.speakers.map{ |speaker| link_to speaker.name, admin_user_path(speaker) }, ',')
|
||||
end
|
||||
|
||||
def speaker_selector_input(form)
|
||||
|
|
@ -157,6 +143,14 @@ module ApplicationHelper
|
|||
include_blank: false, label: 'Speakers', input_html: { class: 'select-help-toggle', multiple: 'true' }
|
||||
end
|
||||
|
||||
def responsibles_selector_input(form)
|
||||
users = User.active.pluck(:id, :name, :username, :email).map { |user| [user[0], user[1].blank? ? user[2] : user[1], user[2], user[3]] }.sort_by { |user| user[1].downcase }
|
||||
form.input :responsibles, as: :select,
|
||||
collection: options_for_select(users.map {|user| ["#{user[1]} (#{user[2]}) #{user[3]}", user[0]]}, @booth.responsibles.map(&:id)),
|
||||
include_blank: false, label: 'Responsibles', input_html: { class: 'select-help-toggle', multiple: 'true' },
|
||||
hint: 'The people responsible for the booth. You can only select existing users.'
|
||||
end
|
||||
|
||||
def event_types(conference)
|
||||
conference.program.event_types.map { |et| et.title.pluralize }.to_sentence
|
||||
end
|
||||
|
|
@ -168,4 +162,13 @@ module ApplicationHelper
|
|||
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
|
||||
|
|
|
|||
|
|
@ -39,4 +39,12 @@ module EventsHelper
|
|||
content_tag :span, 'REPLACEMENT', class: (['label', 'label-info'] + label_classes)
|
||||
end
|
||||
end
|
||||
|
||||
def track_selector_input(form)
|
||||
if @program.tracks.confirmed.cfp_active.any?
|
||||
form.input :track_id, as: :select,
|
||||
collection: @program.tracks.confirmed.cfp_active.pluck(:name, :id),
|
||||
include_blank: '(Please select)'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -15,6 +15,19 @@ module FormatHelper
|
|||
end
|
||||
end
|
||||
|
||||
def booth_status_icon(booth)
|
||||
case booth.state
|
||||
when 'new', 'to_reject', 'to_accept'
|
||||
'fa-eye'
|
||||
when 'accepted'
|
||||
'fa-check text-muted'
|
||||
when 'confirmed'
|
||||
'fa-check text-success'
|
||||
when 'rejected', 'withdrawn', 'canceled'
|
||||
'fa-ban'
|
||||
end
|
||||
end
|
||||
|
||||
def event_progress_color(progress)
|
||||
progress = progress.to_i
|
||||
if progress == 100
|
||||
|
|
@ -102,13 +115,12 @@ module FormatHelper
|
|||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Lint/EndAlignment
|
||||
def word_pluralize(count, singular, plural = nil)
|
||||
word = if (count == 1 || count =~ /^1(\.0+)?$/)
|
||||
singular
|
||||
else
|
||||
plural || singular.pluralize
|
||||
end
|
||||
singular
|
||||
else
|
||||
plural || singular.pluralize
|
||||
end
|
||||
|
||||
"#{word}"
|
||||
end
|
||||
|
|
@ -176,7 +188,7 @@ module FormatHelper
|
|||
(schedule == @selected_schedule) ? 'Yes' : 'No'
|
||||
end
|
||||
|
||||
def markdown(text)
|
||||
def markdown(text, escape_html=true)
|
||||
return '' if text.nil?
|
||||
|
||||
options = {
|
||||
|
|
@ -184,12 +196,12 @@ module FormatHelper
|
|||
space_after_headers: true,
|
||||
no_intra_emphasis: true
|
||||
}
|
||||
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML.new(escape_html: true), options)
|
||||
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")
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -2,14 +2,6 @@ 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)
|
||||
|
|
|
|||
|
|
@ -2,35 +2,88 @@ 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
|
||||
def link_if_alive(version, link_text, link_url, conference)
|
||||
version.item && conference ? link_to(link_text, link_url) : "#{link_text} with ID #{version.item_id}"
|
||||
end
|
||||
|
||||
def link_to_organization(organization_id)
|
||||
return 'deleted organization' unless organization_id
|
||||
|
||||
org = Organization.find_by(id: organization_id)
|
||||
return current_or_last_object_state('Organization', organization_id).try(:name) unless org
|
||||
org.name.to_s
|
||||
end
|
||||
|
||||
def link_to_conference(conference_id)
|
||||
return 'deleted conference' if conference_id.nil?
|
||||
|
||||
conference = Conference.find_by(id: conference_id)
|
||||
if conference
|
||||
link_to conference.short_title,
|
||||
edit_admin_conference_path(conference.short_title)
|
||||
else
|
||||
short_title = current_or_last_object_state('Conference', conference_id).try(:short_title) || ''
|
||||
" #{short_title} with ID #{conference_id}"
|
||||
end
|
||||
end
|
||||
|
||||
def link_to_user(user_id)
|
||||
return 'Someone (probably via the console)' unless user_id
|
||||
|
||||
user = User.find_by(id: user_id)
|
||||
if user
|
||||
link_to user.name, admin_user_path(id: user_id)
|
||||
else
|
||||
name = current_or_last_object_state('User', user_id).try(:name) || PaperTrail::Version.where(item_type: 'User', item_id: user_id).last.changeset['name'].second if PaperTrail::Version.where(item_type: 'User', item_id: user_id).any?
|
||||
"#{name ? name : 'Unknown user'} with ID #{user_id}"
|
||||
end
|
||||
end
|
||||
|
||||
# Receives a model_name and id
|
||||
# Returns nil if model_name is invalid
|
||||
# Returns object in its current state if its alive
|
||||
# Otherwise Returns object state just before deletion
|
||||
def current_or_last_object_state(model_name, id)
|
||||
return nil unless id.present? && model_name.present?
|
||||
begin
|
||||
object = model_name.constantize.find_by(id: id)
|
||||
rescue NameError
|
||||
return nil
|
||||
end
|
||||
|
||||
if object.nil?
|
||||
object_last_version = PaperTrail::Version.where(item_type: model_name, item_id: id).last
|
||||
object = object_last_version.reify if object_last_version
|
||||
end
|
||||
object
|
||||
end
|
||||
|
||||
def subscription_change_description(version)
|
||||
user = current_or_last_object_state(version.item_type, version.item_id).user
|
||||
user_name = user.name unless user.id.to_s == version.whodunnit
|
||||
user_id = current_or_last_object_state(version.item_type, version.item_id).user_id
|
||||
user_name = User.find_by(id: user_id).try(:name) || current_or_last_object_state('User', user_id).try(:name) || PaperTrail::Version.where(item_type: 'User', item_id: user_id).last.changeset[:name].second unless user_id.to_s == version.whodunnit
|
||||
version.event == 'create' ? "subscribed #{user_name} to" : "unsubscribed #{user_name} from"
|
||||
end
|
||||
|
||||
def registration_change_description(version)
|
||||
if version.item_type == 'Registration'
|
||||
user = current_or_last_object_state(version.item_type, version.item_id).user
|
||||
user_id = current_or_last_object_state(version.item_type, version.item_id).user_id
|
||||
elsif version.item_type == 'EventsRegistration'
|
||||
registration_id = current_or_last_object_state(version.item_type, version.item_id).registration_id
|
||||
user = current_or_last_object_state('Registration', registration_id).user
|
||||
user_id = current_or_last_object_state('Registration', registration_id).user_id
|
||||
end
|
||||
user_name = User.find_by(id: user_id).try(:name) || current_or_last_object_state('User', user_id).try(:name) || PaperTrail::Version.where(item_type: 'User', item_id: user_id).last.changeset[:name].second
|
||||
|
||||
if user.id.to_s == version.whodunnit
|
||||
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'
|
||||
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"
|
||||
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
|
||||
|
|
|
|||
|
|
@ -8,6 +8,22 @@ class Mailbot < ActionMailer::Base
|
|||
conference.email_settings.registration_body))
|
||||
end
|
||||
|
||||
def ticket_confirmation_mail(ticket_purchase)
|
||||
@ticket_purchase = ticket_purchase
|
||||
@conference = ticket_purchase.conference
|
||||
@user = ticket_purchase.user
|
||||
|
||||
PhysicalTicket.last(ticket_purchase.quantity).each do |physical_ticket|
|
||||
pdf = TicketPdf.new(@conference, @user, physical_ticket, @conference.ticket_layout.to_sym, "ticket_for_#{@conference.short_title}_#{physical_ticket.id}")
|
||||
attachments["ticket_for_#{@conference.short_title}_#{physical_ticket.id}.pdf"] = pdf.render
|
||||
end
|
||||
|
||||
mail(to: @user.email,
|
||||
from: @conference.contact.email,
|
||||
template_name: 'ticket_confirmation_template',
|
||||
subject: "#{@conference.title} | Ticket Confirmation and PDF!")
|
||||
end
|
||||
|
||||
def acceptance_mail(event)
|
||||
conference = event.program.conference
|
||||
|
||||
|
|
@ -81,6 +97,24 @@ class Mailbot < ActionMailer::Base
|
|||
conference.email_settings.cfp_dates_updated_body))
|
||||
end
|
||||
|
||||
def conference_booths_acceptance_mail(booth)
|
||||
conference = booth.conference
|
||||
|
||||
mail(to: booth.submitter.email,
|
||||
from: conference.contact.email,
|
||||
subject: conference.email_settings.booths_acceptance_subject,
|
||||
body: conference.email_settings.generate_booth_mail(booth, conference.email_settings.booths_acceptance_body))
|
||||
end
|
||||
|
||||
def conference_booths_rejection_mail(booth)
|
||||
conference = booth.conference
|
||||
|
||||
mail(to: booth.submitter.email,
|
||||
from: conference.contact.email,
|
||||
subject: conference.email_settings.booths_rejection_subject,
|
||||
body: conference.email_settings.generate_booth_mail(booth, conference.email_settings.booths_rejection_body))
|
||||
end
|
||||
|
||||
def event_comment_mail(comment, user)
|
||||
@comment = comment
|
||||
@event = @comment.commentable
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -73,7 +60,6 @@ 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
|
||||
|
|
@ -83,9 +69,19 @@ class Ability
|
|||
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 [:new, :create], Booth do |booth|
|
||||
booth.new_record? && booth.conference.program.cfps.for_booths.try(:open?)
|
||||
end
|
||||
|
||||
can [:edit, :update, :index, :show], Booth do |booth|
|
||||
booth.users.include?(user)
|
||||
end
|
||||
|
||||
can [:create, :destroy], Subscription, user_id: user.id
|
||||
|
||||
|
|
@ -93,181 +89,58 @@ class Ability
|
|||
event.program.cfp_open? && event.new_record?
|
||||
end
|
||||
|
||||
can [:update, :show, :delete, :index], Event do |event|
|
||||
can [:update, :show, :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 [:new, :create], Track do |track|
|
||||
track.new_record? && track.program.cfps.for_tracks.try(:open?)
|
||||
end
|
||||
|
||||
can [:index, :show, :restart, :confirm, :withdraw], Track, submitter_id: user.id
|
||||
|
||||
can [:edit, :update], Track do |track|
|
||||
user == track.submitter && !(track.accepted? || track.confirmed?)
|
||||
end
|
||||
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?
|
||||
|
||||
# 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
|
||||
|
||||
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, 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
|
||||
|
||||
# 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
|
||||
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?
|
||||
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
|
||||
|
||||
# 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)
|
||||
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
|
||||
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)
|
||||
if conf_ids_for_info_desk
|
||||
# To access conference/proposals/registrations
|
||||
can :manage, Registration, conference_id: conf_ids_for_info_desk
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
324
app/models/admin_ability.rb
Normal file
324
app/models/admin_ability.rb
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
class AdminAbility
|
||||
include CanCan::Ability
|
||||
|
||||
def initialize(user)
|
||||
# Order Abilities
|
||||
# (Check https://github.com/CanCanCommunity/cancancan/wiki/Ability-Precedence)
|
||||
# Check roles of user, using rolify. Role name is *case sensitive*
|
||||
# user.is_organizer? or user.has_role? :organizer
|
||||
# user.is_cfp_of? Conference or user.has_role? :cfp, Conference
|
||||
# user.is_info_desk_of? Conference
|
||||
# user.is_volunteers_coordinator_of? Conference
|
||||
# user.is_attendee_of? Conference
|
||||
# The following is wrong because a user will only have 'cfp' role for a specific conference
|
||||
# user.is_cfp? # This is always false
|
||||
|
||||
user ||= User.new
|
||||
signed_in_with_roles(user)
|
||||
end
|
||||
|
||||
def common_abilities_for_roles(user)
|
||||
can :manage, Registration, user_id: user.id
|
||||
|
||||
can :index, Conference
|
||||
can :show, Registration, &:new_record?
|
||||
|
||||
can [:new, :create], Registration do |registration|
|
||||
conference = registration.conference
|
||||
conference.registration_open? && !conference.registration_limit_exceeded? || conference.program.speakers.confirmed.include?(user)
|
||||
end
|
||||
|
||||
can [:index, :admins], Organization
|
||||
can :index, Ticket
|
||||
can :manage, TicketPurchase, user_id: user.id
|
||||
can [:new, :create], Payment, user_id: user.id
|
||||
|
||||
can [:create, :destroy], Subscription, user_id: user.id
|
||||
|
||||
can [:new, :create], Event do |event|
|
||||
event.program.cfp_open? && event.new_record?
|
||||
end
|
||||
|
||||
# can manage the commercials of their own events
|
||||
can :manage, Commercial, commercialable_type: 'Event', commercialable_id: user.events.pluck(:id)
|
||||
|
||||
can [:destroy], Openid
|
||||
can :access, Admin
|
||||
can :index, Commercial, commercialable_type: 'Conference'
|
||||
cannot [:edit, :update, :destroy], Question, global: true
|
||||
# for admins
|
||||
can :manage, :all if user.is_admin
|
||||
# even admin cannot create new users with ICHAIN enabled
|
||||
cannot [:new, :create], User if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
|
||||
cannot :revert_object, PaperTrail::Version do |version|
|
||||
(version.event == 'create' && %w[Conference User Event].include?(version.item_type))
|
||||
end
|
||||
cannot :revert_attribute, PaperTrail::Version do |version|
|
||||
version.event != 'update' || version.item.nil?
|
||||
end
|
||||
# Can't create cfp if there are no available cfp types
|
||||
cannot [:new, :create], Cfp do |cfp|
|
||||
cfp.program.remaining_cfp_types.empty?
|
||||
end
|
||||
cannot :destroy, Program
|
||||
# Do not delete venue, when there are rooms being used
|
||||
cannot :destroy, Venue do |venue|
|
||||
venue.conference.program.events.where.not(room_id: nil).any?
|
||||
end
|
||||
|
||||
# Prevent requests for tracks from being destroyed
|
||||
cannot :destroy, Track do |track|
|
||||
track.self_organized?
|
||||
end
|
||||
# Can't accept a booth when booth_limit is reached
|
||||
cannot :accept, Booth do |booth|
|
||||
conference = booth.conference
|
||||
conference.maximum_accepted_booths?
|
||||
end
|
||||
end
|
||||
|
||||
# Abilities for signed in users with roles
|
||||
def signed_in_with_roles(user)
|
||||
signed_in_with_organization_admin_role(user) if user.has_role? :organization_admin, :any
|
||||
signed_in_with_organizer_role(user) if user.has_role? :organizer, :any
|
||||
signed_in_with_cfp_role(user) if user.has_role? :cfp, :any
|
||||
signed_in_with_info_desk_role(user) if user.has_role? :info_desk, :any
|
||||
signed_in_with_volunteers_coordinator_role(user) if user.has_role? :volunteers_coordinator, :any
|
||||
signed_in_with_track_organizer_role(user) if user.has_role? :track_organizer, :any
|
||||
common_abilities_for_roles(user)
|
||||
end
|
||||
|
||||
def signed_in_with_organization_admin_role(user)
|
||||
org_ids_for_organization_admin = Organization.with_role(:organization_admin, user).pluck(:id)
|
||||
conf_ids_for_organization_admin = Conference.where(organization_id: org_ids_for_organization_admin).pluck(:id)
|
||||
|
||||
can [:read, :update, :destroy, :assign_org_admins, :unassign_org_admins, :admins], Organization, id: org_ids_for_organization_admin
|
||||
can :new, Conference
|
||||
can :manage, Conference, organization_id: org_ids_for_organization_admin
|
||||
can [:index, :show], Role
|
||||
|
||||
signed_in_with_organizer_role(user, conf_ids_for_organization_admin)
|
||||
end
|
||||
|
||||
def signed_in_with_organizer_role(user, conf_ids_for_organization_admin = [])
|
||||
# ids of all the conferences for which the user has the 'organizer' role and
|
||||
# conferences that belong to organizations for which user is 'organization_admin'
|
||||
conf_ids = conf_ids_for_organization_admin.concat(Conference.with_role(:organizer, user).pluck(:id)).uniq
|
||||
# ids of all the tracks that belong to the programs of the above conferences
|
||||
track_ids = Track.joins(:program).where('programs.conference_id IN (?)', conf_ids).pluck(:id)
|
||||
|
||||
can :manage, Resource, conference_id: conf_ids
|
||||
can [:read, :update, :destroy], Conference, id: conf_ids
|
||||
can :manage, Splashpage, conference_id: conf_ids
|
||||
can :manage, Contact, conference_id: conf_ids
|
||||
can :manage, EmailSettings, conference_id: conf_ids
|
||||
can :manage, Campaign, conference_id: conf_ids
|
||||
can :manage, Target, conference_id: conf_ids
|
||||
can :manage, Commercial, commercialable_type: 'Conference',
|
||||
commercialable_id: conf_ids
|
||||
can :manage, Registration, conference_id: conf_ids
|
||||
can :manage, RegistrationPeriod do |registration_period|
|
||||
conference = registration_period.conference
|
||||
conf_ids.include?(conference.id) && conference.tickets.for_registration.any?
|
||||
end
|
||||
can :manage, Booth, conference_id: conf_ids
|
||||
can :manage, Question, conference_id: conf_ids
|
||||
can :manage, Question do |question|
|
||||
!(question.conferences.pluck(:id) & conf_ids).empty?
|
||||
end
|
||||
can :manage, Vposition, conference_id: conf_ids
|
||||
can :manage, Vday, conference_id: conf_ids
|
||||
can :manage, Program, conference_id: conf_ids
|
||||
can :manage, Schedule, program: { conference_id: conf_ids }
|
||||
can :manage, EventSchedule, schedule: { program: { conference_id: conf_ids } }
|
||||
can :manage, Cfp, program: { conference_id: conf_ids }
|
||||
can :manage, Event, program: { conference_id: conf_ids }
|
||||
can :manage, EventType, program: { conference_id: conf_ids }
|
||||
can :manage, Track, program: { conference_id: conf_ids }
|
||||
can :manage, DifficultyLevel, program: { conference_id: conf_ids }
|
||||
can :manage, Commercial, commercialable_type: 'Event',
|
||||
commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id)
|
||||
can :manage, Venue, conference_id: conf_ids
|
||||
can :manage, Commercial, commercialable_type: 'Venue',
|
||||
commercialable_id: Venue.where(conference_id: conf_ids).pluck(:id)
|
||||
can :manage, Lodging, conference_id: conf_ids
|
||||
can :manage, Room, venue: { conference_id: conf_ids }
|
||||
can :manage, Sponsor, conference_id: conf_ids
|
||||
can :manage, SponsorshipLevel, conference_id: conf_ids
|
||||
can :manage, Ticket, conference_id: conf_ids
|
||||
can :create, TicketScanning do |ticket_scanning|
|
||||
conf_id = ticket_scanning.physical_ticket.ticket_purchase.conference_id
|
||||
conf_ids.include? conf_id
|
||||
end
|
||||
can :index, Comment, commentable_type: 'Event',
|
||||
commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids).pluck(:id)).pluck(:id)
|
||||
|
||||
# Abilities for Role (Conference resource)
|
||||
can [:index, :show], Role do |role|
|
||||
role.resource_type == 'Conference' || role.resource_type == 'Track'
|
||||
end
|
||||
|
||||
can [:edit, :update, :toggle_user], Role do |role|
|
||||
role.resource_type == 'Conference' && (conf_ids.include? role.resource_id) ||
|
||||
role.resource_type == 'Track' && (track_ids.include? role.resource_id)
|
||||
end
|
||||
|
||||
can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'User'
|
||||
can [:index, :revert_object, :revert_attribute], PaperTrail::Version, conference_id: conf_ids
|
||||
end
|
||||
|
||||
def signed_in_with_cfp_role(user)
|
||||
# ids of all the conferences for which the user has the 'cfp' role
|
||||
conf_ids_for_cfp = Conference.with_role(:cfp, user).pluck(:id)
|
||||
|
||||
can :show, Conference do |conf|
|
||||
conf_ids_for_cfp.include?(conf.id)
|
||||
end
|
||||
can [:index, :show, :update], Resource, conference_id: conf_ids_for_cfp
|
||||
can :manage, Booth, conference_id: conf_ids_for_cfp
|
||||
can :manage, Event, program: { conference_id: conf_ids_for_cfp }
|
||||
can :manage, EventType, program: { conference_id: conf_ids_for_cfp }
|
||||
can :manage, Track, program: { conference_id: conf_ids_for_cfp }
|
||||
can :manage, DifficultyLevel, program: { conference_id: conf_ids_for_cfp }
|
||||
can :manage, EmailSettings, conference_id: conf_ids_for_cfp
|
||||
can :manage, Schedule, program: { conference_id: conf_ids_for_cfp }
|
||||
can :manage, Room, venue: { conference_id: conf_ids_for_cfp }
|
||||
can :show, Venue, conference_id: conf_ids_for_cfp
|
||||
can :show, Commercial, commercialable_type: 'Venue', commercialable_id: Venue.where(conference_id: conf_ids_for_cfp).pluck(:id)
|
||||
can :manage, Cfp, program: { conference_id: conf_ids_for_cfp }
|
||||
can :manage, Program, conference_id: conf_ids_for_cfp
|
||||
can :manage, Commercial, commercialable_type: 'Event',
|
||||
commercialable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id)
|
||||
can :index, Comment, commentable_type: 'Event',
|
||||
commentable_id: Event.where(program_id: Program.where(conference_id: conf_ids_for_cfp).pluck(:id)).pluck(:id)
|
||||
|
||||
# Abilities for Role (Conference resource)
|
||||
can [:index, :show], Role do |role|
|
||||
role.resource_type == 'Conference' || role.resource_type == 'Track'
|
||||
end
|
||||
# Can add or remove users from role, when user has that same role for the conference
|
||||
# Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP')
|
||||
can :toggle_user, Role do |role|
|
||||
role.resource_type == 'Conference' && role.name == 'cfp' &&
|
||||
(Conference.with_role(:cfp, user).pluck(:id).include? role.resource_id)
|
||||
end
|
||||
|
||||
can [:index, :revert_object, :revert_attribute], PaperTrail::Version,
|
||||
item_type: %w[Event EventType Track DifficultyLevel EmailSettings Room Cfp Program Comment], conference_id: conf_ids_for_cfp
|
||||
can [:index, :revert_object, :revert_attribute], PaperTrail::Version,
|
||||
["item_type = 'Commercial' AND conference_id IN (?) AND (object LIKE '%Event%' OR object_changes LIKE '%Event%')", conf_ids_for_cfp] do |version|
|
||||
version.item_type == 'Commercial' && conf_ids_for_cfp.include?(version.conference_id) &&
|
||||
(version.object.to_s.include?('Event') || version.object_changes.to_s.include?('Event'))
|
||||
end
|
||||
end
|
||||
|
||||
def signed_in_with_info_desk_role(user)
|
||||
# ids of all the conferences for which the user has the 'info_desk' role
|
||||
conf_ids_for_info_desk = Conference.with_role(:info_desk, user).pluck(:id)
|
||||
|
||||
can :show, Conference do |conf|
|
||||
conf_ids_for_info_desk.include?(conf.id)
|
||||
end
|
||||
can [:index, :show, :update], Resource, conference_id: conf_ids_for_info_desk
|
||||
can :manage, Registration, conference_id: conf_ids_for_info_desk
|
||||
can :manage, Question, conference_id: conf_ids_for_info_desk
|
||||
can :manage, Question do |question|
|
||||
!(question.conferences.pluck(:id) & conf_ids_for_info_desk).empty?
|
||||
end
|
||||
can :create, TicketScanning do |ticket_scanning|
|
||||
conf_id = ticket_scanning.physical_ticket.ticket_purchase.conference_id
|
||||
conf_ids_for_info_desk.include? conf_id
|
||||
end
|
||||
|
||||
# Abilities for Role (Conference resource)
|
||||
can [:index, :show], Role do |role|
|
||||
role.resource_type == 'Conference' || role.resource_type == 'Track'
|
||||
end
|
||||
# Can add or remove users from role, when user has that same role for the conference
|
||||
# Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP')
|
||||
can :toggle_user, Role do |role|
|
||||
role.resource_type == 'Conference' && role.name == 'info_desk' &&
|
||||
(Conference.with_role(:info_desk, user).pluck(:id).include? role.resource_id)
|
||||
end
|
||||
can [:index, :revert_object, :revert_attribute], PaperTrail::Version, item_type: 'Registration', conference_id: conf_ids_for_info_desk
|
||||
end
|
||||
|
||||
def signed_in_with_volunteers_coordinator_role(user)
|
||||
# ids of all the conferences for which the user has the 'volunteers_coordinator' role
|
||||
conf_ids_for_volunteers_coordinator = Conference.with_role(:volunteers_coordinator, user).pluck(:id)
|
||||
|
||||
can :show, Conference do |conf|
|
||||
conf_ids_for_volunteers_coordinator.include?(conf.id)
|
||||
end
|
||||
can [:index, :show, :update], Resource, conference_id: conf_ids_for_volunteers_coordinator
|
||||
can :manage, Vposition, conference_id: conf_ids_for_volunteers_coordinator
|
||||
can :manage, Vday, conference_id: conf_ids_for_volunteers_coordinator
|
||||
|
||||
# Abilities for Role (Conference resource)
|
||||
can [:index, :show], Role do |role|
|
||||
role.resource_type == 'Conference' || role.resource_type == 'Track'
|
||||
end
|
||||
# Can add or remove users from role, when user has that same role for the conference
|
||||
# Eg. If you are member of the CfP team, you can add more CfP team members (add users to the role 'CfP')
|
||||
can :toggle_user, Role do |role|
|
||||
role.resource_type == 'Conference' && role.name == 'volunteers_coordinator' &&
|
||||
(Conference.with_role(:volunteers_coordinator, user).pluck(:id).include? role.resource_id)
|
||||
end
|
||||
end
|
||||
|
||||
def signed_in_with_track_organizer_role(user)
|
||||
# ids of all the conferences for which the user has the 'track organizer' role
|
||||
conf_ids_for_track_organizer = Track.with_role(:track_organizer, user).joins(:program).pluck(:conference_id)
|
||||
# ids of all the tracks for which the user has the 'track_organizer' role
|
||||
track_ids_for_track_organizer = Track.with_role(:track_organizer, user).pluck(:id)
|
||||
|
||||
can :show, Conference do |conf|
|
||||
conf_ids_for_track_organizer.include?(conf.id)
|
||||
end
|
||||
|
||||
# Show Program in the admin sidebar
|
||||
can :show, Program, conference_id: conf_ids_for_track_organizer
|
||||
|
||||
# Show Tracks in the admin sidebar
|
||||
can :update, Track do |track|
|
||||
track.new_record? && conf_ids_for_track_organizer.include?(track.program.conference_id)
|
||||
end
|
||||
|
||||
can :manage, Track, id: track_ids_for_track_organizer
|
||||
|
||||
cannot [:edit, :update], Track do |track|
|
||||
track.self_organized_and_accepted_or_confirmed?
|
||||
end
|
||||
|
||||
# Show Roles in the admin sidebar and allow authorization of the index action
|
||||
can [:index, :show], Role do |role|
|
||||
role.resource_type == 'Conference' || role.resource_type == 'Track'
|
||||
end
|
||||
|
||||
can :toggle_user, Role do |role|
|
||||
role.resource_type == 'Track' && track_ids_for_track_organizer.include?(role.resource_id)
|
||||
end
|
||||
|
||||
# Show Events in the admin sidebar
|
||||
can :update, Event do |event|
|
||||
event.new_record? && conf_ids_for_track_organizer.include?(event.program.conference_id)
|
||||
end
|
||||
|
||||
can :manage, Event, track_id: track_ids_for_track_organizer
|
||||
can :manage, Commercial, commercialable_type: 'Event',
|
||||
commercialable_id: Event.where(track_id: track_ids_for_track_organizer).pluck(:id)
|
||||
|
||||
# Show Scheduless in the admin sidebar
|
||||
can :update, Schedule do |schedule|
|
||||
schedule.new_record? && conf_ids_for_track_organizer.include?(schedule.program.conference_id)
|
||||
end
|
||||
|
||||
# Show new track schedule button
|
||||
can :new, Schedule do |schedule|
|
||||
schedule.new_record? && conf_ids_for_track_organizer.include?(schedule.program.conference_id) && schedule.track.try(:new_record?)
|
||||
end
|
||||
|
||||
can :manage, Schedule, track_id: track_ids_for_track_organizer
|
||||
can :manage, EventSchedule, schedule: { track_id: track_ids_for_track_organizer }
|
||||
end
|
||||
end
|
||||
83
app/models/booth.rb
Normal file
83
app/models/booth.rb
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
class Booth < ActiveRecord::Base
|
||||
include ActiveRecord::Transitions
|
||||
has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||
|
||||
belongs_to :conference
|
||||
has_many :booth_requests, dependent: :destroy
|
||||
has_many :users, through: :booth_requests
|
||||
|
||||
has_one :submitter_booth_user, -> { where(role: 'submitter') }, class_name: 'BoothRequest'
|
||||
has_one :submitter, through: :submitter_booth_user, source: :user
|
||||
|
||||
has_many :responsibles_booth_user, -> { where(role: 'responsible') }, class_name: 'BoothRequest'
|
||||
has_many :responsibles, through: :responsibles_booth_user, source: :user
|
||||
|
||||
validates :title,
|
||||
uniqueness: { case_sensitive: false },
|
||||
presence: true
|
||||
|
||||
validates :description,
|
||||
:reasoning,
|
||||
:state,
|
||||
:responsibles,
|
||||
:conference_id,
|
||||
:website_url,
|
||||
:submitter_relationship,
|
||||
presence: true
|
||||
|
||||
scope :accepted, -> { where(state: 'accepted') }
|
||||
scope :confirmed, -> { where(state: 'confirmed') }
|
||||
|
||||
mount_uploader :picture, PictureUploader, mount_on: :logo_link
|
||||
|
||||
state_machine initial: :new do
|
||||
state :new
|
||||
state :withdrawn
|
||||
state :to_accept
|
||||
state :accepted
|
||||
state :to_reject
|
||||
state :rejected
|
||||
state :canceled
|
||||
state :confirmed
|
||||
|
||||
event :restart do
|
||||
transitions to: :new, from: [:withdrawn, :rejected, :canceled]
|
||||
end
|
||||
event :withdraw do
|
||||
transitions to: :withdrawn, from: [:new, :to_accept, :accepted, :to_reject, :rejected, :confirmed]
|
||||
end
|
||||
event :confirm do
|
||||
transitions to: :confirmed, from: [:accepted]
|
||||
end
|
||||
event :to_accept do
|
||||
transitions to: :to_accept, from: [:new, :to_reject]
|
||||
end
|
||||
event :to_reject do
|
||||
transitions to: :to_reject, from: [:new, :to_accept]
|
||||
end
|
||||
event :accept do
|
||||
transitions to: :accepted, from: [:new, :to_accept]
|
||||
end
|
||||
event :reject do
|
||||
transitions to: :rejected, from: [:new, :to_reject]
|
||||
end
|
||||
event :cancel do
|
||||
transitions to: :canceled, from: [:accepted, :rejected, :to_accept, :to_reject, :confirmed]
|
||||
end
|
||||
end
|
||||
|
||||
def transition_possible?(transition)
|
||||
self.class.state_machine.events_for(current_state).include?(transition)
|
||||
end
|
||||
|
||||
def update_state(transition, _notice)
|
||||
alert = ''
|
||||
begin
|
||||
send(transition)
|
||||
save
|
||||
rescue Transitions::InvalidTransition => e
|
||||
alert = "Update state failed. #{e.message}"
|
||||
end
|
||||
alert
|
||||
end
|
||||
end
|
||||
9
app/models/booth_request.rb
Normal file
9
app/models/booth_request.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
class BoothRequest < ActiveRecord::Base
|
||||
belongs_to :booth
|
||||
belongs_to :user
|
||||
|
||||
validates :role,
|
||||
presence: true
|
||||
|
||||
ROLES = %w[submitter responsible].freeze
|
||||
end
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
# cannot delete program if there are events submitted
|
||||
|
||||
class Cfp < ActiveRecord::Base
|
||||
TYPES = %w(events booths tracks).freeze
|
||||
|
||||
has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||
belongs_to :program
|
||||
|
||||
|
|
@ -8,6 +10,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
|
||||
|
|
@ -55,15 +66,52 @@ class Cfp < ActiveRecord::Base
|
|||
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
|
||||
|
||||
##
|
||||
# Finds the cfp for events if it exists
|
||||
#
|
||||
# ====Returns
|
||||
# * +Cfp+ -> The cfp with type 'events'
|
||||
def self.for_events
|
||||
find_by(cfp_type: 'events')
|
||||
end
|
||||
|
||||
##
|
||||
# Finds the cfp for tracks if it exists
|
||||
#
|
||||
# ====Returns
|
||||
# * +Cfp+ -> The cfp with type 'tracks'
|
||||
def self.for_tracks
|
||||
find_by(cfp_type: 'tracks')
|
||||
end
|
||||
|
||||
##
|
||||
# Finds the cfp for booths if it exists
|
||||
#
|
||||
# ====Returns
|
||||
# * +Cfp+ -> The cfp with type 'booths'
|
||||
def self.for_booths
|
||||
find_by(cfp_type: 'booths')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def before_end_of_conference
|
||||
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
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ class Comment < ActiveRecord::Base
|
|||
# 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
|
||||
|
|
|
|||
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,6 +7,10 @@ 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) })
|
||||
|
||||
belongs_to :organization
|
||||
|
||||
has_paper_trail ignore: %i(updated_at guid revision events_per_week), meta: { conference_id: :id }
|
||||
|
||||
|
|
@ -17,11 +22,17 @@ 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
|
||||
has_many :tickets, dependent: :destroy
|
||||
has_many :tickets, dependent: :destroy do
|
||||
def for_registration
|
||||
where(registration_ticket: true)
|
||||
end
|
||||
end
|
||||
has_many :resources, dependent: :destroy
|
||||
has_many :booths, dependent: :destroy
|
||||
|
||||
has_many :lodgings, dependent: :destroy
|
||||
has_many :registrations, dependent: :destroy
|
||||
|
|
@ -53,7 +64,9 @@ class Conference < ActiveRecord::Base
|
|||
:start_date,
|
||||
:end_date,
|
||||
:start_hour,
|
||||
:end_hour, presence: true
|
||||
:end_hour,
|
||||
:ticket_layout,
|
||||
:organization, presence: true
|
||||
|
||||
validates :short_title, uniqueness: true
|
||||
validates :short_title, format: { with: /\A[a-zA-Z0-9_-]*\z/ }
|
||||
|
|
@ -69,6 +82,8 @@ class Conference < ActiveRecord::Base
|
|||
after_create :create_free_ticket
|
||||
after_update :delete_event_schedules
|
||||
|
||||
enum ticket_layout: [:portrait, :landscape]
|
||||
|
||||
##
|
||||
# Checks if the user is registered to the conference
|
||||
#
|
||||
|
|
@ -128,7 +143,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)
|
||||
|
|
@ -176,7 +191,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)
|
||||
|
|
@ -184,6 +199,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.
|
||||
#
|
||||
|
|
@ -281,8 +349,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
|
||||
|
||||
|
|
@ -292,10 +360,10 @@ class Conference < ActiveRecord::Base
|
|||
# ====Returns
|
||||
# * +hash+ -> user: submissions
|
||||
def get_top_submitter(limit = 5)
|
||||
submitter = EventUser.joins(:event)
|
||||
submitter = EventUser.joins(:event).select(:user_id)
|
||||
.where('event_role = ? and program_id = ?', 'submitter', Conference.find(id).program.id)
|
||||
.limit(limit).group(:user_id)
|
||||
counter = submitter.order('count_all desc').count
|
||||
counter = submitter.order('count_all desc').count(:all)
|
||||
Conference.calculate_user_submission_hash(submitter, counter)
|
||||
end
|
||||
|
||||
|
|
@ -396,6 +464,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_total(ticket.id)).delete(',').to_i,
|
||||
'color' => "\##{Digest::MD5.hexdigest(ticket.title)[0..5]}"
|
||||
}
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
##
|
||||
# Calculates the overall program minutes
|
||||
#
|
||||
|
|
@ -460,11 +568,11 @@ 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)
|
||||
else
|
||||
tracks_grouped = program.events.select(:track_id).group(:track_id)
|
||||
end
|
||||
tracks_grouped = if state
|
||||
program.events.select(:track_id).where('state = ?', state).group(:track_id)
|
||||
else
|
||||
program.events.select(:track_id).group(:track_id)
|
||||
end
|
||||
tracks_counted = tracks_grouped.count
|
||||
|
||||
calculate_track_distribution_hash(tracks_grouped, tracks_counted)
|
||||
|
|
@ -547,7 +655,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
|
||||
|
|
@ -634,6 +742,28 @@ class Conference < ActiveRecord::Base
|
|||
(start_hour..(end_hour - 1)).cover?(current_hour) ? current_hour - start_hour : 0
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
# ====Returns
|
||||
# * +True+ -> if accepted booths are equal to the booth limit
|
||||
# * +False+ -> Accepted booths have not reached the booth limit
|
||||
def maximum_accepted_booths?
|
||||
booth_limit > 0 && booths.accepted.count + booths.confirmed.count >= booth_limit
|
||||
end
|
||||
|
||||
##
|
||||
# Return the current conference object to be used in RevisionCount
|
||||
#
|
||||
# ====Returns
|
||||
# * +ActiveRecord+
|
||||
def conference
|
||||
self
|
||||
end
|
||||
|
||||
def to_param
|
||||
short_title
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Returns a different html colour for every i and consecutive colors are
|
||||
|
|
@ -803,7 +933,7 @@ class Conference < ActiveRecord::Base
|
|||
hash[key] = 0
|
||||
end
|
||||
end
|
||||
Hash[ hash.sort ]
|
||||
Hash[hash.sort]
|
||||
end
|
||||
|
||||
##
|
||||
|
|
@ -889,11 +1019,11 @@ 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)
|
||||
else
|
||||
grouped = program.events.select(group_by_id).group(group_by_id)
|
||||
end
|
||||
grouped = if state
|
||||
program.events.select(group_by_id).where('state = ?', 'confirmed').group(group_by_id)
|
||||
else
|
||||
program.events.select(group_by_id).group(group_by_id)
|
||||
end
|
||||
counted = grouped.count
|
||||
|
||||
calculate_distribution_hash(grouped, counted, association_symbol)
|
||||
|
|
@ -1004,7 +1134,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
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ class EmailSettings < ActiveRecord::Base
|
|||
|
||||
has_paper_trail on: [:update], ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||
|
||||
def get_values(conference, user, event = nil)
|
||||
def get_values(conference, user, event = nil, booth = nil)
|
||||
h = {
|
||||
'email' => user.email,
|
||||
'name' => user.name,
|
||||
|
|
@ -45,6 +45,10 @@ class EmailSettings < ActiveRecord::Base
|
|||
h['proposalslink'] = Rails.application.routes.url_helpers.conference_program_proposals_url(
|
||||
conference.short_title, host: (ENV['OSEM_HOSTNAME'] || 'localhost:3000'))
|
||||
end
|
||||
|
||||
if booth
|
||||
h['booth_title'] = booth.title
|
||||
end
|
||||
h
|
||||
end
|
||||
|
||||
|
|
@ -58,6 +62,11 @@ class EmailSettings < ActiveRecord::Base
|
|||
parse_template(conf_update_template, values)
|
||||
end
|
||||
|
||||
def generate_booth_mail(booth, booth_template)
|
||||
values = get_values(booth.conference, booth.submitter, nil, booth)
|
||||
parse_template(booth_template, values)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_template(text, values)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -44,6 +45,7 @@ class Event < ActiveRecord::Base
|
|||
validates :max_attendees, numericality: { only_integer: true, greater_than_or_equal_to: 1, allow_nil: true }
|
||||
|
||||
validate :max_attendees_no_more_than_room_size
|
||||
validate :valid_track
|
||||
|
||||
scope :confirmed, -> { where(state: 'confirmed') }
|
||||
scope :canceled, -> { where(state: 'canceled') }
|
||||
|
|
@ -83,7 +85,7 @@ class Event < ActiveRecord::Base
|
|||
# ====Returns
|
||||
# * +true+ or +false+
|
||||
def scheduled?
|
||||
event_schedules.find_by(schedule_id: program.selected_schedule_id).present?
|
||||
event_schedules.find_by(schedule_id: selected_schedule_id).present?
|
||||
end
|
||||
|
||||
def registration_possible?
|
||||
|
|
@ -115,7 +117,7 @@ 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
|
||||
|
|
@ -241,14 +243,22 @@ class Event < ActiveRecord::Base
|
|||
def room
|
||||
# We use try(:selected_schedule_id) because this function is used for
|
||||
# validations so program could not be present there
|
||||
event_schedules.find_by(schedule_id: program.try(:selected_schedule_id)).try(:room)
|
||||
if track.try(:self_organized?)
|
||||
track.room
|
||||
else
|
||||
event_schedules.find_by(schedule_id: program.try(:selected_schedule_id)).try(:room)
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Returns the start time at which this event is scheduled
|
||||
#
|
||||
def time
|
||||
event_schedules.find_by(schedule_id: program.selected_schedule_id).try(:start_time)
|
||||
event_schedules.find_by(schedule_id: selected_schedule_id).try(:start_time)
|
||||
end
|
||||
|
||||
def conference
|
||||
program.conference
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -298,4 +308,25 @@ class Event < ActiveRecord::Base
|
|||
def conference_id
|
||||
program.conference_id
|
||||
end
|
||||
|
||||
##
|
||||
# Allow only confirmed tracks that belong to the same program as the event
|
||||
#
|
||||
def valid_track
|
||||
return unless track && track.program && program
|
||||
errors.add(:track, 'is invalid') unless track.confirmed? && track.program == program
|
||||
end
|
||||
|
||||
##
|
||||
# Return the id of the selected schedule
|
||||
#
|
||||
# ====Returns
|
||||
# * +Integer+ -> selected_schedule_id of self-organized track or program
|
||||
def selected_schedule_id
|
||||
if track.try(:self_organized?)
|
||||
track.selected_schedule_id
|
||||
else
|
||||
program.selected_schedule_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ class EventSchedule < ActiveRecord::Base
|
|||
validates :event, uniqueness: { scope: :schedule }
|
||||
validate :start_after_end_hour
|
||||
validate :start_before_start_hour
|
||||
validate :same_room_as_track
|
||||
validate :during_track
|
||||
validate :valid_schedule
|
||||
|
||||
scope :confirmed, -> { joins(:event).where('state = ?', 'confirmed') }
|
||||
scope :canceled, -> { joins(:event).where('state = ?', 'canceled') }
|
||||
|
|
@ -52,4 +55,35 @@ class EventSchedule < ActiveRecord::Base
|
|||
def conference_id
|
||||
schedule.program.conference_id
|
||||
end
|
||||
|
||||
##
|
||||
# Validates that the event is scheduled in the same room as its track
|
||||
#
|
||||
def same_room_as_track
|
||||
return unless event.try(:track).try(:room)
|
||||
errors.add(:room, "must be the same as the track's room (#{event.track.room.name})") unless event.track.room == room
|
||||
end
|
||||
|
||||
##
|
||||
# Validates that the event is scheduled within its track's time slot
|
||||
#
|
||||
def during_track
|
||||
return unless event.try(:track) && start_time
|
||||
|
||||
if event.track.try(:start_date) && event.track.start_date > start_time
|
||||
errors.add(:start_time, "can't be before the track's start date (#{event.track.start_date})")
|
||||
end
|
||||
|
||||
if event.track.try(:end_date) && event.track.end_date + 1.day < end_time
|
||||
errors.add(:end_time, "can't be after the track's end date (#{event.track.end_date})")
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Validates that the event is scheduled in its self-organized tracks's schedules
|
||||
#
|
||||
def valid_schedule
|
||||
return unless event.try(:track).try(:self_organized?) && schedule
|
||||
errors.add(:schedule, "must be one of #{event.track.name} track's schedules") unless event.track.schedules.include?(schedule)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
19
app/models/organization.rb
Normal file
19
app/models/organization.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
class Organization < ActiveRecord::Base
|
||||
resourcify :roles, dependent: :delete_all
|
||||
|
||||
has_paper_trail
|
||||
|
||||
has_many :conferences, dependent: :destroy
|
||||
|
||||
after_create :create_roles
|
||||
|
||||
validates :name, presence: true
|
||||
|
||||
mount_uploader :picture, PictureUploader, mount_on: :picture
|
||||
|
||||
private
|
||||
|
||||
def create_roles
|
||||
roles.where(name: 'organization_admin').first_or_create(description: 'For the administrators of an organization and its conferences')
|
||||
end
|
||||
end
|
||||
22
app/models/physical_ticket.rb
Normal file
22
app/models/physical_ticket.rb
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
class PhysicalTicket < ActiveRecord::Base
|
||||
belongs_to :ticket_purchase
|
||||
has_one :ticket, through: :ticket_purchase
|
||||
has_one :conference, through: :ticket_purchase
|
||||
has_one :user, through: :ticket_purchase
|
||||
has_many :ticket_scannings
|
||||
|
||||
before_create :set_token
|
||||
|
||||
private
|
||||
|
||||
def set_token
|
||||
self.token = generate_token
|
||||
end
|
||||
|
||||
def generate_token
|
||||
loop do
|
||||
token = SecureRandom.hex(10)
|
||||
break token unless PhysicalTicket.exists?(token: token)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,7 +5,7 @@ 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
|
||||
|
|
@ -71,7 +71,11 @@ class Program < ActiveRecord::Base
|
|||
|
||||
# Returns all event_schedules for the selected schedule ordered by start_time
|
||||
def selected_event_schedules
|
||||
selected_schedule.event_schedules.order(start_time: :asc) if selected_schedule
|
||||
event_schedules = selected_schedule.event_schedules.order(start_time: :asc) if selected_schedule
|
||||
tracks.self_organized.confirmed.order(start_date: :asc).each do |track|
|
||||
event_schedules += track.selected_schedule.event_schedules.order(start_time: :asc) if track.selected_schedule
|
||||
end
|
||||
event_schedules.sort_by(&:start_time) if event_schedules
|
||||
end
|
||||
|
||||
##
|
||||
|
|
@ -163,6 +167,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
|
||||
|
||||
##
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ 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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,6 +1,8 @@
|
|||
class Room < ActiveRecord::Base
|
||||
include RevisionCount
|
||||
belongs_to :venue
|
||||
has_many :event_schedules, dependent: :destroy
|
||||
has_many :tracks
|
||||
|
||||
has_paper_trail ignore: [:guid], meta: { conference_id: :conference_id }
|
||||
|
||||
|
|
@ -10,6 +12,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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
class Schedule < ActiveRecord::Base
|
||||
belongs_to :program
|
||||
belongs_to :track
|
||||
has_many :event_schedules, dependent: :destroy
|
||||
has_many :events, through: :event_schedules
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
class Subscription < ActiveRecord::Base
|
||||
validates :user_id, uniqueness: { scope: [:conference_id] }
|
||||
belongs_to :conference
|
||||
belongs_to :user
|
||||
|
||||
|
|
|
|||
|
|
@ -55,12 +55,18 @@ class Ticket < ActiveRecord::Base
|
|||
result ? result : Money.new(0, 'USD')
|
||||
end
|
||||
|
||||
def tickets_sold
|
||||
ticket_purchases.sum(:quantity)
|
||||
def self.total_price_user(conference, user, paid: false)
|
||||
tickets = TicketPurchase.where(conference: conference, user: user, paid: paid)
|
||||
tickets.inject(0){ |sum, ticket| sum + (ticket.amount_paid * ticket.quantity) }
|
||||
end
|
||||
|
||||
def tickets_turnover
|
||||
tickets_sold * price
|
||||
def tickets_turnover_total(id)
|
||||
tickets = TicketPurchase.where(ticket_id: id)
|
||||
tickets.inject(0){ |sum, ticket| sum + (ticket.amount_paid * ticket.quantity) }
|
||||
end
|
||||
|
||||
def tickets_sold
|
||||
ticket_purchases.paid.sum(:quantity)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -2,9 +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
|
||||
|
||||
validate :one_registration_ticket_per_user
|
||||
validate :registration_ticket_already_purchased, on: :create
|
||||
validates :quantity, numericality: { greater_than: 0 }
|
||||
|
||||
delegate :title, to: :ticket
|
||||
|
|
@ -13,25 +15,32 @@ 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)
|
||||
else
|
||||
purchase = purchase_ticket(conference, quantity, ticket, user)
|
||||
end
|
||||
|
||||
if purchase && !purchase.save
|
||||
errors.push(purchase.errors.full_messages)
|
||||
if count_purchased_registration_tickets(conference, purchases) > 1
|
||||
errors.push('You cannot buy more than one registration tickets.')
|
||||
else
|
||||
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
|
||||
purchase = if ticket.bought?(user) && ticket.unpaid?(user)
|
||||
update_quantity(conference, quantity, ticket, user)
|
||||
else
|
||||
purchase_ticket(conference, quantity, ticket, user)
|
||||
end
|
||||
if purchase && !purchase.save
|
||||
errors.push(purchase.errors.full_messages)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -44,7 +53,8 @@ class TicketPurchase < ActiveRecord::Base
|
|||
conference_id: conference.id,
|
||||
user_id: user.id,
|
||||
quantity: quantity,
|
||||
paid: ticket.price_cents.zero?)
|
||||
amount_paid: ticket.price)
|
||||
purchase.pay(nil) if ticket.price_cents.zero?
|
||||
end
|
||||
purchase
|
||||
end
|
||||
|
|
@ -58,4 +68,37 @@ 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
|
||||
Mailbot.ticket_confirmation_mail(self).deliver_later
|
||||
end
|
||||
|
||||
def one_registration_ticket_per_user
|
||||
if ticket.try(:registration_ticket?) && quantity != 1
|
||||
errors.add(:quantity, 'cannot be greater than one for registration tickets.')
|
||||
end
|
||||
end
|
||||
|
||||
def registration_ticket_already_purchased
|
||||
if ticket.try(:registration_ticket?) && user.tickets.for_registration(conference).present?
|
||||
errors.add(:quantity, 'cannot be greater than one for registration tickets.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_week
|
||||
self.week = created_at.strftime('%W')
|
||||
save!
|
||||
end
|
||||
|
||||
def count_purchased_registration_tickets(conference, purchases)
|
||||
conference.tickets.for_registration.inject(0) do |sum, registration_ticket|
|
||||
sum + purchases[registration_ticket.id.to_s].to_i
|
||||
end
|
||||
end
|
||||
|
|
|
|||
13
app/models/ticket_scanning.rb
Normal file
13
app/models/ticket_scanning.rb
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
class TicketScanning < ActiveRecord::Base
|
||||
belongs_to :physical_ticket
|
||||
|
||||
before_create :mark_user_present
|
||||
|
||||
private
|
||||
|
||||
def mark_user_present
|
||||
if physical_ticket.ticket.registration_ticket?
|
||||
physical_ticket.user.mark_attendance_for_conference(physical_ticket.conference)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,15 +1,176 @@
|
|||
class Track < ActiveRecord::Base
|
||||
belongs_to :program
|
||||
has_many :events, dependent: :nullify
|
||||
include ActiveRecord::Transitions
|
||||
include RevisionCount
|
||||
|
||||
has_paper_trail only: [:name, :description, :color], meta: { conference_id: :conference_id }
|
||||
resourcify :roles, dependent: :delete_all
|
||||
|
||||
belongs_to :program
|
||||
belongs_to :submitter, class_name: 'User'
|
||||
belongs_to :room
|
||||
belongs_to :selected_schedule, class_name: 'Schedule'
|
||||
has_many :events, dependent: :nullify
|
||||
has_many :schedules
|
||||
|
||||
has_paper_trail ignore: [:updated_at], meta: { conference_id: :conference_id }
|
||||
|
||||
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,
|
||||
inclusion: { in: %w(new to_accept accepted confirmed to_reject rejected canceled withdrawn) }
|
||||
validates :cfp_active, inclusion: { in: [true, false] }
|
||||
validates :start_date, presence: true, if: :self_organized_and_accepted_or_confirmed?
|
||||
validates :end_date, presence: true, if: :self_organized_and_accepted_or_confirmed?
|
||||
validates :room, presence: true, if: :self_organized_and_accepted_or_confirmed?
|
||||
validates :relevance, presence: true, if: :self_organized?
|
||||
validates :description, presence: true, if: :self_organized?
|
||||
validate :dates_within_conference_dates
|
||||
validate :start_date_before_end_date
|
||||
validate :valid_room
|
||||
validate :overlapping
|
||||
|
||||
before_validation :capitalize_color
|
||||
|
||||
scope :accepted, -> { where(state: 'accepted') }
|
||||
scope :confirmed, -> { where(state: 'confirmed') }
|
||||
scope :cfp_active, -> { where(cfp_active: true) }
|
||||
scope :self_organized, -> { where.not(submitter: nil) }
|
||||
|
||||
state_machine initial: :pending do
|
||||
state :new
|
||||
state :to_accept
|
||||
state :accepted
|
||||
state :confirmed
|
||||
state :to_reject
|
||||
state :rejected
|
||||
state :canceled
|
||||
state :withdrawn
|
||||
|
||||
event :restart do
|
||||
transitions to: :new, from: [:rejected, :withdrawn, :canceled]
|
||||
end
|
||||
event :to_accept do
|
||||
transitions to: :to_accept, from: [:new, :to_reject]
|
||||
end
|
||||
event :accept do
|
||||
transitions to: :accepted, from: [:new, :to_accept], on_transition: :create_organizer_role
|
||||
end
|
||||
event :confirm do
|
||||
transitions to: :confirmed, from: [:accepted], on_transition: :assign_role_to_submitter
|
||||
end
|
||||
event :to_reject do
|
||||
transitions to: :to_reject, from: [:new, :to_accept]
|
||||
end
|
||||
event :reject do
|
||||
transitions to: :rejected, from: [:new, :to_reject]
|
||||
end
|
||||
event :cancel do
|
||||
transitions to: :canceled, from: [:to_accept, :to_reject, :accepted, :confirmed], on_transition: :revoke_role_and_cleanup
|
||||
end
|
||||
event :withdraw do
|
||||
transitions to: :withdrawn, from: [:new, :to_accept, :to_reject, :accepted, :confirmed], on_transition: :revoke_role_and_cleanup
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
def transition_possible?(transition)
|
||||
self.class.state_machine.events_for(current_state).include?(transition)
|
||||
end
|
||||
|
||||
# Gives the role of the track_organizer to the submitter
|
||||
def assign_role_to_submitter
|
||||
submitter.add_role 'track_organizer', self
|
||||
end
|
||||
|
||||
##
|
||||
# Revokes the track organizer role, destroys the track's schedule, removes the
|
||||
# track from events that have it set and reverts their state to new
|
||||
#
|
||||
def revoke_role_and_cleanup
|
||||
role = Role.find_by(name: 'track_organizer', resource: self)
|
||||
|
||||
if role
|
||||
role.users.each do |user|
|
||||
user.remove_role 'track_organizer', self
|
||||
end
|
||||
end
|
||||
|
||||
self.selected_schedule_id = nil
|
||||
save!
|
||||
|
||||
schedules.each(&:destroy!)
|
||||
|
||||
events.each do |event|
|
||||
event.track = nil
|
||||
event.state = 'new'
|
||||
event.save!
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Checks if the track is accepted
|
||||
# ====Returns
|
||||
# * +true+ -> If the track's state is 'accepted'
|
||||
# * +false+ -> If the track's state isn't 'accepted'
|
||||
def accepted?
|
||||
state == 'accepted'
|
||||
end
|
||||
|
||||
##
|
||||
# Checks if the track is confirmed
|
||||
# ====Returns
|
||||
# * +true+ -> If the track's state is 'confirmed'
|
||||
# * +false+ -> If the track's state isn't 'confirmed'
|
||||
def confirmed?
|
||||
state == 'confirmed'
|
||||
end
|
||||
|
||||
##
|
||||
# Checks if a self-organized track is accepted or confirmed
|
||||
# ====Returns
|
||||
# * +true+ -> If the track's state is 'accepted' or 'confirmed'
|
||||
# * +false+ -> If the track's state is neither 'accepted' nor 'confirmed'
|
||||
def self_organized_and_accepted_or_confirmed?
|
||||
self_organized? && (accepted? || confirmed?)
|
||||
end
|
||||
|
||||
def update_state(transition)
|
||||
error = ''
|
||||
|
||||
begin
|
||||
send(transition)
|
||||
rescue Transitions::InvalidTransition => e
|
||||
error += "State update failed. #{e.message} "
|
||||
end
|
||||
|
||||
error += errors.full_messages.join(', ') unless save
|
||||
error
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_guid
|
||||
|
|
@ -27,4 +188,51 @@ 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
|
||||
|
||||
##
|
||||
# Verify that the track's dates are between the conference's dates
|
||||
#
|
||||
def dates_within_conference_dates
|
||||
return unless start_date && end_date && program.try(:conference).try(:start_date) && program.try(:conference).try(:end_date)
|
||||
errors.add(:start_date, "can't be outside of the conference's dates (#{program.conference.start_date}-#{program.conference.end_date})") unless (program.conference.start_date..program.conference.end_date).cover?(start_date)
|
||||
errors.add(:end_date, "can't be outside of the conference's dates (#{program.conference.start_date}-#{program.conference.end_date})") unless (program.conference.start_date..program.conference.end_date).cover?(end_date)
|
||||
end
|
||||
|
||||
##
|
||||
# Verify that the start date isn't after the end date
|
||||
#
|
||||
def start_date_before_end_date
|
||||
return unless start_date && end_date
|
||||
errors.add(:start_date, 'can\'t be after the end date') if start_date > end_date
|
||||
end
|
||||
|
||||
##
|
||||
# Verify that the room is a room of the conference
|
||||
#
|
||||
def valid_room
|
||||
return unless room.try(:venue).try(:conference) && program.try(:conference)
|
||||
errors.add(:room, "must be a room of #{program.conference.venue.name}") unless room.venue.conference == program.conference
|
||||
end
|
||||
|
||||
##
|
||||
# Check that there is no other track in the same room with overlapping dates
|
||||
#
|
||||
def overlapping
|
||||
return unless start_date && end_date && room && program.try(:tracks)
|
||||
(program.tracks.accepted + program.tracks.confirmed - [self]).each do |existing_track|
|
||||
next unless existing_track.room == room && existing_track.start_date && existing_track.end_date
|
||||
if start_date >= existing_track.start_date && start_date <= existing_track.end_date ||
|
||||
end_date >= existing_track.start_date && end_date <= existing_track.end_date ||
|
||||
start_date <= existing_track.start_date && end_date >= existing_track.end_date
|
||||
errors.add(:track, 'has overlapping dates with a confirmed or accepted track in the same room')
|
||||
break
|
||||
end
|
||||
end
|
||||
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,13 +30,13 @@ 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: [] ]
|
||||
else
|
||||
devise_modules += [:database_authenticatable, :registerable,
|
||||
devise_modules += if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
|
||||
[:ichain_authenticatable, :ichain_registerable, :omniauthable, omniauth_providers: []]
|
||||
else
|
||||
[:database_authenticatable, :registerable,
|
||||
:recoverable, :rememberable, :trackable, :validatable, :confirmable,
|
||||
:omniauthable, omniauth_providers: [:suse, :google, :facebook, :github] ]
|
||||
end
|
||||
:omniauthable, omniauth_providers: [:suse, :google, :facebook, :github]]
|
||||
end
|
||||
|
||||
devise(*devise_modules)
|
||||
|
||||
|
|
@ -42,14 +47,26 @@ 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 :registrations, dependent: :destroy do
|
||||
def for_conference conference
|
||||
where(conference: conference).first
|
||||
end
|
||||
end
|
||||
has_many :events_registrations, through: :registrations
|
||||
has_many :ticket_purchases, dependent: :destroy
|
||||
has_many :payments, dependent: :destroy
|
||||
has_many :tickets, through: :ticket_purchases, source: :ticket
|
||||
has_many :tickets, through: :ticket_purchases, source: :ticket do
|
||||
def for_registration conference
|
||||
where(conference: conference, registration_ticket: true).first
|
||||
end
|
||||
end
|
||||
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'
|
||||
has_many :booth_requests
|
||||
has_many :booth_requests, dependent: :destroy
|
||||
has_many :booths, through: :booth_requests
|
||||
accepts_nested_attributes_for :roles
|
||||
|
||||
scope :admin, -> { where(is_admin: true) }
|
||||
|
|
@ -80,6 +97,12 @@ class User < ActiveRecord::Base
|
|||
event_registration.attended
|
||||
end
|
||||
|
||||
def mark_attendance_for_conference conference
|
||||
registration = registrations.for_conference(conference)
|
||||
registration.attended = true
|
||||
registration.save
|
||||
end
|
||||
|
||||
def name
|
||||
self[:name].blank? ? username : self[:name]
|
||||
end
|
||||
|
|
@ -156,7 +179,11 @@ class User < ActiveRecord::Base
|
|||
def get_roles
|
||||
result = {}
|
||||
roles.each do |role|
|
||||
resource = Conference.find(role.resource_id).short_title
|
||||
resource = if role.resource_type == 'Conference'
|
||||
Conference.find(role.resource_id).short_title
|
||||
elsif role.resource_type == 'Track'
|
||||
Track.find(role.resource_id).name
|
||||
end
|
||||
if result[role.name].nil?
|
||||
result[role.name] = [resource]
|
||||
else
|
||||
|
|
|
|||
92
app/pdfs/ticket_pdf.rb
Normal file
92
app/pdfs/ticket_pdf.rb
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
class TicketPdf < Prawn::Document
|
||||
def initialize(conference, user, physical_ticket, ticket_layout, file_name)
|
||||
super(page_layout: ticket_layout, page_size: 'A4', filename: file_name)
|
||||
@user = user
|
||||
@physical_ticket = physical_ticket
|
||||
@conference = conference
|
||||
|
||||
@left = bounds.left
|
||||
@right = bounds.right
|
||||
@mid_vertical = (bounds.top - bounds.bottom) / 2
|
||||
@mid_horizontal = (bounds.right - bounds.left) / 2
|
||||
@x = 0
|
||||
|
||||
draw_first_square
|
||||
draw_second_square
|
||||
draw_third_square
|
||||
draw_fourth_square
|
||||
end
|
||||
|
||||
def draw_first_square
|
||||
move_down @mid_vertical
|
||||
dash(2, space: 1)
|
||||
stroke_horizontal_rule
|
||||
stroke_vertical_line bounds.top, bounds.bottom, at: @mid_horizontal
|
||||
move_up @mid_vertical
|
||||
draw_text 'TICKET HOLDER', at: [@x, cursor - 30], size: 17
|
||||
dash(2, space: 0)
|
||||
bounding_box [@x, cursor - 50], width: 230, height: 150 do
|
||||
pad(15) do
|
||||
text_box 'NAME', at: [@x + 10, cursor], size: 13
|
||||
fill_color '808080'
|
||||
text_box @user.name.to_s, at: [@x + 10, cursor - 20], size: 18
|
||||
fill_color '000000'
|
||||
text_box 'EMAIL', at: [@x + 10, cursor - 60], size: 13
|
||||
fill_color '808080'
|
||||
text_box @user.email.to_s, at: [@x + 10, cursor - 80], size: 18, overflow: :shrink_to_fit
|
||||
fill_color '000000'
|
||||
end
|
||||
stroke_bounds
|
||||
end
|
||||
end
|
||||
|
||||
def draw_second_square
|
||||
move_up 150
|
||||
if @conference.picture?
|
||||
if 7 * @conference.picture.image[:width] > 12 * @conference.picture.image[:height]
|
||||
image "#{Rails.root}/public#{@conference.picture_url}", at: [@mid_horizontal + 30, cursor], width: 120
|
||||
else
|
||||
image "#{Rails.root}/public#{@conference.picture_url}", at: [@mid_horizontal + 30, cursor], height: 70
|
||||
end
|
||||
else
|
||||
image "#{Rails.root}/public/img/osem-logo.png", at: [@mid_horizontal + 30, cursor], height: 70
|
||||
end
|
||||
move_down 70
|
||||
draw_text @conference.title.to_s, at: [@mid_horizontal + 30, cursor - 30], size: 12
|
||||
draw_text @conference.organization.name.to_s, at: [@mid_horizontal + 30, cursor - 50], size: 12
|
||||
if @conference.venue
|
||||
draw_text @conference.venue.name, at: [@mid_horizontal + 30, cursor - 70]
|
||||
draw_text @conference.venue.street, at: [@mid_horizontal + 30, cursor - 90]
|
||||
draw_text @conference.venue.city, at: [@mid_horizontal + 30, cursor - 110]
|
||||
end
|
||||
move_up 130
|
||||
move_down @mid_vertical
|
||||
end
|
||||
|
||||
def draw_third_square
|
||||
draw_text 'EVENT', at: [@x, cursor - 40], size: 15
|
||||
fill_color '808080'
|
||||
draw_text @conference.title.to_s, at: [@x, cursor - 60], size: 12
|
||||
draw_text @conference.start_date.strftime('%B %d, %Y').to_s, at: [@x, cursor - 80], size: 12
|
||||
move_down 80
|
||||
fill_color '000000'
|
||||
draw_text 'TICKET', at: [@x, cursor - 30], size: 15
|
||||
fill_color '808080'
|
||||
draw_text @physical_ticket.ticket.title.to_s, at: [@x, cursor - 50], size: 12
|
||||
move_down 50
|
||||
fill_color '000000'
|
||||
draw_text 'TICKET REF.', at: [@x, cursor - 30], size: 15
|
||||
fill_color '808080'
|
||||
draw_text @physical_ticket.ticket_purchase.id.to_s, at: [@x, cursor - 50], size: 12
|
||||
move_down 50
|
||||
fill_color '000000'
|
||||
draw_text 'Powered By OSEM', at: [(@mid_horizontal - @left - 100) / 2, cursor - 100], size: 11
|
||||
move_up 180
|
||||
end
|
||||
|
||||
def draw_fourth_square
|
||||
x = @mid_horizontal + (@right - @mid_horizontal - 180) / 2
|
||||
y = cursor - (bounds.top - @mid_vertical - 180) / 2
|
||||
print_qr_code(@physical_ticket.token, pos: [x, y], extent: 180, stroke: false)
|
||||
end
|
||||
end
|
||||
|
|
@ -60,7 +60,7 @@ class ConferenceSerializer < ActiveModel::Serializer
|
|||
|
||||
def date_range
|
||||
if defined? date_string(object.start_date, object.end_date)
|
||||
date_string(object.start_date, object.end_date).try(:split, ',').try(:first)
|
||||
date_string(object.start_date, object.end_date).try(:split, ',').try(:first)
|
||||
end
|
||||
end
|
||||
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]
|
||||
|
|
|
|||
49
app/views/admin/booths/_change_state_dropdown.html.haml
Normal file
49
app/views/admin/booths/_change_state_dropdown.html.haml
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
- if booth.transition_possible? :accept
|
||||
- if can? :accept, booth
|
||||
- if @conference.booth_limit > 0
|
||||
- confirm_message = ' You are able to accept '+ pluralize(@conference.booth_limit - (@conference.booths.accepted.count + @conference.booths.confirmed.count), 'more booth') + " (booth limit set to #{@conference.booth_limit}). Are you sure you want to accept this one?"
|
||||
- if @conference.email_settings.send_on_booths_acceptance
|
||||
- link = 'Accept with email'
|
||||
- confirm_message = "By accepting this booth, an email will be sent informing the submitter for the acceptance. You may change the state to \'To accept\' until you are completely sure." + confirm_message
|
||||
- else
|
||||
- link = 'Accept booth'
|
||||
%li= link_to link,
|
||||
accept_admin_conference_booth_path(@conference.short_title, booth),
|
||||
method: :patch ,id: "accept_booth_#{booth.id}",
|
||||
data: (confirm_message ? { confirm: confirm_message } : nil)
|
||||
|
||||
- if booth.transition_possible? :reject
|
||||
- if @conference.email_settings.send_on_booths_rejection
|
||||
- link = 'Reject with email'
|
||||
- else
|
||||
- link = 'Reject'
|
||||
%li= link_to link,
|
||||
reject_admin_conference_booth_path(@conference.short_title, booth),
|
||||
method: :patch, id: "reject_booth_#{booth.id}",
|
||||
data: (@conference.email_settings.send_on_booths_rejection ? { confirm: 'By rejecting this booth, an email will be sent informing the submitter about the rejection. You may change the state to \'To reject\' until you are completely sure.'} : nil)
|
||||
|
||||
- if booth.transition_possible? :to_reject
|
||||
%li= link_to 'To reject booth',
|
||||
to_reject_admin_conference_booth_path(@conference.short_title, booth),
|
||||
method: :patch, id: "to_reject_booth_#{booth.id}"
|
||||
|
||||
- if booth.transition_possible? :restart
|
||||
%li= link_to 'Start review',
|
||||
restart_admin_conference_booth_path(@conference.short_title, booth),
|
||||
method: :patch, id: "restart_booth_#{booth.id}"
|
||||
|
||||
- if booth.transition_possible? :to_accept
|
||||
%li= link_to 'To accept booth',
|
||||
to_accept_admin_conference_booth_path(@conference.short_title, booth),
|
||||
method: :patch, id: "to_accept_booth_#{booth.id}"
|
||||
|
||||
- if booth.transition_possible? :cancel
|
||||
%li= link_to 'Cancel booth',
|
||||
cancel_admin_conference_booth_path(@conference.short_title, booth),
|
||||
method: :patch, id: "cancel_booth_#{booth.id}"
|
||||
|
||||
- if booth.transition_possible? :confirm
|
||||
%li= link_to 'Confirm booth',
|
||||
confirm_admin_conference_booth_path(@conference.short_title, booth),
|
||||
method: :patch, id: "confirm_booth_#{booth.id}"
|
||||
5
app/views/admin/booths/edit.html.haml
Normal file
5
app/views/admin/booths/edit.html.haml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
%h1
|
||||
Editing
|
||||
= @booth.title
|
||||
|
||||
= render 'booths/form'
|
||||
78
app/views/admin/booths/index.html.haml
Normal file
78
app/views/admin/booths/index.html.haml
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
.row
|
||||
.col-md-12
|
||||
.page-header
|
||||
%h1
|
||||
Booths
|
||||
= "(#{@booths.length})" if @booths.any?
|
||||
%p.text-muted
|
||||
All the booth requests
|
||||
|
||||
.row
|
||||
.col-md-12
|
||||
%h4
|
||||
- if @conference.booth_limit == 0
|
||||
%p
|
||||
Set the
|
||||
= link_to 'Booth limit', edit_admin_conference_path(@conference.short_title)
|
||||
to make sure you are not accepting more booths than you can accommodate.
|
||||
- elsif !@conference.maximum_accepted_booths?
|
||||
%p
|
||||
You cannot accept more than
|
||||
%b
|
||||
= pluralize(@conference.booth_limit, 'booth')
|
||||
(
|
||||
= pluralize(@conference.booths.accepted.count + @conference.booths.confirmed.count, 'accepted booth')
|
||||
so far)
|
||||
- else
|
||||
%p
|
||||
You have reached the maximum number of accepted booths.
|
||||
(
|
||||
= link_to "#{@conference.booth_limit} booths", edit_admin_conference_path(@conference.short_title)
|
||||
)
|
||||
- if @booths.any?
|
||||
%table.table.table-striped.table-bordered.table-hover.datatable
|
||||
%thead
|
||||
%th
|
||||
%b ID
|
||||
%th
|
||||
%b Logo
|
||||
%th
|
||||
%b Title
|
||||
%th
|
||||
%b Submitter
|
||||
%th
|
||||
%b Responsibles
|
||||
%th
|
||||
%b State
|
||||
%th
|
||||
%b Actions
|
||||
- @booths.each do |booth|
|
||||
%tr
|
||||
%td
|
||||
= booth.id
|
||||
%td
|
||||
- if booth.logo_link
|
||||
= image_tag(booth.picture.thumb.url, width: '20%')
|
||||
%td
|
||||
= link_to booth.title, admin_conference_booth_path(@conference.short_title, booth)
|
||||
%td
|
||||
= link_to booth.submitter.name, admin_user_path(booth.submitter) if booth.submitter
|
||||
%td
|
||||
.responsibles
|
||||
- booth.responsibles.each_with_index do |responsible, i|
|
||||
= link_to responsible.name, admin_user_path(responsible)
|
||||
= ", " unless i == booth.responsibles.length - 1
|
||||
%td
|
||||
.btn-group
|
||||
%button{ type: 'button', class: 'btn btn-link dropdown-toggle', 'data-toggle' => 'dropdown' }
|
||||
= booth.state.humanize
|
||||
%span.caret
|
||||
%ul.dropdown-menu{ role: 'menu' }
|
||||
= render 'change_state_dropdown', booth: booth
|
||||
%td
|
||||
= link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id),
|
||||
class: 'btn btn-primary'
|
||||
.row
|
||||
.col-md-12.text-right
|
||||
- if can? :create, Booth
|
||||
= link_to 'New Booth', new_admin_conference_booth_path(@conference.short_title), class: 'button btn btn-primary'
|
||||
3
app/views/admin/booths/new.html.haml
Normal file
3
app/views/admin/booths/new.html.haml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
%h1 New booth
|
||||
|
||||
= render 'booths/form'
|
||||
58
app/views/admin/booths/show.html.haml
Normal file
58
app/views/admin/booths/show.html.haml
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
.row
|
||||
.col-md-12
|
||||
%h3
|
||||
= image_tag(@booth.picture.thumb.url, size: '20%', alt: '')
|
||||
= @booth.title
|
||||
.btn-group.pull-right
|
||||
= link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, @booth), class: 'btn btn-mini btn-primary'
|
||||
|
||||
.row
|
||||
.col-md-12
|
||||
%table.table
|
||||
%tr
|
||||
%td.col-md-2
|
||||
%b Description
|
||||
%td
|
||||
= markdown(@booth.description)
|
||||
%tr
|
||||
%td.col-md-2
|
||||
%b Reasoning
|
||||
%td
|
||||
= markdown(@booth.reasoning)
|
||||
%tr
|
||||
%td.col-md-2
|
||||
%b Website
|
||||
%td
|
||||
- if @booth.website_url.present?
|
||||
= link_to @booth.website_url, @booth.website_url
|
||||
%tr
|
||||
%td.col-md-2
|
||||
%b Submitter
|
||||
%td
|
||||
= link_to @booth.submitter.name, admin_user_path(@booth.submitter)
|
||||
%tr
|
||||
%td.col-md-2
|
||||
%b Submitter's relationship
|
||||
%td
|
||||
= @booth.submitter_relationship
|
||||
%tr
|
||||
%td.col-md-2
|
||||
%b Responsibles
|
||||
%td
|
||||
- @booth.responsibles.each_with_index do |responsibles, i|
|
||||
.responsibles
|
||||
= link_to responsibles.name, admin_user_path(responsibles)
|
||||
(
|
||||
= responsibles.email
|
||||
)
|
||||
= " , " unless i == @booth.responsibles.length - 1
|
||||
%tr
|
||||
%td.col-md-2
|
||||
%b Submitted on
|
||||
%td
|
||||
= @booth.created_at
|
||||
%tr
|
||||
%td.col-md-2
|
||||
%b Last updated on
|
||||
%td
|
||||
= @booth.updated_at
|
||||
16
app/views/admin/cfps/_booths_cfp.html.haml
Normal file
16
app/views/admin/cfps/_booths_cfp.html.haml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
%dt
|
||||
Type:
|
||||
%dd
|
||||
= @cfp.cfp_type.capitalize
|
||||
%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')
|
||||
42
app/views/admin/cfps/_events_cfp.html.haml
Normal file
42
app/views/admin/cfps/_events_cfp.html.haml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
%dt
|
||||
Type:
|
||||
%dd
|
||||
= @cfp.cfp_type.capitalize
|
||||
%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' }
|
||||
|
|
|
|||
16
app/views/admin/cfps/_tracks_cfp.html.haml
Normal file
16
app/views/admin/cfps/_tracks_cfp.html.haml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
%dt
|
||||
Type:
|
||||
%dd
|
||||
= @cfp.cfp_type.capitalize
|
||||
%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')
|
||||
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
|
||||
.row
|
||||
.col-md-12.text-right
|
||||
= link_to(edit_admin_conference_program_cfp_path(@conference.short_title), 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
|
||||
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'
|
||||
.row
|
||||
.col-md-8
|
||||
%dl.dl-horizontal
|
||||
= render "#{@cfp.cfp_type}_cfp"
|
||||
.row
|
||||
.col-md-12.text-right
|
||||
= 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, @cfp.id), method: 'delete', class: 'btn btn-danger', data: { confirm: 'Are you sure you want to delete the CfP?' }) do
|
||||
Delete
|
||||
|
|
|
|||
|
|
@ -1,6 +1,23 @@
|
|||
.text-center
|
||||
%h4 #{title}
|
||||
%canvas.doughnut_chart{ 'data-chart' => data.to_json }
|
||||
%canvas.doughnut_chart{ id: "dough_#{title}", 'data-chart' => data.to_json }
|
||||
- if data
|
||||
- data.each do |key, value|
|
||||
%span{ 'style' => "border-bottom: 3px solid #{value['color']}" } #{key}: #{value['value']}
|
||||
|
||||
:javascript
|
||||
$(document).ready( function(){
|
||||
|
||||
var d = $("#dough_#{title}");
|
||||
var dt = d.get(0).getContext('2d');
|
||||
|
||||
$(window).resize( respondCanvas );
|
||||
|
||||
function respondCanvas(){
|
||||
dt.canvas.width = 150;
|
||||
dt.canvas.height = 150;
|
||||
}
|
||||
|
||||
respondCanvas();
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,3 +27,21 @@
|
|||
%span{ 'style' => "border-bottom: 3px solid #{conference[:color]};", 'data-chart' => "#{name}" }
|
||||
%input{ 'type' => 'checkbox', 'name' => "#{conference[:short_title]}" }
|
||||
#{conference[:short_title]}
|
||||
|
||||
:javascript
|
||||
$(document).ready( function(){
|
||||
|
||||
var c = $("#line_chart_#{name}");
|
||||
var ct = c.get(0).getContext('2d');
|
||||
var container = $(c).parent();
|
||||
|
||||
$(window).resize( respondCanvas );
|
||||
|
||||
function respondCanvas(){
|
||||
c.attr('width', $(container).width() );
|
||||
c.attr('height', $(container).height() );
|
||||
}
|
||||
|
||||
respondCanvas();
|
||||
|
||||
});
|
||||
|
|
|
|||
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