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

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
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 650
Max: 652
# Offense count: 33
Metrics/CyclomaticComplexity:

View file

@ -1,21 +1,8 @@
language: ruby
cache: bundler
rvm:
- 2.6.6
os: linux
dist: bionic
addons:
apt:
packages:
- chromium-browser
services:
- postgresql
branches:
except:
- /^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:
email:
on_success: change
@ -25,22 +12,9 @@ notifications:
- "chat.freenode.net#osem"
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:
- "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
stages:
- test
- finalize
env:
global:
- OSEM_DB_ADAPTER=sqlite3
@ -49,11 +23,90 @@ env:
- OSEM_DB_NAME='osem_test'
- CC_TEST_REPORTER_ID=$CC_TEST_REPORTER
- CCTR=./cc-test-reporter
matrix:
- TOTAL_TEST_SUITES=5
jobs:
include:
- &tests
language: ruby
cache: bundler
rvm:
- 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
matrix:
fast_finish: false
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
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:

View file

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

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
COPY --chown=1000:1000 . /osem/

15
Gemfile
View file

@ -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
@ -273,6 +270,7 @@ group :development, :test, :linters do
# as debugger
gem 'byebug'
gem 'pry'
gem 'pry-byebug'
# Linters and static analysis.
gem 'pronto', require: false
@ -283,3 +281,8 @@ group :development, :test, :linters do
gem 'haml-lint', require: false
end
group :development, :test do
# as development/test database
gem 'sqlite3'
end

View file

@ -36,9 +36,9 @@ GEM
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_model_serializers (0.10.10)
actionpack (>= 4.1, < 6.1)
activemodel (>= 4.1, < 6.1)
active_model_serializers (0.10.12)
actionpack (>= 4.1, < 6.2)
activemodel (>= 4.1, < 6.2)
case_transform (>= 0.2)
jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
activejob (5.2.4.5)
@ -79,13 +79,13 @@ GEM
ast (2.4.0)
autoprefixer-rails (9.6.4)
execjs
awesome_nested_set (3.2.1)
awesome_nested_set (3.4.0)
activerecord (>= 4.0.0, < 7.0)
aws_cf_signer (0.1.3)
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,7 +104,7 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (~> 1.5)
xpath (~> 3.2)
carrierwave (2.2.0)
carrierwave (2.1.1)
activemodel (>= 5.0.0)
activesupport (>= 5.0.0)
addressable (~> 2.6)
@ -126,9 +126,7 @@ GEM
cloudinary (1.11.1)
aws_cf_signer
rest-client
cocoon (1.2.14)
codecov (0.5.0)
simplecov (>= 0.15, < 0.22)
cocoon (1.2.15)
coderay (1.1.1)
concurrent-ruby (1.1.8)
countable-rails (0.0.1)
@ -144,15 +142,15 @@ 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)
activesupport (>= 3.0, < 6.1)
delayed_job_active_record (4.1.4)
activerecord (>= 3.0, < 6.1)
delayed_job (4.1.9)
activesupport (>= 3.0, < 6.2)
delayed_job_active_record (4.1.5)
activerecord (>= 3.0, < 6.2)
delayed_job (>= 3.0, < 5)
devise (4.7.1)
devise (4.7.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
@ -164,10 +162,10 @@ GEM
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)
@ -191,8 +189,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)
@ -254,11 +252,12 @@ GEM
i18n (1.8.9)
concurrent-ruby (~> 1.0)
i18n_data (0.8.0)
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)
inversion (1.1.1)
loggability (~> 0.12)
io-like (0.3.0)
iso-639 (0.2.8)
jaro_winkler (1.5.3)
@ -288,7 +287,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)
@ -300,7 +298,7 @@ GEM
method_source (0.8.2)
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2021.0212)
mime-types-data (3.2021.0225)
mimemagic (0.3.5)
mina (1.2.3)
open4 (~> 1.3.4)
@ -325,7 +323,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)
@ -371,7 +369,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,18 +378,18 @@ GEM
hashery (~> 2.0)
ruby-rc4
ttfunk
pg (1.1.4)
pg (1.2.3)
piwik_analytics (1.0.2)
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)
@ -419,8 +417,11 @@ 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 (5.2.1)
puma (5.2.2)
nio4r (~> 2.0)
racc (1.5.2)
rack (2.2.3)
@ -462,10 +463,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)
@ -485,12 +486,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)
@ -596,6 +591,8 @@ GEM
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)
@ -632,7 +629,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)
@ -647,8 +644,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)
@ -669,7 +666,6 @@ GEM
chronic (>= 0.6.3)
xpath (3.2.0)
nokogiri (~> 1.8)
yajl-ruby (1.4.1)
PLATFORMS
ruby
@ -696,7 +692,6 @@ DEPENDENCIES
climate_control
cloudinary
cocoon
codecov
countable-rails
country_select
daemons
@ -717,6 +712,7 @@ DEPENDENCIES
guard-rspec
haml-lint
haml-rails
icalendar
iso-639
jquery-datatables
jquery-rails
@ -746,6 +742,7 @@ DEPENDENCIES
pronto-haml
pronto-rubocop
pry
pry-byebug
puma (~> 5.2)
rails (~> 5.2)
rails-assets-bootstrap-markdown!
@ -762,7 +759,6 @@ DEPENDENCIES
rails-assets-waypoints!
rails-controller-testing
rails-i18n
rdoc-generator-fivefish
recaptcha
redcarpet
responders (~> 2.0)
@ -778,6 +774,7 @@ DEPENDENCIES
sentry-rails
sentry-ruby
shoulda-matchers
simplecov-cobertura
skylight
spring-commands-rspec
sprockets-rails

