Merge master tidy routes

This commit is contained in:
Michael Ball 2021-03-24 13:32:40 -07:00
commit de8b06c4b3
120 changed files with 1321 additions and 1293 deletions

View file

@ -1 +1,6 @@
coverage:
status:
project:
default:
threshold: 0.5%
comment: off comment: off

51
.github/workflows/spec.yml vendored Normal file
View file

@ -0,0 +1,51 @@
name: Specs
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
workflow_dispatch:
jobs:
linters:
runs-on: ubuntu-latest
env:
OSEM_RUBY_VERSION: 2.6.6
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
bundler-cache: true
- run: bundle exec rubocop
- run: bundle exec haml-lint app/views
spec:
runs-on: ubuntu-latest
name: spec
env:
OSEM_DB_ADAPTER: sqlite3
OSEM_RUBY_VERSION: 2.6.6
RAILS_ENV: test
strategy:
matrix:
suite: [models, features, controllers, ability, leftovers]
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
bundler-cache: true
- name: Prepare spec
run: |
rm -f osem_test osem_development
bundle exec rake db:setup --trace
bundle exec bin/rails webdrivers:chromedriver:update
- name: spec/${{ matrix.suite }}
run: bundle exec rake spec:${{ matrix.suite }}
- name: coverage upload ${{ matrix.suite }}
uses: codacy/codacy-coverage-reporter-action@master
if: github.ref == 'refs/heads/master'
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: coverage/coverage.xml

View file

@ -434,7 +434,7 @@ Metrics/BlockNesting:
# Offense count: 13 # Offense count: 13
# Configuration parameters: CountComments. # Configuration parameters: CountComments.
Metrics/ClassLength: Metrics/ClassLength:
Max: 650 Max: 652
# Offense count: 33 # Offense count: 33
Metrics/CyclomaticComplexity: Metrics/CyclomaticComplexity:

View file

@ -1,21 +1,8 @@
language: ruby os: linux
cache: bundler
rvm:
- 2.6.6
dist: bionic dist: bionic
addons:
apt:
packages:
- chromium-browser
services:
- postgresql
branches: branches:
except: except:
- /^depfu/.*$/ - /^depfu/.*$/
before_install:
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
- gem install bundler -v $(tail -n 1 Gemfile.lock)
notifications: notifications:
email: email:
on_success: change on_success: change
@ -25,22 +12,9 @@ notifications:
- "chat.freenode.net#osem" - "chat.freenode.net#osem"
on_success: change on_success: change
on_failure: change on_failure: change
before_script: stages:
# install CodeClimate test reporter and tell it we are starting a test run - test
# - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > $CCTR - finalize
# - chmod +x $CCTR
# - $CCTR before-build
- RAILS_ENV=test bundle exec rake db:bootstrap --trace
- RAILS_ENV=test bundle exec bin/rails webdrivers:chromedriver:update
script:
- "bin/travis_script.sh $TEST_SUITE"
# TODO Get this working.
# - $CCTR format-coverage -t simplecov --output coverage/codeclimate.$SUITE.json
# after_script:
# combine coverage from all suites, and upload3 to CodeClimate
# - $CCTR sum-coverage coverage/codeclimate.*.json | $CCTR upload-coverage
# - $CCTR after-build --exit-code $TRAVIS_TEST_RESULT
env: env:
global: global:
- OSEM_DB_ADAPTER=sqlite3 - OSEM_DB_ADAPTER=sqlite3
@ -49,11 +23,90 @@ env:
- OSEM_DB_NAME='osem_test' - OSEM_DB_NAME='osem_test'
- CC_TEST_REPORTER_ID=$CC_TEST_REPORTER - CC_TEST_REPORTER_ID=$CC_TEST_REPORTER
- CCTR=./cc-test-reporter - CCTR=./cc-test-reporter
matrix: - TOTAL_TEST_SUITES=5
- TEST_SUITE=ability jobs:
- TEST_SUITE=features include:
- TEST_SUITE=models - &tests
- TEST_SUITE=controllers language: ruby
- TEST_SUITE=rest cache: bundler
matrix: rvm:
fast_finish: false - 2.6.6
addons:
apt:
packages:
- chromium-browser
services:
- postgresql
before_install:
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
- gem install bundler -v $(tail -n 1 Gemfile.lock)
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > $CCTR
- chmod +x $CCTR
before_script:
- RAILS_ENV=test bundle exec rake db:bootstrap --trace
- RAILS_ENV=test bundle exec bin/rails webdrivers:chromedriver:update
- $CCTR before-build
script:
- "bin/travis_script.sh $TEST_SUITE && $CCTR format-coverage -t cobertura -o ./coverage/codeclimate.1.json ./coverage/coverage.xml"
env:
- TEST_SUITE=ability
workspaces:
create:
name: ws1
paths:
- coverage/codeclimate.1.json
- <<: *tests
env:
- TEST_SUITE=features
script:
- "bin/travis_script.sh $TEST_SUITE && $CCTR format-coverage -t cobertura -o ./coverage/codeclimate.2.json ./coverage/coverage.xml"
workspaces:
create:
name: ws2
paths:
- coverage/codeclimate.2.json
- <<: *tests
env:
- TEST_SUITE=models
script:
- "bin/travis_script.sh $TEST_SUITE && $CCTR format-coverage -t cobertura -o ./coverage/codeclimate.3.json ./coverage/coverage.xml"
workspaces:
create:
name: ws3
paths:
- coverage/codeclimate.3.json
- <<: *tests
env:
- TEST_SUITE=controllers
script:
- "bin/travis_script.sh $TEST_SUITE && $CCTR format-coverage -t cobertura -o ./coverage/codeclimate.4.json ./coverage/coverage.xml"
workspaces:
create:
name: ws4
paths:
- coverage/codeclimate.4.json
- <<: *tests
env:
- TEST_SUITE=rest
script:
- "bin/travis_script.sh $TEST_SUITE && $CCTR format-coverage -t cobertura -o ./coverage/codeclimate.5.json ./coverage/coverage.xml"
workspaces:
create:
name: ws5
paths:
- coverage/codeclimate.5.json
- stage: finalize
if: branch = master
language: minimal
before_install:
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > $CCTR
- chmod +x $CCTR
workspaces:
use:
- ws1
- ws2
- ws3
- ws4
- ws5
script: $CCTR sum-coverage --output - --parts $TOTAL_TEST_SUITES coverage/codeclimate.*.json | $CCTR upload-coverage --input -

View file

@ -43,8 +43,8 @@ bundle exec rake data:set_conference_in_versions RAILS_ENV=production
### Organization admins ### Organization admins
We have a new role `organization admins` which allow a user to manage his the We have a new role `organization admins` which allow a user to manage their
organization and create and manage conference within the organization. This organization and create and manage a conference within the organization. This
needs the role to exist in the database, otherwise the application crashes needs the role to exist in the database, otherwise the application crashes
as it is assumed to exist. For that, run the following rake task: as it is assumed to exist. For that, run the following rake task:

View file

@ -1,4 +1,4 @@
FROM osem/base FROM registry.opensuse.org/opensuse/infrastructure/osem/containers/osem/base:latest
ARG CONTAINER_USERID ARG CONTAINER_USERID
# Configure our user # Configure our user
@ -16,6 +16,8 @@ RUN chown -R osem /osem
USER osem USER osem
WORKDIR /osem/ WORKDIR /osem/
# Install bundler & foreman
RUN sudo gem install bundler:1.17.3 foreman
# Install our bundle # Install our bundle
RUN export NOKOGIRI_USE_SYSTEM_LIBRARIES=1; bundle install --jobs=3 --retry=3 RUN export NOKOGIRI_USE_SYSTEM_LIBRARIES=1; bundle install --jobs=3 --retry=3

View file

@ -1,35 +0,0 @@
FROM opensuse/leap:15
# Install our requirements
RUN zypper -n install --no-recommends \
# for compiling assets/gems
nodejs8 gcc-c++ git-core make \
# for ...
ImageMagick \
# for bundler
sudo \
# as databases
libmariadb-devel postgresql-devel sqlite3-devel \
# for nokogiri
libxml2-devel libxslt-devel \
# for the interactive shell
ack curl wget w3m vim which \
# as ruby
ruby2.5-devel \
# as browser for feature tests
chromium xorg-x11-fonts
# Setup sudo
RUN echo 'osem ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers
# Disable versioned gem binary names
RUN echo 'install: --no-format-executable' >> /etc/gemrc
# Install bundler & foreman
RUN gem install bundler:1.17.3 foreman
# Create our user
RUN useradd -m --user-group osem
CMD ["/bin/bash", "-l"]

View file

@ -1,4 +1,4 @@
FROM osem/base FROM opensuse/infrastructure/osem/containers/osem/base
# Add our files # Add our files
COPY --chown=1000:1000 . /osem/ COPY --chown=1000:1000 . /osem/

15
Gemfile
View file

@ -157,9 +157,6 @@ gem 'font-awesome-rails'
# for markdown # for markdown
gem 'redcarpet' gem 'redcarpet'
# as rdoc generator
gem 'rdoc-generator-fivefish'
# for visitor tracking # for visitor tracking
gem 'piwik_analytics', '~> 1.0.1' gem 'piwik_analytics', '~> 1.0.1'
@ -221,6 +218,8 @@ gem 'nokogiri', '>= 1.8.1'
# memcached binary connector # memcached binary connector
gem 'dalli' gem 'dalli'
gem 'icalendar'
# Use guard and spring for testing in development # Use guard and spring for testing in development
group :development do group :development do
# to launch specs when files are modified # to launch specs when files are modified
@ -234,8 +233,6 @@ group :development do
gem 'mina' gem 'mina'
# as debugger on error pages # as debugger on error pages
gem 'web-console' gem 'web-console'
# as development database
gem 'sqlite3'
# prepend models with db schema # prepend models with db schema
gem 'annotate' gem 'annotate'
end end
@ -248,7 +245,7 @@ group :test do
gem 'rspec-rails' gem 'rspec-rails'
gem 'webdrivers' gem 'webdrivers'
# for measuring test coverage # for measuring test coverage
gem 'codecov', require: false gem 'simplecov-cobertura'
# for describing models # for describing models
gem 'shoulda-matchers', require: false gem 'shoulda-matchers', require: false
# for stubing/mocking models # for stubing/mocking models
@ -273,6 +270,7 @@ group :development, :test, :linters do
# as debugger # as debugger
gem 'byebug' gem 'byebug'
gem 'pry' gem 'pry'
gem 'pry-byebug'
# Linters and static analysis. # Linters and static analysis.
gem 'pronto', require: false gem 'pronto', require: false
@ -283,3 +281,8 @@ group :development, :test, :linters do
gem 'haml-lint', require: false gem 'haml-lint', require: false
end end
group :development, :test do
# as development/test database
gem 'sqlite3'
end

View file

