Merge branch 'master' into make-org-name-unique

This commit is contained in:
James Mason 2018-02-27 11:50:01 -08:00 • committed by GitHub
commit 7543761bf9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
76 changed files with 481 additions and 70 deletions

View file

@ -300,7 +300,7 @@ Lint/UnusedBlockArgument:
# Offense count: 136 # Offense count: 136
Metrics/AbcSize: Metrics/AbcSize:
Max: 86 Max: 98
# Offense count: 258 # Offense count: 258
# Configuration parameters: CountComments, ExcludedMethods. # Configuration parameters: CountComments, ExcludedMethods.
@ -320,7 +320,7 @@ Metrics/LineLength:
# Offense count: 133 # Offense count: 133
# Configuration parameters: CountComments. # Configuration parameters: CountComments.
Metrics/MethodLength: Metrics/MethodLength:
Max: 56 Max: 63
# Offense count: 4 # Offense count: 4
# Configuration parameters: CountComments. # Configuration parameters: CountComments.

View file

@ -38,7 +38,10 @@ RUN chown -R osem.root /osem/ && \
# data directory is used to cache the secret key in a file # data directory is used to cache the secret key in a file
ENV DATA_DIR /data ENV DATA_DIR /data
RUN install -d -m 0770 -o osem -g root $DATA_DIR RUN install -d -m 0770 -o osem -g root $DATA_DIR
VOLUME ["$DATA_DIR"] # data persistence for uploaded files (logos, other pictures, etc)
RUN mkdir 0775 -p /osem/tmp/cache /osem/tmp/uploads/ && \
chown -R osem.osem /osem/tmp/
VOLUME ["$DATA_DIR", "/osem/tmp/uploads/", "/osem/public/system/"]
USER osem USER osem
EXPOSE 9292 EXPOSE 9292

View file

@ -209,6 +209,9 @@ gem 'sprockets-rails'
# for multiple speakers select on proposal/event forms # for multiple speakers select on proposal/event forms
gem 'selectize-rails' gem 'selectize-rails'
# For collecting performance data
gem 'skylight'
# Nokogiri < 1.8.1 is subject to: # Nokogiri < 1.8.1 is subject to:
# CVE-2017-0663, CVE-2017-7375, CVE-2017-7376, CVE-2017-9047, CVE-2017-9048, # CVE-2017-0663, CVE-2017-7375, CVE-2017-7376, CVE-2017-9047, CVE-2017-9048,
# CVE-2017-9049, CVE-2017-9050 # CVE-2017-9049, CVE-2017-9050

View file

@ -297,7 +297,7 @@ GEM
nenv (0.3.0) nenv (0.3.0)
netrc (0.11.0) netrc (0.11.0)
nio4r (2.1.0) nio4r (2.1.0)
nokogiri (1.8.1) nokogiri (1.8.2)
mini_portile2 (~> 2.3.0) mini_portile2 (~> 2.3.0)
notiffany (0.1.1) notiffany (0.1.1)
nenv (~> 0.1) nenv (~> 0.1)
@ -505,6 +505,8 @@ GEM
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.0) simplecov-html (0.10.0)
sixarm_ruby_unaccent (1.1.1) sixarm_ruby_unaccent (1.1.1)
skylight (1.5.1)
activesupport (>= 3.0.0)
slop (3.6.0) slop (3.6.0)
sort_alphabetical (1.0.2) sort_alphabetical (1.0.2)
unicode_utils (>= 1.2.2) unicode_utils (>= 1.2.2)
@ -668,6 +670,7 @@ DEPENDENCIES
sass-rails (>= 4.0.2) sass-rails (>= 4.0.2)
selectize-rails selectize-rails
shoulda-matchers shoulda-matchers
skylight
spring-commands-rspec spring-commands-rspec
sprockets-rails sprockets-rails
sqlite3 sqlite3

View file

