Merge branch 'master' into moving-users

This commit is contained in:
Shlok Srivastava 2017-08-01 13:20:51 +05:30 committed by GitHub
commit 6b55a28813
53 changed files with 1105 additions and 318 deletions

View file

@ -11,6 +11,9 @@ linters:
# Offense count: 945
LineLength:
exclude:
- "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"
@ -179,6 +182,7 @@ linters:
# 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"

View file

@ -3,7 +3,7 @@ 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`"

1
CODE_OF_CONDUCT.md Normal file
View 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

View file

@ -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

View file

@ -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
@ -201,7 +201,7 @@ gem 'selectize-rails'
# Use guard and spring for testing in development
group :development do
# to launch specs when files are modified
gem 'guard-rspec', '~> 4.2.8'
gem 'guard-rspec'
gem 'spring-commands-rspec'
gem 'haml_lint', '~> 0.24.0'
# for static code analisys
@ -220,7 +220,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'

View file

@ -12,40 +12,39 @@ 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)
@ -58,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)
@ -67,7 +67,7 @@ GEM
request_store
user_agent_parser
uuidtools
arel (6.0.3)
arel (6.0.4)
ast (2.3.0)
autoprefixer-rails (5.1.9)
execjs
@ -88,7 +88,7 @@ GEM
bootstrap3-datetimepicker-rails (3.0.3)
momentjs-rails (>= 2.8.1)
browser (0.6.0)
builder (3.2.2)
builder (3.2.3)
byebug (9.0.6)
cancancan (1.13.1)
capybara (2.6.2)
@ -107,11 +107,6 @@ 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)
@ -121,7 +116,7 @@ GEM
aws_cf_signer
rest-client
cocoon (1.2.6)
coderay (1.1.0)
coderay (1.1.1)
coffee-rails (4.1.1)
coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.1.x)
@ -143,7 +138,7 @@ 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)
@ -163,7 +158,7 @@ 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)
@ -184,27 +179,32 @@ GEM
multipart-post (>= 1.2, < 3)
fastimage (2.0.0)
addressable (~> 2)
ffi (1.9.3)
ffi (1.9.18)
font-awesome-rails (4.1.0.0)
railties (>= 3.2, < 5.0)
formatador (0.2.4)
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)
@ -218,6 +218,7 @@ GEM
rake (>= 10, < 13)
rubocop (>= 0.47.0)
sysexits (~> 1.1)
hashdiff (0.3.4)
hashie (2.1.1)
hike (1.2.3)
hoptoad_notifier (2.4.11)
@ -228,8 +229,8 @@ 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
@ -252,26 +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.2.0)
minitest (5.10.1)
minitest (5.10.2)
momentjs-rails (2.8.1)
railties (>= 3.1)
monetize (1.4.0)
@ -284,14 +284,17 @@ 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)
nenv (0.3.0)
netrc (0.11.0)
nio4r (1.2.1)
nokogiri (1.8.0)
mini_portile2 (~> 2.2.0)
notiffany (0.1.1)
nenv (~> 0.1)
shellany (~> 0.0)
oauth2 (0.9.4)
faraday (>= 0.8, < 0.10)
jwt (~> 1.0)
@ -347,26 +350,27 @@ GEM
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)
@ -401,24 +405,23 @@ GEM
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.2)
rake
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)
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)
@ -431,30 +434,31 @@ GEM
rolify (5.1.0)
rqrcode (0.10.1)
chunky_png (~> 1.0)
rspec (3.0.0)
rspec-core (~> 3.0.0)
rspec-expectations (~> 3.0.0)
rspec-mocks (~> 3.0.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)
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)
@ -465,6 +469,7 @@ 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)
@ -474,6 +479,7 @@ GEM
sprockets (~> 2.8, < 2.12)
sprockets-rails (~> 2.0)
selectize-rails (0.12.4)
shellany (0.0.1)
shoulda-matchers (2.8.0)
activesupport (>= 3.0.0)
simplecov (0.11.2)
@ -507,11 +513,10 @@ GEM
sysexits (1.2.0)
term-ansicolor (1.3.2)
tins (~> 1.0)
thor (0.19.1)
thor (0.19.4)
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)
@ -537,9 +542,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)
@ -548,7 +554,7 @@ GEM
chronic (>= 0.6.3)
xpath (2.0.0)
nokogiri (~> 1.3)
yajl-ruby (1.2.0)
yajl-ruby (1.3.0)
PLATFORMS
ruby
@ -589,7 +595,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)
@ -616,7 +622,7 @@ DEPENDENCIES
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!
@ -636,7 +642,7 @@ DEPENDENCIES
rolify
rqrcode
rspec-activemodel-mocks
rspec-rails
rspec-rails (~> 3.5, >= 3.5.2)
rubocop (~> 0.49.0)
ruby-oembed
sass-rails (>= 4.0.2)

View file

@ -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;

View file

@ -89,4 +89,8 @@ p.comment-body {
.changeset{
display: none;
}
}
.box{
height: 230px;
}

View file

@ -0,0 +1,94 @@
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; end
def create
@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[:error] = "Creating booth failed. #{@booth.errors.full_messages.to_sentence}."
render :new
end
end
def edit; end
def update
@booth.update_attributes(booth_params)
if @booth.save
redirect_to admin_conference_booths_path,
notice: "Successfully updated booth for #{@booth.title}."
else
flash[:error] = "An error prohibited the Booth for #{@booth.title} "\
"#{@booth.errors.full_messages.join('. ')}."
render :edit
end
end
def destroy
if @booth.destroy
redirect_to admin_conference_booths_path,
notice: 'Booth successfully destroyed.'
else
redirect_to admin_conference_booths_path,
error: "Booth couldn't be deleted. #{@booth.errors.full_messages.join('. ')}."
end
end
def accept
update_state(:accept, 'Booth accepted!')
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
update_state(:reject, 'Booth rejected')
end
def restart
update_state(:restart, 'Booth is submitted')
end
def cancel
update_state(:cancel, 'Booth is canceled')
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

View file

@ -1,7 +1,7 @@
class PhysicalTicketController < ApplicationController
before_action :authenticate_user!
load_resource :conference, find_by: :short_title
load_and_authorize_resource
load_and_authorize_resource find_by: :token
authorize_resource :conference_registrations, class: Registration
def index
@ -13,5 +13,15 @@ class PhysicalTicketController < ApplicationController
@file_name = "ticket_for_#{@conference.short_title}"
@user = @physical_ticket.user
@ticket_layout = @conference.ticket_layout.to_sym
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

View file

@ -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

View file

@ -162,6 +162,13 @@ 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' }
end
def event_types(conference)
conference.program.event_types.map { |et| et.title.pluralize }.to_sentence
end

View file

@ -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.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

View file

@ -119,6 +119,7 @@ class AdminAbility
commercialable_id: conf_ids
can :manage, Registration, conference_id: conf_ids
can :manage, RegistrationPeriod, conference_id: conf_ids
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?
@ -169,6 +170,7 @@ class AdminAbility
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 }

76
app/models/booth.rb Normal file
View file

@ -0,0 +1,76 @@
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
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
event :restart do
transitions to: :new, from: [:withdrawn, :to_accept, :to_reject, :canceled]
end
event :withdraw do
transitions to: :withdrawn, from: [:new, :to_accept, :accepted, :to_reject, :rejected]
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]
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

View 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

View file

@ -28,6 +28,7 @@ class Conference < ActiveRecord::Base
has_many :supporters, through: :ticket_purchases, source: :user
has_many :tickets, dependent: :destroy
has_many :resources, dependent: :destroy
has_many :booths, dependent: :destroy
has_many :lodgings, dependent: :destroy
has_many :registrations, dependent: :destroy

View file

@ -4,4 +4,19 @@ class PhysicalTicket < ActiveRecord::Base
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

View file

@ -1,5 +1,4 @@
class Subscription < ActiveRecord::Base
validates :user_id, uniqueness: { scope: [:conference_id] }
belongs_to :conference
belongs_to :user

View file

@ -69,6 +69,7 @@ class TicketPurchase < ActiveRecord::Base
PhysicalTicket.transaction do
quantity.times { physical_tickets.create }
end
Mailbot.ticket_confirmation_mail(self).deliver_later
end
end

View file

@ -56,6 +56,9 @@ class User < ActiveRecord::Base
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) }

81
app/pdfs/ticket_pdf.rb Normal file
View file

@ -0,0 +1,81 @@
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)
stroke_rectangle [@x, cursor - 50], 230, 150
move_down 80
draw_text 'NAME', at: [@x + 10, cursor], size: 13
fill_color '808080'
draw_text @user.name.to_s, at: [@x + 10, cursor - 25], size: 20
fill_color '000000'
draw_text 'EMAIL', at: [@x + 10, cursor - 50], size: 13
fill_color '808080'
draw_text @user.email.to_s, at: [@x + 10, cursor - 75], size: 20
fill_color '000000'
move_up 20
end
def draw_second_square
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
draw_text @conference.venue.name.to_s, at: [@mid_horizontal + 30, cursor - 70]
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; end
end

View file

@ -0,0 +1,29 @@
- if booth.transition_possible? :accept
%li= link_to 'Accept booth',
accept_admin_conference_booth_path(@conference.short_title, booth),
method: :patch, id: "accept_booth_#{booth.id}"
- if booth.transition_possible? :reject
%li= link_to 'Reject booth',
reject_admin_conference_booth_path(@conference.short_title, booth),
method: :patch, confirm: 'Are you sure?', id: "reject_booth_#{booth.id}"
- if booth.transition_possible? :to_reject
%li= link_to 'To reject booth',
to_reject_admin_conference_booth_path(@conference.short_title, booth),
method: :patch, confirm: 'Are you sure?', 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}"

View file

@ -0,0 +1,33 @@
.row
.col-md-12
.page-header
%title Request a Booth
.row
.col-md-8
= semantic_form_for(@booth, url: @booth.new_record? ? admin_conference_booths_path(@conference.short_title) : admin_conference_booth_path(@conference.short_title, @booth.id), html: { multipart: true }) do |f|
= f.input :title, as: :string, autofocus: true, required: true
= f.input :description, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true,
hint: 'This field becomes public upon request acceptance'
= f.input :reasoning, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true,
label: 'How it fits the conference'
= f.input :submitter_relationship, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true,
label: 'Submitter\'s relation',
hint: 'e.g. employee, comunity manager, etc'
= f.input :website_url
= responsibles_selector_input f
= image_tag f.object.picture.thumb.url if f.object.picture?
= f.input :picture
%p.text-right
- if @booth.new_record?
= f.submit 'Create Booth Request', class: 'btn btn-success'
- else
= f.submit 'Update Booth Request', class: 'btn btn-success'
:javascript
$(document).ready(function() {
$('#booth_responsible_ids').selectize({
plugins: ['remove_button'],
minItems: 2
} )
});

View file

@ -0,0 +1,5 @@
%h1
Editing
= @booth.title
= render 'form'

View file

@ -0,0 +1,59 @@
.row
.col-md-12
.page-header
%h1
Booths
= "(#{@booths.length})" if @booths.any?
.pull-right
- if can? :create, Booth
= link_to 'Add Booth', new_admin_conference_booth_path(@conference.short_title), class: 'button btn btn-primary'
%p.text-muted
All the booth requests
.row
.col-md-12
.margin-booth-table
%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 do |responsible|
= link_to responsible.name, admin_user_path(responsible)
%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
.btn-group{ role: "group" }
= link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, booth.id),
class: 'btn btn-primary'
= link_to 'Delete', admin_conference_booth_path(@conference.short_title, booth.id),
method: :delete, class: 'btn btn-danger',
data: {confirm: "Do you really want to delete this booth request?"}

View file

@ -0,0 +1,3 @@
%h1 New booth
= render 'form'

View file

@ -0,0 +1,57 @@
.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 do |responsibles|
.responsibles
= link_to responsibles.name, admin_user_path(responsibles)
(
= responsibles.email
)
%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

View file

@ -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();
});

View file

@ -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();
});

View file

@ -32,12 +32,12 @@
.btn-group
= link_to 'Show',
conference_physical_ticket_path(@conference.short_title,
physical_ticket.id),
physical_ticket.token),
class: 'btn btn-primary'
= link_to 'Generate PDF',
conference_physical_ticket_path(@conference.short_title,
physical_ticket.id,
format: :pdf),
physical_ticket.token,
format: :pdf),
class: 'button btn btn-default btn-info'
- else
%h5 No Tickets sold!

View file

@ -80,6 +80,12 @@
= link_if_alive version, 'contact details',
edit_admin_conference_contact_path(conference_id: Conference.find(version.conference_id).short_title)
- when 'Booth'
= 'booth'
- booth = current_or_last_object_state(version.item_type, version.item_id)
= link_if_alive version, booth.title,
admin_conference_booth_path(conference_id: Conference.find(version.conference_id).short_title, id: version.item_id )
- when 'Program'
= link_if_alive version, 'program',
admin_conference_program_path(conference_id: Conference.find(version.conference_id).short_title)

View file

@ -60,13 +60,13 @@
.dropdown-menu
- if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
= form_tag User.ichain_login_url do
= text_field_tag 'username', nil, id: 'user_ichain_email_dd', placeholder: 'Username'
= password_field_tag 'password', nil, id: 'user_ichain_password_dd', placeholder: 'Password'
= text_field_tag 'username', nil, id: 'user_ichain_email_dd', class: 'form-control', placeholder: 'Username'
= password_field_tag 'password', nil, id: 'user_ichain_password_dd', class: 'form-control', placeholder: 'Password'
%button.btn.btn-success.btn-block Sign in
- else
= form_tag new_user_session_path do
= text_field_tag 'user[login]', nil, id: 'user_login_dd', placeholder: 'Username / E-Mail'
= password_field_tag 'user[password]', nil, id: 'user_password_dd', placeholder: 'Password'
= text_field_tag 'user[login]', nil, id: 'user_login_dd', class: 'form-control', placeholder: 'Username / E-Mail'
= password_field_tag 'user[password]', nil, id: 'user_password_dd', class: 'form-control', placeholder: 'Password'
%p.text-right
%small
%label{for: 'user_remember_me'} Remember me

View file

@ -0,0 +1,8 @@
Dear <%= @user.name %>,
Thanks! You have successfully booked <%= @ticket_purchase.quantity %> <%= @ticket_purchase.ticket.title %> ticket(s) for the event <%= @conference.title %>. Your transaction id is <%= @ticket_purchase.id %>.
Please, find the ticket(s) pdf attached.
Best wishes,
<%= @conference.title %> Team

View file

@ -24,11 +24,11 @@
.btn-group
= link_to 'Show',
conference_physical_ticket_path(@conference.short_title,
physical_ticket.id),
physical_ticket.token),
class: 'btn btn-primary'
= link_to 'Generate PDF',
conference_physical_ticket_path(@conference.short_title,
physical_ticket.id,
physical_ticket.token,
format: :pdf),
class: 'button btn btn-default btn-info'
- else

View file

@ -0,0 +1,77 @@
.container
.row
.col-md-12
.page-header
%h1
Ticket for
= @conference.title
%p.text-muted
- if @conference.venue
at
%strong
#{@conference.venue.name},
#{@conference.venue.street},
#{@conference.venue.city} / #{@conference.venue.country_name}.
%small
= date_string(@conference.start_date, @conference.end_date)
.row
.col-md-5.box.well
%h3.text-center
Ticket Holder
%p.text-left
%strong
Name
%br
= @user.name
%br
%br
%strong
Email
%br
= @user.email
.col-md-5.col-md-offset-2.box.well
- if @conference.picture?
- width = @conference.picture.image[:width]
- height = @conference.picture.image[:height]
- if 10 * width > 15 * height
= image_tag(@conference.picture_url, width: '150')
- else
= image_tag(@conference.picture_url, height: '100')
- else
= image_tag('/img/osem-logo.png', class: 'img-responsive')
%p.text-left
%br
%strong
Organization
%br
= @conference.organization.name
.col-md-5.box.well
%p.text-left
%strong
Event
%br
= @conference.title
%br
= @conference.start_date.strftime('%B %d, %Y')
%br
%br
%strong
Ticket
%br
= @physical_ticket.ticket.title
%br
%br
%strong
Ticket Ref.
%br
= @physical_ticket.ticket_purchase.id
%br
.col-md-5.col-md-offset-2.box.well
.row
.col-md-12
%p.text-left
= link_to 'Generate PDF',
conference_physical_ticket_path(@conference.short_title,
@physical_ticket.token,
format: :pdf),
class: 'button btn btn-default btn-info'

View file

@ -1,62 +0,0 @@
prawn_document(filename: @file_name, page_layout: @ticket_layout, :page_size =>'A4' ) do |pdf|
# Vertical Layout
top = pdf.bounds.top
bottom = pdf.bounds.bottom
left = pdf.bounds.left
right = pdf.bounds.right
mid_vertical = (pdf.bounds.top-pdf.bounds.bottom)/2
mid_horizontal = (pdf.bounds.right-pdf.bounds.left)/2
x = 0
pdf.move_down mid_vertical
pdf.dash(2, :space => 1)
pdf.stroke_horizontal_rule
pdf.stroke_vertical_line pdf.bounds.top, pdf.bounds.bottom, :at => mid_horizontal
pdf.move_up mid_vertical
pdf.draw_text "TICKET HOLDER", :at => [x,pdf.cursor-30], :size => 17
pdf.dash(2, :space => 0)
pdf.stroke_rectangle [x, pdf.cursor-50], 230, 150
pdf.move_down 80
pdf.draw_text "NAME", :at => [x+10,pdf.cursor], :size => 13
pdf.fill_color "808080"
pdf.draw_text "#{@user.name}", :at => [x+10,pdf.cursor-25], size: 20
pdf.fill_color "000000"
pdf.draw_text "EMAIL", :at => [x+10,pdf.cursor-50], :size => 13
pdf.fill_color "808080"
pdf.draw_text "#{@user.email}", :at => [x+10,pdf.cursor-75], size: 20
pdf.fill_color "000000"
pdf.move_up 20
if @conference.picture?
if 7 * @conference.picture.image[:width] > 12 * @conference.picture.image[:height]
pdf.image "#{Rails.root}/public#{@conference.picture_url}", :at => [mid_horizontal+30, pdf.cursor], :width => 120
else
pdf.image "#{Rails.root}/public#{@conference.picture_url}", :at => [mid_horizontal+30, pdf.cursor], :height => 70
end
else
pdf.image "#{Rails.root}/public/img/osem-logo.png", :at => [mid_horizontal+30, pdf.cursor], :height => 70
end
pdf.move_down 70
pdf.draw_text "#{@conference.title}", :at => [mid_horizontal+30,pdf.cursor-30], :size => 12
pdf.draw_text "#{@conference.organization.name}", :at => [mid_horizontal+30,pdf.cursor-50], :size => 12
pdf.draw_text "#{@conference.venue.name}", :at => [mid_horizontal+30,pdf.cursor-70]
pdf.move_up 130
pdf.move_down mid_vertical
pdf.draw_text "EVENT", :at => [x,pdf.cursor-40], :size => 15
pdf.fill_color "808080"
pdf.draw_text "#{@conference.title}", :at => [x,pdf.cursor-60], size: 12
pdf.draw_text "#{@conference.start_date.strftime('%B %d, %Y')}", :at => [x,pdf.cursor-80], size: 12
pdf.move_down 80
pdf.fill_color "000000"
pdf.draw_text "TICKET", :at => [x,pdf.cursor-30], :size => 15
pdf.fill_color "808080"
pdf.draw_text "#{@physical_ticket.ticket.title}", :at => [x,pdf.cursor-50], size: 12
pdf.move_down 50
pdf.fill_color "000000"
pdf.draw_text "TICKET REF.", :at => [x,pdf.cursor-30], :size => 15
pdf.fill_color "808080"
pdf.draw_text "#{@physical_ticket.ticket_purchase.id}", :at => [x,pdf.cursor-50], size: 12
pdf.move_down 50
pdf.fill_color "000000"
pdf.draw_text "Powered By OSEM", :at => [(mid_horizontal-left-100)/2,pdf.cursor-100], :size => 11
pdf.move_up 180
end

View file

@ -2,7 +2,7 @@
pushd /vagrant
echo -e "\ninstalling required software packages...\n"
zypper -q -n install update-alternatives ruby2.2-devel make gcc gcc-c++ \
zypper -q -n install update-alternatives ruby2.4-devel make gcc gcc-c++ \
libxml2-devel libxslt-devel nodejs screen mariadb \
libmysqld-devel sqlite3-devel ImageMagick
@ -10,7 +10,7 @@ echo -e "\ndisabling versioned gem binary names...\n"
echo 'install: --no-format-executable' >> /etc/gemrc
echo -e "\ninstalling bundler...\n"
gem.ruby2.2 install bundler
gem.ruby2.4 install bundler
echo -e "\ninstalling your bundle...\n"
su - vagrant -c "cd /vagrant/; bundle install --quiet"

View file

@ -37,6 +37,19 @@ Osem::Application.routes.draw do
get '/volunteers' => 'volunteers#index', as: 'volunteers_info'
patch '/volunteers' => 'volunteers#update', as: 'volunteers_update'
resources :booths do
member do
patch :accept
patch :restart
patch :withdrawn
patch :to_accept
patch :reject
patch :reset
patch :to_reject
patch :cancel
end
end
resources :registrations, except: [:create, :new] do
member do
patch :toggle_attendance

View file

@ -0,0 +1,16 @@
class CreateBooths < ActiveRecord::Migration
def change
create_table :booths do |t|
t.string :title
t.text :description
t.text :reasoning
t.string :state
t.string :logo_link
t.string :website_url
t.text :submitter_relationship
t.references :conference
t.timestamps null: false
end
end
end

View file

@ -0,0 +1,11 @@
class CreateBoothRequests < ActiveRecord::Migration
def change
create_table :booth_requests do |t|
t.references :booth, index: true, foreign_key: true
t.references :user, index: true, foreign_key: true
t.string :role
t.timestamps null: false
end
end
end

View file

@ -0,0 +1,6 @@
class AddIndexToPhysicalTickets < ActiveRecord::Migration
def change
add_column :physical_tickets, :token, :string
add_index :physical_tickets, :token, unique: true
end
end

View file

@ -11,10 +11,10 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170711102511) do
ActiveRecord::Schema.define(version: 20170721001700) do
create_table "ahoy_events", force: :cascade do |t|
t.uuid "visit_id", limit: 16
t.integer "visit_id"
t.integer "user_id"
t.string "name"
t.text "properties"
@ -31,6 +31,30 @@ ActiveRecord::Schema.define(version: 20170711102511) do
t.datetime "updated_at"
end
create_table "booth_requests", force: :cascade do |t|
t.integer "booth_id"
t.integer "user_id"
t.string "role"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "booth_requests", ["booth_id"], name: "index_booth_requests_on_booth_id"
add_index "booth_requests", ["user_id"], name: "index_booth_requests_on_user_id"
create_table "booths", force: :cascade do |t|
t.string "title"
t.text "description"
t.text "reasoning"
t.string "state"
t.string "logo_link"
t.string "website_url"
t.text "submitter_relationship"
t.integer "conference_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "campaigns", force: :cascade do |t|
t.integer "conference_id"
t.string "name"
@ -293,8 +317,11 @@ ActiveRecord::Schema.define(version: 20170711102511) do
t.integer "ticket_purchase_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "token"
end
add_index "physical_tickets", ["token"], name: "index_physical_tickets_on_token", unique: true
create_table "programs", force: :cascade do |t|
t.integer "conference_id"
t.integer "rating", default: 0

View file

@ -0,0 +1,148 @@
require 'spec_helper'
describe Admin::BoothsController do
let(:admin) { create(:admin) }
let(:conference) { create(:conference) }
let(:booth) { create(:booth, title: 'Title', conference: conference) }
let(:admin) { create(:admin) }
context 'not logged in user' do
describe 'GET index' do
it 'does not render admin/booths#index' do
get :index, conference_id: conference.short_title
expect(response).to redirect_to(user_session_path)
end
end
describe 'GET show' do
it 'does not render admin/booths#show' do
get :show, id: booth.id, conference_id: conference.short_title
expect(response).to redirect_to(user_session_path)
end
end
end
context 'user is admin' do
before :each do
sign_in admin
end
describe 'GET index' do
before { get :index, conference_id: conference.short_title }
it 'assigns attributes for booths' do
expect(assigns(:booths)).to eq([booth])
end
it 'renders index template' do
expect(response).to render_template('index')
end
end
describe 'GET new' do
before { get :new, conference_id: conference.short_title }
it 'assigns attributes for booths' do
expect(assigns(:booth)).to be_a_new(Booth)
end
it 'renders new template' do
expect(response).to render_template('new')
end
end
describe 'POST #create' do
context 'successfully created' do
before { post :create, booth: attributes_for(:booth), conference_id: conference.short_title }
it 'creates a new booth' do
expected = expect do
post :create, booth: attributes_for(:booth), conference_id: conference.short_title
end
expected.to change { Booth.count }.by(1)
end
it 'redirects to admin booth index' do
expect(response).to redirect_to(admin_conference_booths_path)
end
it 'has responsibles' do
expect(booth.responsibles.count).to_not eq(0)
end
it 'shows success message' do
expect(flash[:notice]).to match('Booth successfully created.')
end
end
context 'create action fails' do
before { post :create, booth: attributes_for(:booth, title: ''), conference_id: conference.short_title }
it 'does not create any record' do
expected = expect do
post :create, booth: attributes_for(:booth, title: ''), conference_id: conference.short_title
end
expected.to_not change(Booth, :count)
end
it 'redirects to new' do
expect(response).to render_template('new')
end
it 'shows flash message' do
expect(flash[:error]).to eq("Creating booth failed. Title can't be blank.")
end
end
end
describe 'GET #edit' do
before { get :edit, id: booth.id, conference_id: conference.short_title }
it 'renders edit template' do
expect(response).to render_template('edit')
end
it 'assigns booth variable' do
expect(assigns(:booth)).to eq booth
end
end
describe 'PATCH #update' do
context 'updates suchessfully' do
before { patch :update, id: booth.id, booth: attributes_for(:booth, title: 'different'), conference_id: conference.short_title }
it 'redirects to admin booth index path' do
expect(response).to redirect_to admin_conference_booths_path
end
it 'shows success message' do
expect(flash[:notice]).to match 'Successfully updated booth.'
end
it 'updates booth' do
booth.reload
expect(booth.title).to eq('different')
end
end
end
describe 'DELETE #destroy' do
context 'deletes successfully' do
before { delete :destroy, id: booth.id, conference_id: conference.short_title }
it 'booth deleted' do
expect(Booth.count).to eq(0)
end
it 'redirects to admin booth index path' do
expect(response).to redirect_to(admin_conference_booths_path)
end
it 'show success message' do
expect(flash[:notice]).to match('Booth successfully destroyed.')
end
end
end
end
end

View file

@ -55,7 +55,7 @@ describe Admin::RolesController do
end
describe 'POST #toggle' do
before:each do
before :each do
sign_in admin
post :toggle_user, conference_id: conference.short_title,
user: { email: 'user1@osem.io' },

View file

@ -9,7 +9,7 @@ describe PhysicalTicketController do
describe 'GET #show' do
before :each do
sign_in user
get :show, id: physical_ticket.id, conference_id: conference.short_title
get :show, id: physical_ticket.token, conference_id: conference.short_title
end
it 'assigns ticket_layout' do

View file

@ -24,7 +24,7 @@ describe SubscriptionsController do
it 'shows success message in flash notice' do
post :create, conference_id: conference.short_title
expect(flash[:notice]).to match("You have been subscribed to receive email notifications for #{conference.short_title}")
expect(flash[:notice]).to match("You have subscribed to receive email notifications for #{conference.title}")
end
it 'subscribes user to conference' do
@ -47,7 +47,7 @@ describe SubscriptionsController do
it 'shows success message in flash notice' do
delete :destroy, conference_id: conference.short_title
expect(flash[:notice]).to match("You have been unsubscribed and now you will not be receiving email notifications for #{conference.short_title}.")
expect(flash[:notice]).to match("You have unsubscribed and you will not be receiving email notifications for #{conference.title}.")
end
end
end

View file

@ -0,0 +1,8 @@
FactoryGirl.define do
factory :booth_request do
booth
user
role 'responsible'
end
end

13
spec/factories/booths.rb Normal file
View file

@ -0,0 +1,13 @@
FactoryGirl.define do
factory :booth do
title { Faker::Hipster.sentence }
description { Faker::Lorem.paragraph }
reasoning { Faker::Lorem.paragraph }
website_url { Faker::Internet.url }
submitter_relationship { Faker::Lorem.paragraph }
conference
responsible_ids { [create(:user).id] }
end
end

View file

@ -249,6 +249,16 @@ feature 'Has correct abilities' do
visit admin_conference_roles_path(conference.short_title)
expect(current_path).to eq(admin_conference_roles_path(conference.short_title))
visit admin_conference_booths_path(conference.short_title)
expect(current_path).to eq(admin_conference_booths_path(conference.short_title))
visit new_admin_conference_booth_path(conference.short_title)
expect(current_path).to eq(new_admin_conference_booth_path(conference.short_title))
create(:booth, conference: conference)
visit edit_admin_conference_booth_path(conference.short_title, conference.booths.first)
expect(current_path).to eq(edit_admin_conference_booth_path(conference.short_title, conference.booths.first))
visit admin_conference_resources_path(conference.short_title)
expect(current_path).to eq(admin_conference_resources_path(conference.short_title))

View file

@ -237,6 +237,16 @@ feature 'Has correct abilities' do
visit edit_admin_conference_target_path(conference.short_title, conference.targets.first)
expect(current_path).to eq(edit_admin_conference_target_path(conference.short_title, conference.targets.first))
visit admin_conference_booths_path(conference.short_title)
expect(current_path).to eq(admin_conference_booths_path(conference.short_title))
visit new_admin_conference_booth_path(conference.short_title)
expect(current_path).to eq(new_admin_conference_booth_path(conference.short_title))
create(:booth, conference: conference)
visit edit_admin_conference_booth_path(conference.short_title, conference.booths.first)
expect(current_path).to eq(edit_admin_conference_booth_path(conference.short_title, conference.booths.first))
visit admin_conference_program_tracks_path(conference.short_title)
expect(current_path).to eq(admin_conference_program_tracks_path(conference.short_title))

View file

@ -28,23 +28,23 @@ feature Event do
scenario 'rejects a proposal', feature: true, js: true do
visit admin_conference_program_events_path(conference.short_title)
expect(page.has_content?('Example Proposal')).to be true
expect(page).to have_content 'Example Proposal'
click_button 'New'
click_link "reject_event_#{@event.id}"
expect(flash).to eq('Event rejected!')
expect(page).to have_content 'Event rejected!'
@event.reload
expect(@event.state).to eq('rejected')
end
scenario 'accepts a proposal', feature: true, js: true do
visit admin_conference_program_events_path(conference.short_title)
expect(page.has_content?('Example Proposal')).to be true
expect(page).to have_content 'Example Proposal'
click_button 'New'
click_link "accept_event_#{@event.id}"
expect(flash).to eq('Event accepted!')
expect(page.has_content?('Unconfirmed')).to be true
expect(page).to have_content 'Event accepted!'
expect(page).to have_content 'Unconfirmed'
@event.reload
expect(@event.state).to eq('unconfirmed')
end
@ -52,11 +52,11 @@ feature Event do
scenario 'restarts review of a proposal', feature: true, js: true do
@event.reject!(@options)
visit admin_conference_program_events_path(conference.short_title)
expect(page.has_content?('Example Proposal')).to be true
expect(page).to have_content 'Example Proposal'
click_button 'Rejected'
click_link "restart_event_#{@event.id}"
expect(flash).to eq('Review started!')
expect(page).to have_content 'Review started!'
@event.reload
expect(@event.state).to eq('new')
end
@ -83,7 +83,7 @@ feature Event do
fill_in 'event_abstract', with: 'Lorem ipsum abstract'
click_button 'Create Proposal'
expect(flash).to eq('Proposal was successfully submitted.')
expect(page).to have_content 'Proposal was successfully submitted.'
expect(Event.count).to eq(expected_count_event)
expect(User.count).to eq(expected_count_user)
@ -101,7 +101,7 @@ feature Event do
select('Easy', from: 'event[difficulty_level_id]')
click_button 'Update Proposal'
expect(flash).to eq('Proposal was successfully updated.')
expect(page).to have_content 'Proposal was successfully updated.'
end
scenario 'signed_in user submits a valid proposal', feature: true, js: true do
@ -119,7 +119,7 @@ feature Event do
fill_in 'event_description', with: 'Lorem ipsum description'
click_button 'Create Proposal'
expect(flash).to eq('Proposal was successfully submitted.')
expect(page).to have_content 'Proposal was successfully submitted.'
expect(current_path).to eq(conference_program_proposals_path(conference.short_title))
expect(Event.count).to eq(expected_count)
@ -128,11 +128,10 @@ feature Event do
scenario 'confirms a proposal', feature: true, js: true do
sign_in participant
visit conference_program_proposals_path(conference.short_title)
expect(page.has_content?('Example Proposal')).to be true
expect(page).to have_content 'Example Proposal'
expect(@event.state).to eq('unconfirmed')
click_link "confirm_proposal_#{@event.id}"
expect(flash)
.to eq('The proposal was confirmed. Please register to attend the conference.')
expect(page).to have_content 'The proposal was confirmed. Please register to attend the conference.'
expect(current_path).to eq(new_conference_conference_registration_path(conference.short_title))
@event.reload
expect(@event.state).to eq('confirmed')
@ -142,9 +141,9 @@ feature Event do
sign_in participant
@event.confirm!
visit conference_program_proposals_path(conference.short_title)
expect(page.has_content?('Example Proposal')).to be true
expect(page).to have_content 'Example Proposal'
click_link "delete_proposal_#{@event.id}"
expect(flash).to eq('Proposal was successfully withdrawn.')
expect(page).to have_content 'Proposal was successfully withdrawn.'
@event.reload
expect(@event.state).to eq('withdrawn')
end

54
spec/models/booth_spec.rb Normal file
View file

@ -0,0 +1,54 @@
require 'spec_helper'
describe 'Booth' do
subject { create(:booth) }
let!(:conference) { create(:conference) }
describe 'validation' do
it 'has a valid factory' do
expect(build(:booth)).to be_valid
end
it { is_expected.to validate_presence_of(:reasoning) }
it { is_expected.to validate_presence_of(:description) }
it { is_expected.to validate_presence_of(:responsibles) }
it { is_expected.to validate_presence_of(:submitter_relationship) }
it { is_expected.to validate_presence_of(:website_url) }
it 'is not valid without a title' do
is_expected.to validate_presence_of(:title)
end
end
describe 'association' do
it { is_expected.to belong_to(:conference) }
it { is_expected.to have_many(:booth_requests) }
end
describe '#transition_possible?(transition)' do
shared_examples 'transition_possible?(transition)' do |state, transition, expected|
it "returns #{expected} for #{transition} transition, when the booth is #{state}}" do
my_booth = create(:booth, state: state)
expect(my_booth.transition_possible?(transition.to_sym)).to eq expected
end
end
states = [:new, :withdrawn, :to_accept, :accepted, :to_reject, :rejected, :canceled]
transitions = [:restart, :withdraw, :accept, :reject, :to_accept, :to_reject, :cancel]
states_transitions = { new: { restart: false, withdraw: true, accept: true, to_accept: true, to_reject: true, reject: true, cancel: false },
withdrawn: { restart: true, withdraw: false, accept: false, to_accept: false, to_reject: false, reject: false, cancel: false },
to_accept: { restart: true, withdraw: true, accept: true, to_accept: false, to_reject: true, reject: false, cancel: true },
to_reject: { restart: true, withdraw: true, accept: false, to_accept: true, to_reject: false, reject: true, cancel: true },
accepted: { restart: false, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true },
rejected: { restart: false, withdraw: true, accept: false, to_accept: false, to_reject: false, reject: false, cancel: true },
canceled: { restart: true, withdraw: false, accept: false, to_accept: false, to_reject: false, reject: false, cancel: false } }
states.each do |state|
transitions.each do |transition|
it_behaves_like 'transition_possible?(transition)', state, transition, states_transitions[state.to_sym][transition.to_sym]
end
end
end
end