@ -36,9 +36,9 @@ GEM
erubi (~> 1.4) erubi (~> 1.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3) rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_model_serializers (0.10.10) active_model_serializers (0.10.12)
actionpack (>= 4.1, < 6.1) actionpack (>= 4.1, < 6.2)
activemodel (>= 4.1, < 6.1) activemodel (>= 4.1, < 6.2)
case_transform (>= 0.2) case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3) jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
activejob (5.2.4.5) activejob (5.2.4.5)
@ -79,13 +79,13 @@ GEM
ast (2.4.0) ast (2.4.0)
autoprefixer-rails (9.6.4) autoprefixer-rails (9.6.4)
execjs execjs
awesome_nested_set (3.2.1) awesome_nested_set (3.4.0)
activerecord (>= 4.0.0, < 7.0) activerecord (>= 4.0.0, < 7.0)
aws_cf_signer (0.1.3) aws_cf_signer (0.1.3)
axlsx_rails (0.5.2) axlsx_rails (0.5.2)
actionpack (>= 3.1) actionpack (>= 3.1)
axlsx (>= 2.0.1) axlsx (>= 2.0.1)
bcrypt (3.1.13) bcrypt (3.1.16)
bindex (0.6.0) bindex (0.6.0)
bootstrap-sass (3.4.1) bootstrap-sass (3.4.1)
autoprefixer-rails (>= 5.2.1) autoprefixer-rails (>= 5.2.1)
@ -104,7 +104,7 @@ GEM
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
regexp_parser (~> 1.5) regexp_parser (~> 1.5)
xpath (~> 3.2) xpath (~> 3.2)
carrierwave (2.2.0) carrierwave (2.1.1)
activemodel (>= 5.0.0) activemodel (>= 5.0.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
addressable (~> 2.6) addressable (~> 2.6)
@ -126,9 +126,7 @@ GEM
cloudinary (1.11.1) cloudinary (1.11.1)
aws_cf_signer aws_cf_signer
rest-client rest-client
cocoon (1.2.14) cocoon (1.2.15)
codecov (0.5.0)
simplecov (>= 0.15, < 0.22)
coderay (1.1.1) coderay (1.1.1)
concurrent-ruby (1.1.8) concurrent-ruby (1.1.8)
countable-rails (0.0.1) countable-rails (0.0.1)
@ -144,15 +142,15 @@ GEM
safe_yaml (~> 1.0.0) safe_yaml (~> 1.0.0)
crass (1.0.6) crass (1.0.6)
daemons (1.3.1) daemons (1.3.1)
dalli (2.7.10) dalli (2.7.11)
dante (0.2.0) dante (0.2.0)
database_cleaner (1.7.0) database_cleaner (1.7.0)
delayed_job (4.1.8) delayed_job (4.1.9)
activesupport (>= 3.0, < 6.1) activesupport (>= 3.0, < 6.2)
delayed_job_active_record (4.1.4) delayed_job_active_record (4.1.5)
activerecord (>= 3.0, < 6.1) activerecord (>= 3.0, < 6.2)
delayed_job (>= 3.0, < 5) delayed_job (>= 3.0, < 5)
devise (4.7.1) devise (4.7.3)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0) railties (>= 4.1.0)
@ -164,10 +162,10 @@ GEM
docile (1.3.5) docile (1.3.5)
domain_name (0.5.20180417) domain_name (0.5.20180417)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
dotenv (2.7.5) dotenv (2.7.6)
dotenv-rails (2.7.5) dotenv-rails (2.7.6)
dotenv (= 2.7.5) dotenv (= 2.7.6)
railties (>= 3.2, < 6.1) railties (>= 3.2)
erubi (1.10.0) erubi (1.10.0)
erubis (2.7.0) erubis (2.7.0)
execjs (2.7.0) execjs (2.7.0)
@ -191,8 +189,8 @@ GEM
path_expander (~> 1.0) path_expander (~> 1.0)
ruby_parser (~> 3.0) ruby_parser (~> 3.0)
sexp_processor (~> 4.0) sexp_processor (~> 4.0)
font-awesome-rails (4.7.0.5) font-awesome-rails (4.7.0.7)
railties (>= 3.2, < 6.1) railties (>= 3.2, < 7)
formatador (0.2.5) formatador (0.2.5)
formtastic (3.1.5) formtastic (3.1.5)
actionpack (>= 3.2.13) actionpack (>= 3.2.13)
@ -254,11 +252,12 @@ GEM
i18n (1.8.9) i18n (1.8.9)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n_data (0.8.0) i18n_data (0.8.0)
icalendar (2.7.0)
ice_cube (~> 0.16)
ice_cube (0.16.3)
image_processing (1.12.1) image_processing (1.12.1)
mini_magick (>= 4.9.5, < 5) mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3) ruby-vips (>= 2.0.17, < 3)
inversion (1.1.1)
loggability (~> 0.12)
io-like (0.3.0) io-like (0.3.0)
iso-639 (0.2.8) iso-639 (0.2.8)
jaro_winkler (1.5.3) jaro_winkler (1.5.3)
@ -288,7 +287,6 @@ GEM
rb-fsevent (~> 0.9, >= 0.9.4) rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7) rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2) ruby_dep (~> 1.2)
loggability (0.14.0)
loofah (2.9.0) loofah (2.9.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
@ -300,7 +298,7 @@ GEM
method_source (0.8.2) method_source (0.8.2)
mime-types (3.3.1) mime-types (3.3.1)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2021.0212) mime-types-data (3.2021.0225)
mimemagic (0.3.5) mimemagic (0.3.5)
mina (1.2.3) mina (1.2.3)
open4 (~> 1.3.4) open4 (~> 1.3.4)
@ -325,7 +323,7 @@ GEM
multipart-post (2.1.1) multipart-post (2.1.1)
nenv (0.3.0) nenv (0.3.0)
netrc (0.11.0) netrc (0.11.0)
nio4r (2.5.5) nio4r (2.5.7)
nokogiri (1.11.1) nokogiri (1.11.1)
mini_portile2 (~> 2.5.0) mini_portile2 (~> 2.5.0)
racc (~> 1.4) racc (~> 1.4)
@ -371,7 +369,7 @@ GEM
parser (2.6.5.0) parser (2.6.5.0)
ast (~> 2.4.0) ast (~> 2.4.0)
path_expander (1.1.0) path_expander (1.1.0)
pdf-core (0.7.0) pdf-core (0.9.0)
pdf-inspector (1.3.0) pdf-inspector (1.3.0)
pdf-reader (>= 1.0, < 3.0.a) pdf-reader (>= 1.0, < 3.0.a)
pdf-reader (2.2.0) pdf-reader (2.2.0)
@ -380,18 +378,18 @@ GEM
hashery (~> 2.0) hashery (~> 2.0)
ruby-rc4 ruby-rc4
ttfunk ttfunk
pg (1.1.4) pg (1.2.3)
piwik_analytics (1.0.2) piwik_analytics (1.0.2)
actionpack actionpack
activesupport activesupport
rails (>= 3.0.0) rails (>= 3.0.0)
prawn (2.2.2) prawn (2.4.0)
pdf-core (~> 0.7.0) pdf-core (~> 0.9.0)
ttfunk (~> 1.5) ttfunk (~> 1.7)
prawn-qrcode (0.3.1) prawn-qrcode (0.3.1)
prawn (>= 1) prawn (>= 1)
rqrcode (>= 0.4.1) rqrcode (>= 0.4.1)
prawn-rails (1.2.0) prawn-rails (1.3.0)
prawn prawn
prawn-table prawn-table
rails (>= 3.1.0) rails (>= 3.1.0)
@ -419,8 +417,11 @@ GEM
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
pry-byebug (3.8.0)
byebug (~> 11.0)
pry (~> 0.10)
public_suffix (3.1.1) public_suffix (3.1.1)
puma (5.2.1) puma (5.2.2)
nio4r (~> 2.0) nio4r (~> 2.0)
racc (1.5.2) racc (1.5.2)
rack (2.2.3) rack (2.2.3)
@ -462,10 +463,10 @@ GEM
rails-assets-to-markdown (3.1.1) rails-assets-to-markdown (3.1.1)
rails-assets-trianglify (1.2.0) rails-assets-trianglify (1.2.0)
rails-assets-waypoints (4.0.0) rails-assets-waypoints (4.0.0)
rails-controller-testing (1.0.4) rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.x) actionpack (>= 5.0.1.rc1)
actionview (>= 5.0.1.x) actionview (>= 5.0.1.rc1)
activesupport (>= 5.0.1.x) activesupport (>= 5.0.1.rc1)
rails-dom-testing (2.0.3) rails-dom-testing (2.0.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
nokogiri (>= 1.6) nokogiri (>= 1.6)
@ -485,12 +486,6 @@ GEM
rb-fsevent (0.10.3) rb-fsevent (0.10.3)
rb-inotify (0.10.0) rb-inotify (0.10.0)
ffi (~> 1.0) ffi (~> 1.0)
rdoc (6.0.4)
rdoc-generator-fivefish (0.4.0)
inversion (~> 1.1)
loggability (~> 0.12)
rdoc (~> 6.0)
yajl-ruby (~> 1.3)
recaptcha (4.14.0) recaptcha (4.14.0)
json json
redcarpet (3.5.1) redcarpet (3.5.1)
@ -596,6 +591,8 @@ GEM
docile (~> 1.1) docile (~> 1.1)
simplecov-html (~> 0.11) simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1) simplecov_json_formatter (~> 0.1)
simplecov-cobertura (1.4.2)
simplecov (~> 0.8)
simplecov-html (0.12.3) simplecov-html (0.12.3)
simplecov_json_formatter (0.1.2) simplecov_json_formatter (0.1.2)
sixarm_ruby_unaccent (1.2.0) sixarm_ruby_unaccent (1.2.0)
@ -632,7 +629,7 @@ GEM
tilt (2.0.9) tilt (2.0.9)
timecop (0.9.1) timecop (0.9.1)
transitions (1.2.1) transitions (1.2.1)
ttfunk (1.5.1) ttfunk (1.7.0)
turbolinks (5.2.1) turbolinks (5.2.1)
turbolinks-source (~> 5.2) turbolinks-source (~> 5.2)
turbolinks-source (5.2.0) turbolinks-source (5.2.0)
@ -647,8 +644,8 @@ GEM
unicode_utils (1.4.0) unicode_utils (1.4.0)
unobtrusive_flash (3.3.1) unobtrusive_flash (3.3.1)
railties railties
warden (1.2.8) warden (1.2.9)
rack (>= 2.0.6) rack (>= 2.0.9)
web-console (3.7.0) web-console (3.7.0)
actionview (>= 5.0) actionview (>= 5.0)
activemodel (>= 5.0) activemodel (>= 5.0)
@ -669,7 +666,6 @@ GEM
chronic (>= 0.6.3) chronic (>= 0.6.3)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
yajl-ruby (1.4.1)
PLATFORMS PLATFORMS
ruby ruby
@ -696,7 +692,6 @@ DEPENDENCIES
climate_control climate_control
cloudinary cloudinary
cocoon cocoon
codecov
countable-rails countable-rails
country_select country_select
daemons daemons
@ -717,6 +712,7 @@ DEPENDENCIES
guard-rspec guard-rspec
haml-lint haml-lint
haml-rails haml-rails
icalendar
iso-639 iso-639
jquery-datatables jquery-datatables
jquery-rails jquery-rails
@ -746,6 +742,7 @@ DEPENDENCIES
pronto-haml pronto-haml
pronto-rubocop pronto-rubocop
pry pry
pry-byebug
puma (~> 5.2) puma (~> 5.2)
rails (~> 5.2) rails (~> 5.2)
rails-assets-bootstrap-markdown! rails-assets-bootstrap-markdown!
@ -762,7 +759,6 @@ DEPENDENCIES
rails-assets-waypoints! rails-assets-waypoints!
rails-controller-testing rails-controller-testing
rails-i18n rails-i18n
rdoc-generator-fivefish
recaptcha recaptcha
redcarpet redcarpet
responders (~> 2.0) responders (~> 2.0)
@ -778,6 +774,7 @@ DEPENDENCIES
sentry-rails sentry-rails
sentry-ruby sentry-ruby
shoulda-matchers shoulda-matchers
simplecov-cobertura
skylight skylight
spring-commands-rspec spring-commands-rspec
sprockets-rails sprockets-rails

View file

@ -1,7 +1,7 @@
### Spring 2021 Student Project ### Spring 2021 Student Project
[![Build Status](https://travis-ci.com/CactusPuppy/snapcon.svg?branch=master)](https://travis-ci.com/CactusPuppy/snapcon) [![Build Status](https://travis-ci.com/CactusPuppy/snapcon.svg?branch=master)](https://travis-ci.com/CactusPuppy/snapcon)
[![Maintainability](https://api.codeclimate.com/v1/badges/6c7fc446b3b10866ba71/maintainability)](https://codeclimate.com/github/CactusPuppy/snapcon/maintainability) [![Maintainability](https://api.codeclimate.com/v1/badges/6c7fc446b3b10866ba71/maintainability)](https://codeclimate.com/github/CactusPuppy/snapcon/maintainability)
[![codecov](https://codecov.io/gh/CactusPuppy/snapcon/branch/master/graph/badge.svg?token=y4aEAtw6KJ)](https://codecov.io/gh/CactusPuppy/snapcon) [![Test Coverage](https://api.codeclimate.com/v1/badges/6c7fc446b3b10866ba71/test_coverage)](https://codeclimate.com/github/CactusPuppy/snapcon/test_coverage)
[![Security Status](https://hakiri.io/github/CactusPuppy/snapcon/master.svg)](https://hakiri.io/github/CactusPuppy/snapcon/master) [![Security Status](https://hakiri.io/github/CactusPuppy/snapcon/master.svg)](https://hakiri.io/github/CactusPuppy/snapcon/master)
[![Depfu](https://badges.depfu.com/badges/16eb1ffb3a9f1a36c4e595a5ae2a1dca/overview.svg)](https://depfu.com/github/CactusPuppy/snapcon?project_id=22682) [![Depfu](https://badges.depfu.com/badges/16eb1ffb3a9f1a36c4e595a5ae2a1dca/overview.svg)](https://depfu.com/github/CactusPuppy/snapcon?project_id=22682)
[![Bluejay Dashboard](https://img.shields.io/badge/Bluejay-Dashboard_5-blue.svg)](http://dashboard.bluejay.governify.io/dashboard/script/dashboardLoader.js?dashboardURL=https://reporter.bluejay.governify.io/api/v4/dashboards/tpa-CS169L-GH-CactusPuppy_snapcon/main) [![Bluejay Dashboard](https://img.shields.io/badge/Bluejay-Dashboard_5-blue.svg)](http://dashboard.bluejay.governify.io/dashboard/script/dashboardLoader.js?dashboardURL=https://reporter.bluejay.governify.io/api/v4/dashboards/tpa-CS169L-GH-CactusPuppy_snapcon/main)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View file

@ -13,11 +13,13 @@ $(function () {
$("#conference-start-datepicker").datetimepicker({ $("#conference-start-datepicker").datetimepicker({
useCurrent: false, useCurrent: false,
format: "YYYY-MM-DD" ignoreReadonly: true,
format: "YYYY-MM-DD",
}); });
$("#conference-end-datepicker").datetimepicker({ $("#conference-end-datepicker").datetimepicker({
useCurrent: false, useCurrent: false,
ignoreReadonly: true,
format: "YYYY-MM-DD" format: "YYYY-MM-DD"
}); });

View file

@ -49,6 +49,8 @@ $(function () {
$('.' + id).collapse('hide'); $('.' + id).collapse('hide');
$('#' + $(this).val() + '-help.' + id).collapse('show'); $('#' + $(this).val() + '-help.' + id).collapse('show');
$('#' + $(this).val() + '-instructions.' + id).collapse('show');
}); });
$('.dropdown-toggle').dropdown(); $('.dropdown-toggle').dropdown();
@ -147,6 +149,15 @@ function word_count(text, divId, maxcount) {
}); });
}; };
function fill_if_empty(text_area, filler) {
let area = $('#' + text_area);
if (!area.val()) {
area.val(filler);
area.trigger('change');
}
}
/* Wait for the DOM to be ready before attaching events to the elements */ /* Wait for the DOM to be ready before attaching events to the elements */
$( document ).ready(function() { $( document ).ready(function() {
/* Set the minimum and maximum proposal abstract and submission text word length */ /* Set the minimum and maximum proposal abstract and submission text word length */
@ -155,17 +166,16 @@ $( document ).ready(function() {
var max = $selected.data("max-words"); var max = $selected.data("max-words");
var min = $selected.data("min-words"); var min = $selected.data("min-words");
// Set the filler text for the submission text
fill_if_empty('event_submission_text', $selected.data("instructions"));
$("#abstract-maximum-word-count").text(max); $("#abstract-maximum-word-count").text(max);
$("#submission-maximum-word-count").text(max); $("#submission-maximum-word-count").text(max);
$("#abstract-minimum-word-count").text(min); $("#abstract-minimum-word-count").text(min);
$("#submission-minimum-word-count").text(min); $("#submission-minimum-word-count").text(min);
word_count($('#event_abstract').get(0), 'abstract-count', max); word_count($('#event_abstract').get(0), 'abstract-count', max);
word_count($('#event_submission_text').get(0), 'submission-count', max); word_count($('#event_submission_text').get(0), 'submission-count', max);
}).trigger('change');
// Set the placeholder text for the abstract
$('#event_submission_text').attr("placeholder", $selected.data("help"));
})
.trigger('change');
/* Count the proposal abstract length */ /* Count the proposal abstract length */
$("#event_abstract").bind('change keyup paste input', function() { $("#event_abstract").bind('change keyup paste input', function() {
@ -180,6 +190,18 @@ $( document ).ready(function() {
var max = $selected.data("max-words"); var max = $selected.data("max-words");
word_count(this, 'submission-count', max); word_count(this, 'submission-count', max);
}); });
/* Listen for reset template button, wait for confirm, and reset. */
$('.js-resetSubmissionText').click((e) => {
let $selected = $("#event_event_type_id option:selected");
let $this = $(e.target);
let affirm = confirm($this.data('confirm'));
if (affirm) {
let sub_text = $('#event_submission_text');
sub_text.val($selected.data('instructions'));
sub_text.trigger('change');
}
});
}); });
/* Commodity function for modal windows */ /* Commodity function for modal windows */

View file

@ -0,0 +1,40 @@
html {
scroll-behavior: smooth;
}
body {
background: #fff;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.06);
color: #000;
font-family: 'Montserrat', sans-serif;
font-size: 16px;
line-height: 1.5;
margin: 0 auto;
}
h1,
h3,
h4,
h5,
h6 {
font-weight: 400;
line-height: 1.3;
}
p {
color: #0B3559;
font-weight: 400;
line-height: 2;
}
#border {
background-color: #0B3559;
padding: 25px;
color:#fff;
}
#content {
background-color: #fff;
padding: 100px;
color: #0B3559;
}

View file

@ -1,26 +1,34 @@
@import "breakpoints.scss"; @import "breakpoints.scss";
.dashbox span.fa { .dashbox span.fa {
line-height: 1.1em; margin-bottom: 2px;
@include breakpoint(xs) {
font-size: 1.5em;
}
@include breakpoint(sm) { @include breakpoint(sm) {
font-size: 3em; font-size: 2em;
} }
@include breakpoint(md) { @include breakpoint(md) {
font-size: 4em; font-size: 3.5em;
} }
@include breakpoint(lg) { @include breakpoint(lg) {
font-size: 5em; font-size: 5em;
} }
} }
.dashbox { .dashbox.panel {
padding-top: 20px; padding: 10px;
padding-bottom: 20px; display: -webkit-flex;
} display: flex;
align-items: center;
justify-content: center;
font-size: 1.4rem;
line-height: 1.6rem;
.dashbox label { label {
display: block; line-height: 2rem;
font-size: 1.1em; }
} }
.todolist-missing span { .todolist-missing span {

View file

@ -124,8 +124,7 @@ module Admin
# current_user.last_sign_in_at # current_user.last_sign_in_at
# ).count # ).count
# Step by step list @conference_todo_list = @conference.get_status
# @conference_progress = @conference.get_status
# Line charts # Line charts
@registrations = @conference.get_registrations_per_week @registrations = @conference.get_registrations_per_week

View file

@ -49,7 +49,7 @@ module Admin
private private
def event_type_params def event_type_params
params.require(:event_type).permit(:title, :length, :minimum_abstract_length, :maximum_abstract_length, :color, :conference_id, :description) params.require(:event_type).permit(:title, :length, :minimum_abstract_length, :maximum_abstract_length, :submission_instructions, :color, :conference_id, :description)
end end
end end
end end

View file

@ -66,6 +66,16 @@ module Admin
def edit; end def edit; end
def destroy
if @user.destroy
redirect_to admin_users_path,
notice: "User #{@user.id} (#{@user.email}) deleted."
else
redirect_to admin_users_path,
error: "User #{@user.id} (#{@user.emai}) could not be deleted. #{@user.full_messages.join(',')}"
end
end
private private
def user_params def user_params

View file

@ -6,8 +6,11 @@ class ConferencesController < ApplicationController
load_and_authorize_resource find_by: :short_title, except: :show load_and_authorize_resource find_by: :short_title, except: :show
def index def index
@current = Conference.where('end_date >= ?', Date.current).reorder(start_date: :asc) @current = Conference.upcoming.reorder(start_date: :asc)
@antiquated = Conference.where('end_date < ?', Date.current) @antiquated = Conference.past
if @antiquated.empty? && @current.empty? && User.empty?
render :new_install
end
end end
def show def show
@ -68,6 +71,47 @@ class ConferencesController < ApplicationController
end end
end end
def calendar
respond_to do |format|
format.ics do
calendar = Icalendar::Calendar.new
Conference.all.each do |conf|
if params[:full]
event_schedules = conf.program.selected_event_schedules(
includes: [{ event: %i[event_type speakers submitter] }]
)
calendar = icalendar_proposals(calendar, event_schedules.map(&:event), conf)
else
calendar.event do |e|
e.dtstart = conf.start_date
e.dtstart.ical_params = { 'VALUE'=>'DATE' }
e.dtend = conf.end_date
e.dtend.ical_params = { 'VALUE'=>'DATE' }
e.duration = "P#{(conf.end_date - conf.start_date + 1).floor}D"
e.created = conf.created_at
e.last_modified = conf.updated_at
e.summary = conf.title
e.description = conf.description
e.uid = conf.guid
e.url = conference_url(conf.short_title)
v = conf.venue
if v
e.geo = v.latitude, v.longitude if v.latitude && v.longitude
location = ''
location += "#{v.street}, " if v.street
location += "#{v.postalcode} #{v.city}, " if v.postalcode && v.city
location += v.country_name if v.country_name
e.location = location if location
end
end
end
end
calendar.publish
render inline: calendar.to_ical
end
end
end
private private
def conference_finder_conditions def conference_finder_conditions

View file

@ -16,6 +16,7 @@ class PaymentsController < ApplicationController
raise CanCan::AccessDenied.new('Nothing to pay for!', :new, Payment) raise CanCan::AccessDenied.new('Nothing to pay for!', :new, Payment)
end end
@has_registration_ticket = params[:has_registration_ticket]
@unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference) @unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference)
end end
@ -24,8 +25,15 @@ class PaymentsController < ApplicationController
if @payment.purchase && @payment.save if @payment.purchase && @payment.save
update_purchased_ticket_purchases update_purchased_ticket_purchases
redirect_to conference_physical_tickets_path,
notice: 'Thanks! Your ticket is booked successfully.' has_registration_ticket = params[:has_registration_ticket]
if has_registration_ticket == 'true'
redirect_to new_conference_conference_registration_path(@conference.short_title),
notice: 'Thanks! Your ticket is booked successfully. Please register for the conference.'
else
redirect_to conference_physical_tickets_path,
notice: 'Thanks! Your ticket is booked successfully.'
end
else else
@total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false) @total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false)
@unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference) @unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference)

View file

@ -21,6 +21,12 @@ class SchedulesController < ApplicationController
format.xml do format.xml do
@events_xml = event_schedules.map(&:event).group_by{ |event| event.time.to_date } if event_schedules @events_xml = event_schedules.map(&:event).group_by{ |event| event.time.to_date } if event_schedules
end end
format.ics do
cal = Icalendar::Calendar.new
cal = icalendar_proposals(cal, event_schedules.map(&:event), @conference)
cal.publish
render inline: cal.to_ical
end
format.html do format.html do
@rooms = @conference.venue.rooms if @conference.venue @rooms = @conference.venue.rooms if @conference.venue

View file

@ -8,23 +8,42 @@ class TicketPurchasesController < ApplicationController
def create def create
current_user.ticket_purchases.by_conference(@conference).unpaid.destroy_all current_user.ticket_purchases.by_conference(@conference).unpaid.destroy_all
# Create a ticket purchase which can be paid or unpaid
count_registration_tickets_before = current_user.count_registration_tickets(@conference)
message = TicketPurchase.purchase(@conference, current_user, params[:tickets].try(:first)) message = TicketPurchase.purchase(@conference, current_user, params[:tickets].try(:first))
if message.blank? # The new ticket_purchase has been added to the database. current_user.ticket_purchases contains the new one.
if current_user.ticket_purchases.by_conference(@conference).unpaid.any? count_registration_tickets_after = current_user.count_registration_tickets(@conference)
redirect_to new_conference_payment_path,
notice: 'Please pay here to get tickets.' # Failed to create ticket purchase
elsif current_user.ticket_purchases.by_conference(@conference).paid.any? unless message.blank?
redirect_to conference_physical_tickets_path,
notice: 'You already have tickets for the conference.'
elsif @conference.tickets.for_registration.any?
redirect_to conference_tickets_path(@conference.short_title),
error: 'Please get at least one ticket to continue.'
else
redirect_to conference_conference_registration_path(@conference.short_title)
end
else
redirect_to conference_tickets_path(@conference.short_title), redirect_to conference_tickets_path(@conference.short_title),
error: "Oops, something went wrong with your purchase! #{message}" error: "Oops, something went wrong with your purchase! #{message}"
return
end
# Current user already paid for a registration ticket and the current ticket purchase contains one
if count_registration_tickets_before == 1 && count_registration_tickets_after > 1
redirect_to conference_physical_tickets_path,
error: 'You already have one registration ticket for the conference.'
return
end
# User needs to pay for tickets if any of them is not free.
if current_user.ticket_purchases.by_conference(@conference).unpaid.any?
has_registration_ticket = count_registration_tickets_before.zero? && count_registration_tickets_after == 1
redirect_to new_conference_payment_path(has_registration_ticket: has_registration_ticket),
notice: 'Please pay here to get tickets.'
return
end
# Redirect to registration page for a user who didn't have a registration ticket and is purchasing one
if count_registration_tickets_before.zero? && count_registration_tickets_after == 1
redirect_to new_conference_conference_registration_path(@conference.short_title),
notice: 'Thanks! Your ticket is booked successfully. Please register for the conference.'
else
redirect_to conference_physical_tickets_path,
notice: 'Thanks! Your ticket is booked successfully.'
end end
end end

View file

@ -35,7 +35,8 @@ class UserDatatable < AjaxDatatablesRails::Base
roles: record.roles.any? ? show_roles(record.get_roles) : 'None', roles: record.roles.any? ? show_roles(record.get_roles) : 'None',
view_url: admin_user_path(record), view_url: admin_user_path(record),
edit_url: edit_admin_user_path(record), edit_url: edit_admin_user_path(record),
DT_RowId: record.id DT_RowId: record.id,
confirmed: record.confirmed_at.present?
} }
end end
end end