View file

@ -1,7 +1,7 @@
### Spring 2021 Student Project
[![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)
[![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)
[![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)

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({
useCurrent: false,
format: "YYYY-MM-DD"
ignoreReadonly: true,
format: "YYYY-MM-DD",
});
$("#conference-end-datepicker").datetimepicker({
useCurrent: false,
ignoreReadonly: true,
format: "YYYY-MM-DD"
});

View file

@ -49,6 +49,8 @@ $(function () {
$('.' + id).collapse('hide');
$('#' + $(this).val() + '-help.' + id).collapse('show');
$('#' + $(this).val() + '-instructions.' + id).collapse('show');
});
$('.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 */
$( document ).ready(function() {
/* 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 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);
$("#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);
// Set the placeholder text for the abstract
$('#event_submission_text').attr("placeholder", $selected.data("help"));
})
.trigger('change');
}).trigger('change');
/* Count the proposal abstract length */
$("#event_abstract").bind('change keyup paste input', function() {
@ -180,6 +190,18 @@ $( document ).ready(function() {
var max = $selected.data("max-words");
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 */

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";
.dashbox span.fa {
line-height: 1.1em;
margin-bottom: 2px;
@include breakpoint(xs) {
font-size: 1.5em;
}
@include breakpoint(sm) {
font-size: 3em;
font-size: 2em;
}
@include breakpoint(md) {
font-size: 4em;
font-size: 3.5em;
}
@include breakpoint(lg) {
font-size: 5em;
}
}
.dashbox {
padding-top: 20px;
padding-bottom: 20px;
}
.dashbox.panel {
padding: 10px;
display: -webkit-flex;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.4rem;
line-height: 1.6rem;
.dashbox label {
display: block;
font-size: 1.1em;
label {
line-height: 2rem;
}
}
.todolist-missing span {

View file

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

View file

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

View file

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

View file

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

View file

@ -16,6 +16,7 @@ class PaymentsController < ApplicationController
raise CanCan::AccessDenied.new('Nothing to pay for!', :new, Payment)
end
@has_registration_ticket = params[:has_registration_ticket]
@unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference)
end
@ -24,8 +25,15 @@ class PaymentsController < ApplicationController
if @payment.purchase && @payment.save
update_purchased_ticket_purchases
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
@total_amount_to_pay = Ticket.total_price(@conference, current_user, paid: false)
@unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference)

View file

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

View file

@ -8,23 +8,42 @@ class TicketPurchasesController < ApplicationController
def create
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))
if message.blank?
if current_user.ticket_purchases.by_conference(@conference).unpaid.any?
redirect_to new_conference_payment_path,
notice: 'Please pay here to get tickets.'
elsif current_user.ticket_purchases.by_conference(@conference).paid.any?
redirect_to conference_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
# The new ticket_purchase has been added to the database. current_user.ticket_purchases contains the new one.
count_registration_tickets_after = current_user.count_registration_tickets(@conference)
# Failed to create ticket purchase
unless message.blank?
redirect_to conference_tickets_path(@conference.short_title),
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

View file

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

View file

@ -1,5 +1,8 @@
# frozen_string_literal: true
DEFAULT_LOGO = 'snapcon_logo.png'
DEFAULT_COLOR = '#0B3559'
module ConferenceHelper
# Return true if only call_for_papers or call_for_tracks or call_for_booths is open
def one_call_open(*calls)
@ -27,4 +30,51 @@ module ConferenceHelper
markdown(ticket.description.split("\n").first&.strip)
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

View file

@ -60,6 +60,20 @@ module EventsHelper
"#{event.average_rating}/#{max_rating}, #{pluralize(event.voters.length, 'vote')}"
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)
selection = event.event_type.try(:title) || 'Event Type'
options = event_types.collect do |event_type|

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -346,6 +346,17 @@ class User < ApplicationRecord
events.where(program_id: conference.program.id, 'event_users.event_role': 'volunteer')
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?
User.count == 1 && User.first.email == 'deleted@localhost.osem'
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.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

View file

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

View file

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

View file

@ -9,24 +9,27 @@
= 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 :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 :color, hint: 'The color will be used eg for the dashboard.', input_html: {size: 6, type: 'color'}
= f.label 'Conference Logo'
= f.input :description,
hint: markdown_hint('A description of the conference. (Supports unsafe HTML.)'),
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
- if @conference.picture?
= 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.input :custom_css,
hint: "Add Custon CSS to the main page. You might find the class '.conference-#{@conference.short_title}' useful.",
input_html: { rows: 5 }
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: 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.inputs name: 'Scheduling' do
= 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 :end_date, as: :string, input_html: { id: 'conference-end-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' }
= 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.inputs name: 'Registrations' do

View file

@ -3,16 +3,16 @@
Dashboard for #{@conference.title}
%hr
.row
.col-sm-3.col-xs-3
.col-sm-3.col-xs-6
= render "big_statistic",
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",
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",
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",
icon: "archive", subtitle: "Withdrawn", value: @total_withdrawn, delta: @new_withdrawn
@ -29,8 +29,20 @@
= render 'line_chart',
title: 'Submissions per week', data: @submissions
.col-md-4
-# = render 'todo_list',
-# conference_progress: @conference_progress, conference: @conference
- unless @conference.ended?
= 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
.col-md-8
= render 'line_chart',
@ -43,6 +55,7 @@
%a{ href: '#distribution_all', 'data-toggle' => 'tab' }
%span.fa.fa-star
All
-# TODO-SNAP: Disabled for Snap!Con
%li
%a{ href: '#distribution_confirmed', 'data-toggle' => 'tab' }
%span.fa.fa-comment
@ -58,33 +71,33 @@
= render 'donut_chart', title: 'Event types',
combined_data: @event_type_distribution
.col-md-4
-# = render 'donut_chart', title: 'Difficulty levels',
-# combined_data: @difficulty_levels_distribution
= render 'donut_chart', title: 'Difficulty levels',
combined_data: @difficulty_levels_distribution
.col-md-4
-# = render 'donut_chart', title: 'Tracks',
-# 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
.tab-pane#distribution_withdrawn
= render 'donut_chart', title: 'Tracks',
combined_data: @tracks_distribution
-# .tab-pane#distribution_withdrawn
.row
.col-md-4
= render 'donut_chart', title: 'Event types',
combined_data: @event_type_distribution_withdrawn
.col-md-4
= render 'donut_chart', title: 'Difficulty levels',
combined_data: @difficulty_levels_distribution_withdrawn
combined_data: @difficulty_levels_distribution
.col-md-4
= 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
.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 :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' }

View file

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

View file

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

View file

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

View file

@ -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 '<input type="checkbox" class="switch-checkbox" '+
'id="user_'+row.id+'_confirmed" '+
'name="user_'+row.id+'_confirmed" '+
@ -73,6 +75,11 @@
'<a class="btn-primary" href="'+data.edit_url+'">Edit</a>'+
'</div>';
}
},
{
"data": "confirmed",
"className": 'hidden',
"render": false
}
]
});

View file

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

View file

@ -1,13 +1,12 @@
- reverse ||= false
- variant = variant_from_delta(delta, reverse: reverse)
.dashbox.text-center
.dashbox.panel.panel-primary
.paenl-body.text-center
%span.fa
= fa_icon(icon)
= value
%p.text-nowrap
%small
%p
= subtitle.pluralize(value)
%span.label{ class: "label-#{variant}" }
= delta
since you last logged in
.label{ class: "label-#{variant}" }
= delta || 0
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
%label{for: "registration_event_ids_#{event.id}"}
%h3{style: 'margin: 0 auto;'}
= 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}"
%label{ for: "registration_event_ids_#{event.id}" }
%h3{ style: 'margin: 0 auto;' }
= 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}"
= 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)
-# = replacement_event_notice(event_schedule)
-#
%p
= canceled_replacement_event_label(event, event_schedule)
= replacement_event_notice(event_schedule)
%p
- if event.speakers.any?
presented by #{event.speaker_names}
- if event_schedule.present?
.h4.track
%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.end_time.strftime('%H:%M')
%p
= markdown(truncate(event.abstract, length: 250))
-# 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
%span.track
%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

