Skip to content

Commit

Permalink
Merge remote-tracking branch 'remotes/origin/dev' into 30_4.6_PrintAp…
Browse files Browse the repository at this point in the history
…plications

# Conflicts:
#	app/controllers/events_controller.rb
#	app/models/ability.rb
#	config/locales/de.events.yml
  • Loading branch information
Lennart L committed Dec 17, 2016
2 parents 9dc21ac + ebba074 commit ba7777a
Show file tree
Hide file tree
Showing 58 changed files with 1,098 additions and 265 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -21,4 +21,5 @@ deploy:
run:
- rake db:schema:load
- rake db:seed
- rake db:populate_sample_data
- restart
3 changes: 3 additions & 0 deletions Gemfile
Expand Up @@ -85,6 +85,9 @@ gem 'prawn-table'
# Simple, Heroku-friendly Rails app configuration using ENV and a single YAML file
gem 'figaro'

# Allow ORM functionality in plain ruby models
gem 'active_attr'

group :development, :test do
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug'
Expand Down
4 changes: 4 additions & 0 deletions Gemfile.lock
Expand Up @@ -21,6 +21,9 @@ GEM
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
active_attr (0.9.0)
activemodel (>= 3.0.2, < 5.1)
activesupport (>= 3.0.2, < 5.1)
activejob (4.2.7.1)
activesupport (= 4.2.7.1)
globalid (>= 0.3.0)
Expand Down Expand Up @@ -289,6 +292,7 @@ PLATFORMS
ruby

DEPENDENCIES
active_attr
airbrake
american_date
annotate
Expand Down
13 changes: 13 additions & 0 deletions app/assets/javascripts/emails.js
@@ -0,0 +1,13 @@
// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

jQuery(function() {
$(document).on('click', "#send-emails-clipboard", function() {
$("#email_recipients").select();
try {
document.execCommand('copy');
} catch (err) {
console.log('Unable to copy emails to the clipboard');
}
});
});
15 changes: 0 additions & 15 deletions app/assets/javascripts/events.js
Expand Up @@ -12,21 +12,6 @@ jQuery(function() {
modal.find('#send-emails-mailto').attr('href', 'mailto:' + list);
modal.find('#send-emails-list').val(list);
});

$('#send-emails-clipboard').click(function () {
var $temp = $("<input>");
$('body').append($temp);
$temp.val($('#send-emails-list').val()).select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Copying emails to the clipboard was ' + msg);
}
catch (err) {
console.log('Unable to copy emails to the clipboard');
}
$temp.remove();
});
});