View file

@ -1,5 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
DEFAULT_LOGO = 'snapcon_logo.png'
DEFAULT_COLOR = '#0B3559'
module ConferenceHelper module ConferenceHelper
# Return true if only call_for_papers or call_for_tracks or call_for_booths is open # Return true if only call_for_papers or call_for_tracks or call_for_booths is open
def one_call_open(*calls) def one_call_open(*calls)
@ -27,4 +30,51 @@ module ConferenceHelper
markdown(ticket.description.split("\n").first&.strip) markdown(ticket.description.split("\n").first&.strip)
end end
def conference_logo_url(conference)
if conference.picture.present?
conference.picture.thumb.url
elsif conference.organization.picture.present?
conference.organization.picture.thumb.url
else
DEFAULT_LOGO
end
end
def conference_color(conference)
if conference.color.present?
conference.color
else
DEFAULT_COLOR
end
end
# adds events to icalendar for proposals in a conference
def icalendar_proposals(calendar, proposals, conference)
proposals.each do |proposal|
calendar.event do |e|
e.dtstart = proposal.time
e.dtend = proposal.time + proposal.event_type.length * 60
e.duration = "PT#{proposal.event_type.length}M"
e.created = proposal.created_at
e.last_modified = proposal.updated_at
e.summary = proposal.title
e.description = proposal.abstract
e.uid = proposal.guid
e.url = conference_program_proposal_url(conference.short_title, proposal.id)
v = conference.venue
if v
e.geo = v.latitude, v.longitude if v.latitude && v.longitude
location = ''
location += "#{proposal.room.name} - " if proposal.room.name
location += " - #{v.street}, " if v.street
location += "#{v.postalcode} #{v.city}, " if v.postalcode && v.city
location += "#{v.country_name}, " if v.country_name
e.location = location
end
e.categories = conference.title, "Difficulty: #{proposal.difficulty_level.title}", "Track: #{proposal.track.name}"
end
end
calendar
end
end end

View file

@ -60,6 +60,20 @@ module EventsHelper
"#{event.average_rating}/#{max_rating}, #{pluralize(event.voters.length, 'vote')}" "#{event.average_rating}/#{max_rating}, #{pluralize(event.voters.length, 'vote')}"
end end
def event_type_options(event_types)
event_types.map do |type|
[
"#{type.title} - #{show_time(type.length)}",
type.id,
data: {
min_words: type.minimum_abstract_length,
max_words: type.maximum_abstract_length,
instructions: type.submission_instructions
}
]
end
end
def event_type_dropdown(event, event_types, conference_id) def event_type_dropdown(event, event_types, conference_id)
selection = event.event_type.try(:title) || 'Event Type' selection = event.event_type.try(:title) || 'Event Type'
options = event_types.collect do |event_type| options = event_types.collect do |event_type|

View file

@ -5,21 +5,26 @@ EMAIL_TEMPLATE = 'email_template'
YTLF_TICKET_ID = 50 YTLF_TICKET_ID = 50
class Mailbot < ActionMailer::Base class Mailbot < ActionMailer::Base
def registration_mail(conference, user) helper ConferenceHelper
@email_body = conference.email_settings.generate_email_on_conf_updates(conference, user, conference.email_settings.registration_body)
@logo = conference.picture.thumb.url
mail(to: user.email, default bcc: SNAPCON_BCC_ADDRESS,
bcc: SNAPCON_BCC_ADDRESS, template_name: EMAIL_TEMPLATE,
from: conference.contact.email, content_type: 'text/html',
subject: conference.email_settings.registration_subject, to: -> { @user.email },
template_name: EMAIL_TEMPLATE) from: -> { @conference.contact.email }
def registration_mail(conference, user)
@user = user
@conference = conference
@email_body = @conference.email_settings.generate_email_on_conf_updates(@conference, @user, @conference.email_settings.registration_body)
mail(subject: @conference.email_settings.registration_subject)
end end
def ticket_confirmation_mail(ticket_purchase) def ticket_confirmation_mail(ticket_purchase)
@ticket_purchase = ticket_purchase @ticket_purchase = ticket_purchase
@conference = ticket_purchase.conference
@user = ticket_purchase.user @user = ticket_purchase.user
@conference = ticket_purchase.conference
PhysicalTicket.last(ticket_purchase.quantity).each do |physical_ticket| 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}") pdf = TicketPdf.new(@conference, @user, physical_ticket, @conference.ticket_layout.to_sym, "ticket_for_#{@conference.short_title}_#{physical_ticket.id}")
@ -31,138 +36,100 @@ class Mailbot < ActionMailer::Base
template_name = 'young_thinkers_ticket_confirmation_template' template_name = 'young_thinkers_ticket_confirmation_template'
end end
mail(to: @user.email, mail(subject: "#{@conference.title} | Ticket Confirmation and PDF!",
bcc: SNAPCON_BCC_ADDRESS, template_name: template_name)
from: @conference.contact.email,
template_name: template_name,
subject: "#{@conference.title} | Ticket Confirmation and PDF!")
end end
def acceptance_mail(event) def acceptance_mail(event)
conference = event.program.conference @user = event.submitter
@conference = event.program.conference
@email_body = @conference.email_settings.generate_event_mail(event, @conference.email_settings.accepted_body)
@logo = conference.picture.thumb.url mail(subject: @conference.email_settings.accepted_subject)
@email_body = conference.email_settings.generate_event_mail(event, conference.email_settings.accepted_body)
mail(to: event.submitter.email,
bcc: SNAPCON_BCC_ADDRESS,
from: conference.contact.email,
subject: conference.email_settings.accepted_subject,
template_name: EMAIL_TEMPLATE)
end end
def submitted_proposal_mail(event) def submitted_proposal_mail(event)
conference = event.program.conference @user = event.submitter
@conference = event.program.conference
@email_body = @conference.email_settings.generate_event_mail(event, @conference.email_settings.submitted_proposal_body)
@logo = conference.picture.thumb.url mail(subject: @conference.email_settings.submitted_proposal_subject)
@email_body = conference.email_settings.generate_event_mail(event, conference.email_settings.submitted_proposal_body)
mail(to: event.submitter.email,
bcc: SNAPCON_BCC_ADDRESS,
from: conference.contact.email,
subject: conference.email_settings.submitted_proposal_subject,
template_name: EMAIL_TEMPLATE)
end end
def rejection_mail(event) def rejection_mail(event)
conference = event.program.conference @user = event.submitter
@conference = event.program.conference
@email_body = @conference.email_settings.generate_event_mail(event, @conference.email_settings.rejected_body)
@logo = conference.picture.thumb.url mail(subject: @conference.email_settings.rejected_subject)
@email_body = conference.email_settings.generate_event_mail(event, conference.email_settings.rejected_body)
mail(to: event.submitter.email,
bcc: SNAPCON_BCC_ADDRESS,
from: conference.contact.email,
subject: conference.email_settings.rejected_subject,
template_name: EMAIL_TEMPLATE)
end end
def confirm_reminder_mail(event) def confirm_reminder_mail(event)
conference = event.program.conference @user = event.submitter
@conference = event.program.conference
@email_body = @conference.email_settings.generate_event_mail(event, @conference.email_settings.confirmed_without_registration_body)
@logo = conference.picture.thumb.url mail(subject: @conference.email_settings.confirmed_without_registration_subject)
@email_body = conference.email_settings.generate_event_mail(event, conference.email_settings.confirmed_without_registration_body)
mail(to: event.submitter.email,
bcc: SNAPCON_BCC_ADDRESS,
from: conference.contact.email,
subject: conference.email_settings.confirmed_without_registration_subject,
template_name: EMAIL_TEMPLATE)
end end
def conference_date_update_mail(conference, user) def conference_date_update_mail(conference, user)
@logo = conference.picture.thumb.url @user = user
@email_body = conference.email_settings.generate_email_on_conf_updates(conference, user, conference.email_settings.conference_dates_updated_body) @conference = conference
@email_body = @conference.email_settings.generate_email_on_conf_updates(@conference, @user, @conference.email_settings.conference_dates_updated_body)
mail(to: user.email, mail(subject: @conference.email_settings.conference_dates_updated_subject)
bcc: SNAPCON_BCC_ADDRESS,
from: conference.contact.email,
subject: conference.email_settings.conference_dates_updated_subject,
template_name: EMAIL_TEMPLATE)
end end
def conference_registration_date_update_mail(conference, user) def conference_registration_date_update_mail(conference, user)
@logo = conference.picture.thumb.url @user = user
@email_body = conference.email_settings.generate_email_on_conf_updates(conference, user, conference.email_settings.conference_registration_dates_updated_body) @conference = conference
@email_body = @conference.email_settings.generate_email_on_conf_updates(@conference, @user, @conference.email_settings.conference_registration_dates_updated_body)
mail(to: user.email, mail(subject: @conference.email_settings.conference_registration_dates_updated_subject)
bcc: SNAPCON_BCC_ADDRESS,
from: conference.contact.email,
subject: conference.email_settings.conference_registration_dates_updated_subject,
template_name: EMAIL_TEMPLATE)
end end
def conference_venue_update_mail(conference, user) def conference_venue_update_mail(conference, user)
@logo = conference.picture.thumb.url @user = user
@email_body = conference.email_settings.generate_email_on_conf_updates(conference, user, conference.email_settings.venue_updated_body) @conference = conference
@email_body = @conference.email_settings.generate_email_on_conf_updates(@conference, @user, @conference.email_settings.venue_updated_body)
mail(to: user.email, mail(subject: @conference.email_settings.venue_updated_subject)
bcc: SNAPCON_BCC_ADDRESS,
from: conference.contact.email,
subject: conference.email_settings.venue_updated_subject,
template_name: EMAIL_TEMPLATE)
end end
def conference_schedule_update_mail(conference, user) def conference_schedule_update_mail(conference, user)
@logo = conference.picture.thumb.url @user = user
@email_body = conference.email_settings.generate_email_on_conf_updates(conference, user, conference.email_settings.program_schedule_public_body) @conference = conference
@email_body = @conference.email_settings.generate_email_on_conf_updates(@conference, @user, @conference.email_settings.program_schedule_public_body)
mail(to: user.email, mail(bcc: nil,
from: conference.contact.email, subject: @conference.email_settings.program_schedule_public_subject)
subject: conference.email_settings.program_schedule_public_subject,
template_name: EMAIL_TEMPLATE)
end end
def conference_cfp_update_mail(conference, user) def conference_cfp_update_mail(conference, user)
@logo = conference.picture.thumb.url @user = user
@email_body = conference.email_settings.generate_email_on_conf_updates(conference, user, conference.email_settings.cfp_dates_updated_body) @conference = conference
@email_body = @conference.email_settings.generate_email_on_conf_updates(@conference, @user, @conference.email_settings.cfp_dates_updated_body)
mail(to: user.email, mail(bcc: nil,
from: conference.contact.email, subject: @conference.email_settings.cfp_dates_updated_subject)
subject: conference.email_settings.cfp_dates_updated_subject,
template_name: EMAIL_TEMPLATE)
end end
def conference_booths_acceptance_mail(booth) def conference_booths_acceptance_mail(booth)
conference = booth.conference @user = booth.submitter
@logo = conference.picture.thumb.url @conference = booth.conference
@email_body = conference.email_settings.generate_booth_mail(booth, conference.email_settings.booths_acceptance_body) @email_body = @conference.email_settings.generate_booth_mail(booth, @conference.email_settings.booths_acceptance_body)
mail(to: booth.submitter.email, mail(bcc: nil,
from: conference.contact.email, subject: @conference.email_settings.booths_acceptance_subject)
subject: conference.email_settings.booths_acceptance_subject,
template_name: EMAIL_TEMPLATE)
end end
def conference_booths_rejection_mail(booth) def conference_booths_rejection_mail(booth)
conference = booth.conference @user = booth.submitter
@logo = conference.picture.thumb.url @conference = booth.conference
@email_body = conference.email_settings.generate_booth_mail(booth, conference.email_settings.booths_rejection_body) @email_body = @conference.email_settings.generate_booth_mail(booth, @conference.email_settings.booths_rejection_body)
mail(to: booth.submitter.email, mail(bcc: nil,
from: conference.contact.email, subject: @conference.email_settings.booths_rejection_subject)
subject: conference.email_settings.booths_rejection_subject,
template_name: EMAIL_TEMPLATE)
end end
def event_comment_mail(comment, user) def event_comment_mail(comment, user)
@ -171,8 +138,7 @@ class Mailbot < ActionMailer::Base
@conference = @event.program.conference @conference = @event.program.conference
@user = user @user = user
mail(to: @user.email, mail(bcc: nil,
from: @conference.contact.email,
template_name: 'comment_template', template_name: 'comment_template',
subject: "New comment has been posted for #{@event.title}") subject: "New comment has been posted for #{@event.title}")
end end