View file

@ -18,6 +18,6 @@
You are registered for #{pluralize(@registration.events.count, 'event')}.
They are at the end of this list.
- @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

View file

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

View file

@ -12,7 +12,7 @@
= 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, escape_html=false)

View file

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

View file

@ -2,13 +2,14 @@
#banner{ style: ("background-image: url(#{conference.picture_url})" if conference.picture_url) }
.container
.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
-# - if conference.picture?
-# .col-md-4
-# = image_tag(conference.picture_url,
-# class: 'img-responsive img-center',
-# id: 'splash-logo')
-#
- if conference.picture?
.col-md-4
= image_tag(conference.picture_url,
class: 'img-responsive img-center',
id: 'splash-logo')
.col-md-8
%h1
= conference.title.html_safe

View file

@ -2,7 +2,7 @@
%li
%a.smoothscroll{ href: '#program' } Program
%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
%section#program

View file

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

View file

@ -22,6 +22,6 @@
.word_break
= short_ticket_description(ticket)
%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)
.trapezoid

View file

@ -18,8 +18,11 @@
#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

View file

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

View file

@ -20,25 +20,23 @@
- if @unpaid_tickets
.row
.col-md-12
.alert.alert-dismissable.alert-info.text-center#unpaid-tickets{role: 'alert'}
%button.button.close{"data-dismiss" => "alert", "aria-label"=>"close"}
.alert.alert-dismissable.alert-info.text-center#unpaid-tickets{ role: 'alert' }
%button.button.close{ "data-dismiss" => "alert", "aria-label"=>"close" }
&times;
%p
You have unpaid tickets. Please complete your purchase.
= link_to('Purchase Tickets', new_conference_payment_path(@conference), class: 'btn btn-success btn-lg')
- if @user_needs_to_register
.row
.col-md-12
.alert.alert-dismissable.alert-warning.text-center#flash{role: 'alert'}
%button.button.close{"data-dismiss" => "alert", 'aria-label': 'close'}
.alert.alert-dismissable.alert-warning.text-center#flash{ role: 'alert' }
%button.button.close{ "data-dismiss" => "alert", 'aria-label': 'close' }
&times;
%p
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')
#splash
- if @conference.code_of_conduct.present?
= render 'code_of_conduct', organization: @conference.organization
@ -79,29 +77,8 @@
sponsorship_levels: @sponsorship_levels,
sponsors: @sponsors
-# footer
- if @conference.splashpage.include_social_media
- if @conference.contact.has_social_media?
= render 'social_media', contact: @conference.contact
= 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
- if devise_mapping.rememberable?
%p.text-right.small
= f.label 'Remember me'
= f.label 'Remember me', for: 'user_remember_me'
= f.check_box :remember_me
%p.text-right
= 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
%span.fa.fa-user
Sign In
-# %li.dropdown.visible-desktop
-# %a.dropdown-toggle{"data-toggle" => "dropdown", href: '#'}
-# %span.fa.fa-user
-# Sign In
-# %span.caret
-# .dropdown-menu
-# - if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
-# = form_tag User.ichain_login_url do
-# = text_field_tag 'username', nil, id: 'user_ichain_email_dd', class: 'form-control', placeholder: 'Username'
-# = password_field_tag 'password', nil, id: 'user_ichain_password_dd', class: 'form-control', placeholder: 'Password'
-# %button.btn.btn-success.btn-block Sign in
-# - else
-# %div{style: "padding: 6px"}
-# = form_tag new_user_session_path, class: 'form-group' do
-# = text_field_tag 'user[login]', nil, id: 'user_login_dd', class: 'form-control', placeholder: 'Username / E-Mail'
-# = password_field_tag 'user[password]', nil, id: 'user_password_dd', class: 'form-control', placeholder: 'Password'
-# %p.text-right
-# %small
-# %label{for: 'user_remember_me'} Remember me
-# = check_box_tag 'user[remember_me]'
-# %br
-# %button.btn.btn-success.btn-block Sign in
-# - unless omniauth_configured.empty?
-# .divider
-# %h6.text-center
-# or
-# = render 'devise/shared/openid_links'
-# %p.text-right
-# %br
-# %a.small.btn.btn-xs.btn-default{"data-toggle" => "collapse", "data-target" => "#navbar-devise-help"}
-# Need Help?
-# #navbar-devise-help.collapse
-# = render 'devise/shared/links'
-#
%li.dropdown.visible-desktop
%a.dropdown-toggle{"data-toggle" => "dropdown", href: '#'}
%span.fa.fa-user
Sign In
%span.caret
.dropdown-menu
- if ENV['OSEM_ICHAIN_ENABLED'] == 'true'
= form_tag User.ichain_login_url do
= text_field_tag 'username', nil, id: 'user_ichain_email_dd', class: 'form-control', placeholder: 'Username'
= password_field_tag 'password', nil, id: 'user_ichain_password_dd', class: 'form-control', placeholder: 'Password'
%button.btn.btn-success.btn-block Sign in
- else
%div{style: "padding: 6px"}
= form_tag new_user_session_path, class: 'form-group' do
= text_field_tag 'user[login]', nil, id: 'user_login_dd', class: 'form-control', placeholder: 'Username / E-Mail'
= password_field_tag 'user[password]', nil, id: 'user_password_dd', class: 'form-control', placeholder: 'Password'
%p.text-right
%small
%label{for: 'user_remember_me'} Remember me
= check_box_tag 'user[remember_me]'
%br
%button.btn.btn-success.btn-block Sign in
- unless omniauth_configured.empty?
.divider
%h6.text-center
or
= render 'devise/shared/openid_links'
%p.text-right
%br
%a.small.btn.btn-xs.btn-default{"data-toggle" => "collapse", "data-target" => "#navbar-devise-help"}
Need Help?
#navbar-devise-help.collapse
= render 'devise/shared/links'
.trapezoid

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
= 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",
'data': {amount: @total_amount_to_pay.cents,
label: "Pay #{humanized_money_with_symbol @total_amount_to_pay}",

View file

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

View file

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

View file

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

View file

@ -11,83 +11,49 @@
= 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?
= f.input :language, as: :select,
collection: @languages,
include_blank: false, label: 'Language', input_html: { class: 'select-help-toggle' }
- @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" }
= event_type.description
= f.input :difficulty_level, as: :select, collection: @conference.program.difficulty_levels, input_html: { class: 'select-help-toggle' },
- if @program.difficulty_levels.present?
= f.input :difficulty_level, as: :select, collection: @program.difficulty_levels,
input_html: { class: 'select-help-toggle' },
include_blank: '(Please select)' if @conference.program.difficulty_levels.any?
- @conference.program.difficulty_levels.each do |difficulty_level|
- @program.difficulty_levels.each do |difficulty_level|
%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.
= render 'proposals/submission_type_content_form', f: f, program: @program
-# 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 }
%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.')
- if current_user.is_admin? or @program.cfp.enable_registrations?
- if @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.'
= 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
= link_to '#description', 'data-toggle' => 'collapse' do
Do you require something special?
#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.'
- 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
- if @event.new_record?
= f.submit 'Submit Proposal', class: 'btn btn-success'
- else
= f.submit 'Update Proposal', class: 'btn btn-success'
= f.submit 'Update Proposal', class: 'btn btn-primary'
:javascript
$(document).ready(function() {

View file

@ -1,13 +1,13 @@
.speakerinfo
.row
.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
%h4
= link_to speaker.name, user_path(speaker.id)
%br
- if speaker.email_public?
= mail_to "#{ speaker.email }" do
= mail_to speaker.email.to_s do
%i.fa.fa-envelope-o.fa-2x
- if speaker.affiliation?
.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
%ul.list-unstyled
- if can? :create, @conference.registrations.new
%li{'class'=>class_for_todo(progress_status['registered'])}
%span{'class'=>icon_for_todo(progress_status['registered'])}
- if progress_status['registered']
%li{class: class_for_todo(progress_status[:registered])}
%span{class: icon_for_todo(progress_status[:registered])}
- if progress_status[:registered]
Speaker(s) registered to the conference
- else
= 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'])}
%span{'class'=>icon_for_todo(progress_status['biographies'])}
- if progress_status['biographies']
%li{class: class_for_todo(progress_status[:biographies])}
%span{class: icon_for_todo(progress_status[:biographies])}
- if progress_status[:biographies]
Speakers have filled out their biographies
- elsif current_user.biography.blank? && event.speakers.include?(current_user)
= link_to 'Fill out your biography', edit_user_path(current_user)
- else
Speakers' biographies missing
%li{'class'=>class_for_todo(progress_status['subtitle'])}
%span{'class'=>icon_for_todo(progress_status['subtitle'])}
%li{class: class_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)
%li{'class'=>class_for_todo(progress_status['commercials'])}
%span{'class'=>icon_for_todo(progress_status['commercials'])}
%li{class: class_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')
- unless progress_status['track'].nil?
%li{'class'=>class_for_todo(progress_status['track'])}
%span{'class'=>icon_for_todo(progress_status['track'])}
- unless progress_status[:track].nil?
%li{class: class_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)
%li{'class'=>class_for_todo(progress_status['difficulty_level'])}
%span{'class'=>icon_for_todo(progress_status['difficulty_level'])}
- unless progress_status[:difficulty_level].nil?
%li{class: class_for_todo(progress_status[:difficulty_level])}
%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
.row
.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
%h4
= link_to speaker.name, user_path(speaker.id)

View file

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

View file

@ -121,7 +121,7 @@
Volunteer Duties
%small
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
.col-md-12

View file

@ -5,6 +5,7 @@
%h1 New #{@conference.title} Proposal
- if @program.cfp_open?
- if @program.cfp.description.present?
%h2 Call for Proposals
.row
.col-md-12
= markdown(@program.cfp.description, escape_html=false)
@ -31,51 +32,22 @@
= f.inputs name: 'Proposal Information' do
= 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?
= 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
%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.
= 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.
- if @program.difficulty_levels.present?
= f.input :difficulty_level, as: :select, collection: @program.difficulty_levels,
input_html: { class: 'select-help-toggle' },
include_blank: '(Please select)' if @conference.program.difficulty_levels.any?
- @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?
= 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.'
%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'}
= 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'
.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" }
- 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
= canceled_replacement_event_label(event, event_schedule)
= replacement_event_notice(event_schedule)
%span.h3{style: "margin-bottom: 14px"}
%span.h3{ style: 'margin-bottom: 14px' }
= event.title
%br
%small{style: "color: #{contrast_color(header_color)}"}
%small{ style: "color: #{contrast_color(header_color)}" }
= event.subtitle
.trapezoid{style: "color: #{header_color}; top: 12px;"}
.trapezoid{ style: "color: #{header_color}; top: 12px;" }
.panel-body
%h4
@ -30,13 +30,13 @@
= inyourtz(event_schedule.start_time) do
%span.track
%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.end_time.strftime('%l:%M %P')
%span.track
%span.fa.fa-map-marker
%span.label{ style: "background-color: grey" }
%span.label{ style: 'background-color: grey' }
= event_schedule.room.name
- if event.track
%span.track

View file

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

View file

@ -26,7 +26,11 @@
.visible-md-inline.visible-lg-inline
= render partial: 'carousel', locals: { date: date, hrs_per_slide: 3 }
%p.pull-right
%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!

View file

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

View file

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

View file

@ -26,7 +26,7 @@ Osem::Application.configure do
config.assets.digest = true
config.assets.css_compressor = :sass
config.assets.js_compressor = :uglifier
config.assets.js_compressor = Uglifier.new(harmony: true)
config.assets.gzip = true
# 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'],
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"]

View file

@ -52,4 +52,5 @@ Osem::Application.configure do
ActiveSupport::Deprecation.silenced = true
end
config.assets.precompile += ['mailbot.css']
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|
config.storage = :file
config.cache_storage = :file
config.cache_dir = "#{Rails.root}/tmp/uploads"
config.enable_processing = false if Rails.env.test?
end

View file

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

View file

@ -1,6 +1,7 @@
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.
@ -10,4 +11,13 @@ Sentry.init do |config|
# 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

View file

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

View file

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

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.
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
enable_extension "plpgsql"
@ -222,6 +222,7 @@ ActiveRecord::Schema.define(version: 2021_03_03_052026) 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|

View file

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

View file

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

View file

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

View file

@ -1,235 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=EXOv
-----END PGP PUBLIC KEY BLOCK-----

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