@ -106,6 +106,8 @@ There are a couple of environment variables you can set to configure OSEM. Check
| STRIPE_PUBLISHABLE_KEY | *string* | Publishable Key for Stripe Gateway | STRIPE_PUBLISHABLE_KEY | *string* | Publishable Key for Stripe Gateway
| STRIPE_SECRET_KEY | *string* | Secret Key for Stripe Gateway | STRIPE_SECRET_KEY | *string* | Secret Key for Stripe Gateway
| OSEM_REDIS_URL | *string* | Redis server URL e.g. redis://localhost:6379/1 | OSEM_REDIS_URL | *string* | Redis server URL e.g. redis://localhost:6379/1
| SKYLIGHT_AUTHENTICATION | *string* | (Optional) Authentication token for Skylight
| SKYLIGHT_PUBLIC_DASHBOARD_URL | *string* | (Optional) URL to your public Skylight dashboard
### Online Ticket Payments ### Online Ticket Payments
We use [Stripe](https://stripe.com) for accepting your ticket payments securely over the web. We use [Stripe](https://stripe.com) for accepting your ticket payments securely over the web.
@ -130,3 +132,8 @@ Open a separate terminal and go into the directory where the rails app is presen
``` ```
bundle exec rake jobs:work bundle exec rake jobs:work
``` ```
## Performance
If you are experiencing performance issues (or just curious), you may be able to [apply a free Skylight account](https://www.skylight.io/oss).
Once you have your account setup, simply set `SKYLIGHT_AUTHENTICATION` and `SKYLIGHT_PUBLIC_DASHBOARD_URL` in your `.env` file.
If you are reporting a performance issue or submiting a performance patch, it would be helpful (but not required) to link to the relevant Skylight data.

BIN
app/assets/fonts/mastodon.eot Executable file

Binary file not shown.

BIN
app/assets/fonts/mastodon.otf Executable file

Binary file not shown.

14
app/assets/fonts/mastodon.svg Executable file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Copyright (C) 2017 by original authors @ fontello.com</metadata>
<defs>
<font id="mastodon" horiz-adv-x="1000" >
<font-face font-family="mastodon" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
<missing-glyph horiz-adv-x="1000" />
<glyph glyph-name="logo" unicode="&#xe800;" d="M947 251c-14-71-123-148-248-163-66-8-130-15-199-12-112 5-200 27-200 27 0-11 0-21 2-31 14-111 109-118 200-121 91-3 172 23 172 23l3-83c0 0-63-34-177-40-62-3-140 2-230 25-197 52-230 262-235 474-2 63-1 122-1 172 0 217 142 280 142 280 72 33 195 47 323 48l3 0c128-1 251-15 322-48 0 0 142-63 142-280 0 0 2-160-19-271m-148 254l0-263-104 0 0 255c0 54-23 81-68 81-50 0-75-32-75-96l0-140-104 0 0 140c0 64-25 96-75 96-45 0-68-27-68-81l0-255-104 0 0 263c0 54 14 96 41 128 29 31 66 48 112 48 53 0 93-21 120-62l26-43 26 43c27 41 67 62 120 62 46 0 83-17 112-48 27-32 41-74 41-128" horiz-adv-x="1000" />
<glyph glyph-name="logo_alt" unicode="&#xe801;" d="M945 251c-14-71-122-148-247-163-65-8-129-15-198-12-112 5-200 27-200 27 0-11 1-22 2-31 15-111 110-118 199-121 91-3 172 23 172 23l4-83c0 0-64-34-177-40-62-4-139 1-230 25-195 52-229 262-234 474-1 63 0 122 0 172 0 217 141 280 141 280 72 33 194 47 322 48l3 0c127-1 250-15 321-48 0 0 142-63 142-280 0 0 2-160-20-271m-628 183c0-39-31-70-70-70-38 0-70 31-70 70 0 39 32 71 70 71 39 0 70-32 70-71m253 0c0-39-31-70-70-70-39 0-70 31-70 70 0 39 31 71 70 71 39 0 70-32 70-71m253 0c0-39-32-70-70-70-39 0-70 31-70 70 0 39 31 71 70 71 38 0 70-32 70-71" horiz-adv-x="1000" />
</font>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
app/assets/fonts/mastodon.ttf Executable file

Binary file not shown.

BIN
app/assets/fonts/mastodon.woff Executable file

Binary file not shown.

View file

@ -18,4 +18,5 @@
*= require osem-navbar *= require osem-navbar
*= require selectize *= require selectize
*= require selectize.bootstrap3 *= require selectize.bootstrap3
*= require mastodon
*/ */

View file

@ -0,0 +1,45 @@
@font-face {
font-family: 'mastodon';
src: font-url('mastodon.eot');
src: local('☺'),
font-url('mastodon.otf') format('opentype'),
font-url('mastodon.woff') format('woff'),
font-url('mastodon.ttf') format('truetype'),
font-url('mastodon.svg') format('svg');
font-weight: normal;
font-style: normal;
}
[class^="icon-"]:before, [class*=" icon-"]:before {
font-family: "mastodon";
font-style: normal;
font-weight: normal;
speak: none;
display: inline-block;
text-decoration: inherit;
width: 1em;
margin-right: .2em;
text-align: center;
/* opacity: .8; */
/* For safety - reset parent styles, that can break glyph codes*/
font-variant: normal;
text-transform: none;
/* fix buttons height, for twitter bootstrap */
line-height: 1em;
/* you can be more comfortable with increased icons size */
/* font-size: 120%; */
/* Font smoothing. That was taken from TWBS */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
/* Uncomment for 3D effect */
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
}
.icon-mastodon:before { content: '\e800'; } /* '' */
.icon-mastodon_alt:before { content: '\e801'; } /* '' */

View file

@ -1,4 +1,4 @@
@import "breakpoints.css.scss"; @import "breakpoints.scss";
.dashbox span.fa { .dashbox span.fa {
line-height: 1.1em; line-height: 1.1em;

View file

@ -1,4 +1,4 @@
@import "breakpoints.css.scss"; @import "breakpoints.scss";
.nav-osem { .nav-osem {
border: none; border: none;
@include breakpoint(xs) { @include breakpoint(xs) {

View file

@ -1,4 +1,4 @@
@import "breakpoints.css.scss"; @import "breakpoints.scss";
#splash { #splash {
// Counter the general padding for #content // Counter the general padding for #content

View file

@ -115,3 +115,9 @@ p.comment-body {
float: right; float: right;
} }
} }
/* omniauth btn grp */
#openid-btn-grp{
display: flex;
justify-content: center;
}

View file

@ -20,6 +20,10 @@ module Admin
@total_submissions = Event.count @total_submissions = Event.count
@new_submissions = Event.where('created_at > ?', current_user.last_sign_in_at).count @new_submissions = Event.where('created_at > ?', current_user.last_sign_in_at).count
@total_withdrawn = Event.where(state: :withdrawn).count
@new_withdrawn = Event
.where('state = ? and created_at > ?', 'withdrawn', current_user.last_sign_in_at).count
@active_conferences = Conference.get_active_conferences_for_dashboard # pending or the last two @active_conferences = Conference.get_active_conferences_for_dashboard # pending or the last two
@deactive_conferences = Conference @deactive_conferences = Conference
.get_conferences_without_active_for_dashboard(@active_conferences) # conferences without active .get_conferences_without_active_for_dashboard(@active_conferences) # conferences without active
@ -116,13 +120,19 @@ module Admin
@total_reg = @conference.registrations.count @total_reg = @conference.registrations.count
@new_reg = @conference.registrations.where('created_at > ?', current_user.last_sign_in_at).count @new_reg = @conference.registrations.where('created_at > ?', current_user.last_sign_in_at).count
@total_submissions = @program.events.count @all_events = @program.events
@new_submissions = @program.events
@total_submissions = @all_events.count
@new_submissions = @all_events
.where('created_at > ?', current_user.last_sign_in_at).count .where('created_at > ?', current_user.last_sign_in_at).count
@program_length = @conference.current_program_hours @program_length = @conference.current_program_hours
@new_program_length = @conference.new_program_hours(current_user.last_sign_in_at) @new_program_length = @conference.new_program_hours(current_user.last_sign_in_at)
@total_withdrawn = @all_events.where(state: :withdrawn).count
@new_withdrawn = @all_events
.where('state = "withdrawn" and created_at > ?', current_user.last_sign_in_at).count
# Step by step list # Step by step list
@conference_progress = @conference.get_status @conference_progress = @conference.get_status
@ -162,13 +172,17 @@ module Admin
# Doughnut charts # Doughnut charts
@event_type_distribution = @conference.event_type_distribution @event_type_distribution = @conference.event_type_distribution
@event_type_distribution_confirmed = @conference.event_type_distribution(:confirmed) @event_type_distribution_confirmed = @conference.event_type_distribution(:confirmed)
@event_type_distribution_withdrawn = @conference.event_type_distribution(:withdrawn)
@difficulty_levels_distribution = @conference.difficulty_levels_distribution @difficulty_levels_distribution = @conference.difficulty_levels_distribution
@difficulty_levels_distribution_confirmed = @conference @difficulty_levels_distribution_confirmed = @conference
.difficulty_levels_distribution(:confirmed) .difficulty_levels_distribution(:confirmed)
@difficulty_levels_distribution_withdrawn = @conference
.difficulty_levels_distribution(:withdrawn)
@tracks_distribution = @conference.tracks_distribution @tracks_distribution = @conference.tracks_distribution
@tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed) @tracks_distribution_confirmed = @conference.tracks_distribution(:confirmed)
@tracks_distribution_withdrawn = @conference.tracks_distribution(:withdrawn)
# Recent actions information # Recent actions information
@recent_events = @conference.program.events.limit(5).order(created_at: :desc) @recent_events = @conference.program.events.limit(5).order(created_at: :desc)

View file

@ -22,7 +22,7 @@ module Admin
# Only allow a trusted parameter "white list" through. # Only allow a trusted parameter "white list" through.
def contact_params def contact_params
params.require(:contact).permit(:social_tag, :email, :facebook, :googleplus, :twitter, :instagram, :public, :sponsor_email) params.require(:contact).permit(:social_tag, :email, :facebook, :googleplus, :twitter, :instagram, :mastodon, :public, :sponsor_email)
end end
end end
end end

View file

@ -20,6 +20,11 @@ class ConferencesController < ApplicationController
authorize! :show, @conference # TODO: reduce the 10 queries performed here authorize! :show, @conference # TODO: reduce the 10 queries performed here
splashpage = @conference.splashpage splashpage = @conference.splashpage
unless splashpage.present?
redirect_to admin_conference_splashpage_path(@conference.short_title) && return
end
if splashpage.include_cfp if splashpage.include_cfp
cfps = @conference.program.cfps cfps = @conference.program.cfps
@call_for_events = cfps.find { |call| call.cfp_type == 'events' } @call_for_events = cfps.find { |call| call.cfp_type == 'events' }
@ -50,6 +55,7 @@ class ConferencesController < ApplicationController
@sponsorship_levels = @conference.sponsorship_levels.eager_load( @sponsorship_levels = @conference.sponsorship_levels.eager_load(
:sponsors :sponsors
).order('sponsorship_levels.position ASC', 'sponsors.name') ).order('sponsorship_levels.position ASC', 'sponsors.name')
@sponsors = @conference.sponsors
end end
end end

View file

@ -10,7 +10,7 @@ class PhysicalTicketsController < ApplicationController
end end
def show def show
@file_name = "ticket_for_#{@conference.short_title}" @file_name = "ticket_for_#{@conference.short_title}.pdf"
@user = @physical_ticket.user @user = @physical_ticket.user
@ticket_layout = @conference.ticket_layout.to_sym @ticket_layout = @conference.ticket_layout.to_sym
@qrcode_image = RQRCode::QRCode.new(@physical_ticket.token).as_png(size: 180, border_modules: 0) @qrcode_image = RQRCode::QRCode.new(@physical_ticket.token).as_png(size: 180, border_modules: 0)

View file

@ -66,7 +66,13 @@ class Ability
can [:new, :create], Registration do |registration| can [:new, :create], Registration do |registration|
conference = registration.conference conference = registration.conference
conference.registration_open? && !conference.registration_limit_exceeded? || conference.program.speakers.confirmed.include?(user) if conference.user_registered? user
false
elsif conference.program.speakers.confirmed.include?(user) && conference.registration_period
true
else
conference.registration_open? && !conference.registration_limit_exceeded?
end
end end
can :index, Organization can :index, Organization

View file

@ -595,11 +595,11 @@ class Conference < ApplicationRecord
# * +ActiveRecord+ # * +ActiveRecord+
def self.get_active_conferences_for_dashboard def self.get_active_conferences_for_dashboard
result = Conference.where('start_date > ?', Time.now) result = Conference.where('start_date > ?', Time.now)
.select('id, short_title, color, start_date') .select('id, short_title, color, start_date, organization_id')
if result.empty? if result.empty?
result = Conference result = Conference
.select('id, short_title, color, start_date').limit(2) .select('id, short_title, color, start_date, organization_id').limit(2)
.order(start_date: :desc) .order(start_date: :desc)
end end
result result
@ -611,7 +611,7 @@ class Conference < ApplicationRecord
# ====Returns # ====Returns
# * +ActiveRecord+ # * +ActiveRecord+
def self.get_conferences_without_active_for_dashboard(active_conferences) def self.get_conferences_without_active_for_dashboard(active_conferences)
result = Conference.select('id, short_title, color, start_date').order(start_date: :desc) result = Conference.select('id, short_title, color, start_date, organization_id').order(start_date: :desc)
result - active_conferences result - active_conferences
end end
@ -719,7 +719,7 @@ class Conference < ApplicationRecord
# * +True+ -> If the registration limit has been reached or exceeded # * +True+ -> If the registration limit has been reached or exceeded
# * +False+ -> If the registration limit hasn't been exceeded # * +False+ -> If the registration limit hasn't been exceeded
def registration_limit_exceeded? def registration_limit_exceeded?
registration_limit > 0 && registrations.count + program.speakers.confirmed.count - program.speakers.confirmed.registered(program.conference).count >= registration_limit registration_limit > 0 && registrations.count + program.speakers.confirmed.unregistered(program.conference).count >= registration_limit
end end
# Returns an hexadecimal color given a collection. The returned color changed # Returns an hexadecimal color given a collection. The returned color changed
@ -1029,7 +1029,7 @@ class Conference < ApplicationRecord
# * +hash+ -> object_type => {color, value} # * +hash+ -> object_type => {color, value}
def calculate_event_distribution(group_by_id, association_symbol, state = nil) def calculate_event_distribution(group_by_id, association_symbol, state = nil)
grouped = if state grouped = if state
program.events.select(group_by_id).where('state = ?', 'confirmed').group(group_by_id) program.events.select(group_by_id).where('state = ?', state).group(group_by_id)
else else
program.events.select(group_by_id).group(group_by_id) program.events.select(group_by_id).group(group_by_id)
end end

View file

@ -5,11 +5,11 @@ class Contact < ApplicationRecord
validates :conference, presence: true validates :conference, presence: true
# Conferences only have one contact # Conferences only have one contact
validates :facebook, :twitter, :googleplus, :instagram, validates :facebook, :twitter, :googleplus, :instagram, :mastodon,
format: URI::regexp(%w(http https)), allow_blank: true format: URI::regexp(%w(http https)), allow_blank: true
def has_social_media? def has_social_media?
return true if facebook.present? || twitter.present? || googleplus.present? || instagram.present? || email.present? return true if facebook.present? || twitter.present? || googleplus.present? || instagram.present? || mastodon.present? || email.present?
false false
end end
end end

View file

@ -51,6 +51,10 @@ class Program < ApplicationRecord
def registered(conference) def registered(conference)
joins(:registrations).where('registrations.conference_id = ?', conference.id) joins(:registrations).where('registrations.conference_id = ?', conference.id)
end end
def unregistered(conference)
self - registered(conference)
end
end end
accepts_nested_attributes_for :event_types, allow_destroy: true accepts_nested_attributes_for :event_types, allow_destroy: true

View file

@ -1,4 +1,5 @@
class Registration < ApplicationRecord class Registration < ApplicationRecord
require 'csv'
belongs_to :user belongs_to :user
belongs_to :conference belongs_to :conference

View file

@ -62,7 +62,11 @@ class Ticket < ApplicationRecord
def tickets_turnover_total(id) def tickets_turnover_total(id)
tickets = TicketPurchase.where(ticket_id: id).paid tickets = TicketPurchase.where(ticket_id: id).paid
tickets.inject(0){ |sum, ticket| sum + (ticket.amount_paid * ticket.quantity) } if tickets.blank?
Money.new(0, Ticket.find(id).price_currency)
else
tickets.inject(Money.new(0, tickets.first.price_currency)){ |sum, ticket| sum + (ticket.amount_paid * ticket.quantity) }
end
end end
def tickets_sold def tickets_sold

View file

@ -1,6 +1,7 @@
.row .row
.col-md-12 .col-md-12
%h3 %h3
- if @booth.logo_link
= image_tag( @booth.picture.thumb.url, size: '20%', alt: '') = image_tag( @booth.picture.thumb.url, size: '20%', alt: '')
= @booth.title = @booth.title
.btn-group.pull-right .btn-group.pull-right

View file

@ -11,7 +11,7 @@
.col-md-8 .col-md-8
= semantic_form_for(@campaign, url: (@campaign.new_record? ? admin_conference_campaigns_path : admin_conference_campaign_path(@conference.short_title, @campaign))) do |f| = semantic_form_for(@campaign, url: (@campaign.new_record? ? admin_conference_campaigns_path : admin_conference_campaign_path(@conference.short_title, @campaign))) do |f|
= f.inputs do = f.inputs do
= f.input :name = f.input :name, input_html: { autofocus: true }
= f.inputs name: 'UTM Parameters' do = f.inputs name: 'UTM Parameters' do
= f.input :utm_campaign, label: 'Campaign', hint: 'Groups all of the content from one campaign. E.g. 20percentpromocode' = f.input :utm_campaign, label: 'Campaign', hint: 'Groups all of the content from one campaign. E.g. 20percentpromocode'
= f.input :utm_source, label: 'Source', hint: 'Which website is sending you traffic. E.g. Facebook, google+, blog' = f.input :utm_source, label: 'Source', hint: 'Which website is sending you traffic. E.g. Facebook, google+, blog'

View file

@ -7,7 +7,7 @@
- if @program.cfps - if @program.cfps
.row .row
.col-md-12 .col-md-12
%table.table.table-hover.datatable#tickets %table.table.table-hover#tickets
%thead %thead
%th Type %th Type
%th Start Date %th Start Date

View file

@ -14,7 +14,7 @@
.row .row
.col-md-6 .col-md-6
= semantic_form_for(@commercial, url: admin_conference_commercials_path(conference_id: @conference.short_title)) do |f| = semantic_form_for(@commercial, url: admin_conference_commercials_path(conference_id: @conference.short_title)) do |f|
= f.input :url, label: 'URL', as: :string, input_html: { required: 'required' }, = f.input :url, label: 'URL', as: :string, input_html: { required: 'required', autofocus: true },
hint: 'Just paste the url of your video/photo provider. YouTube, Vimeo, SpeakerDeck, SlideShare, Instagram, Flickr.' hint: 'Just paste the url of your video/photo provider. YouTube, Vimeo, SpeakerDeck, SlideShare, Instagram, Flickr.'
= f.action :submit, as: :button, button_html: { class: 'btn btn-primary pull-right', disabled: true } = f.action :submit, as: :button, button_html: { class: 'btn btn-primary pull-right', disabled: true }
%hr %hr

View file

@ -1,6 +1,6 @@
.text-center .text-center
%h4 #{title} %h4 #{title}
%canvas.doughnut_chart{ id: "dough_#{title}", 'data-chart' => data.to_json } %canvas.doughnut_chart{ id: "dough_#{title.parameterize.underscore}", 'data-chart' => data.to_json }
- if data - if data
- data.each do |key, value| - data.each do |key, value|
%span{ 'style' => "border-bottom: 3px solid #{value['color']}" } #{key}: #{value['value']} %span{ 'style' => "border-bottom: 3px solid #{value['color']}" } #{key}: #{value['value']}
@ -8,7 +8,7 @@
:javascript :javascript
$(document).ready( function(){ $(document).ready( function(){
var d = $("#dough_#{title}"); var d = $("#dough_#{title.parameterize.underscore}");
var dt = d.get(0).getContext('2d'); var dt = d.get(0).getContext('2d');
$(window).resize( respondCanvas ); $(window).resize( respondCanvas );

View file

@ -1,5 +1,5 @@
.row .row
.col-sm-4.col-xs-4 .col-sm-3.col-xs-3
.dashbox.text-center .dashbox.text-center
%span.fa.fa-user.fa-lg %span.fa.fa-user.fa-lg
%span.fa.fa-lg %span.fa.fa-lg
@ -11,7 +11,7 @@
%span.label.label-success{ title: "+ #{@new_user} since you last logged in!" } %span.label.label-success{ title: "+ #{@new_user} since you last logged in!" }
+ +
= @new_user = @new_user
.col-sm-4.col-xs-4 .col-sm-3.col-xs-3
.dashbox.text-center .dashbox.text-center
%span.fa.fa-check-square.fa-lg %span.fa.fa-check-square.fa-lg
%span.fa.fa-lg %span.fa.fa-lg
@ -23,7 +23,7 @@
%span.label.label-success{ title: "+#{@new_reg} since you last logged in!" } %span.label.label-success{ title: "+#{@new_reg} since you last logged in!" }
+ +
= @new_reg = @new_reg
.col-sm-4.col-xs-4 .col-sm-3.col-xs-3
.dashbox.text-center .dashbox.text-center
%span.fa.fa-file-text.fa-lg %span.fa.fa-file-text.fa-lg
%span.fa.fa-lg %span.fa.fa-lg
@ -35,6 +35,18 @@
%span.label.label-success{ title: "+#{@new_submissions} since you last logged in!" } %span.label.label-success{ title: "+#{@new_submissions} since you last logged in!" }
+ +
= @new_submissions = @new_submissions
.col-sm-3.col-xs-3
.dashbox.text-center
%span.fa.fa-archive.fa-lg
%span.fa.fa-lg
= @total_withdrawn
%p
%small
#{'Withdrawn'.pluralize(@total_withdrawn)}
- if @new_withdrawn
%span.label.label-success{ title: "+#{@new_withdrawn} since you last logged in!" }
+
= @new_withdrawn
.row#registrations .row#registrations
.col-md-8 .col-md-8

View file

@ -3,7 +3,7 @@
Dashboard for #{@conference.title} Dashboard for #{@conference.title}
%hr %hr
.row .row
.col-sm-4.col-xs-4 .col-sm-3.col-xs-3
.dashbox.text-center .dashbox.text-center
%span.fa.fa-user.fa-lg %span.fa.fa-user.fa-lg
%span.fa.fa-lg %span.fa.fa-lg
@ -16,7 +16,7 @@
+ +
= @new_reg = @new_reg
.col-sm-4.col-xs-4 .col-sm-3.col-xs-3
.dashbox.text-center .dashbox.text-center
%span.fa.fa-check-square.fa-lg %span.fa.fa-check-square.fa-lg
%span.fa.fa-lg %span.fa.fa-lg
@ -29,7 +29,7 @@
+ +
= @new_submissions = @new_submissions
.col-sm-4.col-xs-4 .col-sm-3.col-xs-3
.dashbox.text-center .dashbox.text-center
%span.fa.fa-file-text.fa-lg %span.fa.fa-file-text.fa-lg
%span.fa.fa-lg %span.fa.fa-lg
@ -42,6 +42,19 @@
+ +
= @new_program_length = @new_program_length
.col-sm-3.col-xs-3
.dashbox.text-center
%span.fa.fa-archive.fa-lg
%span.fa.fa-lg
= @total_withdrawn
%p
%small
#{'Withdrawn'.pluralize(@total_withdrawn)}
- if @new_withdrawn
%span.label.label-success{ title: "+#{@new_withdrawn} since you last logged in!" }
+
= @new_withdrawn
.row .row
.col-md-12 .col-md-12
.row .row
@ -91,6 +104,10 @@
%a{ href: '#distribution_confirmed', 'data-toggle' => 'tab' } %a{ href: '#distribution_confirmed', 'data-toggle' => 'tab' }
%span.fa.fa-comment %span.fa.fa-comment
Confirmed Confirmed
%li
%a{ href: '#distribution_withdrawn', 'data-toggle' => 'tab' }
%span.fa.fa-archive
Withdrawn
.tab-content .tab-content
.tab-pane.active#distribution_all .tab-pane.active#distribution_all
.row .row
@ -108,6 +125,14 @@
= render partial: 'doughnut_chart', locals: {title: 'Difficulty levels', data: @difficulty_levels_distribution_confirmed} = render partial: 'doughnut_chart', locals: {title: 'Difficulty levels', data: @difficulty_levels_distribution_confirmed}
.col-md-4 .col-md-4
= render partial: 'doughnut_chart', locals: {title: 'Tracks', data: @tracks_distribution_confirmed} = render partial: 'doughnut_chart', locals: {title: 'Tracks', data: @tracks_distribution_confirmed}
.tab-pane#distribution_withdrawn
.row
.col-md-4
= render partial: 'doughnut_chart', locals: {title: 'Event types', data: @event_type_distribution_withdrawn}
.col-md-4
= render partial: 'doughnut_chart', locals: {title: 'Difficulty levels', data: @difficulty_levels_distribution_withdrawn}
.col-md-4
= render partial: 'doughnut_chart', locals: {title: 'Tracks', data: @tracks_distribution_withdrawn}
.row .row
.col-md-8 .col-md-8

View file

@ -8,7 +8,7 @@
.col-md-8 .col-md-8
= semantic_form_for(@contact, url: admin_conference_contact_path(@conference.short_title), html: {multipart: true}) do |f| = semantic_form_for(@contact, url: admin_conference_contact_path(@conference.short_title), html: {multipart: true}) do |f|
= f.inputs name: 'Mail' do = f.inputs name: 'Mail' do
= f.input :email, hint: 'Contact email address for your conference. Will be used as reply-to address in emails sent out by the system.' = f.input :email, input_html: { autofocus: true }, hint: 'Contact email address for your conference. Will be used as reply-to address in emails sent out by the system.'
= f.input :sponsor_email, hint: 'This will appear in the sponsor segment of the splash for the sponsors to contact to the organizers' = f.input :sponsor_email, hint: 'This will appear in the sponsor segment of the splash for the sponsors to contact to the organizers'
= f.inputs name: 'Social Media' do = f.inputs name: 'Social Media' do
= f.input :social_tag, hint: "The hashtag you'll use on Twitter and Google+. Don't include the '#' sign!'" = f.input :social_tag, hint: "The hashtag you'll use on Twitter and Google+. Don't include the '#' sign!'"
@ -16,4 +16,5 @@
= f.input :googleplus, label: 'Google+ Url', hint: 'This will appear in the social media section as the link to the Google+ Page of your Conference' = f.input :googleplus, label: 'Google+ Url', hint: 'This will appear in the social media section as the link to the Google+ Page of your Conference'
= f.input :twitter, hint: 'This will appear in the social media section as the link to the Twitter Page of your Conference' = f.input :twitter, hint: 'This will appear in the social media section as the link to the Twitter Page of your Conference'
= f.input :instagram, hint: 'This will appear in the social media section as the link to the Instagram Page of your Conference' = f.input :instagram, hint: 'This will appear in the social media section as the link to the Instagram Page of your Conference'
= f.input :mastodon, hint: 'This will appear in the social media section as the link to the Mastodon Page of your Conference'
= f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' }

View file

@ -9,7 +9,7 @@
.row .row
.col-md-8 .col-md-8
= semantic_form_for(@difficulty_level, url: (@difficulty_level.new_record? ? admin_conference_program_difficulty_levels_path : admin_conference_program_difficulty_level_path(@conference.short_title, @difficulty_level))) do |f| = semantic_form_for(@difficulty_level, url: (@difficulty_level.new_record? ? admin_conference_program_difficulty_levels_path : admin_conference_program_difficulty_level_path(@conference.short_title, @difficulty_level))) do |f|
= f.input :title, required: true = f.input :title, input_html: { autofocus: true }, required: true
= f.input :description, input_html: {rows: 3, class: 'span6'} = f.input :description, input_html: {rows: 3, class: 'span6'}
= f.input :color, input_html: {size: 6, type: 'color'} = f.input :color, input_html: {size: 6, type: 'color'}
%p.text-right %p.text-right

View file

@ -9,7 +9,7 @@
.row .row
.col-md-12 .col-md-12
= semantic_form_for(@event_type, url: (@event_type.new_record? ? admin_conference_program_event_types_path : admin_conference_program_event_type_path(@conference.short_title, @event_type))) do |f| = semantic_form_for(@event_type, url: (@event_type.new_record? ? admin_conference_program_event_types_path : admin_conference_program_event_type_path(@conference.short_title, @event_type))) do |f|
= f.input :title = f.input :title, input_html: { autofocus: true }
= f.input :length, input_html: {size: 3, type: 'number', step: @event_type.program.schedule_interval, min: @event_type.program.schedule_interval} = f.input :length, input_html: {size: 3, type: 'number', step: @event_type.program.schedule_interval, min: @event_type.program.schedule_interval}
= f.input :description = f.input :description
= f.input :minimum_abstract_length, input_html: {size: 3} = f.input :minimum_abstract_length, input_html: {size: 3}

View file

@ -2,6 +2,7 @@
.col-md-12 .col-md-12
.page-header .page-header
%h1 Organizations %h1 Organizations
- if can? :manage, :all
.btn-group.pull-right .btn-group.pull-right
= link_to 'Create Organization', new_admin_organization_path, class: 'btn btn-success pull-right' = link_to 'Create Organization', new_admin_organization_path, class: 'btn btn-success pull-right'
%p.text-muted %p.text-muted

View file

@ -9,7 +9,7 @@
= f.input :schedule_fluid, label: 'Allow submitters to change their event after it is scheduled' = f.input :schedule_fluid, label: 'Allow submitters to change their event after it is scheduled'
= f.input :rating, hint: 'Enter the number of different rating levels you want to have for voting on proposals. Enter 0 if you do not want to vote on proposals.' = f.input :rating, hint: 'Enter the number of different rating levels you want to have for voting on proposals. Enter 0 if you do not want to vote on proposals.'
= f.input :languages, hint: "Enter the languages allowed for events as values of #{link_to('ISO 639-1', 'http://www.loc.gov/standards/iso639-2/php/code_list.php', target: "_blank")} language codes separated with commas. The first language would be the default language. Leave it blank if you do not want to specify languages.".html_safe = f.input :languages, hint: "Enter the languages allowed for events as values of #{link_to('ISO 639-1', 'http://www.loc.gov/standards/iso639-2/php/code_list.php', target: "_blank")} language codes separated with commas. The first language would be the default language. Leave it blank if you do not want to specify languages.".html_safe
= f.input :schedule_interval, hint: "It is the minimal time interval of your schedule. The value should be 5, 6, 10, 12, 15, 20, 30 or 60. Warning! Some events could be unscheduled when changing this value." = f.input :schedule_interval, input_html: { autofocus: true }, hint: "It is the minimal time interval of your schedule. The value should be 5, 6, 10, 12, 15, 20, 30 or 60. Warning! Some events could be unscheduled when changing this value."
= f.input :blind_voting, hint: 'Enable this feature if you do not want to show voting results and voters prior to user submitting a vote. For the feature to work you need to set the voting dates below as well' = f.input :blind_voting, hint: 'Enable this feature if you do not want to show voting results and voters prior to user submitting a vote. For the feature to work you need to set the voting dates below as well'
= f.input :voting_start_date, as: :string, input_html: { id: 'datetimepicker-voting_start_date', readonly: true, value: (f.object.voting_start_date.to_formatted_s(:db_without_seconds) unless f.object.voting_start_date.nil?) } = f.input :voting_start_date, as: :string, input_html: { id: 'datetimepicker-voting_start_date', readonly: true, value: (f.object.voting_start_date.to_formatted_s(:db_without_seconds) unless f.object.voting_start_date.nil?) }
= f.input :voting_end_date, as: :string, input_html: { id: 'datetimepicker-voting_start_date', readonly: true, value: (f.object.voting_end_date.to_formatted_s(:db_without_seconds) unless f.object.voting_end_date.nil?) } = f.input :voting_end_date, as: :string, input_html: { id: 'datetimepicker-voting_start_date', readonly: true, value: (f.object.voting_end_date.to_formatted_s(:db_without_seconds) unless f.object.voting_end_date.nil?) }

View file

@ -5,7 +5,7 @@
All Events All Events
= "(#{@events.length})" = "(#{@events.length})"
%p.text-muted %p.text-muted
All submissions and the information that they are mssing All submissions and the information that they are missing
.col-md-12 .col-md-12
%table.table.table-striped.table-bordered.table-hover.datatable %table.table.table-striped.table-bordered.table-hover.datatable

View file

@ -8,7 +8,7 @@
.row .row
.col-md-8 .col-md-8
= semantic_form_for(@resource, :url => (@resource.new_record? ? admin_conference_resources_path : admin_conference_resource_path(@conference.short_title, @resource))) do |f| = semantic_form_for(@resource, :url => (@resource.new_record? ? admin_conference_resources_path : admin_conference_resource_path(@conference.short_title, @resource))) do |f|
= f.input :name = f.input :name, input_html: { autofocus: true }
= f.input :description, input_html: { rows: 5, data: { provide: 'markdown-editable' } } = f.input :description, input_html: { rows: 5, data: { provide: 'markdown-editable' } }
= f.input :used = f.input :used
= f.input :quantity = f.input :quantity

View file

@ -10,6 +10,6 @@
= semantic_form_for @role, url: @url do |f| = semantic_form_for @role, url: @url do |f|
.row .row
.col-md-5 .col-md-5
= f.input :description = f.input :description, input_html: { autofocus: true }
= f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' }

View file

@ -24,7 +24,7 @@
= u.label 'Add user by email: ' = u.label 'Add user by email: '
.input-group .input-group
= u.input :email, label: false, placeholder: "User's email" = u.input :email, input_html: { autofocus: true }, label: false, placeholder: "User's email"
.input-group-btn .input-group-btn
= u.submit 'Add', id: 'user-add', class: 'btn btn-primary' = u.submit 'Add', id: 'user-add', class: 'btn btn-primary'

View file

@ -9,7 +9,7 @@
.row .row
.col-md-8 .col-md-8
= semantic_form_for(@sponsor, url: (@sponsor.new_record? ? admin_conference_sponsors_path : admin_conference_sponsor_path(@conference.short_title, @sponsor))) do |f| = semantic_form_for(@sponsor, url: (@sponsor.new_record? ? admin_conference_sponsors_path : admin_conference_sponsor_path(@conference.short_title, @sponsor))) do |f|
= f.input :name = f.input :name, input_html: { autofocus: true }
= f.input :description = f.input :description
= image_tag f.object.picture.thumb.url if f.object.picture? = image_tag f.object.picture.thumb.url if f.object.picture?
= f.input :picture = f.input :picture

View file

@ -19,6 +19,7 @@
- @conference.sponsors.each do |sponsor| - @conference.sponsors.each do |sponsor|
%tr %tr
%td %td
- if sponsor.picture?
= image_tag(sponsor.picture.thumb.url, width: '20%') = image_tag(sponsor.picture.thumb.url, width: '20%')
%td %td
= sponsor.name = sponsor.name

View file

@ -9,6 +9,6 @@
.row .row
.col-md-8 .col-md-8
= semantic_form_for(@sponsorship_level, url: (@sponsorship_level.new_record? ? admin_conference_sponsorship_levels_path : admin_conference_sponsorship_level_path(@conference.short_title, @sponsorship_level))) do |f| = semantic_form_for(@sponsorship_level, url: (@sponsorship_level.new_record? ? admin_conference_sponsorship_levels_path : admin_conference_sponsorship_level_path(@conference.short_title, @sponsorship_level))) do |f|
= f.input :title = f.input :title, input_html: { autofocus: true }
%p.text-right %p.text-right
= f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' }

View file

@ -9,7 +9,7 @@
.col-md-8 .col-md-8
= semantic_form_for(@target, url: (@target.new_record? ? admin_conference_targets_path : admin_conference_target_path(@conference.short_title, @target))) do |f| = semantic_form_for(@target, url: (@target.new_record? ? admin_conference_targets_path : admin_conference_target_path(@conference.short_title, @target))) do |f|
= f.input :due_date, as: :string, input_html: { class: 'target-due-date-datepicker'}, label: 'Until when do you want to have ' = f.input :due_date, as: :string, input_html: { class: 'target-due-date-datepicker'}, label: 'Until when do you want to have '
= f.input :target_count, label: 'this amount of ' = f.input :target_count, input_html: { autofocus: true }, label: 'this amount of '
= f.input :unit, as: :select, label: 'Unit', class: 'form-control', collection: Target.units.values, include_blank: false = f.input :unit, as: :select, label: 'Unit', class: 'form-control', collection: Target.units.values, include_blank: false
%p.text-right %p.text-right
= f.action :submit, as: :button, button_html: { class: 'btn btn-primary' } = f.action :submit, as: :button, button_html: { class: 'btn btn-primary' }

View file

@ -9,7 +9,7 @@
.row .row
.col-md-12 .col-md-12
= semantic_form_for(@track, url: (@track.new_record? ? admin_conference_program_tracks_path(@conference.short_title) : admin_conference_program_track_path(@conference.short_title, @track))) do |f| = semantic_form_for(@track, url: (@track.new_record? ? admin_conference_program_tracks_path(@conference.short_title) : admin_conference_program_track_path(@conference.short_title, @track))) do |f|
= f.input :name = f.input :name, input_html: { autofocus: true }
= f.input :short_name, hint: "A short and unique handle for the track, using only letters, numbers, underscores, and dashes. This will be used to identify the track in URLs etc. Example: 'my_awesome_track'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' } = f.input :short_name, hint: "A short and unique handle for the track, using only letters, numbers, underscores, and dashes. This will be used to identify the track in URLs etc. Example: 'my_awesome_track'", input_html: { required: 'required', pattern: '[a-zA-Z0-9_-]+', title: 'Only letters, numbers, underscores, and dashes.' }
= f.input :color, input_html: {size: 6, type: 'color'}, required: true = f.input :color, input_html: {size: 6, type: 'color'}, required: true
= f.input :start_date, as: :string, input_html: { id: 'registration-period-start-datepicker', start_date: @conference.start_date, end_date: @conference.end_date, readonly: 'readonly', required: @track.self_organized_and_accepted_or_confirmed? } = f.input :start_date, as: :string, input_html: { id: 'registration-period-start-datepicker', start_date: @conference.start_date, end_date: @conference.end_date, readonly: 'readonly', required: @track.self_organized_and_accepted_or_confirmed? }

View file

@ -8,7 +8,7 @@
.row .row
.col-md-6 .col-md-6
- if @conference.venue.location? - if @conference.venue.location?
= render '/conferences/venue_map' = render '/conferences/venue_map', venue: @conference.venue
-else -else
- if @venue.commercial.nil? - if @venue.commercial.nil?
.row .row

View file

@ -2,7 +2,7 @@
.row .row
.col-md-8 .col-md-8
= semantic_form_for(@booth, url: @url, html: { multipart: true }) do |f| = semantic_form_for(@booth, url: @url, html: { multipart: true }) do |f|
= f.input :title, as: :string, autofocus: true, required: true = f.input :title, as: :string, input_html: { autofocus: true }, required: true
= f.input :description, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, = f.input :description, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true,
hint: 'This field becomes public upon request acceptance' hint: 'This field becomes public upon request acceptance'
= f.input :reasoning, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true, = f.input :reasoning, input_html: { rows: 5, data: { provide: 'markdown-editable' } }, required: true,

View file

@ -6,7 +6,7 @@
= image_tag(@booth.picture.thumb.url, size: '20%', alt: '') = image_tag(@booth.picture.thumb.url, size: '20%', alt: '')
= @booth.title = @booth.title
.btn-group.pull-right .btn-group.pull-right
= link_to 'Edit', edit_admin_conference_booth_path(@conference.short_title, @booth), class: 'btn btn-mini btn-primary' = link_to 'Edit', edit_conference_booth_path(@conference.short_title, @booth), class: 'btn btn-mini btn-primary'
.row .row
.col-md-12 .col-md-12

View file

@ -23,5 +23,5 @@
left! left!
%p.cta-button %p.cta-button
= link_to "Submit your proposal now", = link_to "Submit your proposal now",
conference_program_proposals_path(conference_id), new_conference_program_proposal_path(conference_id),
class: 'btn btn-success btn-lg text-center' class: 'btn btn-success btn-lg text-center'

View file

@ -15,5 +15,5 @@
left! left!
%p.cta-button %p.cta-button
= link_to("Submit your request for track", = link_to("Submit your request for track",
conference_program_tracks_path(conference_id), new_conference_program_track_path(conference_id),
class: 'btn btn-success btn-lg text-center') class: 'btn btn-success btn-lg text-center')

View file

@ -15,6 +15,7 @@
- if object.is_a? Sponsor - if object.is_a? Sponsor
- img_classes << ['img-sponsor', - img_classes << ['img-sponsor',
"img-sponsor-#{object.sponsorship_level.position}"] "img-sponsor-#{object.sponsorship_level.position}"]
- if object.picture?
= image_tag get_logo(object), class: img_classes = image_tag get_logo(object), class: img_classes
%p.description %p.description
= object.description = object.description

View file

@ -15,6 +15,9 @@
- unless contact.googleplus.blank? - unless contact.googleplus.blank?
= link_to "#{ contact.googleplus }" do = link_to "#{ contact.googleplus }" do
%i.fa.fa-google-plus-square.fa-4x %i.fa.fa-google-plus-square.fa-4x
- unless contact.mastodon.blank?
= link_to "#{ contact.mastodon }" do
%i.fa.icon-mastodon.fa-4x
- unless contact.email.blank? - unless contact.email.blank?
= mail_to "#{ contact.email }" do = mail_to "#{ contact.email }" do
%i.fa.fa-envelope-o.fa-4x %i.fa.fa-envelope-o.fa-4x

View file

@ -2,7 +2,7 @@
%li %li
%a.smoothscroll{ href: '#sponsors' } Sponsors %a.smoothscroll{ href: '#sponsors' } Sponsors
- cache [conference, sponsorship_levels, '#splash#sponsors'] do - cache [conference, sponsors, sponsorship_levels, '#splash#sponsors'] do
%section#sponsors %section#sponsors
.container .container
- sponsorship_levels.each do |sponsorship_level| - sponsorship_levels.each do |sponsorship_level|
@ -31,6 +31,6 @@
= link_to(sponsorship_mailto(conference)) do = link_to(sponsorship_mailto(conference)) do
Contact us! Contact us!
- sponsorship_levels.collect(&:sponsors).flatten.each do |sponsor| - sponsors.each do |sponsor|
- content_for :modals do - content_for :modals do
= render 'modal_description', object: sponsor = render 'modal_description', object: sponsor

View file

@ -29,7 +29,7 @@
- if @conference.registration_open? - if @conference.registration_open?
= render 'registration', conference: @conference, = render 'registration', conference: @conference,
registration_period: @conference.registration_period, registration_period: @conference.registration_period,
tickets: @tickets, conference_id: @conference_id.short_title tickets: @tickets, conference_id: @conference.short_title
- if @conference.splashpage.include_tickets && @conference.tickets.any? - if @conference.splashpage.include_tickets && @conference.tickets.any?
= render 'tickets', conference: @conference, tickets: @tickets = render 'tickets', conference: @conference, tickets: @tickets
@ -43,7 +43,8 @@
-# sponsorship -# sponsorship
- if @conference.splashpage.include_sponsors - if @conference.splashpage.include_sponsors
= render 'sponsors', conference: @conference, = render 'sponsors', conference: @conference,
sponsorship_levels: @sponsorship_levels sponsorship_levels: @sponsorship_levels,
sponsors: @sponsors
-# footer -# footer
- if @conference.splashpage.include_social_media - if @conference.splashpage.include_social_media

View file

@ -1,5 +1,5 @@
.text-center .text-center
.btn-group.btn-group-lg .btn-group.btn-group-lg#openid-btn-grp
- omniauth_configured.each do |provider| - omniauth_configured.each do |provider|
= link_to "user_#{provider}_omniauth_authorize".to_sym, class: "btn btn-success btn-lg", = link_to "user_#{provider}_omniauth_authorize".to_sym, class: "btn btn-success btn-lg",
id: "omniauth-#{provider}", id: "omniauth-#{provider}",

View file

@ -37,11 +37,14 @@
%p.muted.text-center %p.muted.text-center
%small %small
This tool is This tool is
=link_to "free software,", "http://www.gnu.org/philosophy/free-sw.html" #{link_to "free software", "http://www.gnu.org/philosophy/free-sw.html"},
released under the released under the
=link_to "MIT license.", "http://opensource.org/licenses/MIT" #{link_to "MIT license", "http://opensource.org/licenses/MIT"}.
You can run, copy, distribute, study, change and improve it. You can run, copy, distribute, study, change and improve it.
The source code and the developers are on The source code and the developers are on
=link_to "github.", "https://github.com/openSUSE/osem" #{link_to "GitHub", "https://github.com/openSUSE/osem"}.
- if ENV["SKYLIGHT_PUBLIC_DASHBOARD_URL"].present?
Performance data is available on
#{link_to "Skylight", ENV["SKYLIGHT_PUBLIC_DASHBOARD_URL"]}.
= yield :script_body = yield :script_body
= piwik_tracking_tag = piwik_tracking_tag

View file

@ -1,6 +1,6 @@
= semantic_form_for(@event, url: @url) do |f| = semantic_form_for(@event, url: @url) do |f|
= f.inputs name: 'Proposal Information' do = f.inputs name: 'Proposal Information' do
= f.input :title, as: :string, required: true = f.input :title, as: :string, input_html: { autofocus: true }, required: true
= f.input :subtitle, as: :string = f.input :subtitle, as: :string

View file

@ -1,4 +1,5 @@
# This file is used by Rack-based servers to start the application. # This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__) require ::File.expand_path('../config/environment', __FILE__)
use Rack::Deflater
run Osem::Application run Osem::Application

View file

@ -60,6 +60,9 @@ module Osem
# Version of your assets, change this if you want to expire all your assets # Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0' config.assets.version = '1.0'
# Set cache headers
config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=31536000' }
config.active_job.queue_adapter = :delayed_job config.active_job.queue_adapter = :delayed_job
end end
end end

View file

@ -25,6 +25,10 @@ Osem::Application.configure do
# Generate digests for assets URLs # Generate digests for assets URLs
config.assets.digest = true config.assets.digest = true
config.assets.css_compressor = :sass
config.assets.js_compressor = :uglifier
config.assets.gzip = true
# Defaults to nil and saved in location specified by config.assets.prefix # Defaults to nil and saved in location specified by config.assets.prefix
# config.assets.manifest = YOUR_PATH # config.assets.manifest = YOUR_PATH

View file

@ -0,0 +1,5 @@
class AddMastodonToContact < ActiveRecord::Migration
def change
add_column :contacts, :mastodon, :string
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20171130172334) do ActiveRecord::Schema.define(version: 20171201163628) do
create_table "ahoy_events", force: :cascade do |t| create_table "ahoy_events", force: :cascade do |t|
t.integer "visit_id" t.integer "visit_id"
@ -145,6 +145,7 @@ ActiveRecord::Schema.define(version: 20171130172334) do
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "sponsor_email" t.string "sponsor_email"
t.string "mastodon"
end end
create_table "delayed_jobs", force: :cascade do |t| create_table "delayed_jobs", force: :cascade do |t|
@ -495,7 +496,7 @@ ActiveRecord::Schema.define(version: 20171130172334) do
t.integer "user_id" t.integer "user_id"
t.integer "payment_id" t.integer "payment_id"
t.integer "week" t.integer "week"
t.float "amount_paid" t.float "amount_paid", default: 0.0
end end
create_table "ticket_scannings", force: :cascade do |t| create_table "ticket_scannings", force: :cascade do |t|

View file

@ -34,7 +34,7 @@ SECRET_KEY_BASE=changemechangemechangeme"
OSEM_EMAIL_ADDRESS="osem@mailhog" OSEM_EMAIL_ADDRESS="osem@mailhog"
OSEM_SMTP_AUTHENTICATION="login" OSEM_SMTP_AUTHENTICATION="login"
OSEM_SMTP_ADDRESS="mailhog" OSEM_SMTP_ADDRESS="mailhog"
OSEM_SMTP_PORT="1025" OSEM_SMTP_PORT=1025
OSEM_SMTP_USERNAME="mailhog" OSEM_SMTP_USERNAME="mailhog"
OSEM_SMTP_PASSWORD="mailhog" OSEM_SMTP_PASSWORD="mailhog"

View file

@ -46,6 +46,10 @@ OSEM_SUSE_SECRET=''
STRIPE_PUBLISHABLE_KEY='' STRIPE_PUBLISHABLE_KEY=''
STRIPE_SECRET_KEY='' STRIPE_SECRET_KEY=''
# (OPTIONAL) Skylight keys. See https://www.skylight.io/oss.
# SKYLIGHT_AUTHENTICATION=''
# SKYLIGHT_PUBLIC_DASHBOARD_URL='https://oss.skylight.io/app/applications/xxxxxxxxxxxx'
# Disable linting of factories in the test suite. # Disable linting of factories in the test suite.
# Speeds up turn around times of tests # Speeds up turn around times of tests
OSEM_FACTORY_LINT="false" OSEM_FACTORY_LINT="false"

View file

@ -95,6 +95,75 @@ describe Admin::ConferencesController do
get :show, id: conference.short_title get :show, id: conference.short_title
expect(response).to render_template :show expect(response).to render_template :show
end end
it 'assigns conference withdrawn events distribution to event_type_distribution_withdrawn' do
conference
create(:event, program: conference.program)
workshop = create(:event_type, title: 'Workshop', color: '#000000', program: conference.program)
lecture = create(:event_type, title: 'Lecture', color: '#ffffff', program: conference.program)
get :show, id: conference.short_title
expect(assigns(:event_type_distribution_withdrawn)).to be_empty
create(:event, program: conference.program, state: 'withdrawn', event_type: lecture)
create(:event, program: conference.program, state: 'withdrawn', event_type: workshop)
get :show, id: conference.short_title
expect(assigns(:event_type_distribution_withdrawn)).not_to be_empty
result = {}
result['Workshop'] = {
'value' => 1,
'color' => '#000000'
}
result['Lecture'] = {
'value' => 1,
'color' => '#FFFFFF'
}
expect(assigns(:event_type_distribution_withdrawn)).to eq(result)
end
it 'assigns conference withdrawn difficulty level distribution to difficulty_levels_distribution_withdrawn' do
conference
create(:event, program: conference.program)
get :show, id: conference.short_title
expect(assigns(:difficulty_levels_distribution_withdrawn)).to be_empty
easy = create(:difficulty_level, title: 'Easy', color: '#000000')
hard = create(:difficulty_level, title: 'Hard', color: '#ffffff')
create(:event, program: conference.program, state: 'withdrawn', difficulty_level: easy)
create(:event, program: conference.program, state: 'withdrawn', difficulty_level: hard)
get :show, id: conference.short_title
expect(assigns(:difficulty_levels_distribution_withdrawn)).not_to be_empty
result = {}
result['Easy'] = {
'value' => 1,
'color' => '#000000'
}
result['Hard'] = {
'value' => 1,
'color' => '#FFFFFF'
}
expect(assigns(:difficulty_levels_distribution_withdrawn)).to eq(result)
end
it 'assigns conference withdrawn track distribution to tracks_distribution_withdrawn' do
conference
create(:event, program: conference.program)
get :show, id: conference.short_title
expect(assigns(:tracks_distribution_withdrawn)).to be_empty
track_one = create(:track, name: 'Track One', color: '#000000', program: conference.program)
track_two = create(:track, name: 'Track Two', color: '#FFFFFF', program: conference.program)
create(:event, program: conference.program, state: 'withdrawn', track: track_one)
create(:event, program: conference.program, state: 'withdrawn', track: track_two)
get :show, id: conference.short_title
expect(assigns(:tracks_distribution_withdrawn)).not_to be_empty
result = {}
result['Track One'] = {
'value' => 1,
'color' => '#000000'
}
result['Track Two'] = {
'value' => 1,
'color' => '#FFFFFF'
}
expect(assigns(:tracks_distribution_withdrawn)).to eq(result)
end
end end
describe 'GET #index' do describe 'GET #index' do

View file

@ -30,7 +30,45 @@ describe ApplicationController, type: :controller do
expect(controller.after_sign_in_path_for(user)).to eq conferences_path expect(controller.after_sign_in_path_for(user)).to eq conferences_path
end end
end end
end
end
end
describe ApplicationController, type: :request do
let(:conference) { create(:conference) }
describe 'Skylight link' do
around do |example|
original_value = ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL']
example.run
ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL'] = original_value
end
context 'when SKYLIGHT_PUBLIC_DASHBOARD_URL is set' do
before do
ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL'] = 'https://oss.skylight.io/app/applications/my-osem'
end
it 'should include a link to view performance data' do
get '/'
expect(response.body).to match(/Performance data/i)
expect(response.body).to include('https://oss.skylight.io/app/applications/my-osem')
end
end
context 'when SKYLIGHT_PUBLIC_DASHBOARD_URL is not set' do
before do
ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL'] = nil
end
it 'should not include a link to view performance data' do
get '/'
expect(response.body).to_not match(/performance data/i)
expect(response.body).to_not match(/skylight/i)
end
end end
end end

View file

@ -89,11 +89,131 @@ describe 'User' do
let(:other_self_organized_track) { create(:track, :self_organized) } let(:other_self_organized_track) { create(:track, :self_organized) }
it{ should be_able_to(:manage, user) } it{ should be_able_to(:manage, user) }
it{ should be_able_to(:manage, registration_public) } it{ should be_able_to(:manage, registration_public) }
it{ should be_able_to(:manage, registration_not_public) } it{ should be_able_to(:manage, registration_not_public) }
it{ should_not be_able_to(:new, Registration.new(conference_id: conference_with_closed_registration.id))}
it{ should_not be_able_to(:create, Registration.new(conference_id: conference_with_closed_registration.id))} # Test for user can register or not
context 'when user is not a speaker with event confirmed' do
let(:conference) { create(:conference) }
context 'when the registration is closed' do
before :each do
create(:registration_period, conference: conference, start_date: Date.current - 6.days, end_date: Date.current - 6.days)
end
it{ should_not be_able_to(:new, Registration.new(conference: conference)) }
it{ should_not be_able_to(:create, Registration.new(conference: conference)) }
end
context 'when the registration period is not set' do
it{ should_not be_able_to(:new, Registration.new(conference: conference)) }
it{ should_not be_able_to(:create, Registration.new(conference: conference)) }
end
context 'when user has already registered' do
before :each do
create(:registration, conference: conference, user: user)
end
it{ should_not be_able_to(:new, Registration.new(conference: conference)) }
it{ should_not be_able_to(:create, Registration.new(conference: conference)) }
end
context 'when registrations are open' do
before :each do
create(:registration_period, conference: conference)
end
it{ should be_able_to(:new, Registration.new(conference: conference)) }
it{ should be_able_to(:create, Registration.new(conference: conference)) }
context 'when user has not registered with no registration_limit_exceeded' do
before :each do
conference.registration_limit = 1
end
it{ should be_able_to(:new, Registration.new(conference: conference)) }
it{ should be_able_to(:create, Registration.new(conference: conference)) }
end
context 'when user has not registered with registration_limit_exceeded' do
before :each do
conference.registration_limit = 1
create(:registration, conference: conference, user: user2)
end
it{ should_not be_able_to(:new, Registration.new(conference: conference)) }
it{ should_not be_able_to(:create, Registration.new(conference: conference)) }
end
end
end
context 'when user is a speaker with event confirmed' do
let(:conference_with_speaker_confirmed) { create(:conference) }
let(:event_with_speaker_confirmed) { create(:event, state: 'confirmed', program: conference_with_speaker_confirmed.program) }
before :each do
event_with_speaker_confirmed.speakers << user
end
context 'when registration period is not set' do
it{ should_not be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) }
it{ should_not be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) }
end
context 'when speaker has already registered' do
before :each do
create(:registration, conference: conference_with_speaker_confirmed, user: user)
end
it{ should_not be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) }
it{ should_not be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) }
end
context 'when registration period is set' do
before :each do
create(:registration_period, conference: conference_with_speaker_confirmed)
end
context 'when registrations are open' do
context 'when speaker has not registered' do
it{ should be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) }
it{ should be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) }
end
context 'when registration_limit_exceeded' do
before :each do
conference_with_speaker_confirmed.registration_limit = 1
create(:registration, conference: conference_with_speaker_confirmed, user: user2)
end
it{ should be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) }
it{ should be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) }
end
end
context 'when registrations are closed' do
before :each do
create(:registration_period, conference: conference_with_speaker_confirmed, start_date: Date.current - 6.days, end_date: Date.current - 6.days)
end
context 'when speaker has not registered' do
it{ should be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) }
it{ should be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) }
end
context 'with registration_limit_exceeded' do
before :each do
conference_with_speaker_confirmed.registration_limit = 1
create(:registration, conference: conference_with_speaker_confirmed, user: user2)
end
it{ should be_able_to(:new, Registration.new(conference: conference_with_speaker_confirmed)) }
it{ should be_able_to(:create, Registration.new(conference: conference_with_speaker_confirmed)) }
end
end
end
end
it{ should be_able_to(:index, Ticket) } it{ should be_able_to(:index, Ticket) }
it{ should be_able_to(:manage, TicketPurchase.new(user_id: user.id)) } it{ should be_able_to(:manage, TicketPurchase.new(user_id: user.id)) }