View file

@ -61,6 +61,9 @@ class Conference < ApplicationRecord
has_one :email_settings, dependent: :destroy has_one :email_settings, dependent: :destroy
has_one :program, dependent: :destroy has_one :program, dependent: :destroy
has_one :venue, dependent: :destroy has_one :venue, dependent: :destroy
delegate :city, :country_name, to: :venue, allow_nil: true
delegate :name, :street, to: :venue, prefix: true, allow_nil: true
has_many :ticket_purchases, dependent: :destroy has_many :ticket_purchases, dependent: :destroy
has_many :physical_tickets, through: :ticket_purchases has_many :physical_tickets, through: :ticket_purchases
has_many :payments, dependent: :destroy has_many :payments, dependent: :destroy

View file

@ -274,7 +274,7 @@ class Event < ApplicationRecord
biographies: speakers.all? { |speaker| !speaker.biography.blank? }, biographies: speakers.all? { |speaker| !speaker.biography.blank? },
subtitle: !subtitle.blank?, subtitle: !subtitle.blank?,
track: (!track.blank? unless program.tracks.empty?), track: (!track.blank? unless program.tracks.empty?),
difficulty_level: !difficulty_level.blank?, difficulty_level: (difficulty_level.present? unless program.difficulty_levels.empty?),
title: true, title: true,
abstract: true abstract: true
}.with_indifferent_access }.with_indifferent_access

View file

@ -10,6 +10,7 @@
# length :integer default(30) # length :integer default(30)
# maximum_abstract_length :integer default(500) # maximum_abstract_length :integer default(500)
# minimum_abstract_length :integer default(0) # minimum_abstract_length :integer default(0)
# submission_instructions :text
# title :string not null # title :string not null
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime

View file

@ -24,8 +24,8 @@ class SurveyQuestion < ActiveRecord::Base
validates :title, presence: true validates :title, presence: true
validates :possible_answers, :max_choices, :min_choices, presence: true, if: :choice? validates :possible_answers, :max_choices, :min_choices, presence: true, if: :choice?
validates :min_choices, numericality: { greater_than_or_equal_to: 1 }, allow_blank: true validates :min_choices, numericality: { greater_than_or_equal_to: 1 }, allow_blank: true, if: :choice?
validates :max_choices, numericality: { greater_than_or_equal_to: 1 }, allow_blank: true validates :max_choices, numericality: { greater_than_or_equal_to: 1 }, allow_blank: true, if: :choice?
validate :max_choices_greater_than_min validate :max_choices_greater_than_min

View file

@ -346,6 +346,17 @@ class User < ApplicationRecord
events.where(program_id: conference.program.id, 'event_users.event_role': 'volunteer') events.where(program_id: conference.program.id, 'event_users.event_role': 'volunteer')
end end
def count_registration_tickets(conference)
count = 0
ticket_purchases.by_conference(conference).each do |ticket_purchase|
if ticket_purchase.ticket.registration_ticket
count += 1
end
end
count
end
def self.empty? def self.empty?
User.count == 1 && User.first.email == 'deleted@localhost.osem' User.count == 1 && User.first.email == 'deleted@localhost.osem'
end end

View file

@ -69,9 +69,9 @@ class TicketPdf < Prawn::Document
draw_text @conference.title.to_s, at: [@mid_horizontal + 30, cursor - 30], size: 12 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.organization.name.to_s, at: [@mid_horizontal + 30, cursor - 50], size: 12
if @conference.venue if @conference.venue
draw_text @conference.venue.name, at: [@mid_horizontal + 30, cursor - 70] 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_street, at: [@mid_horizontal + 30, cursor - 90]
draw_text @conference.venue.city, at: [@mid_horizontal + 30, cursor - 110] draw_text @conference.city, at: [@mid_horizontal + 30, cursor - 110]
end end
move_up 130 move_up 130
move_down @mid_vertical move_down @mid_vertical

View file

@ -6,6 +6,8 @@ class PictureUploader < CarrierWave::Uploader::Base
include CarrierWave::Compatibility::Paperclip include CarrierWave::Compatibility::Paperclip
include CarrierWave::BombShelter include CarrierWave::BombShelter
storage :file
# use cloudinary if it's configured # use cloudinary if it's configured
if Cloudinary.config.cloud_name if Cloudinary.config.cloud_name
# use https by default # use https by default

View file

@ -1,13 +1,14 @@
.list-group %ul.list-group
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)}" } .list-group-item
%h4 %h4
Conference progress Conference progress
.progress .progress
.progress-bar{ 'role' => 'progressbar', 'aria-valuenow' => "#{conference_progress['process']}", 'aria-valuemin' => '0', .progress-bar{ role: 'progressbar', 'aria-valuenow': conference_progress['process'],
'aria-valuemax' => '100', 'style' => "width: #{conference_progress['process']}%;" } 'aria-valuemin': 0, 'aria-valuemax': 100,
style: "width: #{conference_progress['process']}%;" }
= conference_progress['process'] + '%' = conference_progress['process'] + '%'
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['registration'])}" } %li.list-group-item{ class: class_for_todo(conference_progress['registration']) }
%span{ 'class' => icon_for_todo(conference_progress['registration']) } %span{ class: icon_for_todo(conference_progress['registration']) }
- if can? :update, @conference - if can? :update, @conference
- if conference.registration_period - if conference.registration_period
= link_to 'Set up registration period', edit_admin_conference_registration_period_path(conference_progress['short_title']) = link_to 'Set up registration period', edit_admin_conference_registration_period_path(conference_progress['short_title'])
@ -15,14 +16,14 @@
= link_to 'Set up registration period', new_admin_conference_registration_period_path(conference_progress['short_title']) = link_to 'Set up registration period', new_admin_conference_registration_period_path(conference_progress['short_title'])
- else - else
Set up registration period Set up registration period
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['cfp'])}" } %li.list-group-item{ class: class_for_todo(conference_progress['cfp']) }
%span{ 'class' => icon_for_todo(conference_progress['cfp']) } %span{ class: icon_for_todo(conference_progress['cfp']) }
- if can? :update, Cfp.new(program_id: @program.id) - if can? :update, Cfp.new(program_id: @program.id)
= link_to 'Set up call for papers', admin_conference_program_cfps_path(conference_progress['short_title']) = link_to 'Set up call for papers', admin_conference_program_cfps_path(conference_progress['short_title'])
- else - else
Set up call for papers Set up call for papers
%li{'class'=>"list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['venue'])}"} %li.list-group-item{ class: class_for_todo(conference_progress['venue']) }
%span{'class'=>icon_for_todo(conference_progress['venue'])} %span{ class: icon_for_todo(conference_progress['venue'])}
- if can? :update, Venue.new(conference: @conference) - if can? :update, Venue.new(conference: @conference)
- @conference.reload - @conference.reload
- if conference.venue - if conference.venue
@ -32,32 +33,32 @@
- else - else
- @conference.reload - @conference.reload
Add venue Add venue
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['rooms'])}" } %li.list-group-item{ class: class_for_todo(conference_progress['rooms']) }
%span{ 'class' => icon_for_todo(conference_progress['rooms']) } %span{ class: icon_for_todo(conference_progress['rooms']) }
- if @conference.venue && (can? :update, @conference.venue.rooms.build) - if @conference.venue && (can? :update, @conference.venue.rooms.build)
= link_to 'Add rooms', admin_conference_venue_rooms_path(conference_progress['short_title']) = link_to 'Add rooms', admin_conference_venue_rooms_path(conference_progress['short_title'])
- else - else
Add rooms Add rooms
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['tracks'])}" } %li.list-group-item{ class: class_for_todo(conference_progress['tracks']) }
%span{ 'class' => icon_for_todo(conference_progress['tracks']) } %span{ class: icon_for_todo(conference_progress['tracks']) }
- if can? :update, @conference.program.tracks.build - if can? :update, @conference.program.tracks.build
= link_to 'Add tracks', admin_conference_program_tracks_path(conference_progress['short_title']) = link_to 'Add tracks', admin_conference_program_tracks_path(conference_progress['short_title'])
- else - else
Add tracks Add tracks
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['event_types'])}" } %li{ class: "list-group-item #{class_for_todo(conference_progress['event_types'])}" }
%span{ 'class' => icon_for_todo(conference_progress['event_types']) } %span{ class: icon_for_todo(conference_progress['event_types']) }
- if can? :update, @conference.program.event_types.build - if can? :update, @conference.program.event_types.build
= link_to 'Add event types', admin_conference_program_event_types_path(conference_progress['short_title']) = link_to 'Add event types', admin_conference_program_event_types_path(conference_progress['short_title'])
- else - else
Add event types Add event types
%li{ 'class' => "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['difficulty_levels'])}" } %li{ class: "list-group-item #{class_for_todo(conference_progress['difficulty_levels'])}" }
%span{ 'class' => icon_for_todo(conference_progress['difficulty_levels']) } %span{ class: icon_for_todo(conference_progress['difficulty_levels']) }
- if can? :update, @conference.program.difficulty_levels.build - if can? :update, @conference.program.difficulty_levels.build
= link_to 'Add difficulty levels', admin_conference_program_difficulty_levels_path(conference_progress['short_title']) = link_to 'Add difficulty levels', admin_conference_program_difficulty_levels_path(conference_progress['short_title'])
- else - else
Add difficulty levels Add difficulty levels
%li{ class: "list-group-item #{hidden_if_conference_over(conference)} #{class_for_todo(conference_progress['splashpage'])}" } %li.list-group-item{ class: "#{class_for_todo(conference_progress['splashpage'])}" }
%span{ 'class' => icon_for_todo(conference_progress['splashpage']) } %span{ class: icon_for_todo(conference_progress['splashpage']) }
- if can? :update, @conference - if can? :update, @conference
= link_to 'Set up a Splashpage', admin_conference_splashpage_path(conference_progress['short_title']) = link_to 'Set up a Splashpage', admin_conference_splashpage_path(conference_progress['short_title'])
- else - else

View file

@ -9,24 +9,27 @@
= semantic_form_for(@conference, url: admin_conference_path(@conference.short_title), html: {multipart: true}) do |f| = semantic_form_for(@conference, url: admin_conference_path(@conference.short_title), html: {multipart: true}) do |f|
= f.input :title, hint: "The full title of the conference, e.g. 'openSUSE Conference 2014'" = f.input :title, hint: "The full title of the conference, e.g. 'openSUSE Conference 2014'"
= f.input :short_title, hint: "A short title, e.g. 'oSC14', to be used in URLs" = f.input :short_title, hint: "A short title, e.g. 'oSC14', to be used in URLs"
= f.input :description, hint: markdown_hint('A description of the conference.'), input_html: { rows: 5, data: { provide: 'markdown' } } = f.input :description,
= f.input :color, hint: 'The color will be used eg for the dashboard.', input_html: {size: 6, type: 'color'} hint: markdown_hint('A description of the conference. (Supports unsafe HTML.)'),
= f.label 'Conference Logo' input_html: { rows: 5, data: { provide: 'markdown' } }
= f.input :color, hint: 'The will be used in emails.',
input_html: {size: 6, type: 'color'}
= f.label 'Conference Logo', for: 'conference_picture'
%br %br
- if @conference.picture? - if @conference.picture?
= image_tag @conference.picture.thumb.url = image_tag @conference.picture.thumb.url
= f.input :picture, label: false, hint: 'This will be displayed on the front page.' = f.input :picture, label: false, hint: 'This will be shown in the navigation bar and emails.'
= f.hidden_field :picture_cache = f.hidden_field :picture_cache
= f.input :custom_css, = f.input :custom_css,
hint: "Add Custon CSS to the main page. You might find the class '.conference-#{@conference.short_title}' useful.", hint: "Add custon CSS to all pages within the conference. The class <code>.conference-#{@conference.short_title}</code> is included on the body element.".html_safe,
input_html: { rows: 5 } input_html: { rows: 10, style: 'font-family: monospace' }
= f.input :ticket_layout, as: :select, collection: Conference.ticket_layouts.keys, hint: "Layout type for tickets of the conference." = f.input :ticket_layout, as: :select, collection: Conference.ticket_layouts.keys, hint: "Layout type for tickets of the conference."
= f.inputs name: 'Scheduling' do = f.inputs name: 'Scheduling' do
= f.input :timezone, as: :time_zone, hint: 'The conference time zone' = f.input :timezone, as: :time_zone, hint: 'The conference time zone'
= f.input :start_date, as: :string, input_html: { id: 'conference-start-datepicker', readonly: 'readonly' } = f.input :start_date, as: :string, input_html: { id: 'conference-start-datepicker' }
= f.input :end_date, as: :string, input_html: { id: 'conference-end-datepicker', readonly: 'readonly' } = f.input :end_date, as: :string, input_html: { id: 'conference-end-datepicker' }
= f.input :start_hour, input_html: {size: 2, type: 'number', min: 0, max: 23}, hint: rescheduling_hint(@affected_event_count) = f.input :start_hour, input_html: {size: 2, type: 'number', min: 0, max: 23}, hint: rescheduling_hint(@affected_event_count)
= f.input :end_hour, input_html: {size: 2, type: 'number', min: 1, max: 24}, hint: rescheduling_hint(@affected_event_count) = f.input :end_hour, input_html: {size: 2, type: 'number', min: 1, max: 24}, hint: rescheduling_hint(@affected_event_count)
= f.inputs name: 'Registrations' do = f.inputs name: 'Registrations' do

View file