function addEventDatePicker() {
Expand Down
7 changes: 7 additions & 0 deletions app/assets/stylesheets/email.css
@@ -0,0 +1,7 @@
.email-content {
width: 100%;
}

.email-submit {
float: right;
}
4 changes: 4 additions & 0 deletions app/assets/stylesheets/emails.css
@@ -0,0 +1,4 @@
/*
Place all the styles related to the matching controller here.
They will automatically be included in application.css.
*/
18 changes: 16 additions & 2 deletions app/controllers/application_letters_controller.rb
Expand Up @@ -52,7 +52,16 @@ def create
# PATCH/PUT /applications/1
def update
if @application_letter.update_attributes(application_params)
redirect_to :back, notice: 'Application was successfully updated.' rescue ActionController::RedirectBackError redirect_to root_path
redirect_to :back, notice: I18n.t('application_letters.successful_update') rescue ActionController::RedirectBackError redirect_to root_path
else
render :edit
end
end

# PATCH/PUT /applications/1/status
def update_status
if @application_letter.update_attributes(application_status_param)
redirect_to :back, notice: I18n.t('application_letters.successful_update') rescue ActionController::RedirectBackError redirect_to root_path
else
render :edit
end
Expand All @@ -73,6 +82,11 @@ def set_application
# Only allow a trusted parameter "white list" through.
# Don't allow user_id as you shouldn't be able to set the user from outside of create/update.
def application_params
params.require(:application_letter).permit(:grade, :experience, :motivation, :coding_skills, :emergency_number, :vegeterian, :vegan, :allergic, :allergies, :user_id, :event_id, :status)
params.require(:application_letter).permit(:grade, :experience, :motivation, :coding_skills, :emergency_number, :vegeterian, :vegan, :allergic, :allergies, :user_id, :event_id)
end

# Only allow to update the status
def application_status_param
params.require(:application_letter).permit(:status)
end
end
14 changes: 14 additions & 0 deletions app/controllers/emails_controller.rb
@@ -0,0 +1,14 @@
class EmailsController < ApplicationController
def send_email
@email = Email.new(email_params)
Mailer.send_generic_email(@email.hide_recipients, @email.recipients, @email.reply_to, @email.subject, @email.content)
redirect_to :events, notice: t('.sending_successful')
end

private

# Only allow a trusted parameter "white list" through.
def email_params
params.require(:email).permit(:hide_recipients, :recipients, :reply_to, :subject, :content)
end
end
21 changes: 18 additions & 3 deletions app/controllers/events_controller.rb
Expand Up @@ -31,7 +31,7 @@ def create
@event.draft = (params[:draft] != nil)

if @event.save
redirect_to @event, notice: 'Event wurde erstellt.'
redirect_to @event, notice: I18n.t('.events.notices.created')
else
render :new
end
Expand All @@ -44,7 +44,7 @@ def update
@event.draft = (params[:commit] == "draft")

if @event.update(attrs)
redirect_to @event, notice: 'Event wurde aktualisiert.'
redirect_to @event, notice: I18n.t('events.notices.updated')
else
render :edit
end
Expand All @@ -53,7 +53,7 @@ def update
# DELETE /events/1
def destroy
@event.destroy
redirect_to events_url, notice: 'Event wurde gelöscht.'
redirect_to events_url, notice: I18n.t('events.notices.destroyed')
end

# GET /events/1/badges
Expand Down Expand Up @@ -92,6 +92,21 @@ def print_applications
pdf = ApplicationsPDF.generate(@event)
send_data pdf, filename: "applications_#{@event.name}_#{Date.today}.pdf", type: "application/pdf", disposition: "inline"
end
# GET /events/1/send-acceptances-email
def send_acceptance_emails
event = Event.find(params[:id])
@email = event.generate_acceptances_email
@templates = [{subject: 'Zusage 1', content: 'Lorem Ispum...'}, {subject: 'Zusage 2', content: 'Lorem Ispum...'}, {subject: 'Zusage 3', content: 'Lorem Ispum...'}]
render :email
end

# GET /events/1/send-rejections-email
def send_rejection_emails
event = Event.find(params[:id])
@email = event.generate_rejections_email
@templates = [{subject: 'Absage 1', content: 'Lorem Ispum...'}, {subject: 'Absage 2', content: 'Lorem Ispum...'}, {subject: 'Absage 3', content: 'Lorem Ispum...'}]
render :email
end

private
# Use callbacks to share common setup or constraints between actions.
Expand Down
2 changes: 2 additions & 0 deletions app/helpers/emails_helper.rb
@@ -0,0 +1,2 @@
module EmailsHelper
end
15 changes: 5 additions & 10 deletions app/mailers/portal_mailer.rb
@@ -1,17 +1,12 @@
class PortalMailer < ApplicationMailer

# @param hide_recipients [Boolean] - identify whether recipients should be hidden from each other (true) or not (false)
# @param recipients [Array<String>] - email addresses of recipients
# @param reply_to [Array<String>] - email addresses of recipient of the answer

# @param recipients [Array<String>] - email addresses of recipients - can be a string of comma separated email adresses too
# @param reply_to [Array<String>] - email addresses of recipient of the answer - can be a string of comma separated email adresses too
# @param subject [String] - subject of the mail
# @param content [String] - content of the mail
# @return [ActionMailer::MessageDelivery] a mail object with the given parameters.
def generic_email(hide_recipients, recipients, reply_to, subject, content)
def generic_email(recipients, reply_to, subject, content)
@content = content
if (hide_recipients)
mail(bcc: recipients, reply_to: reply_to, subject: subject)
else
mail(to: recipients, reply_to: reply_to, subject: subject)
end
mail(to: recipients, reply_to: reply_to, subject: subject)
end
end
5 changes: 3 additions & 2 deletions app/models/ability.rb
Expand Up @@ -51,8 +51,9 @@ def initialize(user)
end
if user.role? :organizer
can [:index, :show], Profile
can [:index, :show, :view_and_add_notes], ApplicationLetter
# Organizers can view and edit Applications for Events
can [:index, :show, :view_and_add_notes, :update_status], ApplicationLetter
cannot :update, ApplicationLetter
# Organizers can view, edit and print Applications and view participants for Events
can [:view_applicants, :edit_applicants, :view_participants, :print_applications], Event
end
if user.role? :admin
Expand Down
21 changes: 20 additions & 1 deletion app/models/application_letter.rb
Expand Up @@ -24,8 +24,11 @@ class ApplicationLetter < ActiveRecord::Base
validates :vegeterian, :vegan, :allergic, inclusion: { in: [true, false] }
validates :vegeterian, :vegan, :allergic, exclusion: { in: [nil] }
validate :deadline_cannot_be_in_the_past, :if => Proc.new { |letter| !(letter.status_changed?) }
validate :status_cannot_be_changed, :if => Proc.new { |letter| letter.status_changed?}

enum status: {accepted: 1, rejected: 0, pending: 2}
enum status: {accepted: 1, rejected: 0, pending: 2, alternative: 3}
validates :status, inclusion: { in: statuses.keys }


# Checks if the deadline is over
# additionally only return if event and event.application_deadline is present
Expand All @@ -37,11 +40,27 @@ def after_deadline?
Date.current > event.application_deadline if event.present?
end

# Checks if it is allowed to change the status of the application
#
# @param none
# @return [Boolean] true if no status changes are allowed anymore
def status_change_allowed?
!event.application_status_locked
end

# Validator for after_deadline?
# Adds error
def deadline_cannot_be_in_the_past
if after_deadline?
errors.add(:event, I18n.t("application_letters.form.warning"))
end
end

# Validator for status_change_allowed?
# Adds error
def status_cannot_be_changed
unless status_change_allowed?
errors.add(:event, "Die Bewerbungen wurden bereits bearbeitet, eine Statusänderung ist nicht mehr erlaubt.")
end
end
end
8 changes: 4 additions & 4 deletions app/models/date_range.rb
Expand Up @@ -20,24 +20,24 @@ class DateRange < ActiveRecord::Base

def validate_start_date_not_in_past
if start_date < Date.current
errors.add(:start_date, "darf nicht in der Vergangenheit liegen.")
errors.add(:start_date, I18n.t('date_range.errors.starts_in_past'))
end
if end_date < Date.current
errors.add(:end_date, "darf nicht in der Vergangenheit liegen.")
errors.add(:end_date, I18n.t('date_range.errors.end_in_past'))
end
end

def validate_end_not_before_start
if end_date < start_date
errors.add(:end_date, "kann nicht vor Start-Datum liegen.")
errors.add(:end_date, I18n.t('date_range.errors.end_before_start'))
end
end

def to_s
if start_date == end_date
start_date
else
I18n.l(start_date) + ' ' + I18n.t('date_range.to') + ' ' + I18n.l(end_date)
I18n.l(start_date) + ' ' + I18n.t('date_range.pronouns.to') + ' ' + I18n.l(end_date)
end
end
end
24 changes: 24 additions & 0 deletions app/models/email.rb
@@ -0,0 +1,24 @@
class Email
include ActiveAttr::TypecastedAttributes
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming

attribute :hide_recipients, :type => Boolean
attribute :recipients, :type => String
attribute :reply_to, :type => String
attribute :subject, :type => String
attribute :content, :type => String

validates_presence_of :hide_recipients, :recipients, :reply_to, :subject, :content

def initialize(attributes = {})
attributes.each do |name, value|
send("#{name}=", value)
end
end

def persisted?
false
end
end
45 changes: 37 additions & 8 deletions app/models/event.rb
Expand Up @@ -10,6 +10,7 @@
# active :boolean
# created_at :datetime not null
# updated_at :datetime not null
# application_status_locked :boolean
#

class Event < ActiveRecord::Base
Expand Down Expand Up @@ -56,12 +57,12 @@ def unreasonably_long

# validation function on whether we have at least one date range
def has_date_ranges
errors.add(:date_ranges, 'Bitte mindestens eine Zeitspanne auswählen!') if date_ranges.blank?
errors.add(:date_ranges, I18n.t('date_range.errors.no_timespan')) if date_ranges.blank?
end

#validate that application deadline is before the start of the event
def application_deadline_before_start_of_event
errors.add(:application_deadline, I18n.t('events.errors.application_deadline_before_start_of_event')) if application_deadline.present? && !date_ranges.blank? && application_deadline > start_date
errors.add(:application_deadline, I18n.t('events.errors.application_deadline_before_start_of_event')) if application_deadline.present? && !date_ranges.blank? && application_deadline > start_date
end

# Returns the participants whose application for this Event has been accepted
Expand Down Expand Up @@ -91,6 +92,15 @@ def applications_classified?
application_letters.all? { |application_letter| application_letter.status != 'pending' }
end

# Returns a string of all email addresses of accepted applications
#
# @param none
# @return [String] Concatenation of all email addresses of accepted applications, seperated by ','
def email_adresses_of_accepted_applicants
accepted_applications = application_letters.where(status: ApplicationLetter.statuses[:accepted])
accepted_applications.map{ |application_letter| application_letter.user.email }.join(',')
end

# Returns a string of all email addresses of rejected applications
#
# @param none
Expand All @@ -100,13 +110,32 @@ def email_adresses_of_rejected_applicants
rejected_applications.map{ |applications_letter| applications_letter.user.email }.join(',')
end

# Returns a string of all email addresses of accepted applications
# Returns a new acceptance email
#
# @param none
# @return [String] Concatenation of all email addresses of accepted applications, seperated by ','
def email_adresses_of_accepted_applicants
accepted_applications = application_letters.where(status: ApplicationLetter.statuses[:accepted])
accepted_applications.map{ |application_letter| application_letter.user.email }.join(',')
# @return [Email] new acceptance email
def generate_acceptances_email
email = Email.new
email.hide_recipients = false
email.recipients = email_adresses_of_accepted_applicants
email.reply_to = 'workshop.portal@hpi.de'
email.subject = ''
email.content = ''
return email
end

# Returns a new rejection email
#
# @param none
# @return [Email] new rejection email
def generate_rejections_email
email = Email.new
email.hide_recipients = false
email.recipients = email_adresses_of_rejected_applicants
email.reply_to = 'workshop.portal@hpi.de'
email.subject = ''
email.content = ''
return email
end

# Returns the number of free places of the event, this value may be negative
Expand Down Expand Up @@ -138,7 +167,7 @@ def date_ranges_attributes=(*args)
event.date_ranges.each do |date_range|
next if date_range.valid?
date_range.errors.full_messages.each do |msg|
errors.add :date_ranges, msg
errors.add :date_ranges, msg unless errors[:date_ranges].include? msg
end
end
end
Expand Down

0 comments on commit ba7777a

Please sign in to comment.