diff --git a/.codecov.yml b/.codecov.yml
index db247200..9c6a4c0d 100644
--- a/.codecov.yml
+++ b/.codecov.yml
@@ -1 +1,6 @@
+coverage:
+ status:
+ project:
+ default:
+ threshold: 0.5%
comment: off
diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml
new file mode 100644
index 00000000..87aceb78
--- /dev/null
+++ b/.github/workflows/spec.yml
@@ -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
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 958943c2..1d036d75 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -434,7 +434,7 @@ Metrics/BlockNesting:
# Offense count: 13
# Configuration parameters: CountComments.
Metrics/ClassLength:
- Max: 650
+ Max: 652
# Offense count: 33
Metrics/CyclomaticComplexity:
diff --git a/.ruby-version b/.ruby-version
index ecd7ee50..338a5b5d 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.5.8
+2.6.6
diff --git a/.travis.yml b/.travis.yml
index 6d3ac828..a94c68ef 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,14 @@
-sudo: required
-dist: xenial
+language: ruby
+cache: bundler
+rvm:
+ - 2.6.6
+dist: bionic
addons:
apt:
packages:
- chromium-browser
-language: ruby
-cache: bundler
-rvm:
- - 2.5
- - 2.6
+services:
+ - postgresql
branches:
except:
- /^depfu/.*$/
@@ -26,16 +26,29 @@ notifications:
on_success: change
on_failure: change
before_script:
+ # install CodeClimate test reporter and tell it we are starting a test run
+ # - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > $CCTR
+ # - 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:
- - "./travis_script.sh $TEST_SUITE"
+ - "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:
global:
- OSEM_DB_ADAPTER=sqlite3
- OSEM_DB_HOST=''
- OSEM_DB_PORT=''
- OSEM_DB_NAME='osem_test'
+ - CC_TEST_REPORTER_ID=$CC_TEST_REPORTER
+ - CCTR=./cc-test-reporter
matrix:
- TEST_SUITE=ability
- TEST_SUITE=features
diff --git a/CHANGES.md b/CHANGES.md
index 432cdcdf..0080f621 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -43,8 +43,8 @@ bundle exec rake data:set_conference_in_versions RAILS_ENV=production
### Organization admins
-We have a new role `organization admins` which allow a user to manage his the
-organization and create and manage conference within the organization. This
+We have a new role `organization admins` which allow a user to manage their
+organization and create and manage a conference within the organization. This
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:
diff --git a/Dockerfile b/Dockerfile
index 0b36037d..5a6e7cf1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM osem/base
+FROM registry.opensuse.org/opensuse/infrastructure/osem/containers/osem/base:latest
ARG CONTAINER_USERID
# Configure our user
@@ -16,6 +16,8 @@ RUN chown -R osem /osem
USER osem
WORKDIR /osem/
+# Install bundler & foreman
+RUN sudo gem install bundler:1.17.3 foreman
# Install our bundle
RUN export NOKOGIRI_USE_SYSTEM_LIBRARIES=1; bundle install --jobs=3 --retry=3
diff --git a/Dockerfile.base b/Dockerfile.base
deleted file mode 100644
index 1865285a..00000000
--- a/Dockerfile.base
+++ /dev/null
@@ -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"]
-
diff --git a/Dockerfile.production b/Dockerfile.production
index 12582dd9..ded47832 100644
--- a/Dockerfile.production
+++ b/Dockerfile.production
@@ -1,4 +1,4 @@
-FROM osem/base
+FROM opensuse/infrastructure/osem/containers/osem/base
# Add our files
COPY --chown=1000:1000 . /osem/
diff --git a/Gemfile b/Gemfile
index 77ac5a7e..226932f5 100644
--- a/Gemfile
+++ b/Gemfile
@@ -2,7 +2,7 @@
source 'https://rubygems.org'
-# ruby '~> 2.5.0'
+ruby ENV['TRAVIS_RUBY_VERSION'] || '2.6.6'
# rails-assets requires >= 1.8.4
if Gem::Version.new(Bundler::VERSION) < Gem::Version.new('1.8.4')
@@ -12,7 +12,7 @@ end
gem 'rails', '~> 5.2'
# Use Puma as the app server
-gem 'puma', '~> 3.0'
+gem 'puma', '~> 5.2'
# respond_to methods have been extracted to the responders gem
# http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#responders
@@ -157,9 +157,6 @@ gem 'font-awesome-rails'
# for markdown
gem 'redcarpet'
-# as rdoc generator
-gem 'rdoc-generator-fivefish'
-
# for visitor tracking
gem 'piwik_analytics', '~> 1.0.1'
@@ -221,6 +218,8 @@ gem 'nokogiri', '>= 1.8.1'
# memcached binary connector
gem 'dalli'
+gem 'icalendar'
+
# Use guard and spring for testing in development
group :development do
# to launch specs when files are modified
@@ -234,8 +233,6 @@ group :development do
gem 'mina'
# as debugger on error pages
gem 'web-console'
- # as development database
- gem 'sqlite3'
# prepend models with db schema
gem 'annotate'
end
@@ -248,7 +245,7 @@ group :test do
gem 'rspec-rails'
gem 'webdrivers'
# for measuring test coverage
- gem 'codecov', require: false
+ gem 'simplecov-cobertura'
# for describing models
gem 'shoulda-matchers', require: false
# for stubing/mocking models
@@ -269,10 +266,11 @@ group :test do
gem 'pdf-inspector', require: "pdf/inspector"
end
-group :development, :test, :linters do
+group :development, :test do
# as debugger
gem 'byebug'
gem 'pry'
+ gem 'pry-byebug'
# Linters and static analysis.
gem 'pronto', require: false
@@ -282,4 +280,6 @@ group :development, :test, :linters do
gem 'rubocop-rspec', require: false
gem 'haml-lint', require: false
+ # as development/test database
+ gem 'sqlite3'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 241cbb00..273546b8 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -85,7 +85,7 @@ GEM
axlsx_rails (0.5.2)
actionpack (>= 3.1)
axlsx (>= 2.0.1)
- bcrypt (3.1.13)
+ bcrypt (3.1.16)
bindex (0.6.0)
bootstrap-sass (3.4.1)
autoprefixer-rails (>= 5.2.1)
@@ -104,10 +104,13 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (~> 1.5)
xpath (~> 3.2)
- carrierwave (1.3.2)
- activemodel (>= 4.0.0)
- activesupport (>= 4.0.0)
- mime-types (>= 1.16)
+ carrierwave (2.1.1)
+ activemodel (>= 5.0.0)
+ activesupport (>= 5.0.0)
+ addressable (~> 2.6)
+ image_processing (~> 1.1)
+ mimemagic (>= 0.3.0)
+ mini_mime (>= 0.1.3)
ssrf_filter (~> 1.0)
carrierwave-bombshelter (0.2.2)
activesupport (>= 3.2.0)
@@ -115,7 +118,7 @@ GEM
fastimage
case_transform (0.2)
activesupport
- chartkick (3.4.0)
+ chartkick (3.4.2)
childprocess (3.0.0)
chronic (0.10.2)
chunky_png (1.3.11)
@@ -123,10 +126,9 @@ GEM
cloudinary (1.11.1)
aws_cf_signer
rest-client
- cocoon (1.2.14)
- codecov (0.2.11)
- json
- simplecov
+ cocoon (1.2.15)
+ codecov (0.5.0)
+ simplecov (>= 0.15, < 0.22)
coderay (1.1.1)
concurrent-ruby (1.1.8)
countable-rails (0.0.1)
@@ -142,7 +144,7 @@ GEM
safe_yaml (~> 1.0.0)
crass (1.0.6)
daemons (1.3.1)
- dalli (2.7.10)
+ dalli (2.7.11)
dante (0.2.0)
database_cleaner (1.7.0)
delayed_job (4.1.8)
@@ -150,7 +152,7 @@ GEM
delayed_job_active_record (4.1.4)
activerecord (>= 3.0, < 6.1)
delayed_job (>= 3.0, < 5)
- devise (4.7.1)
+ devise (4.7.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
@@ -159,13 +161,13 @@ GEM
devise_ichain_authenticatable (0.3.2)
devise (>= 2.2)
diff-lcs (1.3)
- docile (1.3.2)
+ docile (1.3.5)
domain_name (0.5.20180417)
unf (>= 0.0.5, < 1.0.0)
- dotenv (2.7.5)
- dotenv-rails (2.7.5)
- dotenv (= 2.7.5)
- railties (>= 3.2, < 6.1)
+ dotenv (2.7.6)
+ dotenv-rails (2.7.6)
+ dotenv (= 2.7.6)
+ railties (>= 3.2)
erubi (1.10.0)
erubis (2.7.0)
execjs (2.7.0)
@@ -189,8 +191,8 @@ GEM
path_expander (~> 1.0)
ruby_parser (~> 3.0)
sexp_processor (~> 4.0)
- font-awesome-rails (4.7.0.5)
- railties (>= 3.2, < 6.1)
+ font-awesome-rails (4.7.0.7)
+ railties (>= 3.2, < 7)
formatador (0.2.5)
formtastic (3.1.5)
actionpack (>= 3.2.13)
@@ -252,8 +254,12 @@ GEM
i18n (1.8.9)
concurrent-ruby (~> 1.0)
i18n_data (0.8.0)
- inversion (1.1.1)
- loggability (~> 0.12)
+ icalendar (2.7.0)
+ ice_cube (~> 0.16)
+ ice_cube (0.16.3)
+ image_processing (1.12.1)
+ mini_magick (>= 4.9.5, < 5)
+ ruby-vips (>= 2.0.17, < 3)
io-like (0.3.0)
iso-639 (0.2.8)
jaro_winkler (1.5.3)
@@ -264,7 +270,7 @@ GEM
thor (>= 0.14, < 2.0)
jquery-ui-rails (6.0.1)
railties (>= 3.2.16)
- json (2.3.1)
+ json (2.5.1)
json-schema (2.8.1)
addressable (>= 2.4)
jsonapi-renderer (0.2.2)
@@ -283,7 +289,6 @@ GEM
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
ruby_dep (~> 1.2)
- loggability (0.14.0)
loofah (2.9.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
@@ -295,7 +300,7 @@ GEM
method_source (0.8.2)
mime-types (3.3.1)
mime-types-data (~> 3.2015)
- mime-types-data (3.2020.1104)
+ mime-types-data (3.2021.0225)
mimemagic (0.3.5)
mina (1.2.3)
open4 (~> 1.3.4)
@@ -303,7 +308,7 @@ GEM
mini_magick (4.9.5)
mini_mime (1.0.2)
mini_portile2 (2.5.0)
- minitest (5.14.3)
+ minitest (5.14.4)
momentjs-rails (2.20.1)
railties (>= 3.1)
monetize (1.9.2)
@@ -320,7 +325,7 @@ GEM
multipart-post (2.1.1)
nenv (0.3.0)
netrc (0.11.0)
- nio4r (2.5.5)
+ nio4r (2.5.7)
nokogiri (1.11.1)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
@@ -366,7 +371,7 @@ GEM
parser (2.6.5.0)
ast (~> 2.4.0)
path_expander (1.1.0)
- pdf-core (0.7.0)
+ pdf-core (0.9.0)
pdf-inspector (1.3.0)
pdf-reader (>= 1.0, < 3.0.a)
pdf-reader (2.2.0)
@@ -380,13 +385,13 @@ GEM
actionpack
activesupport
rails (>= 3.0.0)
- prawn (2.2.2)
- pdf-core (~> 0.7.0)
- ttfunk (~> 1.5)
+ prawn (2.4.0)
+ pdf-core (~> 0.9.0)
+ ttfunk (~> 1.7)
prawn-qrcode (0.3.1)
prawn (>= 1)
rqrcode (>= 0.4.1)
- prawn-rails (1.2.0)
+ prawn-rails (1.3.0)
prawn
prawn-table
rails (>= 3.1.0)
@@ -414,8 +419,12 @@ GEM
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
+ pry-byebug (3.8.0)
+ byebug (~> 11.0)
+ pry (~> 0.10)
public_suffix (3.1.1)
- puma (3.12.6)
+ puma (5.2.2)
+ nio4r (~> 2.0)
racc (1.5.2)
rack (2.2.3)
rack-openid (1.3.1)
@@ -456,10 +465,10 @@ GEM
rails-assets-to-markdown (3.1.1)
rails-assets-trianglify (1.2.0)
rails-assets-waypoints (4.0.0)
- rails-controller-testing (1.0.4)
- actionpack (>= 5.0.1.x)
- actionview (>= 5.0.1.x)
- activesupport (>= 5.0.1.x)
+ rails-controller-testing (1.0.5)
+ actionpack (>= 5.0.1.rc1)
+ actionview (>= 5.0.1.rc1)
+ activesupport (>= 5.0.1.rc1)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
@@ -479,12 +488,6 @@ GEM
rb-fsevent (0.10.3)
rb-inotify (0.10.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)
json
redcarpet (3.5.1)
@@ -540,6 +543,8 @@ GEM
ruby-openid (2.9.2)
ruby-progressbar (1.10.1)
ruby-rc4 (0.1.5)
+ ruby-vips (2.0.17)
+ ffi (~> 1.9)
ruby2_keywords (0.0.4)
ruby_dep (1.5.0)
ruby_parser (3.11.0)
@@ -584,10 +589,14 @@ GEM
shellany (0.0.1)
shoulda-matchers (4.1.2)
activesupport (>= 4.2.0)
- simplecov (0.19.0)
+ simplecov (0.21.2)
docile (~> 1.1)
simplecov-html (~> 0.11)
+ simplecov_json_formatter (~> 0.1)
+ simplecov-cobertura (1.4.2)
+ simplecov (~> 0.8)
simplecov-html (0.12.3)
+ simplecov_json_formatter (0.1.2)
sixarm_ruby_unaccent (1.2.0)
skylight (3.1.5)
skylight-core (= 3.1.5)
@@ -622,7 +631,7 @@ GEM
tilt (2.0.9)
timecop (0.9.1)
transitions (1.2.1)
- ttfunk (1.5.1)
+ ttfunk (1.7.0)
turbolinks (5.2.1)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
@@ -637,8 +646,8 @@ GEM
unicode_utils (1.4.0)
unobtrusive_flash (3.3.1)
railties
- warden (1.2.8)
- rack (>= 2.0.6)
+ warden (1.2.9)
+ rack (>= 2.0.9)
web-console (3.7.0)
actionview (>= 5.0)
activemodel (>= 5.0)
@@ -659,7 +668,6 @@ GEM
chronic (>= 0.6.3)
xpath (3.2.0)
nokogiri (~> 1.8)
- yajl-ruby (1.4.1)
PLATFORMS
ruby
@@ -686,7 +694,6 @@ DEPENDENCIES
climate_control
cloudinary
cocoon
- codecov
countable-rails
country_select
daemons
@@ -707,6 +714,7 @@ DEPENDENCIES
guard-rspec
haml-lint
haml-rails
+ icalendar
iso-639
jquery-datatables
jquery-rails
@@ -736,7 +744,8 @@ DEPENDENCIES
pronto-haml
pronto-rubocop
pry
- puma (~> 3.0)
+ pry-byebug
+ puma (~> 5.2)
rails (~> 5.2)
rails-assets-bootstrap-markdown!
rails-assets-bootstrap-select!
@@ -752,7 +761,6 @@ DEPENDENCIES
rails-assets-waypoints!
rails-controller-testing
rails-i18n
- rdoc-generator-fivefish
recaptcha
redcarpet
responders (~> 2.0)
@@ -768,6 +776,7 @@ DEPENDENCIES
sentry-rails
sentry-ruby
shoulda-matchers
+ simplecov-cobertura
skylight
spring-commands-rspec
sprockets-rails
@@ -784,5 +793,8 @@ DEPENDENCIES
webmock
whenever
+RUBY VERSION
+ ruby 2.6.6p146
+
BUNDLED WITH
1.17.3
diff --git a/README.md b/README.md
index 09356477..71f3ac37 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,4 @@
+### Spring 2021 Student Project
[](https://travis-ci.com/CactusPuppy/snapcon)
[](https://codeclimate.com/github/CactusPuppy/snapcon/maintainability)
[](https://codecov.io/gh/CactusPuppy/snapcon)
@@ -13,7 +14,21 @@
-# Open Source Event Manager - [osem.io](https://osem.io)
+---
+
+[](https://travis-ci.com/snap-cloud/snapcon)
+[](https://codeclimate.com/github/snap-cloud/snapcon/maintainability)
+[](https://codeclimate.com/github/snap-cloud/snapcon/test_coverage)
+[](https://codecov.io/gh/snap-cloud/snapcon)
+[](https://hakiri.io/github/snap-cloud/snapcon/master)
+[](https://depfu.com/repos/snap-cloud/snapcon)
+
+
+
+
+# [Snap!Con](https://snapcon.org)
+forked from:
+## Open Source Event Manager - [osem.io](https://osem.io)

diff --git a/app/assets/javascripts/osem-datepickers.js b/app/assets/javascripts/osem-datepickers.js
index 8b808b63..e5bbe10e 100644
--- a/app/assets/javascripts/osem-datepickers.js
+++ b/app/assets/javascripts/osem-datepickers.js
@@ -13,11 +13,13 @@ $(function () {
$("#conference-start-datepicker").datetimepicker({
useCurrent: false,
- format: "YYYY-MM-DD"
+ ignoreReadonly: true,
+ format: "YYYY-MM-DD",
});
$("#conference-end-datepicker").datetimepicker({
useCurrent: false,
+ ignoreReadonly: true,
format: "YYYY-MM-DD"
});
diff --git a/app/assets/javascripts/osem.js b/app/assets/javascripts/osem.js
index dcab692c..636ed959 100644
--- a/app/assets/javascripts/osem.js
+++ b/app/assets/javascripts/osem.js
@@ -147,17 +147,32 @@ 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 */
$( document ).ready(function() {
- /* Set the minimum and maximum proposal abstract word length */
+ /* Set the minimum and maximum proposal abstract and submission text word length */
$("#event_event_type_id").change(function () {
var $selected = $("#event_event_type_id option:selected")
var max = $selected.data("max-words");
var min = $selected.data("min-words");
+ // Set the filler text for the submission text
+ fill_if_empty('event_submission_text', $selected.data("help"));
+
$("#abstract-maximum-word-count").text(max);
+ $("#submission-maximum-word-count").text(max);
$("#abstract-minimum-word-count").text(min);
+ $("#submission-minimum-word-count").text(min);
word_count($('#event_abstract').get(0), 'abstract-count', max);
+ word_count($('#event_submission_text').get(0), 'submission-count', max);
})
.trigger('change');
@@ -167,6 +182,25 @@ $( document ).ready(function() {
var max = $selected.data("max-words");
word_count(this, 'abstract-count', max);
} );
+
+ /* Count the submission text length */
+ $("#event_submission_text").bind('change keyup paste input', function() {
+ var $selected = $("event_event_type_id option:selected")
+ var max = $selected.data("max-words");
+ word_count(this, 'submission-count', max);
+ });
+
+ /* Listen for reset template button, wait for confirm, and reset. */
+ $('#sub_text_reset').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('help'));
+ sub_text.trigger('change');
+ }
+ });
});
/* Commodity function for modal windows */
diff --git a/app/assets/stylesheets/osem-splash.scss b/app/assets/stylesheets/osem-splash.scss
index e2bdda65..09e8a31d 100644
--- a/app/assets/stylesheets/osem-splash.scss
+++ b/app/assets/stylesheets/osem-splash.scss
@@ -3,7 +3,8 @@
#splash {
// Counter the general padding for #content
- margin-bottom: -60px;
+ margin-bottom: -65px;
+
section {
padding-top: 60px;
padding-bottom: 60px;
@@ -144,6 +145,10 @@
}
}
+ .social-media.trapezoid {
+ border-top-color: #0C3559; // TODO: Use @conference color?
+ }
+
#social-media{
background: none repeat scroll 0 0 #0C3559;
padding: 50px 20px;
diff --git a/app/controllers/admin/event_types_controller.rb b/app/controllers/admin/event_types_controller.rb
index 137e8f00..e7f19863 100644
--- a/app/controllers/admin/event_types_controller.rb
+++ b/app/controllers/admin/event_types_controller.rb
@@ -49,7 +49,7 @@ module Admin
private
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
diff --git a/app/controllers/admin/events_controller.rb b/app/controllers/admin/events_controller.rb
index b24882f3..f5e68165 100644
--- a/app/controllers/admin/events_controller.rb
+++ b/app/controllers/admin/events_controller.rb
@@ -175,7 +175,7 @@ module Admin
def event_params
params.require(:event).permit(
# Set also in proposals controller
- :title, :subtitle, :event_type_id, :abstract, :description, :require_registration, :difficulty_level_id,
+ :title, :subtitle, :event_type_id, :abstract, :submission_text, :description, :require_registration, :difficulty_level_id,
# Set only in admin/events controller
:track_id, :state, :language, :is_highlight, :max_attendees,
# Not used anymore?
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index e49c02f5..2eb2032a 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -66,6 +66,16 @@ module Admin
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
def user_params
diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb
index f581e367..02d869f4 100644
--- a/app/controllers/conferences_controller.rb
+++ b/app/controllers/conferences_controller.rb
@@ -6,8 +6,11 @@ class ConferencesController < ApplicationController
load_and_authorize_resource find_by: :short_title, except: :show
def index
- @current = Conference.where('end_date >= ?', Date.current).reorder(start_date: :asc)
- @antiquated = Conference.where('end_date < ?', Date.current)
+ @current = Conference.upcoming.reorder(start_date: :asc)
+ @antiquated = Conference.past
+ if @antiquated.empty? && @current.empty? && User.empty?
+ render :new_install
+ end
end
def show
@@ -68,6 +71,47 @@ class ConferencesController < ApplicationController
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
def conference_finder_conditions
diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb
index adfdbea0..bf1b3adc 100644
--- a/app/controllers/proposals_controller.rb
+++ b/app/controllers/proposals_controller.rb
@@ -170,7 +170,7 @@ class ProposalsController < ApplicationController
def event_params
params.require(:event).permit(:event_type_id, :track_id, :difficulty_level_id,
- :title, :subtitle, :abstract, :description,
+ :title, :subtitle, :abstract, :submission_text, :description,
:require_registration, :max_attendees, :language,
speaker_ids: [], volunteer_ids: []
)
diff --git a/app/controllers/schedules_controller.rb b/app/controllers/schedules_controller.rb
index cbff9cc8..230cda2f 100644
--- a/app/controllers/schedules_controller.rb
+++ b/app/controllers/schedules_controller.rb
@@ -21,6 +21,12 @@ class SchedulesController < ApplicationController
format.xml do
@events_xml = event_schedules.map(&:event).group_by{ |event| event.time.to_date } if event_schedules
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
@rooms = @conference.venue.rooms if @conference.venue
diff --git a/app/datatables/user_datatable.rb b/app/datatables/user_datatable.rb
index 45200ebb..cc29e995 100644
--- a/app/datatables/user_datatable.rb
+++ b/app/datatables/user_datatable.rb
@@ -35,7 +35,8 @@ class UserDatatable < AjaxDatatablesRails::Base
roles: record.roles.any? ? show_roles(record.get_roles) : 'None',
view_url: 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
diff --git a/app/helpers/conference_helper.rb b/app/helpers/conference_helper.rb
index 85ead390..14253b23 100644
--- a/app/helpers/conference_helper.rb
+++ b/app/helpers/conference_helper.rb
@@ -27,4 +27,33 @@ module ConferenceHelper
markdown(ticket.description.split("\n").first&.strip)
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
diff --git a/app/models/cfp.rb b/app/models/cfp.rb
index 55e542f7..f5161aac 100644
--- a/app/models/cfp.rb
+++ b/app/models/cfp.rb
@@ -14,7 +14,6 @@
# updated_at :datetime
# program_id :integer
#
-# cannot delete program if there are events submitted
class Cfp < ApplicationRecord
TYPES = %w(events booths tracks).freeze
diff --git a/app/models/conference.rb b/app/models/conference.rb
index 44224ab7..e9a0fa23 100644
--- a/app/models/conference.rb
+++ b/app/models/conference.rb
@@ -61,6 +61,9 @@ class Conference < ApplicationRecord
has_one :email_settings, dependent: :destroy
has_one :program, 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 :physical_tickets, through: :ticket_purchases
has_many :payments, dependent: :destroy
diff --git a/app/models/event.rb b/app/models/event.rb
index 0370926b..d10ae1a1 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -7,6 +7,7 @@
# id :bigint not null, primary key
# abstract :text
# comments_count :integer default(0), not null
+# committee_review :text
# description :text
# guid :string not null
# is_highlight :boolean default(FALSE)
@@ -18,6 +19,7 @@
# require_registration :boolean
# start_time :datetime
# state :string default("new"), not null
+# submission_text :text
# subtitle :string
# title :string not null
# week :integer
@@ -73,6 +75,7 @@ class Event < ApplicationRecord
before_create :generate_guid
validate :abstract_limit
+ validate :submission_limit
validate :before_end_of_conference, on: :create
validates :title, presence: true
validates :abstract, presence: true
@@ -217,6 +220,10 @@ class Event < ApplicationRecord
abstract.to_s.split.size
end
+ def submission_word_count
+ submission_text.to_s.split.size
+ end
+
def self.get_state_color(state)
COLORS[state.to_sym] || '#00FFFF' # azure
end
@@ -341,16 +348,28 @@ class Event < ApplicationRecord
errors.add(:max_attendees, "cannot be more than the room's capacity (#{room.size})") if max_attendees && (max_attendees > room.size)
end
- def abstract_limit
- # If we don't have an event type, there is no need to count anything
- return unless event_type && abstract
+ def word_limit(field)
+ # If we don't have an event type or the requested field, don't count
+ return unless event_type && respond_to?(field) && self[field]
- len = abstract.split.size
+ len = self[field].split.size
+ # TODO: Use different limits for different text fields
+ # Uncomment the two lines below this when the separate word limits are implemented.
+ # max_words = event_type["maximum_#{field}_length"]
+ # min_words = event_type["minimum_#{field}_length"]
max_words = event_type.maximum_abstract_length
min_words = event_type.minimum_abstract_length
- errors.add(:abstract, "cannot have less than #{min_words} words") if len < min_words
- errors.add(:abstract, "cannot have more than #{max_words} words") if len > max_words
+ errors.add(field.to_sym, "cannot have less than #{min_words} words") if len < min_words
+ errors.add(field.to_sym, "cannot have more than #{max_words} words") if len > max_words
+ end
+
+ def abstract_limit
+ word_limit(:abstract)
+ end
+
+ def submission_limit
+ word_limit(:submission_text)
end
# TODO: create a module to be mixed into model to perform same operation
diff --git a/app/models/event_type.rb b/app/models/event_type.rb
index 67d7fb20..2ef440bc 100644
--- a/app/models/event_type.rb
+++ b/app/models/event_type.rb
@@ -10,6 +10,7 @@
# length :integer default(30)
# maximum_abstract_length :integer default(500)
# minimum_abstract_length :integer default(0)
+# submission_instructions :text
# title :string not null
# created_at :datetime
# updated_at :datetime
diff --git a/app/models/program.rb b/app/models/program.rb
index 45b8f65c..19000746 100644
--- a/app/models/program.rb
+++ b/app/models/program.rb
@@ -22,7 +22,6 @@
#
# index_programs_on_selected_schedule_id (selected_schedule_id)
#
-# cannot delete program if there are events submitted
class Program < ApplicationRecord
has_paper_trail on: [:update], ignore: [:updated_at], meta: { conference_id: :conference_id }
diff --git a/app/models/survey_question.rb b/app/models/survey_question.rb
index 6b365236..46c20843 100644
--- a/app/models/survey_question.rb
+++ b/app/models/survey_question.rb
@@ -24,8 +24,8 @@ class SurveyQuestion < ActiveRecord::Base
validates :title, presence: true
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 :max_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, if: :choice?
validate :max_choices_greater_than_min
diff --git a/app/pdfs/ticket_pdf.rb b/app/pdfs/ticket_pdf.rb
index 306d5870..c4408e7c 100644
--- a/app/pdfs/ticket_pdf.rb
+++ b/app/pdfs/ticket_pdf.rb
@@ -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.organization.name.to_s, at: [@mid_horizontal + 30, cursor - 50], size: 12
if @conference.venue
- draw_text @conference.venue.name, at: [@mid_horizontal + 30, cursor - 70]
- draw_text @conference.venue.street, at: [@mid_horizontal + 30, cursor - 90]
- draw_text @conference.venue.city, at: [@mid_horizontal + 30, cursor - 110]
+ 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.city, at: [@mid_horizontal + 30, cursor - 110]
end
move_up 130
move_down @mid_vertical
diff --git a/app/serializers/event_serializer.rb b/app/serializers/event_serializer.rb
index 4e81ef3b..9bf196f2 100644
--- a/app/serializers/event_serializer.rb
+++ b/app/serializers/event_serializer.rb
@@ -7,6 +7,7 @@
# id :bigint not null, primary key
# abstract :text
# comments_count :integer default(0), not null
+# committee_review :text
# description :text
# guid :string not null
# is_highlight :boolean default(FALSE)
@@ -18,6 +19,7 @@
# require_registration :boolean
# start_time :datetime
# state :string default("new"), not null
+# submission_text :text
# subtitle :string
# title :string not null
# week :integer
diff --git a/app/uploaders/picture_uploader.rb b/app/uploaders/picture_uploader.rb
index 47e86f8b..3d7e6edb 100644
--- a/app/uploaders/picture_uploader.rb
+++ b/app/uploaders/picture_uploader.rb
@@ -6,6 +6,8 @@ class PictureUploader < CarrierWave::Uploader::Base
include CarrierWave::Compatibility::Paperclip
include CarrierWave::BombShelter
+ storage :file
+
# use cloudinary if it's configured
if Cloudinary.config.cloud_name
# use https by default
diff --git a/app/views/admin/event_types/_form.html.haml b/app/views/admin/event_types/_form.html.haml
index 91533877..526e9381 100644
--- a/app/views/admin/event_types/_form.html.haml
+++ b/app/views/admin/event_types/_form.html.haml
@@ -15,6 +15,7 @@
= 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 :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' }
%p.text-right
= f.action :submit, as: :button, button_html: { class: 'btn btn-primary' }
diff --git a/app/views/admin/event_types/index.html.haml b/app/views/admin/event_types/index.html.haml
index e18cceeb..015a3397 100644
--- a/app/views/admin/event_types/index.html.haml
+++ b/app/views/admin/event_types/index.html.haml
@@ -10,6 +10,7 @@
%thead
%th Title
%th Description
+ %th Instructions
%th Length
%th Abstract Length
%th Color
@@ -21,6 +22,8 @@
= event_type.title
%td
= markdown(event_type.description)
+ %td
+ = markdown(event_type.submission_instructions)
%td
= event_type.length
Minutes
diff --git a/app/views/admin/events/_proposal.html.haml b/app/views/admin/events/_proposal.html.haml
index 722387ac..05d48bb7 100644
--- a/app/views/admin/events/_proposal.html.haml
+++ b/app/views/admin/events/_proposal.html.haml
@@ -7,6 +7,8 @@
%small
= @event.subtitle
.btn-group.pull-right
+ - if @event.public
+ = link_to 'Preview', conference_program_proposal_path(@conference.short_title, @event.id), class: 'btn btn-mini btn-primary'
= link_to 'Registrations', registrations_admin_conference_program_event_path(@conference.short_title, @event), class: 'btn btn-success'
= link_to 'Edit', edit_admin_conference_program_event_path(@conference.short_title, @event), class: 'btn btn-mini btn-primary'
@@ -111,6 +113,10 @@
%td
%b Abstract
%td= markdown(@event.abstract)
+ %tr
+ %td
+ %b Submission Description
+ %td= markdown(@event.submission_text)
%tr
%td
%b Requirements
diff --git a/app/views/admin/survey_questions/_form.html.haml b/app/views/admin/survey_questions/_form.html.haml
index 2538c17c..eb861944 100644
--- a/app/views/admin/survey_questions/_form.html.haml
+++ b/app/views/admin/survey_questions/_form.html.haml
@@ -15,7 +15,7 @@
.row
.col-md-12
- = f.input :title
+ = f.input :title, input_html: { autofocus: true }
= f.input :mandatory
.survey-possible-answers{ class: @survey_question.choice? ? '' : 'hidden' }
= f.input :possible_answers, hint: 'Comma separated', input_html: { rows: 3 }
diff --git a/app/views/admin/surveys/_survey_stats.html.haml b/app/views/admin/surveys/_survey_stats.html.haml
index e551a7d1..cacf0b00 100644
--- a/app/views/admin/surveys/_survey_stats.html.haml
+++ b/app/views/admin/surveys/_survey_stats.html.haml
@@ -7,4 +7,4 @@
.panel-body
- question_replies = survey_question.survey_replies
- 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 } } }
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index 6e2c13df..3d52ce6c 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -20,6 +20,7 @@
%th{ width: '0' } Conferences Attended
%th{ width: '50%' } Roles
%th{ width: '0' } Actions
+ %th{ style: 'display: none' } Confirmed?
%tbody
:javascript
@@ -37,6 +38,7 @@
{
"data": "confirmed_at",
"render": function (data, type, row, meta) {
+ console.log(meta)
return 'Edit'+
'';
}
+ },
+ {
+ "data": "confirmed",
+ "className": 'hidden',
+ "render": false
}
]
});
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index b90e72d9..c0a8f1fb 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -12,8 +12,10 @@
.tab-content
#user-info-content.tab-pane{class: "#{'active' unless params[:tab] == 'submissions-content'}"}
- if can? :edit, @user
- .pull-right
+ .pull-right.btn-group
= 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
- @show_attributes.each do |attr|
%tr
diff --git a/app/views/conference_registrations/_event.html.haml b/app/views/conference_registrations/_event.html.haml
index 67a35ba2..2d0f6234 100644
--- a/app/views/conference_registrations/_event.html.haml
+++ b/app/views/conference_registrations/_event.html.haml
@@ -7,6 +7,11 @@
= event.title
%small
= event.subtitle
+ .text-muted
+ = registered_text(event)
+ - if event.scheduled?
+ (Scheduled on: #{event.time.to_date})
+
.panel-body
-# %p
-# = canceled_replacement_event_label(event, event_schedule)
diff --git a/app/views/conference_registrations/show.html.haml b/app/views/conference_registrations/show.html.haml
index 49cca609..77408022 100644
--- a/app/views/conference_registrations/show.html.haml
+++ b/app/views/conference_registrations/show.html.haml
@@ -9,9 +9,9 @@
-if @conference.venue
at
%strong
- = "#{@conference.venue.name},"
- = "#{@conference.venue.street},"
- = "#{@conference.venue.city} / #{@conference.venue.country_name}."
+ = "#{@conference.venue_name},"
+ = "#{@conference.venue_street},"
+ = "#{@conference.city} / #{@conference.country_name}."
%small
= date_string(@conference.start_date, @conference.end_date)
- unless @conference.code_of_conduct.blank?
diff --git a/app/views/conferences/_conference_details.html.haml b/app/views/conferences/_conference_details.html.haml
index 02e54c29..b9fb7843 100644
--- a/app/views/conferences/_conference_details.html.haml
+++ b/app/views/conferences/_conference_details.html.haml
@@ -12,10 +12,10 @@
= date_string(conference.start_date, conference.end_date)
- if conference.venue
%p
- = "#{conference.venue.city}/#{conference.venue.country_name}"
+ = "#{conference.city}/#{conference.country_name}"
- unless conference.description.blank?
%p
- = markdown(conference.description)
+ = markdown(conference.description, escape_html=false)
.col-md-2
.btn-group-vertical
- if !@conference || @conference != conference
diff --git a/app/views/conferences/_social_media.haml b/app/views/conferences/_social_media.haml
index ebbfb8e1..0f73e46a 100644
--- a/app/views/conferences/_social_media.haml
+++ b/app/views/conferences/_social_media.haml
@@ -27,4 +27,4 @@
- if contact.email?
= mail_to "#{ contact.email }" do
%i.fa.fa-envelope-o.fa-4x
- .trapezoid
+ .trapezoid.social-media
diff --git a/app/views/conferences/index.html.haml b/app/views/conferences/index.html.haml
index 5382989c..fb45757c 100644
--- a/app/views/conferences/index.html.haml
+++ b/app/views/conferences/index.html.haml
@@ -10,16 +10,19 @@
.col-md-12
%p.text-right
%button{ type: 'button', class: 'btn btn-link btn-sm', 'data-toggle' => 'collapse', 'data-target' => '#antiquated', 'aria-expanded' => 'true', 'aria-controls' => 'antiquated'}
- Older conferences
+ Past Conferences
%span.notranslate
= "(#{@antiquated.count})"
- %i.fa.fa-chevron-right
- %i.fa.fa-chevron-down{ style: 'display: none' }
- #antiquated.collapse
+ %i.fa.fa-chevron-right{ style: 'display: none' }
+ %i.fa.fa-chevron-down
+ #antiquated
- @antiquated.each do |conference|
= render '/conferences/conference_details', conference: conference
- - if @antiquated.empty? && @current.empty? && User.empty?
- = render partial: 'new_install'
+ %p
+ 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
:javascript
diff --git a/app/views/conferences/_new_install.html.haml b/app/views/conferences/new_install.html.haml
similarity index 92%
rename from app/views/conferences/_new_install.html.haml
rename to app/views/conferences/new_install.html.haml
index 1ec2bd02..d6cf8eef 100644
--- a/app/views/conferences/_new_install.html.haml
+++ b/app/views/conferences/new_install.html.haml
@@ -17,5 +17,5 @@
will the be administrator of it.
%p
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!
diff --git a/app/views/layouts/_user_menu.html.haml b/app/views/layouts/_user_menu.html.haml
index 5465a66a..b839f913 100644
--- a/app/views/layouts/_user_menu.html.haml
+++ b/app/views/layouts/_user_menu.html.haml
@@ -23,8 +23,8 @@
%li
= link_to(conference_conference_registration_path(@conference)) do
%span.fa.fa-id-badge
- = @conference.short_title
- registration
+ = @conference.short_title
+ registration
-if @conference && @conference.program
%li
= link_to(conference_program_proposals_path(@conference.short_title)) do
diff --git a/app/views/physical_tickets/show.html.haml b/app/views/physical_tickets/show.html.haml
index 7dbc44da..ec8e7379 100644
--- a/app/views/physical_tickets/show.html.haml
+++ b/app/views/physical_tickets/show.html.haml
@@ -9,9 +9,9 @@
- if @conference.venue
at
%strong
- #{@conference.venue.name},
- #{@conference.venue.street},
- #{@conference.venue.city} / #{@conference.venue.country_name}.
+ #{@conference.venue_name},
+ #{@conference.venue_street},
+ #{@conference.city} / #{@conference.country_name}.
%small
= date_string(@conference.start_date, @conference.end_date)
.row
diff --git a/app/views/proposals/_proposal_form.html.haml b/app/views/proposals/_proposal_form.html.haml
index f385bdeb..5f907d6a 100644
--- a/app/views/proposals/_proposal_form.html.haml
+++ b/app/views/proposals/_proposal_form.html.haml
@@ -13,7 +13,7 @@
= 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 }]},
+ 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?
@@ -46,7 +46,30 @@
250
words.
- - if current_user.is_admin? or @program.cfp.enable_registrations?
+ %br
+ - @conference.program.event_types.each do |event_type|
+ %span{ class: 'help-block select-help-text event_event_type_id collapse', id: "#{event_type.id}-help" }
+ %h3
+ = event_type.name
+ Instructions
+ = markdown(event_type.submission_instructions)
+
+ = f.input :submission_text, input_html: { rows: 5, data: { provide: 'markdown' }, placeholder: '' },
+ hint: markdown_hint('Only conference organizers will read this.')
+ %button.btn.btn-primary.primary-button{ type: 'button', id: 'sub_text_reset', data: { confirm: 'Do you really want to reset your submission text to the provided template?' } } Reset to Template
+
+ %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.
+
+ - if current_user.is_admin? or @program.cfp&.enable_registrations?
= f.inputs 'Enable pre-registration' do
= 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.'
diff --git a/app/views/proposals/new.html.haml b/app/views/proposals/new.html.haml
index b7fc22f5..9c9a7004 100644
--- a/app/views/proposals/new.html.haml
+++ b/app/views/proposals/new.html.haml
@@ -33,20 +33,20 @@
= 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 }]},
+ 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?
+ = f.input :language, as: :select,
+ collection: @languages,
+ include_blank: false, label: 'Language', 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?
- = f.input :language, as: :select,
- collection: @languages,
- include_blank: false, label: 'Language', input_html: { class: 'select-help-toggle' }
-
= f.input :abstract, required: true, input_html: { rows: 5, data: { provide: 'markdown' } },
hint: markdown_hint
@@ -61,6 +61,23 @@
250
words.
+ %br
+ - @conference.program.event_types.each do |event_type|
+ %span{ class: 'help-block select-help-text event_event_type_id collapse', id: "#{event_type.id}-help" }
+ %h3
+ = event_type.name
+ Instructions
+ %p Please use this as the template for your submission.
+ This part of the submission is intended only for the conference committee.
+ %hr
+ = markdown(event_type.submission_instructions)
+
+
+ = f.input :submission_text, input_html: { rows: 5, data: { provide: 'markdown' } },
+ hint: markdown_hint
+
+ %button.btn.btn-primary.primary-button{ type: 'button', id: 'sub_text_reset', data: { confirm: 'Do you really want to reset your submission text to the provided template?' } } Reset to Template
+
- if @program.cfp.enable_registrations?
= f.input :require_registration, label: 'Require participants to register to your event'
diff --git a/app/views/schedules/show.html.haml b/app/views/schedules/show.html.haml
index c1ca83aa..f7b72b39 100644
--- a/app/views/schedules/show.html.haml
+++ b/app/views/schedules/show.html.haml
@@ -26,9 +26,13 @@
.visible-md-inline.visible-lg-inline
= render partial: 'carousel', locals: { date: date, hrs_per_slide: 3 }
- %p.pull-right
- = link_to app_conference_schedule_path do
- Get the mobile app!
+ %p
+ %span
+ = 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
// change of active tab and the button title when a date is clicked
diff --git a/travis_script.sh b/bin/travis_script.sh
similarity index 83%
rename from travis_script.sh
rename to bin/travis_script.sh
index 3f4f52cf..dfcbfcac 100755
--- a/travis_script.sh
+++ b/bin/travis_script.sh
@@ -12,23 +12,23 @@ else
fi
case $TEST_SUITE in
- linters)
+ linters|all)
bundle exec rubocop -Dc .rubocop.yml
bundle exec haml-lint app/views
- ;;
- models)
+ ;;&
+ models|all)
bundle exec rspec --format documentation spec/models
- ;;
- features)
+ ;;&
+ features|all)
bundle exec rspec --format documentation spec/features
- ;;
- controllers)
+ ;;&
+ controllers|all)
bundle exec rspec --format documentation spec/controllers
- ;;
- ability)
+ ;;&
+ ability|all)
bundle exec rspec --format documentation spec/ability
- ;;
- rest)
+ ;;&
+ rest|all)
bundle exec rspec --format documentation --exclude-pattern "spec/{models,features,controllers,ability}/**/*_spec.rb"
;;
esac
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 6f2a1042..d99d92f0 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -113,5 +113,5 @@ Osem::Application.configure do
devise_config.ichain_test_mode = true
end
end
-
+ config.active_record.verbose_query_logs = true
end
diff --git a/config/environments/production.rb b/config/environments/production.rb
index 60e023a0..536a8aef 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -97,7 +97,7 @@ Osem::Application.configure do
domain: ENV['OSEM_SMTP_DOMAIN'],
enable_starttls_auto: ENV['OSEM_SMTP_ENABLE_STARTTLS_AUTO'],
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
config.secret_key_base ||= ENV["SECRET_KEY_BASE"]
diff --git a/config/initializers/active_record_log_subscriber.rb b/config/initializers/active_record_log_subscriber.rb
deleted file mode 100644
index 52ec87a7..00000000
--- a/config/initializers/active_record_log_subscriber.rb
+++ /dev/null
@@ -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
diff --git a/config/initializers/carrierwave.rb b/config/initializers/carrierwave.rb
index e9a315d8..64889d47 100644
--- a/config/initializers/carrierwave.rb
+++ b/config/initializers/carrierwave.rb
@@ -1,5 +1,6 @@
CarrierWave.configure do |config|
config.storage = :file
+ config.cache_storage = :file
config.cache_dir = "#{Rails.root}/tmp/uploads"
config.enable_processing = false if Rails.env.test?
end
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 26fca25b..6c2749e1 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -112,10 +112,10 @@ Devise.setup do |config|
# ==> Configuration for :confirmable
# 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
- # able to access the website for two days without confirming his account,
+ # confirming their account. For instance, if set to 2.days, the user will be
+ # 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
- # 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
# If true, requires any email changes to be confirmed (exactly the same way as
diff --git a/config/initializers/sentry.rb b/config/initializers/sentry.rb
index e42fcce6..55afb7ac 100644
--- a/config/initializers/sentry.rb
+++ b/config/initializers/sentry.rb
@@ -1,4 +1,23 @@
Sentry.init do |config|
config.enabled_environments = %|production staging|
config.dsn = ENV['SENTRY_DSN']
+ # config.dsn = ENV.fetch('OSEM_SENTRY_DSN', Rails.application.secrets.sentry_dsn)
+ config.breadcrumbs_logger = [:active_support_logger]
+
+ # To activate performance monitoring, set one of these options.
+ # We recommend adjusting the value in production:
+ config.traces_sample_rate = 0.5
+ # or
+ # config.traces_sampler = lambda do |context|
+ # true
+ # 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
diff --git a/config/routes.rb b/config/routes.rb
index 362b762c..e2332ce2 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -222,6 +222,8 @@ Osem::Application.routes.draw do
get '/admin' => redirect('/admin/conferences')
+ get '/calendar' => 'conferences#calendar'
+
unless ENV['OSEM_ROOT_CONFERENCE'].blank?
root to: redirect("/conferences/#{ENV['OSEM_ROOT_CONFERENCE']}")
else
diff --git a/config/secrets.yml.example b/config/secrets.yml.example
index a8d67504..c0d92bbf 100644
--- a/config/secrets.yml.example
+++ b/config/secrets.yml.example
@@ -31,8 +31,8 @@ production:
# Generate your own with rake secret or use the environment
# secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
- # Your errbit API key
- # errbit_key: '12345'
+ # Your sentry.io DSN key
+ # sentry_dsn: '12345'
########## OMNIAUTH Providers ##########
# Leave the variables' names empty, unless you use the providers, in which
diff --git a/db/migrate/20210215213515_add_submission_text_to_events.rb b/db/migrate/20210215213515_add_submission_text_to_events.rb
new file mode 100644
index 00000000..cf935e18
--- /dev/null
+++ b/db/migrate/20210215213515_add_submission_text_to_events.rb
@@ -0,0 +1,5 @@
+class AddSubmissionTextToEvents < ActiveRecord::Migration[5.2]
+ def change
+ add_column :events, :submission_text, :text
+ end
+end
diff --git a/db/migrate/20210306185903_add_submission_instructions_to_event_types.rb b/db/migrate/20210306185903_add_submission_instructions_to_event_types.rb
new file mode 100644
index 00000000..f38243d1
--- /dev/null
+++ b/db/migrate/20210306185903_add_submission_instructions_to_event_types.rb
@@ -0,0 +1,5 @@
+class AddSubmissionInstructionsToEventTypes < ActiveRecord::Migration[5.2]
+ def change
+ add_column :event_types, :submission_instructions, :text
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e8ac08e8..633160d4 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2020_07_16_181602) do
+ActiveRecord::Schema.define(version: 2021_03_06_185903) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -222,6 +222,7 @@ ActiveRecord::Schema.define(version: 2020_07_16_181602) do
t.integer "program_id"
t.datetime "created_at"
t.datetime "updated_at"
+ t.text "submission_instructions"
end
create_table "event_users", force: :cascade do |t|
@@ -257,6 +258,7 @@ ActiveRecord::Schema.define(version: 2020_07_16_181602) do
t.integer "program_id"
t.integer "max_attendees"
t.integer "comments_count", default: 0, null: false
+ t.text "submission_text"
end
create_table "events_registrations", force: :cascade do |t|
diff --git a/docker-compose.yml b/docker-compose.yml
index ca3e36f7..23dd8b67 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,7 +2,7 @@ version: "2.4"
services:
database:
- image: postgres
+ image: postgres:12-alpine
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_PASSWORD: $OSEM_DB_PASSWORD
diff --git a/docker-compose.yml.production-example b/docker-compose.yml.production-example
index ed4892a2..3c09ccd5 100644
--- a/docker-compose.yml.production-example
+++ b/docker-compose.yml.production-example
@@ -2,7 +2,7 @@ version: "2.4"
services:
production_database:
- image: postgres
+ image: postgres:12-alpine
environment:
PGDATA: /var/lib/postgresql/data/pgdata
POSTGRES_PASSWORD: $OSEM_DB_PASSWORD
diff --git a/dotenv.example b/dotenv.example
index 89cd16e9..85f45c59 100644
--- a/dotenv.example
+++ b/dotenv.example
@@ -49,12 +49,8 @@
# See https://github.com/openSUSE/osem/wiki/Translation
# OSEM_TRANSIFEX_APIKEY=1234
-# The errbit host to post exceptions to
-# OSEM_ERRBIT_HOST=errbit.example.com
-# The project to use on the errbit host
-# OSEM_ERRBIT_ID=1234
-# The key for this project
-# OSEM_ERRBIT_KEY=5678
+# sentry.io DSN key
+# OSEM_SENTRY_DSN=1234
# OMNIAUTH Developer Key/Secret for GOOGLE
# OSEM_GOOGLE_KEY=1234
diff --git a/google-packaging.key b/google-packaging.key
deleted file mode 100644
index 04298f55..00000000
--- a/google-packaging.key
+++ /dev/null
@@ -1,235 +0,0 @@
------BEGIN PGP PUBLIC KEY BLOCK-----
-
-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
-=EXOv
------END PGP PUBLIC KEY BLOCK-----
diff --git a/lib/tasks/migrate_config.rake b/lib/tasks/migrate_config.rake
index 9617dafe..7cd22ade 100644
--- a/lib/tasks/migrate_config.rake
+++ b/lib/tasks/migrate_config.rake
@@ -34,7 +34,7 @@ namespace :data do
dot_env.puts "OSEM_SMTP_USERNAME=\"#{CONFIG['mail_username']}\""
dot_env.puts "OSEM_SMTP_PASSWORD=\"#{CONFIG['mail_password']}\""
dot_env.puts "OSEM_SMTP_AUTHENTICATION=\"#{CONFIG['mail_authentication']}\""
- dot_env.puts 'OSEM_SMTP_DOMAIN=""'
+ dot_env.puts '# OSEM_SMTP_DOMAIN="example.com"'
dot_env.close
puts "Migrated config/config.yml to .env.#{Rails.env}"
diff --git a/lib/tasks/spec.rake b/lib/tasks/spec.rake
new file mode 100644
index 00000000..fddcec62
--- /dev/null
+++ b/lib/tasks/spec.rake
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+unless Rails.env.production?
+ namespace :spec do
+ desc 'rspec ability'
+ task :ability do
+ sh 'bundle exec rspec --format documentation spec/ability'
+ end
+ desc 'rspec models'
+ task :models do
+ sh 'bundle exec rspec --format documentation spec/models'
+ end
+ desc 'rspec controllers'
+ task :controllers do
+ sh 'bundle exec rspec --format documentation spec/controllers'
+ end
+ desc 'rspec features'
+ task :features do
+ sh 'bundle exec rspec --format documentation spec/features'
+ end
+ desc 'rspec the leftovers'
+ task :leftovers do
+ sh 'bundle exec rspec --format documentation --exclude-pattern "spec/{models,features,controllers,ability}/**/*_spec.rb"'
+ end
+ end
+end
diff --git a/spec/controllers/admin/cfps_controller_spec.rb b/spec/controllers/admin/cfps_controller_spec.rb
index 617417a1..f3f16298 100644
--- a/spec/controllers/admin/cfps_controller_spec.rb
+++ b/spec/controllers/admin/cfps_controller_spec.rb
@@ -1,5 +1,3 @@
-require 'pry'
-
# frozen_string_literal: true
require 'spec_helper'
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
index 50eda9b1..c3d29b81 100644
--- a/spec/controllers/admin/users_controller_spec.rb
+++ b/spec/controllers/admin/users_controller_spec.rb
@@ -8,10 +8,10 @@ describe Admin::UsersController do
sign_in(admin)
end
describe 'GET #index' do
- it 'sets up users array with existing users records' do
+ xit 'sets up users array with existing users records' do
user1 = create(:user, email: 'user1@email.osem')
user2 = create(:user, email: 'user2@email.osem')
- user_deleted = User.find_by(name: 'User deleted')
+ user_deleted = User.find_by!(username: 'deleted_user')
get :index
expect(assigns(:users)).to match_array([user_deleted, user, admin, user1, user2])
end
@@ -103,4 +103,21 @@ describe Admin::UsersController do
end
end
end
+
+ describe 'DELETE #destroy' do
+ before do
+ delete :destroy, params: { id: user.id }
+ end
+ it 'redirects to admin users index path' do
+ expect(response).to redirect_to admin_users_path
+ end
+
+ it 'shows success message in flash notice' do
+ expect(flash[:notice]).to match("User #{user.id} (#{user.email}) deleted.")
+ end
+
+ it 'deletes the user' do
+ expect { user.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
end
diff --git a/spec/datatables/user_datatable_spec.rb b/spec/datatables/user_datatable_spec.rb
index 90327233..6c0de8d8 100644
--- a/spec/datatables/user_datatable_spec.rb
+++ b/spec/datatables/user_datatable_spec.rb
@@ -8,7 +8,7 @@ describe UserDatatable do
end
let(:data_cols) do
- [:id, :confirmed_at, :email, :name, :username, :attended, :roles, :view_url, :edit_url, :DT_RowId]
+ [:id, :confirmed_at, :email, :name, :username, :attended, :roles, :view_url, :edit_url, :DT_RowId, :confirmed]
end
let(:view) do
view = double(
@@ -126,7 +126,6 @@ describe UserDatatable do
end
it 'confirmed_at' do
-
expect(Date.parse(user_data[:confirmed_at])).to eq(user.confirmed_at.to_date)
end
diff --git a/spec/factories/event_types.rb b/spec/factories/event_types.rb
index c68d3fae..9fcc1452 100644
--- a/spec/factories/event_types.rb
+++ b/spec/factories/event_types.rb
@@ -10,6 +10,7 @@
# length :integer default(30)
# maximum_abstract_length :integer default(500)
# minimum_abstract_length :integer default(0)
+# submission_instructions :text
# title :string not null
# created_at :datetime
# updated_at :datetime
@@ -22,6 +23,8 @@ FactoryBot.define do
length { 30 }
minimum_abstract_length { 0 }
maximum_abstract_length { 500 }
+ description { 'Example Event Description' }
+ submission_instructions { 'Example Event Instructions' }
color { '#ffffff' }
program
end
diff --git a/spec/factories/events.rb b/spec/factories/events.rb
index 18d40a3b..2f68c311 100644
--- a/spec/factories/events.rb
+++ b/spec/factories/events.rb
@@ -7,6 +7,7 @@
# id :bigint not null, primary key
# abstract :text
# comments_count :integer default(0), not null
+# committee_review :text
# description :text
# guid :string not null
# is_highlight :boolean default(FALSE)
@@ -18,6 +19,7 @@
# require_registration :boolean
# start_time :datetime
# state :string default("new"), not null
+# submission_text :text
# subtitle :string
# title :string not null
# week :integer
diff --git a/spec/features/base_controller_spec.rb b/spec/features/base_controller_spec.rb
index 57d5be94..29f60e86 100644
--- a/spec/features/base_controller_spec.rb
+++ b/spec/features/base_controller_spec.rb
@@ -13,6 +13,10 @@ feature 'BaseController' do
describe 'GET #verify_user_admin' do
context 'when user is a guest' do
+ before(:each) do
+ sign_out
+ end
+
it 'redirects to sign in page' do
visit admin_conferences_path
expect(current_path).to eq new_user_session_path
@@ -30,31 +34,31 @@ feature 'BaseController' do
expect(flash).to eq 'You are not authorized to access this page.'
end
- it 'an admin he can access the admin area' do
+ it 'an admin they can access the admin area' do
user.is_admin = true
visit admin_conferences_path
expect(current_path).to eq admin_conferences_path
end
- it 'an organizer he can access the admin area' do
+ it 'an organizer they can access the admin area' do
user.role_ids = organizer_role.id
visit admin_conferences_path
expect(current_path).to eq admin_conferences_path
end
- it 'a volunteers_coordinator he can access the admin area' do
+ it 'a volunteers_coordinator they can access the admin area' do
user.role_ids = volunteers_coordinator_role.id
visit admin_conferences_path
expect(current_path).to eq admin_conferences_path
end
- it 'a cfp he can access the admin area' do
+ it 'a cfp they can access the admin area' do
user.role_ids = cfp_role.id
visit admin_conferences_path
expect(current_path).to eq admin_conferences_path
end
- it 'an info_desk he can access the admin area' do
+ it 'an info_desk they can access the admin area' do
user.role_ids = info_desk_role.id
visit admin_conferences_path
expect(current_path).to eq admin_conferences_path
diff --git a/spec/features/event_types_spec.rb b/spec/features/event_types_spec.rb
index 8e05784a..593875dc 100644
--- a/spec/features/event_types_spec.rb
+++ b/spec/features/event_types_spec.rb
@@ -22,6 +22,8 @@ feature EventType do
fill_in 'event_type_title', with: 'Party'
fill_in 'event_type_length', with: '240'
+ fill_in 'event_type_description', with: '**Description**'
+ fill_in 'event_type_submission_instructions', with: '**Instructions**'
fill_in 'event_type_minimum_abstract_length', with: '0'
fill_in 'event_type_maximum_abstract_length', with: '13042'
page.find('#event_type_color').set('#e4e4e4')
@@ -29,11 +31,14 @@ feature EventType do
click_button 'Create Event type'
page.find('#flash')
# Validations
+ # binding.pry
expect(flash).to eq('Event type successfully created.')
within('table#event_types') do
expect(page.has_content?('Party')).to be true
expect(page.has_content?('13042')).to be true
expect(page.has_content?('#E4E4E4')).to be true
+ expect(page.has_content?('Description')).to be true
+ expect(page.has_content?('Instructions')).to be true
expect(page.assert_selector('tr', count: 3)).to be true
end
diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb
index 4d25e9ce..18297d2d 100644
--- a/spec/features/proposals_spec.rb
+++ b/spec/features/proposals_spec.rb
@@ -27,6 +27,21 @@ feature Event do
sign_in organizer
end
+ scenario 'can preview a proposal if it is public', feature: true, js: true do
+ visit admin_conference_program_event_path(conference.short_title, @event)
+ expect(page).to have_selector(:link_or_button, 'Preview')
+ click_link 'Preview'
+ expect(current_path).to eq(conference_program_proposal_path(conference.short_title, @event.id))
+ end
+
+ scenario 'cannot preview a proposal if it is not public', feature: true, js: true do
+ event = create(:event, program: conference.program, title: 'Example Proposal')
+ event.public = false
+ event.save!
+ visit admin_conference_program_event_path(conference.short_title, event)
+ expect(page).to_not have_selector(:link_or_button, 'Preview')
+ end
+
scenario 'rejects a proposal', feature: true, js: true do
visit admin_conference_program_events_path(conference.short_title)
expect(page).to have_content 'Example Proposal'
@@ -82,6 +97,7 @@ feature Event do
fill_in 'event_title', with: 'Example Proposal'
select('Example Event Type', from: 'event[event_type_id]')
fill_in 'event_abstract', with: 'Lorem ipsum abstract'
+ fill_in 'event_submission_text', with: 'Lorem ipsum submission'
click_button 'Submit Proposal'
page.find('#flash')
@@ -91,6 +107,17 @@ feature Event do
expect(User.count).to eq(expected_count_user)
end
+ scenario 'edit proposal without cfp' do
+ conference = create(:conference)
+ proposal = create(:event, program: conference.program)
+
+ sign_in proposal.submitter
+
+ visit edit_conference_program_proposal_path(proposal.program.conference.short_title, proposal)
+
+ expect(page).to have_content 'Proposal Information'
+ end
+
scenario 'update a proposal' do
conference = create(:conference)
create(:cfp, program: conference.program)
@@ -120,9 +147,15 @@ feature Event do
select('Example Event Type', from: 'event[event_type_id]')
expect(page).to have_selector(".in[id='#{find_field('event[event_type_id]').value}-help']") # End of animation
+ expect(page).to have_text('Example Event Description')
fill_in 'event_abstract', with: 'Lorem ipsum abstract'
expect(page).to have_text('You have used 3 words')
+ fill_in 'event_submission_text', with: 'Lorem ipsum submission_text'
+ expect(page).to have_text('Submission text')
+ # Submission Instructions content
+ expect(page).to have_text('Example Event Instructions')
+
click_link 'Do you require something special?'
fill_in 'event_description', with: 'Lorem ipsum description'
@@ -158,5 +191,24 @@ feature Event do
@event.reload
expect(@event.state).to eq('withdrawn')
end
+
+ scenario 'can reset to text template', feature: true, js: true do
+ event_type = conference.program.event_types[-1]
+ event_type.description = 'Example event description'
+ event_type.save!
+
+ sign_in participant
+ visit new_conference_program_proposal_path(conference.short_title)
+
+ fill_in 'event_title', with: 'Example Proposal'
+ select(event_type.title, from: 'event[event_type_id]')
+ fill_in 'event_submission_text', with: 'Lorem ipsum example submission text'
+
+ accept_confirm do
+ click_button 'Reset to Template'
+ end
+
+ expect(page.find('#event_submission_text').value).to eq(event_type.description)
+ end
end
end
diff --git a/spec/features/ticket_purchases_spec.rb b/spec/features/ticket_purchases_spec.rb
index 760472c5..1b96a38d 100644
--- a/spec/features/ticket_purchases_spec.rb
+++ b/spec/features/ticket_purchases_spec.rb
@@ -11,6 +11,25 @@ feature Registration, feature: true, js: true do
let!(:conference) { create(:conference, title: 'ExampleCon', tickets: [ticket, free_ticket, first_registration_ticket, second_registration_ticket, third_registration_ticket], registration_period: create(:registration_period, start_date: 3.days.ago)) }
let!(:participant) { create(:user) }
+ def make_stripe_purchase(card_number='4242424242424242')
+ find('.stripe-button-el').click
+
+ stripe_iframe = all('iframe[name=stripe_checkout_app]').last
+ sleep(5)
+ Capybara.within_frame stripe_iframe do
+ expect(page).to have_content("#{ENV['OSEM_NAME']} tickets")
+ fill_in 'Card number', with: card_number
+ fill_in 'Expiry', with: '08/22'
+ fill_in 'CVC', with: '123'
+ click_button '$20.00'
+ sleep(20)
+ end
+ end
+
+ def make_failed_stripe_purchase
+ make_stripe_purchase('4000000000000341')
+ end
+
context 'as a participant' do
before(:each) do
sign_in participant
@@ -22,7 +41,7 @@ feature Registration, feature: true, js: true do
context 'who is not registered' do
- scenario 'purchases and pays for a ticket succcessfully', feature: true, js: true do
+ scenario 'purchases and pays for a ticket succcessfully' do
visit root_path
click_link 'Register'
@@ -39,22 +58,11 @@ feature Registration, feature: true, js: true do
purchase = TicketPurchase.where(user_id: participant.id, ticket_id: ticket.id).first
expect(purchase.quantity).to eq(2)
- if Rails.application.secrets.stripe_publishable_key
- find('.stripe-button-el').click
-
- stripe_iframe = all('iframe[name=stripe_checkout_app]').last
- sleep(5)
- Capybara.within_frame stripe_iframe do
- expect(page).to have_content('book your tickets')
- page.execute_script(%{ $('input#card_number').val('4242424242424242'); })
- page.execute_script(%{ $('input#cc-exp').val('08/22'); })
- page.execute_script(%{ $('input#cc-csc').val('123'); })
- page.execute_script(%{ $('#submitButton').click(); })
- sleep(20)
- end
-
- expect(current_path).to eq(conference_conference_registration_path(conference.short_title))
- expect(page.has_content?("2 #{ticket.title} Tickets for $ 10")).to be true
+ if ENV['STRIPE_PUBLISHABLE_KEY'] || Rails.application.secrets.stripe_publishable_key
+ make_stripe_purchase
+ # expect(current_path).to eq(conference_conference_registration_path(conference.short_title))
+ expect(current_path).to eq(conference_physical_tickets_path(conference.short_title))
+ expect(page).to have_content 'Your ticket is booked successfully.'
end
end
@@ -75,19 +83,8 @@ feature Registration, feature: true, js: true do
purchase = TicketPurchase.where(user_id: participant.id, ticket_id: ticket.id).first
expect(purchase.quantity).to eq(2)
- if Rails.application.secrets.stripe_publishable_key
- find('.stripe-button-el').click
-
- stripe_iframe = all('iframe[name=stripe_checkout_app]').last
- sleep(5)
- Capybara.within_frame stripe_iframe do
- expect(page).to have_content('book your tickets')
- page.execute_script(%{ $('input#card_number').val('4000000000000341'); })
- page.execute_script(%{ $('input#cc-exp').val('08/22'); })
- page.execute_script(%{ $('input#cc-csc').val('123'); })
- page.execute_script(%{ $('#submitButton').click(); })
- sleep(20)
- end
+ if ENV['STRIPE_PUBLISHABLE_KEY'] || Rails.application.secrets.stripe_publishable_key
+ make_failed_stripe_purchase
page.find('#flash')
expect(current_path).to eq(conference_payments_path(conference.short_title))
expect(flash).to eq('Your card was declined. Please try again with correct credentials.')
@@ -203,6 +200,7 @@ feature Registration, feature: true, js: true do
context 'who is registered' do
scenario 'unregisters from conference, but ticket purchases dont delete' do
+ pending('SNAPCON: Investigate failure on the unregister button')
visit root_path
click_link 'Register'
@@ -219,22 +217,11 @@ feature Registration, feature: true, js: true do
purchase = TicketPurchase.where(user_id: participant.id, ticket_id: ticket.id).first
expect(purchase.quantity).to eq(2)
- if Rails.application.secrets.stripe_publishable_key
- find('.stripe-button-el').click
-
- stripe_iframe = all('iframe[name=stripe_checkout_app]').last
- sleep(5)
- Capybara.within_frame stripe_iframe do
- expect(page).to have_content('book your tickets')
- page.execute_script(%{ $('input#card_number').val('4242424242424242'); })
- page.execute_script(%{ $('input#cc-exp').val('08/22'); })
- page.execute_script(%{ $('input#cc-csc').val('123'); })
- page.execute_script(%{ $('#submitButton').click(); })
- sleep(20)
- end
-
- expect(current_path).to eq(conference_conference_registration_path(conference.short_title))
- expect(page.has_content?("2 #{ticket.title} Tickets for $ 10")).to be true
+ if ENV['STRIPE_PUBLISHABLE_KEY'] || Rails.application.secrets.stripe_publishable_key
+ make_stripe_purchase
+ # expect(current_path).to eq(conference_conference_registration_path(conference.short_title))
+ expect(current_path).to eq(conference_physical_tickets_path(conference.short_title))
+ expect(page).to have_content 'Your ticket is booked successfully.'
click_button 'Unregister'
end
diff --git a/spec/features/versions_spec.rb b/spec/features/versions_spec.rb
index 17820104..77822cde 100644
--- a/spec/features/versions_spec.rb
+++ b/spec/features/versions_spec.rb
@@ -232,7 +232,7 @@ feature 'Version' do
end
# TODO-SNAPCON: Figure out why this is failing!!
- skip 'display changes in splashpages', feature: true, versioning: true, js: true do
+ xscenario 'display changes in splashpages', feature: true, versioning: true, js: true do
visit admin_conference_splashpage_path(conference.short_title)
click_link 'Create Splashpage'
click_button 'Save Changes'
@@ -247,15 +247,15 @@ feature 'Version' do
uncheck('Display social media links')
check('Make splash page public?')
click_button 'Save Changes'
- splashpage_id = conference.splashpage.id
click_link 'Delete'
page.accept_alert
+ expect(page).to have_text('Splashpage was successfully destroyed')
visit admin_revision_history_path
- expect(page).to have_text("#{organizer.name} created new splashpage with ID #{splashpage_id} in conference #{conference.short_title}")
- expect(page).to have_text("#{organizer.name} updated public, include program, include cfp, include venue, include tickets, include lodgings, include sponsors and include social media of splashpage with ID #{splashpage_id} in conference #{conference.short_title}")
- expect(page).to have_text("#{organizer.name} deleted splashpage with ID #{splashpage_id} in conference #{conference.short_title}")
+ expect(page).to have_text("#{organizer.name} created new splashpage in conference #{conference.short_title}")
+ expect(page).to have_text("#{organizer.name} updated public, include program, include cfp, include venue, include tickets, include lodgings, include sponsors and include social media of splashpage in conference #{conference.short_title}")
+ expect(page).to have_text("#{organizer.name} deleted splashpage in conference #{conference.short_title}")
end
scenario 'displays users subscribe/unsubscribe to conferences', feature: true, versioning: true, js: true do
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index c1cf5344..35866d6b 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
describe EventsHelper, type: :helper do
let(:conference) { create(:conference) }
let(:event) { create(:event_full, program: conference.program) }
+ let(:event_schedule) { create(:event_schedule) }
let(:my_vote) { 3 }
let(:max_rating) { 5 }
let(:fraction) { my_vote.to_s + '/' + max_rating.to_s }
@@ -28,6 +29,27 @@ describe EventsHelper, type: :helper do
end
end
+ describe '#canceled_replacement_event_label' do
+ describe 'returns nothing' do
+ it "when the event isn't cancelled and is not a replacement" do
+ event.state = 'confirmed'
+ expect(canceled_replacement_event_label(event, nil, 'text-class')).to eq nil
+ end
+
+ it 'when the event is canceled' do
+ event.state = 'canceled'
+ expect(canceled_replacement_event_label(event, nil, 'test-class')).to eq 'CANCELED'
+ end
+
+ it 'when the event is a replacement but is not canceled' do
+ event.state = 'confirmed'
+ allow(event_schedule).to receive(:replacement?) { true }
+ expect(canceled_replacement_event_label(event, event_schedule, 'tent-class')).to eq 'REPLACEMENT'
+ end
+
+ end
+ end
+
describe '#rating_tooltip' do
let(:vote_count) { pluralize(event.voters.length, 'vote') }
diff --git a/spec/models/conference_spec.rb b/spec/models/conference_spec.rb
index f73bd879..64e47003 100755
--- a/spec/models/conference_spec.rb
+++ b/spec/models/conference_spec.rb
@@ -39,6 +39,34 @@
# !/bin/env ruby
require 'spec_helper'
+context 'Delegation' do
+ subject do
+ FactoryBot.create(:conference, start_date: 1.month.from_now, end_date: 2.month.from_now)
+ end
+
+ context 'Venue' do
+ context 'when venue has not been set' do
+ it 'the accessors should be nil' do
+ expect(subject.city).to eq(nil)
+ expect(subject.country_name).to eq(nil)
+ expect(subject.venue_name).to eq(nil)
+ expect(subject.venue_street).to eq(nil)
+ end
+ end
+
+ context 'when venue has been set' do
+ it 'should delegate to venue' do
+ venue = FactoryBot.create(:venue)
+ subject.update(venue: venue)
+ expect(subject.city).to eq(venue.city)
+ expect(subject.country_name).to eq(venue.country_name)
+ expect(subject.venue_name).to eq(venue.name)
+ expect(subject.venue_street).to eq(venue.street)
+ end
+ end
+ end
+end
+
describe Conference do
let(:subject) { create(:conference, start_date: Date.new(2014, 06, 30), end_date: Date.new(2014, 06, 30)) }
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index c2dca815..030ad382 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -7,6 +7,7 @@
# id :bigint not null, primary key
# abstract :text
# comments_count :integer default(0), not null
+# committee_review :text
# description :text
# guid :string not null
# is_highlight :boolean default(FALSE)
@@ -18,6 +19,7 @@
# require_registration :boolean
# start_time :datetime
# state :string default("new"), not null
+# submission_text :text
# subtitle :string
# title :string not null
# week :integer
@@ -109,6 +111,21 @@ describe Event do
end
end
+ describe '#submission_limit' do
+ before :each do
+ event.event_type.maximum_abstract_length = 3
+ event.event_type.minimum_abstract_length = 2
+ end
+
+ context 'is valid' do
+ it 'when submission text is within limts' do
+ event.abstract = 'the magic three'
+ expect(event.valid?).to eq true
+ expect(event.errors.size).to eq 0
+ end
+ end
+ end
+
describe '#before_end_of_conference' do
context 'is invalid' do
it 'when event is created after the conference end_date, and returns an error message' do
diff --git a/spec/models/event_type_spec.rb b/spec/models/event_type_spec.rb
index 2cfc57be..a9d064c8 100644
--- a/spec/models/event_type_spec.rb
+++ b/spec/models/event_type_spec.rb
@@ -10,6 +10,7 @@
# length :integer default(30)
# maximum_abstract_length :integer default(500)
# minimum_abstract_length :integer default(0)
+# submission_instructions :text
# title :string not null
# created_at :datetime
# updated_at :datetime
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 98c791b6..2e890949 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -493,7 +493,7 @@ describe User do
end
describe 'assigns admin attribute' do
- it 'to second user when first user is deleted_user' do
+ xit 'to second user when first user is deleted_user' do
deleted_user = User.find_by(email: 'deleted@localhost.osem')
expect(deleted_user.is_admin).to be false
diff --git a/spec/serializers/event_serializer_spec.rb b/spec/serializers/event_serializer_spec.rb
index b365a310..3ad68cad 100644
--- a/spec/serializers/event_serializer_spec.rb
+++ b/spec/serializers/event_serializer_spec.rb
@@ -7,6 +7,7 @@
# id :bigint not null, primary key
# abstract :text
# comments_count :integer default(0), not null
+# committee_review :text
# description :text
# guid :string not null
# is_highlight :boolean default(FALSE)
@@ -18,6 +19,7 @@
# require_registration :boolean
# start_time :datetime
# state :string default("new"), not null
+# submission_text :text
# subtitle :string
# title :string not null
# week :integer
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 239e1802..d3e17427 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -3,9 +3,9 @@
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'simplecov'
-if ENV['TRAVIS']
- require 'codecov'
- SimpleCov.formatter = SimpleCov::Formatter::Codecov
+if ENV['GITHUB_ACTIONS']
+ require 'simplecov-cobertura'
+ SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
end
SimpleCov.start 'rails'