@ -3,16 +3,16 @@
Dashboard for #{@conference.title} Dashboard for #{@conference.title}
%hr %hr
.row .row
.col-sm-3.col-xs-3 .col-sm-3.col-xs-6
= render "big_statistic", = render "big_statistic",
icon: "user", subtitle: "Registration", value: @total_reg, delta: @new_reg icon: "user", subtitle: "Registration", value: @total_reg, delta: @new_reg
.col-sm-3.col-xs-3 .col-sm-3.col-xs-6
= render "big_statistic", = render "big_statistic",
icon: "check-square", subtitle: "Submission", value: @total_submissions, delta: @new_submissions icon: "check-square", subtitle: "Submission", value: @total_submissions, delta: @new_submissions
.col-sm-3.col-xs-3 .col-sm-3.col-xs-6
= render "big_statistic", = render "big_statistic",
icon: "file-text", subtitle: "Hour", value: @program_length, delta: @new_program_length icon: "file-text", subtitle: "Hour", value: @program_length, delta: @new_program_length
.col-sm-3.col-xs-3 .col-sm-3.col-xs-6
= render "big_statistic", = render "big_statistic",
icon: "archive", subtitle: "Withdrawn", value: @total_withdrawn, delta: @new_withdrawn icon: "archive", subtitle: "Withdrawn", value: @total_withdrawn, delta: @new_withdrawn
@ -29,8 +29,20 @@
= render 'line_chart', = render 'line_chart',
title: 'Submissions per week', data: @submissions title: 'Submissions per week', data: @submissions
.col-md-4 .col-md-4
-# = render 'todo_list', - unless @conference.ended?
-# conference_progress: @conference_progress, conference: @conference = render 'todo_list',
conference_progress: @conference_todo_list, conference: @conference
- else
.list-group
.list-group-item
%h4
Conference Progress
.progress
.progress-bar{ role: 'progressbar', 'aria-valuenow': 100,
'aria-valuemin': 0, 'aria-valuemax': 100,
style: 'width: 100%;' }
Conference Complete!
.row#tickets .row#tickets
.col-md-8 .col-md-8
= render 'line_chart', = render 'line_chart',
@ -43,14 +55,15 @@
%a{ href: '#distribution_all', 'data-toggle' => 'tab' } %a{ href: '#distribution_all', 'data-toggle' => 'tab' }
%span.fa.fa-star %span.fa.fa-star
All All
%li -# TODO-SNAP: Disabled for Snap!Con
%a{ href: '#distribution_confirmed', 'data-toggle' => 'tab' } %li
%span.fa.fa-comment %a{ href: '#distribution_confirmed', 'data-toggle' => 'tab' }
Confirmed %span.fa.fa-comment
%li Confirmed
%a{ href: '#distribution_withdrawn', 'data-toggle' => 'tab' } %li
%span.fa.fa-archive %a{ href: '#distribution_withdrawn', 'data-toggle' => 'tab' }
Withdrawn %span.fa.fa-archive
Withdrawn
.tab-content .tab-content
.tab-pane.active#distribution_all .tab-pane.active#distribution_all
.row .row
@ -58,33 +71,33 @@
= render 'donut_chart', title: 'Event types', = render 'donut_chart', title: 'Event types',
combined_data: @event_type_distribution combined_data: @event_type_distribution
.col-md-4 .col-md-4
-# = render 'donut_chart', title: 'Difficulty levels', = render 'donut_chart', title: 'Difficulty levels',
-# combined_data: @difficulty_levels_distribution combined_data: @difficulty_levels_distribution
.col-md-4 .col-md-4
-# = render 'donut_chart', title: 'Tracks', = render 'donut_chart', title: 'Tracks',
-# combined_data: @tracks_distribution combined_data: @tracks_distribution
.tab-pane#distribution_confirmed -# .tab-pane#distribution_withdrawn
.row
.col-md-4
-# = render 'donut_chart', title: 'Event types',
-# combined_data: @event_type_distribution_confirmed
.col-md-4
-# = render 'donut_chart', title: 'Difficulty levels',
-# combined_data: @difficulty_levels_distribution_confirmed
.col-md-4
-# = render 'donut_chart', title: 'Tracks',
-# combined_data: @tracks_distribution_confirmed
.tab-pane#distribution_withdrawn
.row .row
.col-md-4 .col-md-4
= render 'donut_chart', title: 'Event types', = render 'donut_chart', title: 'Event types',
combined_data: @event_type_distribution_withdrawn combined_data: @event_type_distribution_withdrawn
.col-md-4 .col-md-4
= render 'donut_chart', title: 'Difficulty levels', = render 'donut_chart', title: 'Difficulty levels',
combined_data: @difficulty_levels_distribution_withdrawn combined_data: @difficulty_levels_distribution
.col-md-4 .col-md-4
= render 'donut_chart', title: 'Tracks', = render 'donut_chart', title: 'Tracks',
combined_data: @tracks_distribution_withdrawn combined_data: @tracks_distribution
-# .tab-pane#distribution_confirmed
.row
.col-md-4
= render 'donut_chart', title: 'Event types',
combined_data: @event_type_distribution_confirmed
.col-md-4
= render 'donut_chart', title: 'Difficulty levels',
combined_data: @difficulty_levels_distribution_confirmed
.col-md-4
= render 'donut_chart', title: 'Tracks',
combined_data: @tracks_distribution_confirmed
.row .row
.col-md-8 .col-md-8

View file

@ -15,6 +15,7 @@
= f.input :description, as: :text, hint: markdown_hint, input_html: { rows: 5, data: { provide: 'markdown-editable' } } = f.input :description, as: :text, hint: markdown_hint, input_html: { rows: 5, data: { provide: 'markdown-editable' } }
= f.input :minimum_abstract_length, input_html: {size: 3} = f.input :minimum_abstract_length, input_html: {size: 3}
= f.input :maximum_abstract_length, input_html: {size: 3} = f.input :maximum_abstract_length, input_html: {size: 3}
= f.input :submission_instructions, as: :text, hint: markdown_hint, input_html: { rows: 5, data: { provide: 'markdown-editable' } }
= f.input :color, input_html: { size: 6, type: 'color' } = f.input :color, input_html: { size: 6, type: 'color' }
%p.text-right %p.text-right
= f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' }

View file

@ -10,6 +10,7 @@
%thead %thead
%th Title %th Title
%th Description %th Description
%th Instructions
%th Length %th Length
%th Abstract Length %th Abstract Length
%th Color %th Color
@ -21,6 +22,8 @@
= event_type.title = event_type.title
%td %td
= markdown(event_type.description) = markdown(event_type.description)
%td
= markdown(event_type.submission_instructions)
%td %td
= event_type.length = event_type.length
Minutes Minutes

View file

@ -15,7 +15,7 @@
.row .row
.col-md-12 .col-md-12
= f.input :title = f.input :title, input_html: { autofocus: true }
= f.input :mandatory = f.input :mandatory
.survey-possible-answers{ class: @survey_question.choice? ? '' : 'hidden' } .survey-possible-answers{ class: @survey_question.choice? ? '' : 'hidden' }
= f.input :possible_answers, hint: 'Comma separated', input_html: { rows: 3 } = f.input :possible_answers, hint: 'Comma separated', input_html: { rows: 3 }

View file

@ -7,4 +7,4 @@
.panel-body .panel-body
- question_replies = survey_question.survey_replies - question_replies = survey_question.survey_replies
- if question_replies.any? - if question_replies.any?
= pie_chart question_replies.group(:text).count, library: { legend: 'bottom', plotOptions: { pie: { dataLabels: { enabled: false }, showInLegend: true } } } = pie_chart question_replies.group(:text).count, library: { legend: { position: 'bottom' }, plotOptions: { pie: { dataLabels: { enabled: false }, showInLegend: true } } }

View file

@ -20,6 +20,7 @@
%th{ width: '0' } Conferences Attended %th{ width: '0' } Conferences Attended
%th{ width: '50%' } Roles %th{ width: '50%' } Roles
%th{ width: '0' } Actions %th{ width: '0' } Actions
%th{ style: 'display: none' } Confirmed?
%tbody %tbody
:javascript :javascript
@ -37,6 +38,7 @@
{ {
"data": "confirmed_at", "data": "confirmed_at",
"render": function (data, type, row, meta) { "render": function (data, type, row, meta) {
console.log(meta)
return '<input type="checkbox" class="switch-checkbox" '+ return '<input type="checkbox" class="switch-checkbox" '+
'id="user_'+row.id+'_confirmed" '+ 'id="user_'+row.id+'_confirmed" '+
'name="user_'+row.id+'_confirmed" '+ 'name="user_'+row.id+'_confirmed" '+
@ -73,6 +75,11 @@
'<a class="btn-primary" href="'+data.edit_url+'">Edit</a>'+ '<a class="btn-primary" href="'+data.edit_url+'">Edit</a>'+
'</div>'; '</div>';
} }
},
{
"data": "confirmed",
"className": 'hidden',
"render": false
} }
] ]
}); });

View file

@ -12,8 +12,10 @@
.tab-content .tab-content
#user-info-content.tab-pane{class: "#{'active' unless params[:tab] == 'submissions-content'}"} #user-info-content.tab-pane{class: "#{'active' unless params[:tab] == 'submissions-content'}"}
- if can? :edit, @user - if can? :edit, @user
.pull-right .pull-right.btn-group
= link_to 'Edit', edit_admin_user_path(@user), class: 'btn btn-primary' = link_to 'Edit', edit_admin_user_path(@user), class: 'btn btn-primary'
= link_to 'Delete', admin_user_path(@user),method: :delete, class: 'btn btn-danger',
data: {confirm: "Are you sure?"}
%table.table %table.table
- @show_attributes.each do |attr| - @show_attributes.each do |attr|
%tr %tr

View file

@ -1,13 +1,12 @@
- reverse ||= false - reverse ||= false
- variant = variant_from_delta(delta, reverse: reverse) - variant = variant_from_delta(delta, reverse: reverse)
.dashbox.text-center .dashbox.panel.panel-primary
%span.fa .paenl-body.text-center
= fa_icon(icon) %span.fa
= value = fa_icon(icon)
%p.text-nowrap = value
%small %p
= subtitle.pluralize(value) = subtitle.pluralize(value)
%span.label{ class: "label-#{variant}" } .label{ class: "label-#{variant}" }
= delta = delta || 0
since you last logged in since last log in

View file

@ -1,33 +1,39 @@
.panel.panel-default{class: ("panel-success" if event.registrations.include?(@registration)) } .panel.panel-default{ class: ('panel-success' if event.registrations.include?(registration)) }
.panel-heading .panel-heading
%label{for: "registration_event_ids_#{event.id}"} %label{ for: "registration_event_ids_#{event.id}" }
%h3{style: 'margin: 0 auto;'} %h3{ style: 'margin: 0 auto;' }
= hidden_field_tag "registration[event_ids][]", nil = hidden_field_tag 'registration[event_ids][]', nil
= check_box_tag "registration[event_ids][]", event.id, event.registrations.include?(@registration), id: "registration_event_ids_#{event.id}" = check_box_tag 'registration[event_ids][]', event.id, event.registrations.include?(registration), id: "registration_event_ids_#{event.id}"
= event.title = event.title
%small %small
= event.subtitle = event.subtitle
.text-muted
= registered_text(event)
- if event.scheduled?
(Scheduled on: #{event.time.to_date})
.panel-body .panel-body
-# %p -#
-# = canceled_replacement_event_label(event, event_schedule) %p
-# = replacement_event_notice(event_schedule) = canceled_replacement_event_label(event, event_schedule)
= replacement_event_notice(event_schedule)
%p %p
- if event.speakers.any? - if event.speakers.any?
presented by #{event.speaker_names} presented by #{event.speaker_names}
- if event_schedule.present? - if event_schedule.present?
.h4.track .h4.track
%span.fa.fa-clock-o %span.fa.fa-clock-o
%span.label{ style: "background-color: grey" } %span.label{ style: 'background-color: grey' }
= event_schedule.start_time.strftime('%A, %B %-d %H:%M') = event_schedule.start_time.strftime('%A, %B %-d %H:%M')
\- \-
= event_schedule.end_time.strftime('%H:%M') = event_schedule.end_time.strftime('%H:%M')
%p %p
= markdown(truncate(event.abstract, length: 250)) = markdown(truncate(event.abstract, length: 250))
-# TODO: More informative text or aria-label. -# TODO: More informative text or aria-label.
= link_to 'more', conference_program_proposal_path(@conference.short_title, event.id), target: '_blank' = link_to 'more', conference_program_proposal_path(conference.short_title, event.id), target: '_blank'
- if event.track - if event.track
%span.track %span.track
%span.fa.fa-road %span.fa.fa-road
%span.label{ style: "background-color: #{event.track.color}; color: #{ contrast_color(event.track.color) }" } %span.label{ style: "background-color: #{event.track.color}; color: #{contrast_color(event.track.color)}" }
= event.track.name = event.track.name

View file

@ -18,6 +18,6 @@
You are registered for #{pluralize(@registration.events.count, 'event')}. You are registered for #{pluralize(@registration.events.count, 'event')}.
They are at the end of this list. They are at the end of this list.
- @registration.events_ordered.each do |event| - @registration.events_ordered.each do |event|
= render 'conference_registrations/event', event: event, event_schedule: event.event_schedules.first = render 'conference_registrations/event', event: event, event_schedule: event.event_schedules.first, conference: @conference, registration: @registration
= render 'conferences/code_of_conduct', organization: @conference.organization = render 'conferences/code_of_conduct', organization: @conference.organization

View file

@ -9,9 +9,9 @@
-if @conference.venue -if @conference.venue
at at
%strong %strong
= "#{@conference.venue.name}," = "#{@conference.venue_name},"
= "#{@conference.venue.street}," = "#{@conference.venue_street},"
= "#{@conference.venue.city} / #{@conference.venue.country_name}." = "#{@conference.city} / #{@conference.country_name}."
%small %small
= date_string(@conference.start_date, @conference.end_date) = date_string(@conference.start_date, @conference.end_date)
- unless @conference.code_of_conduct.blank? - unless @conference.code_of_conduct.blank?

View file

@ -12,7 +12,7 @@
= date_string(conference.start_date, conference.end_date) = date_string(conference.start_date, conference.end_date)
- if conference.venue - if conference.venue
%p %p
= "#{conference.venue.city}/#{conference.venue.country_name}" = "#{conference.city}/#{conference.country_name}"
- unless conference.description.blank? - unless conference.description.blank?
%p %p
= markdown(conference.description, escape_html=false) = markdown(conference.description, escape_html=false)

View file

@ -1,14 +1,15 @@
-# .scroll-top-wrapper -#
-# = link_to "#banner", class: "smoothscroll" do scroll-top-wrapper
-# %i.fa.fa-2x.fa-arrow-circle-up = link_to "#banner", class: "smoothscroll" do
%i.fa.fa-2x.fa-arrow-circle-up
-# :javascript :javascript
-# $(function(){ $(function(){
-# $(document).on( 'scroll', function(){ $(document).on( 'scroll', function(){
-# if ($(window).scrollTop() > 100) { if ($(window).scrollTop() > 100) {
-# $('.scroll-top-wrapper').addClass('show'); $('.scroll-top-wrapper').addClass('show');
-# } else { } else {
-# $('.scroll-top-wrapper').removeClass('show'); $('.scroll-top-wrapper').removeClass('show');
-# } }
-# }); });
-# }); });

View file

@ -2,13 +2,14 @@
#banner{ style: ("background-image: url(#{conference.picture_url})" if conference.picture_url) } #banner{ style: ("background-image: url(#{conference.picture_url})" if conference.picture_url) }
.container .container
.row .row
.col-md-6.col-md-offset-3{id: (conference.picture? ? "header-image" : "header-no-image")} .col-md-6.col-md-offset-3{ id: (conference.picture? ? "header-image" : "header-no-image") }
.row .row
-# - if conference.picture? -#
-# .col-md-4 - if conference.picture?
-# = image_tag(conference.picture_url, .col-md-4
-# class: 'img-responsive img-center', = image_tag(conference.picture_url,
-# id: 'splash-logo') class: 'img-responsive img-center',
id: 'splash-logo')
.col-md-8 .col-md-8
%h1 %h1
= conference.title.html_safe = conference.title.html_safe

View file

@ -2,7 +2,7 @@
%li %li
%a.smoothscroll{ href: '#program' } Program %a.smoothscroll{ href: '#program' } Program
%li %li
= link_to('Schedule', events_conference_schedule_path(@conference)) = link_to('Schedule', events_conference_schedule_path(conference))
- cache [conference, highlights, tracks, booths, '#splash#program'] do - cache [conference, highlights, tracks, booths, '#splash#program'] do
%section#program %section#program

View file

@ -27,7 +27,7 @@
.row .row
.col-md-12 .col-md-12
%h3.text-center %h3.text-center
= "Interested in sponsoring #{conference.title}?" Interested in sponsoring #{conference.title}?
= link_to(sponsorship_mailto(conference)) do = link_to(sponsorship_mailto(conference)) do
Please, contact us! Please, contact us!
.trapezoid .trapezoid

View file

@ -22,6 +22,6 @@
.word_break .word_break
= short_ticket_description(ticket) = short_ticket_description(ticket)
%button.btn-block.btn.btn-lg.btn-success %button.btn-block.btn.btn-lg.btn-success
%i.fa.fa-ticket.fa-fw{"aria-hidden": true} %i.fa.fa-ticket.fa-fw{ "aria-hidden": true }
= humanized_money_with_symbol(ticket.price) = humanized_money_with_symbol(ticket.price)
.trapezoid .trapezoid

View file

@ -18,8 +18,11 @@
#antiquated #antiquated
- @antiquated.each do |conference| - @antiquated.each do |conference|
= render '/conferences/conference_details', conference: conference = render '/conferences/conference_details', conference: conference
- if @antiquated.empty? && @current.empty? && User.empty? %p
= render partial: 'new_install' Add the events to your calendar:
%span.btn-group
= link_to("Days only", calendar_url(protocol: 'webcal', format: 'ics'), class: 'btn btn-default')
= link_to("Detailed", calendar_url(protocol: 'webcal', format: 'ics', full: true), class: 'btn btn-default')
-content_for :script_body do -content_for :script_body do
:javascript :javascript

View file

@ -17,5 +17,5 @@
will the be administrator of it. will the be administrator of it.
%p %p
We hope you enjoy using OSEM, if you have any question don't hesitate to We hope you enjoy using OSEM, if you have any question don't hesitate to
= link_to('http://osem.io/#contact') do = link_to('https://osem.io/#contact') do
contact us! contact us!

View file

@ -20,24 +20,22 @@
- if @unpaid_tickets - if @unpaid_tickets
.row .row
.col-md-12 .col-md-12
.alert.alert-dismissable.alert-info.text-center#unpaid-tickets{role: 'alert'} .alert.alert-dismissable.alert-info.text-center#unpaid-tickets{ role: 'alert' }
%button.button.close{"data-dismiss" => "alert", "aria-label"=>"close"} %button.button.close{ "data-dismiss" => "alert", "aria-label"=>"close" }
&times; &times;
%p %p
You have unpaid tickets. Please complete your purchase. You have unpaid tickets. Please complete your purchase.
= link_to('Purchase Tickets', new_conference_payment_path(@conference), class: 'btn btn-success btn-lg') = link_to('Purchase Tickets', new_conference_payment_path(@conference), class: 'btn btn-success btn-lg')
- if @user_needs_to_register - if @user_needs_to_register
.row .row
.col-md-12 .col-md-12
.alert.alert-dismissable.alert-warning.text-center#flash{role: 'alert'} .alert.alert-dismissable.alert-warning.text-center#flash{ role: 'alert' }
%button.button.close{"data-dismiss" => "alert", 'aria-label': 'close'} %button.button.close{ "data-dismiss" => "alert", 'aria-label': 'close' }
&times; &times;
%p %p
You still need to complete your registration for #{@conference.title}. You still need to complete your registration for #{@conference.title}.
= link_to('Complete Registration', new_conference_conference_registration_path(@conference), class: 'btn btn-success btn-lg') = link_to('Complete Registration', new_conference_conference_registration_path(@conference), class: 'btn btn-success btn-lg')
#splash #splash
- if @conference.code_of_conduct.present? - if @conference.code_of_conduct.present?
@ -79,29 +77,8 @@
sponsorship_levels: @sponsorship_levels, sponsorship_levels: @sponsorship_levels,
sponsors: @sponsors sponsors: @sponsors
-# footer -# footer
- if @conference.splashpage.include_social_media - if @conference.splashpage.include_social_media
- if @conference.contact.has_social_media? - if @conference.contact.has_social_media?
= render 'social_media', contact: @conference.contact = render 'social_media', contact: @conference.contact
= render 'footer' = render 'footer'
-# - content_for :script_head do
-# :javascript
-# var triangle_tcs = tinycolor("#{h(@conference.color)}").monochromatic();
-# var triangle_colors = triangle_tcs.map(function(t) {
-# return t.toHexString();
-# });
-# $(function () {
-# $(document).ready(function() {
-# var triangle_width = document.body.clientWidth;
-# var triangle_height = ($( "#banner" ).height() + 200 );
-# var pattern = Trianglify({ width: triangle_width,
-# height: triangle_height,
-# cell_size: 100,
-# x_colors: triangle_colors
-# });
-# $('#banner').css('background-image', 'url(' + 0 + ')');
-# });
-# });

View file

@ -11,7 +11,7 @@
= f.input :password = f.input :password
- if devise_mapping.rememberable? - if devise_mapping.rememberable?
%p.text-right.small %p.text-right.small
= f.label 'Remember me' = f.label 'Remember me', for: 'user_remember_me'
= f.check_box :remember_me = f.check_box :remember_me
%p.text-right %p.text-right
= f.action :submit, as: :button, label: 'Sign In', button_html: {class: 'btn btn-success'} = f.action :submit, as: :button, label: 'Sign In', button_html: {class: 'btn btn-success'}

View file

@ -0,0 +1,12 @@
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<meta content="Snap!Con -- A conference all about Snap!, a programing language from UC Berkeley." name="description"/>
<meta content="Michael Ball, Brian Harvey, Jens Moenig, Bernat Romagosa, Dan Garcia, Lauren Mock" name="author"/>
<%= stylesheet_link_tag "mailbot" %>
</head>
<body>
<div id="border" style="background-color: <%= conference_color(@conference) %>"></div>
</body>
</html>

View file

@ -0,0 +1,25 @@
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1" name="viewport"/>
<title>
<%= 'Email' %>
</title>
<meta content="Snap!Con -- A conference all about Snap!, a programing language from UC Berkeley." name="description"/>
<meta content="Michael Ball, Brian Harvey, Jens Moenig, Bernat Romagosa, Dan Garcia, Lauren Mock" name="author"/>
<%= stylesheet_link_tag "mailbot" %>
</head>
<body>
<div id="border" style="background-color: <%= conference_color(@conference) %>">
<div class="row">
<div class="col-md-2">
<% if @conference.present? %>
<%= image_tag(conference_logo_url(@conference), style: "display:block;height:70px;width:auto;", alt: @conference.title + ' logo') %>
<% end %>
</div>
</div>
</div>
</body>

View file

@ -51,37 +51,38 @@
= link_to(sign_in_path) do = link_to(sign_in_path) do
%span.fa.fa-user %span.fa.fa-user
Sign In Sign In
-# %li.dropdown.visible-desktop -#
-# %a.dropdown-toggle{"data-toggle" => "dropdown", href: '#'} %li.dropdown.visible-desktop
-# %span.fa.fa-user %a.dropdown-toggle{"data-toggle" => "dropdown", href: '#'}
-# Sign In %span.fa.fa-user
-# %span.caret Sign In
-# .dropdown-menu %span.caret
-# - if ENV['OSEM_ICHAIN_ENABLED'] == 'true' .dropdown-menu
-# = form_tag User.ichain_login_url do - if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
-# = text_field_tag 'username', nil, id: 'user_ichain_email_dd', class: 'form-control', placeholder: 'Username' = form_tag User.ichain_login_url do
-# = password_field_tag 'password', nil, id: 'user_ichain_password_dd', class: 'form-control', placeholder: 'Password' = text_field_tag 'username', nil, id: 'user_ichain_email_dd', class: 'form-control', placeholder: 'Username'
-# %button.btn.btn-success.btn-block Sign in = password_field_tag 'password', nil, id: 'user_ichain_password_dd', class: 'form-control', placeholder: 'Password'
-# - else %button.btn.btn-success.btn-block Sign in
-# %div{style: "padding: 6px"} - else
-# = form_tag new_user_session_path, class: 'form-group' do %div{style: "padding: 6px"}
-# = text_field_tag 'user[login]', nil, id: 'user_login_dd', class: 'form-control', placeholder: 'Username / E-Mail' = form_tag new_user_session_path, class: 'form-group' do
-# = password_field_tag 'user[password]', nil, id: 'user_password_dd', class: 'form-control', placeholder: 'Password' = text_field_tag 'user[login]', nil, id: 'user_login_dd', class: 'form-control', placeholder: 'Username / E-Mail'
-# %p.text-right = password_field_tag 'user[password]', nil, id: 'user_password_dd', class: 'form-control', placeholder: 'Password'
-# %small %p.text-right
-# %label{for: 'user_remember_me'} Remember me %small
-# = check_box_tag 'user[remember_me]' %label{for: 'user_remember_me'} Remember me
-# %br = check_box_tag 'user[remember_me]'
-# %button.btn.btn-success.btn-block Sign in %br
-# - unless omniauth_configured.empty? %button.btn.btn-success.btn-block Sign in
-# .divider - unless omniauth_configured.empty?
-# %h6.text-center .divider
-# or %h6.text-center
-# = render 'devise/shared/openid_links' or
-# %p.text-right = render 'devise/shared/openid_links'
-# %br %p.text-right
-# %a.small.btn.btn-xs.btn-default{"data-toggle" => "collapse", "data-target" => "#navbar-devise-help"} %br
-# Need Help? %a.small.btn.btn-xs.btn-default{"data-toggle" => "collapse", "data-target" => "#navbar-devise-help"}
-# #navbar-devise-help.collapse Need Help?
-# = render 'devise/shared/links' #navbar-devise-help.collapse
= render 'devise/shared/links'
.trapezoid .trapezoid

View file

@ -23,8 +23,8 @@
%li %li
= link_to(conference_conference_registration_path(@conference)) do = link_to(conference_conference_registration_path(@conference)) do
%span.fa.fa-id-badge %span.fa.fa-id-badge
= @conference.short_title = @conference.short_title
registration registration
-if @conference && @conference.program -if @conference && @conference.program
%li %li
= link_to(conference_program_proposals_path(@conference.short_title)) do = link_to(conference_program_proposals_path(@conference.short_title)) do

View file

@ -0,0 +1,16 @@
<%= render partial: "layouts/mailbot_header" %>
<div id="content">
<span style="white-space: pre-line">
Dear <%= @user.name %>,
User <%= @comment.user.name %> posted a new comment for event <%= @event.title %> of <%= @conference.short_title %> .
"<%= @comment.body %>"
To reply to this comment, please go to <%= h(admin_conference_program_event_url(@conference.short_title, @event, only_path: false)) %>
Best wishes,
<%= @conference.title %> Team
</span>
</div>
<%= render partial: "layouts/mailbot_footer" %>

View file

@ -1,83 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- CSS -->
<link rel="stylesheet" href="main.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Montserrat:100,200,300,400,500,600,700,800" rel="stylesheet">
<style>
html {
scroll-behavior: smooth;
}
body {
background: #fff;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.06);
color: #000;
font-family: 'Montserrat', sans-serif;
font-size: 16px;
line-height: 1.5;
margin: 0 auto;
}
h1,
h3,
h4,
h5,
h6 {
font-weight: 400;
line-height: 1.3;
}
p {
color: #0B3559;
font-weight: 400;
line-height: 2;
}
#border {
background-color: #0B3559;
padding: 25px;
color:#fff;
}
#content {
background-color: #fff;
padding: 100px;
color: #0B3559;
}
</style>
<!-- Page Title -->
<title>Email</title>
</head>
<body>
<div id="border">
<div class="row">
<!-- Uncomment below to get logo -->
<div class="col-md-2">
</div>
<div class="col-md-10"><h1></h1></div>
</div>
</div>
<div id="content">
<span style="white-space: pre-line">
Dear <%= @user.name %>,
User <%= @comment.user.name %> posted a new comment for event <%= @event.title %> of <%= @conference.short_title %> .
"<%= @comment.body %>"
To reply to this comment, please go to <%= h(admin_conference_program_event_url(@conference.short_title, @event, only_path: false)) %>
Best wishes,
<%= @conference.title %> Team
</span>
</div>
<div id="border">
<h1></h1>
</div>
</body>
</html>

View file

@ -1,77 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- CSS -->
<link rel="stylesheet" href="main.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Montserrat:100,200,300,400,500,600,700,800" rel="stylesheet">
<style>
html {
scroll-behavior: smooth;
}
body {
background: #fff;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.06);
color: #000;
font-family: 'Montserrat', sans-serif;
font-size: 16px;
line-height: 1.5;
margin: 0 auto;
}
h1,
h3,
h4,
h5,
h6 {
font-weight: 400;
line-height: 1.3;
}
p {
color: #0B3559;
font-weight: 400;
line-height: 2;
}
#border {
background-color: #0B3559;
padding: 25px;
color:#fff;
}
#content {
background-color: #fff;
padding: 100px;
color: #0B3559;
}
</style>
<!-- Page Title -->
<title>Email</title>
</head>
<body>
<div id="border">
<div class="row">
<!-- Uncomment below to get logo -->
<div class="col-md-2">
<% if !@logo.nil? %>
<%= image_tag(@logo, style: "display:block") %>
<% end %>
</div>
<div class="col-md-10"><h1></h1></div>
</div>
</div>
<div id="content">
<span style="white-space: pre-line">
<%= @email_body %>
</span>
</div>
<div id="border">
<h1></h1>
</div>
</body>
</html>

View file

@ -0,0 +1,7 @@
<%= render partial: "layouts/mailbot_header" %>
<div id="content">
<span style="white-space: pre-line">
<%= @email_body %>
</span>
</div>
<%= render partial: "layouts/mailbot_footer" %>

View file

@ -0,0 +1,14 @@
<%= render partial: "layouts/mailbot_header" %>
<div id="content">
<span style="white-space: pre-line">
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
</span>
</div>
<%= render partial: "layouts/mailbot_footer" %>

View file

@ -1,81 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- CSS -->
<link rel="stylesheet" href="main.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Montserrat:100,200,300,400,500,600,700,800" rel="stylesheet">
<style>
html {
scroll-behavior: smooth;
}
body {
background: #fff;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.06);
color: #000;
font-family: 'Montserrat', sans-serif;
font-size: 16px;
line-height: 1.5;
margin: 0 auto;
}
h1,
h3,
h4,
h5,
h6 {
font-weight: 400;
line-height: 1.3;
}
p {
color: #0B3559;
font-weight: 400;
line-height: 2;
}
#border {
background-color: #0B3559;
padding: 25px;
color:#fff;
}
#content {
background-color: #fff;
padding: 100px;
color: #0B3559;
}
</style>
<!-- Page Title -->
<title>Email</title>
</head>
<body>
<div id="border">
<div class="row">
<!-- Uncomment below to get logo -->
<div class="col-md-2">
</div>
<div class="col-md-10"><h1></h1></div>
</div>
</div>
<div id="content">
<span style="white-space: pre-line">
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
</span>
</div>
<div id="border">
<h1></h1>
</div>
</body>
</html>

View file

@ -0,0 +1,16 @@
<%= render partial: "layouts/mailbot_header" %>
<div id="content">
<span style="white-space: pre-line">
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.
The SAP Young Thinkers team will reach out to you with information on how to participate in the event soon. In the meantime, you can check the event page (https://events.sap.com/yt-learning-festival-at-snapcon-2020/en/home) or send an email with your questions to youngthinkers@sap.com.
Best wishes,
<%= @conference.title %> Team
</span>
</div>
<%= render partial: "layouts/mailbot_footer" %>

View file

@ -1,83 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- CSS -->
<link rel="stylesheet" href="main.css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Montserrat:100,200,300,400,500,600,700,800" rel="stylesheet">
<style>
html {
scroll-behavior: smooth;
}
body {
background: #fff;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.06);
color: #000;
font-family: 'Montserrat', sans-serif;
font-size: 16px;
line-height: 1.5;
margin: 0 auto;
}
h1,
h3,
h4,
h5,
h6 {
font-weight: 400;
line-height: 1.3;
}
p {
color: #0B3559;
font-weight: 400;
line-height: 2;
}
#border {
background-color: #0B3559;
padding: 25px;
color:#fff;
}
#content {
background-color: #fff;
padding: 100px;
color: #0B3559;
}
</style>
<!-- Page Title -->
<title>Email</title>
</head>
<body>
<div id="border">
<div class="row">
<!-- Uncomment below to get logo -->
<div class="col-md-2">
</div>
<div class="col-md-10"><h1></h1></div>
</div>
</div>
<div id="content">
<span style="white-space: pre-line">
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.
The SAP Young Thinkers team will reach out to you with information on how to participate in the event soon. In the meantime, you can check the event page (https://events.sap.com/yt-learning-festival-at-snapcon-2020/en/home) or send an email with your questions to youngthinkers@sap.com.
Best wishes,
<%= @conference.title %> Team
</span>
</div>
<div id="border">
<h1></h1>
</div>
</body>
</html>

View file

@ -19,7 +19,7 @@
%td %td
= humanized_money_with_symbol ticket.quantity * ticket.price = humanized_money_with_symbol ticket.quantity * ticket.price
= form_tag conference_payments_path do = form_tag conference_payments_path(@conference.short_title, :has_registration_ticket => @has_registration_ticket) do
%script.stripe-button{'src': "https://checkout.stripe.com/checkout.js", %script.stripe-button{'src': "https://checkout.stripe.com/checkout.js",
'data': {amount: @total_amount_to_pay.cents, 'data': {amount: @total_amount_to_pay.cents,
label: "Pay #{humanized_money_with_symbol @total_amount_to_pay}", label: "Pay #{humanized_money_with_symbol @total_amount_to_pay}",

View file

@ -12,7 +12,7 @@
-# TODO: And if they have a registration ticket? -# TODO: And if they have a registration ticket?
- if !@conference.user_registered?(@user) && @has_registration_ticket - if !@conference.user_registered?(@user) && @has_registration_ticket
.col-md-12 .col-md-12
.alert.alert-success{role: 'alert'} .alert.alert-success{ role: 'alert' }
= link_to 'Complete Registration', = link_to 'Complete Registration',
new_conference_conference_registration_path(@conference), new_conference_conference_registration_path(@conference),
class: 'btn btn-info pull-right btn-lg' class: 'btn btn-info pull-right btn-lg'

View file

@ -9,9 +9,9 @@
- if @conference.venue - if @conference.venue
at at
%strong %strong
#{@conference.venue.name}, #{@conference.venue_name},
#{@conference.venue.street}, #{@conference.venue_street},
#{@conference.venue.city} / #{@conference.venue.country_name}. #{@conference.city} / #{@conference.country_name}.
%small %small
= date_string(@conference.start_date, @conference.end_date) = date_string(@conference.start_date, @conference.end_date)
.row .row

View file

@ -16,7 +16,8 @@
That means you have That means you have
%b.notranslate= pluralize(@program.cfp.remaining_days, 'day') %b.notranslate= pluralize(@program.cfp.remaining_days, 'day')
left! left!
%span.notranslate #{@conference.title} %span.notranslate= @conference.title
will only be as good as the content you present. Submit early, submit often! will only be as good as the content you present.
%br Submit early, submit often!
- else - else
The submission period is closed now. The submission period is closed now.

View file

@ -11,83 +11,49 @@
= track_selector_input f = track_selector_input f
= f.input :event_type_id, as: :select,
collection: @conference.program.event_types.map {|type| ["#{type.title} - #{show_time(type.length)}", type.id,
data: { min_words: type.minimum_abstract_length, max_words: type.maximum_abstract_length, help: type.description }]},
include_blank: false, label: 'Type', input_html: { class: 'select-help-toggle' }
- if @program.languages.present? - if @program.languages.present?
= f.input :language, as: :select, = f.input :language, as: :select,
collection: @languages, collection: @languages,
include_blank: false, label: 'Language', input_html: { class: 'select-help-toggle' } include_blank: false, label: 'Language', input_html: { class: 'select-help-toggle' }
- @conference.program.event_types.each do |event_type| - if @program.difficulty_levels.present?
%span{ class: 'help-block select-help-text event_event_type_id collapse', id: "#{event_type.id}-help" } = f.input :difficulty_level, as: :select, collection: @program.difficulty_levels,
= event_type.description input_html: { class: 'select-help-toggle' },
include_blank: '(Please select)' if @conference.program.difficulty_levels.any?
= f.input :difficulty_level, as: :select, collection: @conference.program.difficulty_levels, input_html: { class: 'select-help-toggle' }, - @program.difficulty_levels.each do |difficulty_level|
include_blank: '(Please select)' if @conference.program.difficulty_levels.any? %span{ class: 'help-block select-help-text collapse event_difficulty_level_id', id: "#{difficulty_level.id}-help" }
= difficulty_level.description
- @conference.program.difficulty_levels.each do |difficulty_level| = render 'proposals/submission_type_content_form', f: f, program: @program
%span{ class: 'help-block select-help-text collapse event_difficulty_level_id', id: "#{difficulty_level.id}-help" }
= difficulty_level.description
= f.input :abstract, required: true, input_html: { rows: 5, data: { provide: 'markdown' } },
hint: markdown_hint('[Tips to improve your presentations.](http://blog.hubspot.com/blog/tabid/6307/bid/5975/10-Rules-to-Instantly-Improve-Your-Presentations.aspx)')
%p
You have used
%span#abstract-count #{@event.abstract_word_count}
words. Abstracts must be between
%span#abstract-minimum-word-count
0
and
%span#abstract-maximum-word-count
250
words.
%br
= f.input :submission_text, input_html: { rows: 5, data: { provide: 'markdown' }, placeholder: '' },
hint: markdown_hint('Only conference organizers will read this.')
%p
You have used
%span#submission-count #{@event.submission_word_count}
words. Submission descriptions must be between
%span#submission-minimum-word-count
0
and
%span#submission-maximum-word-count
250
words.
-# TODO-SNAPCON: Extract this to be a `conference_committee_role?`
- if current_user.has_any_role? :admin, { name: :organizer, resource: @conference }, { name: :cfp, resource: @conference } - if current_user.has_any_role? :admin, { name: :organizer, resource: @conference }, { name: :cfp, resource: @conference }
%br %br
= f.input :committee_review, input_html: { rows: 5, data: { provide: 'markdown' }, placeholder: '' }, = f.input :committee_review, input_html: { rows: 5, data: { provide: 'markdown' } },
hint: markdown_hint('This field is shared with the submission authors.') hint: markdown_hint('This field is shared with the submission authors.')
- if current_user.is_admin? or @program.cfp.enable_registrations? - if @program.cfp&.enable_registrations?
= f.inputs 'Enable pre-registration' do = f.inputs 'Enable pre-registration' do
= f.input :require_registration, label: 'Require participants to register to your event' = f.input :require_registration, label: 'Require participants to register to your event'
- message = @event.room ? "Value must be between 1 and #{@event.room.size}" : 'Check room capacity after scheduling.' - message = @event.room ? "Value must be between 1 and #{@event.room.size}" : 'Check room capacity after scheduling.'
= f.input :max_attendees, hint: 'The maximum number of participants. ' + message = f.input :max_attendees, hint: 'The maximum number of participants. ' + message
- if current_user.has_any_role? :admin, { name: :organizer, resource: @conference }, { name: :cfp, resource: @conference }
= f.input :is_highlight
%p.text-right %p.text-right
= link_to '#description', 'data-toggle' => 'collapse' do = link_to '#description', 'data-toggle' => 'collapse' do
Do you require something special? Do you require something special?
#description{ class: "collapse #{ 'in' if @event.description.present? }" } #description{ class: "collapse #{ 'in' if @event.description.present? }" }
= f.input :description, input_html: { rows: 5 }, label: 'Requirements', placeholder: 'Eg. Whiteboard, printer, or something like that.' = f.input :description, input_html: { rows: 5 }, label: 'Requirements', placeholder: 'Eg. Whiteboard, printer, or something like that.'
- if current_user.has_any_role? :admin, { name: :organizer, resource: @conference }, { name: :cfp, resource: @conference }
%p (Admin Only)
= f.input :is_highlight
%p.text-right %p.text-right
- if @event.new_record? - if @event.new_record?
= f.submit 'Submit Proposal', class: 'btn btn-success' = f.submit 'Submit Proposal', class: 'btn btn-success'
- else - else
= f.submit 'Update Proposal', class: 'btn btn-success' = f.submit 'Update Proposal', class: 'btn btn-primary'
:javascript :javascript
$(document).ready(function() { $(document).ready(function() {

View file

@ -1,13 +1,13 @@
.speakerinfo .speakerinfo
.row .row
.col-md-4 .col-md-4
= image_tag speaker.profile_picture(:size => 120), class: 'img-responsive img-rounded' = image_tag speaker.profile_picture(size: 120), class: 'img-responsive img-rounded'
.col-md-8 .col-md-8
%h4 %h4
= link_to speaker.name, user_path(speaker.id) = link_to speaker.name, user_path(speaker.id)
%br %br
- if speaker.email_public? - if speaker.email_public?
= mail_to "#{ speaker.email }" do = mail_to speaker.email.to_s do
%i.fa.fa-envelope-o.fa-2x %i.fa.fa-envelope-o.fa-2x
- if speaker.affiliation? - if speaker.affiliation?
.text-muted .text-muted

View file

@ -0,0 +1,68 @@
-# PARTIAL FOR EVENT/PROPOSAL FORM
= f.input :event_type_id, as: :select, include_blank: false, label: 'Type',
input_html: { class: 'select-help-toggle' },
collection: event_type_options(program.event_types)
- program.event_types.each do |event_type|
.help-block.event_event_type_id.collapse{ id: "#{event_type.id}-help" }
%strong Description
%div
= markdown(event_type.description)
%h3 Submission Abstract
%p
The abstract is reviewed by the committee and included in the conference program.
You are encouraged to include links or other references as appropriate.
= f.label :abstract, class: 'sr-only'
= f.input :abstract, required: true, label: false,
input_html: { rows: 5, data: { provide: 'markdown' } },
hint: markdown_hint
%p
You have used
%span#abstract-count 0
words. Abstracts must be between
%span#abstract-minimum-word-count 0
and
%span#abstract-maximum-word-count 250
words.
%hr
%h3 Submission Details
%p
This part of the submission is intended only for the conference committee.
- program.event_types.each do |event_type|
.help-block.select-help-text.event_event_type_id.collapse{ id: "#{event_type.id}-instructions" }
- if event_type.submission_instructions.blank?
%p
Use this space to include any additional inforrmation that is helpful in reviewing your
submission. If you have any co-presenters, please include them
below. After submission, you will have the opportunity to add them to the
speakers list. (However, they must have an active #{ENV['OSEM_NAME']} account.)
- else
%p
Please use the following as the template for your submission. This will help the conference
committee review your submission with all the details they need. If you have any
co-presenters, please include them below. After submission, you will have the opportunity
to add them to the speakers list. (However, they must have an active #{ENV['OSEM_NAME']}
account.)
.panel.panel-primary
.panel-heading
= event_type.name
Template
.panel-body
= markdown(event_type.submission_instructions)
.panel-footer
%button.btn.btn-warning.btn-xs.js-resetSubmissionText{ type: 'button',
data: { confirm: 'Do you really want to reset your submission text to the provided template?' } }
Reset Submission to Template
%span.small You may want to use this if you have changed the submission type.
= f.label :submission_text, class: 'sr-only'
= f.input :submission_text, label: false,
input_html: { rows: 10, data: { provide: 'markdown' } },
hint: markdown_hint

View file

@ -1,30 +1,31 @@
- progress_status = event.progress_status - progress_status = event.progress_status
%ul.list-unstyled %ul.list-unstyled
- if can? :create, @conference.registrations.new - if can? :create, @conference.registrations.new
%li{'class'=>class_for_todo(progress_status['registered'])} %li{class: class_for_todo(progress_status[:registered])}
%span{'class'=>icon_for_todo(progress_status['registered'])} %span{class: icon_for_todo(progress_status[:registered])}
- if progress_status['registered'] - if progress_status[:registered]
Speaker(s) registered to the conference Speaker(s) registered to the conference
- else - else
= link_to 'Speaker(s) not registered to the conference', new_conference_conference_registration_path(event.program.conference.short_title) = link_to 'Speaker(s) not registered to the conference', new_conference_conference_registration_path(event.program.conference.short_title)
%li{'class'=>class_for_todo(progress_status['biographies'])} %li{class: class_for_todo(progress_status[:biographies])}
%span{'class'=>icon_for_todo(progress_status['biographies'])} %span{class: icon_for_todo(progress_status[:biographies])}
- if progress_status['biographies'] - if progress_status[:biographies]
Speakers have filled out their biographies Speakers have filled out their biographies
- elsif current_user.biography.blank? && event.speakers.include?(current_user) - elsif current_user.biography.blank? && event.speakers.include?(current_user)
= link_to 'Fill out your biography', edit_user_path(current_user) = link_to 'Fill out your biography', edit_user_path(current_user)
- else - else
Speakers' biographies missing Speakers' biographies missing
%li{'class'=>class_for_todo(progress_status['subtitle'])} %li{class: class_for_todo(progress_status[:subtitle])}
%span{'class'=>icon_for_todo(progress_status['subtitle'])} %span{class: icon_for_todo(progress_status[:subtitle])}
= link_to 'Add a subtitle', edit_conference_program_proposal_path(event.program.conference.short_title, event) = link_to 'Add a subtitle', edit_conference_program_proposal_path(event.program.conference.short_title, event)
%li{'class'=>class_for_todo(progress_status['commercials'])} %li{class: class_for_todo(progress_status[:commercials])}
%span{'class'=>icon_for_todo(progress_status['commercials'])} %span{class: icon_for_todo(progress_status[:commercials])}
= link_to 'Add materials', edit_conference_program_proposal_path(event.program.conference.short_title, event, anchor: 'commercials-content') = link_to 'Add materials', edit_conference_program_proposal_path(event.program.conference.short_title, event, anchor: 'commercials-content')
- unless progress_status['track'].nil? - unless progress_status[:track].nil?
%li{'class'=>class_for_todo(progress_status['track'])} %li{class: class_for_todo(progress_status[:track])}
%span{'class'=>icon_for_todo(progress_status['track'])} %span{class: icon_for_todo(progress_status[:track])}
= link_to 'Add a track', edit_conference_program_proposal_path(event.program.conference.short_title, event) = link_to 'Add a track', edit_conference_program_proposal_path(event.program.conference.short_title, event)
%li{'class'=>class_for_todo(progress_status['difficulty_level'])} - unless progress_status[:difficulty_level].nil?
%span{'class'=>icon_for_todo(progress_status['difficulty_level'])} %li{class: class_for_todo(progress_status[:difficulty_level])}
= link_to 'Add a difficulty level', edit_conference_program_proposal_path(event.program.conference.short_title, event) %span{class: icon_for_todo(progress_status[:difficulty_level])}
= link_to 'Add a difficulty level', edit_conference_program_proposal_path(event.program.conference.short_title, event)

View file

@ -1,7 +1,7 @@
.speakerinfo .speakerinfo
.row .row
.col-md-4 .col-md-4
= image_tag speaker.profile_picture(:size => 120), class: 'img-responsive img-rounded' = image_tag speaker.profile_picture(size: 120), class: 'img-responsive img-rounded'
.col-md-8 .col-md-8
%h4 %h4
= link_to speaker.name, user_path(speaker.id) = link_to speaker.name, user_path(speaker.id)

View file

@ -1,8 +1,8 @@
%table.table.table-striped#events %table.table.table-striped#events
- events.each do |event| - events.each do |event|
%tr %tr
%td.col-md-7{style: "padding:20px 8px 20px 8px;"} %td.col-md-7{ style: 'padding:20px 8px 20px 8px;' }
= link_to event.title, conference_program_proposal_path(@conference.short_title, event.id) = link_to event.title, conference_program_proposal_path(conference.short_title, event.id)
%br %br
%small.text-muted %small.text-muted
= event.event_type.title = event.event_type.title
@ -10,10 +10,11 @@
= "in #{event.track.name}" if event.track = "in #{event.track.name}" if event.track
- if event.require_registration - if event.require_registration
%br %br
= link_to registered_text(event), registrations_conference_program_proposal_path(@conference.short_title, event), class: 'btn btn-xs btn-danger' = link_to registered_text(event), registrations_conference_program_proposal_path(conference.short_title, event),
class: 'btn btn-xs btn-danger'
%td.col-md-2{style: "padding:20px 8px 20px 8px;"} %td.col-md-2{ style: 'padding:20px 8px 20px 8px;' }
- event_schedule = event.event_schedules.find_by(schedule_id: @program.selected_schedule_id) - event_schedule = event.event_schedules.find_by(schedule_id: program.selected_schedule_id)
- if event_schedule.present? - if event_schedule.present?
= inyourtz(event_schedule.start_time, @conference.timezone) do = inyourtz(event_schedule.start_time, conference.timezone) do
= event_schedule.start_time.strftime("%Y %B %e - %H:%M") = event_schedule.start_time.strftime('%Y %B %e - %H:%M')

View file

@ -121,7 +121,7 @@
Volunteer Duties Volunteer Duties
%small %small
Thanks for being a host at #{@conference.title} Thanks for being a host at #{@conference.title}
= render 'volunteers_table', events: @volunteer_events = render 'volunteers_table', events: @volunteer_events, conference: @conference, program: @program
.row .row
.col-md-12 .col-md-12

View file

@ -5,6 +5,7 @@
%h1 New #{@conference.title} Proposal %h1 New #{@conference.title} Proposal
- if @program.cfp_open? - if @program.cfp_open?
- if @program.cfp.description.present? - if @program.cfp.description.present?
%h2 Call for Proposals
.row .row
.col-md-12 .col-md-12
= markdown(@program.cfp.description, escape_html=false) = markdown(@program.cfp.description, escape_html=false)
@ -31,51 +32,22 @@
= f.inputs name: 'Proposal Information' do = f.inputs name: 'Proposal Information' do
= f.input :title, as: :string, required: true, input_html: { required: true } = f.input :title, as: :string, required: true, input_html: { required: true }
= f.input :event_type_id, as: :select,
collection: @program.event_types.map {|type| ["#{type.title} - #{show_time(type.length)}", type.id,
data: { min_words: type.minimum_abstract_length, max_words: type.maximum_abstract_length }]},
include_blank: false, label: 'Type', input_html: { class: 'select-help-toggle' }
- @program.event_types.each do |event_type|
%div{ class: 'help-block event_event_type_id collapse', id: "#{event_type.id}-help"}
%strong Directions
%div
= markdown(event_type.description)
- if @program.languages.present? - if @program.languages.present?
= f.input :language, as: :select, = f.input :language, as: :select,
collection: @languages, collection: @languages,
include_blank: false, label: 'Language', input_html: { class: 'select-help-toggle' } include_blank: false, label: 'Language', input_html: { class: 'select-help-toggle' }
= f.input :abstract, required: true, input_html: { rows: 5, data: { provide: 'markdown' } }, - if @program.difficulty_levels.present?
hint: markdown_hint = f.input :difficulty_level, as: :select, collection: @program.difficulty_levels,
input_html: { class: 'select-help-toggle' },
%p include_blank: '(Please select)' if @conference.program.difficulty_levels.any?
You have used
%span#abstract-count #{@event.abstract_word_count}
words. Abstracts must be between
%span#abstract-minimum-word-count
0
and
%span#abstract-maximum-word-count
250
words.
= f.input :submission_text, input_html: { rows: 5, data: { provide: 'markdown' } },
hint: markdown_hint
%p
You have used
%span#submission-count #{@event.submission_word_count}
words. Submission descriptions must be between
%span#submission-minimum-word-count
0
and
%span#submission-maximum-word-count
250
words.
- @program.difficulty_levels.each do |difficulty_level|
%span.help-block.select-help-text.collapse.event_difficulty_level_id{ id: "#{difficulty_level.id}-help" }
= difficulty_level.description
= render 'submission_type_content_form', f: f, program: @program
- if @program.cfp.enable_registrations? - if @program.cfp.enable_registrations?
= f.input :require_registration, label: 'Require participants to register to your event' = f.input :require_registration, label: 'Require participants to register to your event'
@ -88,7 +60,7 @@
= f.input :description, input_html: { rows: 5 }, label: 'Requirements', placeholder: 'Eg. Whiteboard, printer, or something like that.' = f.input :description, input_html: { rows: 5 }, label: 'Requirements', placeholder: 'Eg. Whiteboard, printer, or something like that.'
%p.text-right %p.text-right
= f.submit 'Submit Proposal', class: 'btn btn-success' = f.submit 'Submit Proposal', class: 'btn btn-success btn-lg'
.tab-pane{role: 'tabpanel', id: 'signin'} .tab-pane{role: 'tabpanel', id: 'signin'}
= render partial: 'devise/shared/sign_in_form_embedded' = render partial: 'devise/shared/sign_in_form_embedded'

View file

@ -1,20 +1,20 @@
.panel.panel-default.event-panel{ onClick: 'eventClicked(event, this);', "data-url" => "#{url_for(conference_program_proposal_path(@conference.short_title, event.id))}" } .panel.panel-default.event-panel{ onClick: 'eventClicked(event, this);', 'data-url' => "#{url_for(conference_program_proposal_path(@conference.short_title, event.id))}" }
- header_color = event.event_type&.color || '#f5f5f5' - header_color = event.event_type&.color || '#f5f5f5'
.trapezoid{style: "color: white; top: 12px; z-index: 100;"} .trapezoid{ style: 'color: white; top: 12px; z-index: 100;' }
.panel-heading{ style: "background-color: #{header_color}; color: #{ contrast_color(header_color) }; border-radius: 4px" } .panel-heading{ style: "background-color: #{header_color}; color: #{ contrast_color(header_color) }; border-radius: 4px" }
- event.speakers_ordered.each do |speaker| - event.speakers_ordered.each do |speaker|
= image_tag speaker.profile_picture, class: "img-circle pull-right", alt: speaker.name, style: "padding: 2px;" = image_tag speaker.profile_picture, class: 'img-circle pull-right', alt: speaker.name, style: 'padding: 2px;'
%p %p
= canceled_replacement_event_label(event, event_schedule) = canceled_replacement_event_label(event, event_schedule)
= replacement_event_notice(event_schedule) = replacement_event_notice(event_schedule)
%span.h3{style: "margin-bottom: 14px"} %span.h3{ style: 'margin-bottom: 14px' }
= event.title = event.title
%br %br
%small{style: "color: #{contrast_color(header_color)}"} %small{ style: "color: #{contrast_color(header_color)}" }
= event.subtitle = event.subtitle
.trapezoid{style: "color: #{header_color}; top: 12px;"} .trapezoid{ style: "color: #{header_color}; top: 12px;" }
.panel-body .panel-body
%h4 %h4
@ -30,13 +30,13 @@
= inyourtz(event_schedule.start_time) do = inyourtz(event_schedule.start_time) do
%span.track %span.track
%span.fa.fa-clock-o %span.fa.fa-clock-o
%span.label{ style: "background-color: grey" } %span.label{ style: 'background-color: grey' }
= event_schedule.start_time.strftime('%l:%M %P') = event_schedule.start_time.strftime('%l:%M %P')
\- \-
= event_schedule.end_time.strftime('%l:%M %P') = event_schedule.end_time.strftime('%l:%M %P')
%span.track %span.track
%span.fa.fa-map-marker %span.fa.fa-map-marker
%span.label{ style: "background-color: grey" } %span.label{ style: 'background-color: grey' }
= event_schedule.room.name = event_schedule.room.name
- if event.track - if event.track
%span.track %span.track

View file

@ -9,26 +9,30 @@
.col-md-12 .col-md-12
%h2 %h2
#{pluralize(@events_schedules.count, 'Event')} Occurring Within The Next 30 minutes. #{pluralize(@events_schedules.count, 'Event')} Occurring Within The Next 30 minutes.
%h3 %br
This page was loaded at %small
= inyourtz(Time.now) do This page was loaded at
#{Time.now.strftime('%a %b %d at %I:%M %P (%z)')} = inyourtz(Time.now) do
= Time.now.strftime('%a %b %d at %I:%M %P (%z)')
\.
.row .row
/ TODO: Clean this up, merge with all events page. / TODO: Clean this up, merge with all events page.
/ scheduled events
- date = nil - date = nil
- time = nil - time = nil
- @events_schedules.each do |event_schedule| - @events_schedules.each do |event_schedule|
- unless event_schedule.start_time.strftime('%Y-%m-%d').eql?(date) - unless event_schedule.start_time.strftime('%Y-%m-%d').eql?(date)
.col-xs-12.col-md-12 .col-xs-12.col-md-12
.date-content .date-content
%span{ class: 'date-title', id: "#{ event_schedule.start_time.strftime('%Y-%m-%d') }" } %span.date-title{ id: event_schedule.start_time.strftime('%Y-%m-%d').to_s }
= inyourtz(event_schedule.start_time, @conference.timezone) do = inyourtz(event_schedule.start_time, @conference.timezone) do
= date = event_schedule.start_time.strftime('%Y-%m-%d') = date = event_schedule.start_time.strftime('%Y-%m-%d')
%a{ title: "Go up", class: "pull-right", href: "#program" } %a.pull-right{ title: 'Go up', href: '#program' }
%i{ class: "fa fa-angle-double-up fa-lg", 'aria-hidden' => true } %i.fa.fa-angle-double-up.fa-lg{ 'aria-hidden' => true }
- unless event_schedule.start_time.strftime('%H:%M').eql?(time) - if event_schedule.start_time.strftime('%H:%M').eql?(time)
.col-xs-12.col-md-11.col-md-offset-1
= render 'event', event: event_schedule.event, event_schedule: event_schedule
- else
.col-xs-12.col-md-1 .col-xs-12.col-md-1
.start-time .start-time
= inyourtz(event_schedule.start_time, @conference.timezone) do = inyourtz(event_schedule.start_time, @conference.timezone) do
@ -36,9 +40,6 @@
.col-xs-12.col-md-11 .col-xs-12.col-md-11
.new-time-event .new-time-event
= render 'event', event: event_schedule.event, event_schedule: event_schedule = render 'event', event: event_schedule.event, event_schedule: event_schedule
- else
.col-xs-12.col-md-11.col-md-offset-1
= render 'event', event: event_schedule.event, event_schedule: event_schedule
:javascript :javascript
// Refresh the page every 5 minutes. // Refresh the page every 5 minutes.

View file

@ -26,9 +26,13 @@
.visible-md-inline.visible-lg-inline .visible-md-inline.visible-lg-inline
= render partial: 'carousel', locals: { date: date, hrs_per_slide: 3 } = render partial: 'carousel', locals: { date: date, hrs_per_slide: 3 }
%p.pull-right %p
= link_to app_conference_schedule_path do %span
Get the mobile app! = link_to conference_schedule_url(protocol: 'webcal', format: 'ics') do
Add the schedule to your calendar
%span.pull-right
= link_to app_conference_schedule_path do
Get the mobile app!
:javascript :javascript
// change of active tab and the button title when a date is clicked // change of active tab and the button title when a date is clicked

View file

@ -12,23 +12,23 @@ else
fi fi
case $TEST_SUITE in case $TEST_SUITE in
linters) linters|all)
bundle exec rubocop -Dc .rubocop.yml bundle exec rubocop -Dc .rubocop.yml
bundle exec haml-lint app/views bundle exec haml-lint app/views
;; ;;&
models) models|all)
bundle exec rspec --format documentation spec/models bundle exec rspec --format documentation spec/models
;; ;;&
features) features|all)
bundle exec rspec --format documentation spec/features bundle exec rspec --format documentation spec/features
;; ;;&
controllers) controllers|all)
bundle exec rspec --format documentation spec/controllers bundle exec rspec --format documentation spec/controllers
;; ;;&
ability) ability|all)
bundle exec rspec --format documentation spec/ability bundle exec rspec --format documentation spec/ability
;; ;;&
rest) rest|all)
bundle exec rspec --format documentation --exclude-pattern "spec/{models,features,controllers,ability}/**/*_spec.rb" bundle exec rspec --format documentation --exclude-pattern "spec/{models,features,controllers,ability}/**/*_spec.rb"
;; ;;
esac esac

View file

@ -114,4 +114,6 @@ Osem::Application.configure do
end end
end end
config.assets.precompile += ['mailbot.css']
config.active_record.verbose_query_logs = true
end end

View file

@ -26,7 +26,7 @@ Osem::Application.configure do
config.assets.digest = true config.assets.digest = true
config.assets.css_compressor = :sass config.assets.css_compressor = :sass
config.assets.js_compressor = :uglifier config.assets.js_compressor = Uglifier.new(harmony: true)
config.assets.gzip = true config.assets.gzip = true
# Defaults to nil and saved in location specified by config.assets.prefix # Defaults to nil and saved in location specified by config.assets.prefix
@ -97,7 +97,7 @@ Osem::Application.configure do
domain: ENV['OSEM_SMTP_DOMAIN'], domain: ENV['OSEM_SMTP_DOMAIN'],
enable_starttls_auto: ENV['OSEM_SMTP_ENABLE_STARTTLS_AUTO'], enable_starttls_auto: ENV['OSEM_SMTP_ENABLE_STARTTLS_AUTO'],
openssl_verify_mode: ENV['OSEM_SMTP_OPENSSL_VERIFY_MODE'] openssl_verify_mode: ENV['OSEM_SMTP_OPENSSL_VERIFY_MODE']
} }.compact
# Set the secret_key_base from the env, if not set by any other means # Set the secret_key_base from the env, if not set by any other means
config.secret_key_base ||= ENV["SECRET_KEY_BASE"] config.secret_key_base ||= ENV["SECRET_KEY_BASE"]

View file

@ -52,4 +52,5 @@ Osem::Application.configure do
ActiveSupport::Deprecation.silenced = true ActiveSupport::Deprecation.silenced = true
end end
config.assets.precompile += ['mailbot.css']
end end

View file

@ -1,17 +0,0 @@
# http://www.jkfill.com/2015/02/14/log-which-line-caused-a-query/
module LogQuerySource
def debug(*args, &block)
return unless super
backtrace = Rails.backtrace_cleaner.clean caller
relevant_caller_line = backtrace.detect do |caller_line|
!caller_line.include?('/initializers/')
end
if relevant_caller_line
logger.debug("#{ relevant_caller_line.sub("#{ Rails.root }/", '') }")
end
end
end
ActiveRecord::LogSubscriber.send :prepend, LogQuerySource

View file

@ -1,5 +1,6 @@
CarrierWave.configure do |config| CarrierWave.configure do |config|
config.storage = :file config.storage = :file
config.cache_storage = :file
config.cache_dir = "#{Rails.root}/tmp/uploads" config.cache_dir = "#{Rails.root}/tmp/uploads"
config.enable_processing = false if Rails.env.test? config.enable_processing = false if Rails.env.test?
end end

View file

@ -112,10 +112,10 @@ Devise.setup do |config|
# ==> Configuration for :confirmable # ==> Configuration for :confirmable
# A period that the user is allowed to access the website even without # A period that the user is allowed to access the website even without
# confirming his account. For instance, if set to 2.days, the user will be # confirming their account. For instance, if set to 2.days, the user will be
# able to access the website for two days without confirming his account, # able to access the website for two days without confirming their account,
# access will be blocked just in the third day. Default is 0.days, meaning # access will be blocked just in the third day. Default is 0.days, meaning
# the user cannot access the website without confirming his account. # the user cannot access the website without confirming their account.
config.allow_unconfirmed_access_for = 2.days config.allow_unconfirmed_access_for = 2.days
# If true, requires any email changes to be confirmed (exactly the same way as # If true, requires any email changes to be confirmed (exactly the same way as

View file

@ -1,6 +1,7 @@
Sentry.init do |config| Sentry.init do |config|
config.enabled_environments = %|production staging| config.enabled_environments = %|production staging|
config.dsn = ENV['SENTRY_DSN'] config.dsn = ENV['SENTRY_DSN']
# config.dsn = ENV.fetch('OSEM_SENTRY_DSN', Rails.application.secrets.sentry_dsn)
config.breadcrumbs_logger = [:active_support_logger] config.breadcrumbs_logger = [:active_support_logger]
# To activate performance monitoring, set one of these options. # To activate performance monitoring, set one of these options.
@ -8,6 +9,15 @@ Sentry.init do |config|
config.traces_sample_rate = 0.5 config.traces_sample_rate = 0.5
# or # or
# config.traces_sampler = lambda do |context| # config.traces_sampler = lambda do |context|
# true # true
# end # end
# During deployment we touch tmp/restart.txt, let's use its last access time as release.
# Unless someone has set a variable of course...
# osem_version_from_file = nil
# version_file = File.expand_path('../../tmp/restart.txt', __dir__)
# osem_version_from_file = File.new(version_file).atime.to_i if File.file?(version_file)
# osem_version = ENV.fetch('OSEM_SENTRY_RELEASE', osem_version_from_file)
osem_version = ENV['HEROKU_RELEASE_VERSION']
config.release = osem_version if osem_version
end end

View file

@ -221,8 +221,8 @@ Osem::Application.routes.draw do
end end
end end
get '/admin' => redirect('/admin/conferences') # Handle conferences on custom domains.
# This *must* come before any other root definition.
constraints DomainConstraint do constraints DomainConstraint do
root to: 'conferences#show' root to: 'conferences#show'
end end
@ -233,5 +233,7 @@ Osem::Application.routes.draw do
root to: 'conferences#index', via: [:get, :options] root to: 'conferences#index', via: [:get, :options]
end end
get '/admin' => redirect('/admin/conferences')
get '/calendar' => 'conferences#calendar'
get '/.well-known/apple-developer-merchantid-domain-association', to: 'application#apple_pay' get '/.well-known/apple-developer-merchantid-domain-association', to: 'application#apple_pay'
end end

View file

@ -31,8 +31,8 @@ production:
# Generate your own with rake secret or use the environment # Generate your own with rake secret or use the environment
# secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> # secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
# Your errbit API key # Your sentry.io DSN key
# errbit_key: '12345' # sentry_dsn: '12345'
########## OMNIAUTH Providers ########## ########## OMNIAUTH Providers ##########
# Leave the variables' names empty, unless you use the providers, in which # Leave the variables' names empty, unless you use the providers, in which

View file

@ -0,0 +1,5 @@
class AddSubmissionInstructionsToEventTypes < ActiveRecord::Migration[5.2]
def change
add_column :event_types, :submission_instructions, :text
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2021_03_03_052026) do ActiveRecord::Schema.define(version: 2021_03_06_185903) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -222,6 +222,7 @@ ActiveRecord::Schema.define(version: 2021_03_03_052026) do
t.integer "program_id" t.integer "program_id"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.text "submission_instructions"
end end
create_table "event_users", force: :cascade do |t| create_table "event_users", force: :cascade do |t|

View file

@ -2,7 +2,7 @@ version: "2.4"
services: services:
database: database:
image: postgres image: postgres:12-alpine
environment: environment:
PGDATA: /var/lib/postgresql/data/pgdata PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_PASSWORD: $OSEM_DB_PASSWORD POSTGRES_PASSWORD: $OSEM_DB_PASSWORD

View file

@ -2,7 +2,7 @@ version: "2.4"
services: services:
production_database: production_database:
image: postgres image: postgres:12-alpine
environment: environment:
PGDATA: /var/lib/postgresql/data/pgdata PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_PASSWORD: $OSEM_DB_PASSWORD POSTGRES_PASSWORD: $OSEM_DB_PASSWORD

View file

@ -49,12 +49,8 @@
# See https://github.com/openSUSE/osem/wiki/Translation # See https://github.com/openSUSE/osem/wiki/Translation
# OSEM_TRANSIFEX_APIKEY=1234 # OSEM_TRANSIFEX_APIKEY=1234
# The errbit host to post exceptions to # sentry.io DSN key
# OSEM_ERRBIT_HOST=errbit.example.com # OSEM_SENTRY_DSN=1234
# The project to use on the errbit host
# OSEM_ERRBIT_ID=1234
# The key for this project
# OSEM_ERRBIT_KEY=5678
# OMNIAUTH Developer Key/Secret for GOOGLE # OMNIAUTH Developer Key/Secret for GOOGLE
# OSEM_GOOGLE_KEY=1234 # OSEM_GOOGLE_KEY=1234

Some files were not shown because too many files have changed in this diff Show more