Commit 80ce11c3 authored by Beat Seeliger's avatar Beat Seeliger

Merge branch 'develop' into 'master'

Develop to Master

See merge request !888
parents 02d409f5 2fc9f1e9
Pipeline #32666 failed with stage
in 21 minutes and 18 seconds
......@@ -27,3 +27,4 @@ lib/access_import_test/*.xlsx
.stylelintrc
doc
/.idea
.vscode/
image: git.panter.ch:5001/panter/gitlab-ci-docker-images/ruby-and-rails:ruby-2.4.4-imagemagick-node-8-chrome
stages:
- test
services:
- postgres:9.6
cache:
key: "$CI_PROJECT_ID"
paths:
- tmp/cache/ruby
- tmp/cache/yarn
variables:
RAILS_ENV: test
POSTGRES_DB: aoz_test
DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/$POSTGRES_DB"
before_script:
- bundle install --without development --path /gems_cache
- node --version
- ruby --version
- yarn --version
- bundle install --without development --path tmp/cache
- yarn install --cache-folder tmp/cache/yarn
- bundle exec rails db:schema:load
test:
image: git.panter.ch:5001/open-source/aoz-003/unit:2.4.4-0.3
stage: test
script:
- bundle exec rails test
cache:
paths:
- /gems_cache
system:
image: git.panter.ch:5001/open-source/aoz-003/system:2.36-0.3
stage: test
script:
- bundle exec rails test:system
......@@ -34,5 +41,3 @@ system:
expire_in: 1 week
cache:
policy: pull
paths:
- /gems_cache
......@@ -8,7 +8,11 @@ end
gem 'rails', '~> 5.1'
gem 'autocomplete_rails'
# gem 'autoprefixer-rails' # Exclude Autoprefixer temporary, because of bug in autoprefixer
# FIXME:
# - autoprefixer doesn't run with rubyracer anymore, it would with miniracer
# - installing miniracer ist blocked by panter/panter-rails-deploy rubyracer requirement
# - using Node as Execjs Runtime is not possible, because our hosts don't have node
# gem 'autoprefixer-rails'
gem 'axlsx', github: 'randym/axlsx', ref: '776037c0fc799bb09da8c9ea47980bd3bf296874'
gem 'axlsx_rails'
gem 'bootstrap-datepicker-rails'
......@@ -23,7 +27,7 @@ gem 'country_select'
gem 'devise'
gem 'devise-i18n'
gem 'devise_invitable'
gem 'font-awesome-rails'
gem 'font-awesome-sass'
gem 'i18n_data'
gem 'i18n_rails_helpers'
gem 'jbuilder'
......@@ -56,7 +60,7 @@ gem 'wkhtmltopdf-binary'
group :development do
gem 'awesome_print'
gem 'i18n_yaml_sorter'
gem 'letter_opener'
gem 'letter_opener_web', '~> 1.0'
gem 'overcommit', require: false
gem 'rubocop', require: false
gem 'scss_lint', require: false
......
......@@ -72,7 +72,7 @@ GEM
ast (2.4.0)
autocomplete_rails (0.3.1)
rails (>= 4.0, < 5.2)
autoprefixer-rails (7.2.5)
autoprefixer-rails (9.1.4)
execjs
awesome_print (1.8.0)
axlsx_rails (0.5.1)
......@@ -183,8 +183,8 @@ GEM
railties (>= 3.0.0)
ffaker (2.9.0)
ffi (1.9.25)
font-awesome-rails (4.7.0.4)
railties (>= 3.2, < 6.0)
font-awesome-sass (5.3.1)
sassc (>= 1.11)
globalid (0.4.1)
activesupport (>= 4.2.0)
hashery (2.1.2)
......@@ -216,6 +216,10 @@ GEM
addressable (~> 2.3)
letter_opener (1.6.0)
launchy (~> 2.2)
letter_opener_web (1.3.4)
actionmailer (>= 3.2)
letter_opener (~> 1.0)
railties (>= 3.2)
libv8 (3.16.14.19)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
......@@ -467,7 +471,7 @@ DEPENDENCIES
devise_invitable
factory_bot_rails
ffaker
font-awesome-rails
font-awesome-sass
i18n_data
i18n_rails_helpers
i18n_yaml_sorter
......@@ -475,7 +479,7 @@ DEPENDENCIES
jquery-rails
jquery-ui-rails
js-routes
letter_opener
letter_opener_web (~> 1.0)
listen
lodash-rails
mdb
......@@ -513,4 +517,4 @@ DEPENDENCIES
wkhtmltopdf-binary
BUNDLED WITH
1.16.2
1.17.1
# AOZ Voluntary Platform
[master](https://github.com/panter/aoz-003/tree/master): [![Build Status](https://travis-ci.org/panter/aoz-003.svg?branch=master)](https://travis-ci.org/panter/aoz-003) |
[develop](https://github.com/panter/aoz-003): [![Build Status](https://travis-ci.org/panter/aoz-003.svg?branch=develop)](https://travis-ci.org/panter/aoz-003)
## Pipeline Status
- Develop: [![pipeline status](https://git.panter.ch/open-source/aoz-003/badges/develop/pipeline.svg)](https://git.panter.ch/open-source/aoz-003/commits/develop)
- Master: [![pipeline status](https://git.panter.ch/open-source/aoz-003/badges/master/pipeline.svg)](https://git.panter.ch/open-source/aoz-003/commits/master)
Ruby version: 2.4.2
## Table of content
1. [Dependencies](#dependencies)
1. [Developer Dependencies](#developer-dependencies)
1. [User seeds for development](#user-seeds-for-development)
1. [Create initial superadmin account](#create-initial-superadmin-account)
1. [Sort locale yaml files](#sort-locale-yaml-files)
1. [Importing from access db with rake task](#importing-from-access-db-with-rake-task)
1. [Run model, integration and controller tests](#run-model-integration-and-controller-tests)
1. [Run system (acceptance) tests](#run-system-acceptance-tests)
1. [LICENSE](#license)
- [AOZ Voluntary Platform](#aoz-voluntary-platform)
- [Pipeline Status](#pipeline-status)
- [Table of content](#table-of-content)
- [Dependencies](#dependencies)
- [Developer Dependencies](#developer-dependencies)
- [User seeds for development](#user-seeds-for-development)
- [Create initial superadmin account](#create-initial-superadmin-account)
- [Sort locale yaml files](#sort-locale-yaml-files)
- [Importing from access db with rake task](#importing-from-access-db-with-rake-task)
- [Run model, integration and controller tests](#run-model-integration-and-controller-tests)
- [Run system (acceptance) tests](#run-system-acceptance-tests)
- [LICENSE](#license)
### Dependencies
......
$(() => {
$('.api-button').click(({target}) => {
const { method, url, template } = $(target).data()
const tableCell = $(target).closest('td')
$.ajax({ method, url, dataType: 'json' })
.done(data => {
if (data.errors) {
$(tableCell).append(`<p class="text-danger">Es gab einen Fehler: ${data.errors.join('; ')}</p>`)
} else {
const compiled = _.template(template, { 'variable': 'data', 'imports': { 'data': data } })
$(target).remove()
$(tableCell).append(compiled(data))
}
})
})
})
$(() => {
// Only run this on new_semester_process_path
if (Routes.new_semester_process_path() !== window.location.pathname) { return }
$('select.semester-selector').change(({ target }) => {
window.location.href = `${window.location.origin}${Routes.new_semester_process_path({ semester: $(target).val() })}`
})
})
......@@ -12,7 +12,7 @@ $a4-short-side: 210mm;
$a4-long-side: 297mm;
// Colours
$custom-red: #a51a0f;
$custom-red: #e63028;
$white: #fff;
$black: #000;
$dark: #333;
......
......@@ -171,3 +171,7 @@ h5.small {
.fixed-width-lg {
width: 600px;
}
.float-right {
float: right;
}
......@@ -3,7 +3,8 @@
@import 'inplace_fields';
@import 'bootstrap-datepicker3';
@import "font-awesome";
@import 'font-awesome-sprockets';
@import 'font-awesome';
@import 'jquery-ui/core';
@import 'jquery-ui/autocomplete';
@import 'jquery-ui/theme';
......
......@@ -13,9 +13,17 @@ body,
}
.footer {
align-self: center;
background-color: $white;
flex: 0 0 auto;
text-align: center;
font-family: Arial,Helvetica Neue, Helvetica, sans-serif;
width: 100%;
hr {
border-color: $custom-red;
}
p .red {
background: none;
color: $custom-red;
}
}
......@@ -2,6 +2,18 @@
.limit-width {
width: 5%;
}
.limit-width-10 {
width: 10%;
}
.limit-width-15 {
width: 15%;
}
.limit-width-40 {
width: 40%;
}
}
.table-scrollable {
......
class FeedbacksController < ApplicationController
before_action :set_feedback,
only: [:show, :edit, :update, :destroy, :mark_as_done, :take_responsibility]
before_action :set_feedbackable
before_action :set_feedbackable, except: [:index]
before_action :set_volunteer
before_action :set_list_response_feedback_redirect_back_path,
only: [:mark_as_done, :take_responsibility]
def index
authorize Feedback
@feedbacks = policy_scope(Feedback).where(feedbackable: @feedbackable)
@feedbacks = if params[:assignment_id]
SemesterFeedback.where(assignment_id: params[:assignment_id])
elsif params[:group_offer_id]
SemesterFeedback.where(group_assignment_id: GroupAssignment.where(group_offer_id: params[:group_offer_id]).ids)
else
[]
end
end
def show; end
def new
@feedback = Feedback.new(feedbackable: @feedbackable, volunteer: @volunteer,
@feedback = SemesterFeedback.new(feedbackable: @feedbackable, volunteer: @volunteer,
author: current_user)
authorize @feedback
simple_form_params
......@@ -51,18 +57,29 @@ class FeedbacksController < ApplicationController
end
def mark_as_done
if @feedback.update(reviewer: current_user)
redirect_to(@redirect_back_path, notice: 'Halbjahres-Rapport quittiert.')
else
redirect_to(@redirect_back_path, notice: 'Fehler: Quittieren fehlgeschlagen.')
respond_to do |format|
if @feedback.update(reviewer: current_user)
format.html { redirect_to(@redirect_back_path, notice: 'Halbjahres-Rapport quittiert.') }
format.json { render json: { link: polymorphic_path([@feedback.volunteer, @feedback.feedbackable, @feedback]) }, status: :ok }
else
format.html { redirect_to(@redirect_back_path, notice: 'Fehler: Quittieren fehlgeschlagen.') }
format.json { render json: { errors: @feedback.errors.messages }, status: :unprocessable_entity }
end
end
end
def take_responsibility
if @feedback.update(responsible: current_user)
redirect_to(@redirect_back_path, notice: 'Halbjahres-Rapport übernommen.')
else
redirect_to(@redirect_back_path, notice: 'Fehler: Übernehmen fehlgeschlagen.')
respond_to do |format|
if @feedback.update(responsible: current_user)
format.html { redirect_to(@redirect_back_path, notice: 'Halbjahres-Rapport übernommen.') }
format.json do
render json: { link: url_for(@feedback.responsible), at: I18n.l(@feedback.responsible_at.to_date),
email: @feedback.responsible.email }, status: :ok
end
else
format.html { redirect_to(@redirect_back_path, notice: 'Fehler: Übernehmen fehlgeschlagen.') }
format.json { render json: { errors: @feedback.errors.messages }, status: :unprocessable_entity }
end
end
end
......
......@@ -11,6 +11,8 @@ class JournalsController < ApplicationController
def new
@journal = @journaled.journals.new
handle_feedback_quote
handle_semester_feedback_quote
authorize @journal
end
......@@ -56,6 +58,28 @@ class JournalsController < ApplicationController
@journaled = Volunteer.find(params[:volunteer_id])
end
def handle_feedback_quote
return unless params[:feedback_id]
@feedback = Feedback.find_by(id: params[:feedback_id])
return unless @feedback
@journal.category = :feedback
@journal.title = "Feedback vom #{I18n.l(@feedback.created_at.to_date)}: "
@journal.body = @feedback.slice(:goals, :achievements, :future, :comments).map do |key, fb_quote|
"#{I18n.t("activerecord.attributes.feedback.#{key}")}:\n«#{fb_quote}»" if fb_quote.present?
end.compact.join("\n\n")
end
def handle_semester_feedback_quote
return unless params[:semester_feedback_id]
@semester_feedback = SemesterFeedback.find_by(id: params[:semester_feedback_id])
return unless @semester_feedback
@journal.category = :feedback
@journal.title = "Semester Prozess Feedback vom #{I18n.l(@semester_feedback.created_at.to_date)}: "
@journal.body = @semester_feedback.slice(:goals, :achievements, :future, :comments).map do |key, sfb_quote|
"#{I18n.t("activerecord.attributes.feedback.#{key}")}:\n«#{sfb_quote}»" if sfb_quote.present?
end.compact.join("\n\n")
end
def journal_params
params.require(:journal).permit(
:category, :user_id, :body, :title, :client_id, :volunteer_id
......
class SemesterProcessVolunteersController < ApplicationController
before_action :prepare_review, :initialize_nested_objects, only: [:review_semester, :submit_review]
before_action :set_semester_process_volunteer, only: [:show, :edit, :update, :take_responsibility, :mark_as_done, :update_notes]
before_action :set_semester, only: [:index]
include SemesterProcessVolunteerHelper
def review_semester; end
def submit_review
# you shall not pass
return if @semester_process_volunteer.commited_at
set_reviewed
assign_volunteer_attributes
build_nested_objects
@semester_process_volunteer.volunteer.validate_waive_and_bank = true
ActiveRecord::Base.transaction do
@semester_process_volunteer.save!
@volunteer.save!
@nested_objects.each do |_key, hash|
hash.each { |_id, obj| obj.save! }
end
end
create_journals
redirect_to review_semester_semester_process_volunteer_path(@semester_process_volunteer), notice: t('.success')
rescue ActiveRecord::RecordInvalid => exception
logger.error exception.message
null_reviewed
flash[:alert] = exception.message
render :review_semester
end
def index
authorize SemesterProcessVolunteer
semester = Semester.parse(params[:semester])
@semester_process = SemesterProcess.find_by_semester(semester).last
@q = SemesterProcessVolunteer.index(@semester_process).ransack(params[:q])
@q.sorts = ['volunteer_contact_last_name asc'] if @q.sorts.empty?
@spvs = @q.result.paginate(page: params[:page])
set_responsibles
set_reviewers
end
def show; end
def edit; end
def update
if @spv.update(semester_process_params)
redirect_to @spv, notice: 'Semester process was successfully updated.'
else
render :edit
end
end
def take_responsibility
respond_to do |format|
if @spv.update(responsible: current_user)
format.html { redirect_to semester_process_volunteers_path, notice: 'Semester Prozess übernommen.' }
format.json do
render json: { link: url_for(@spv.responsible), at: I18n.l(@spv.responsibility_taken_at.to_date),
email: @spv.responsible.email }, status: :ok
end
else
format.html { redirect_to semester_process_volunteers_path, notice: 'Fehler: Übernehmen fehlgeschlagen.' }
format.json { render json: { errors: @spv.errors.messages }, status: :unprocessable_entity }
end
end
end
def mark_as_done
respond_to do |format|
if @spv.update(reviewed_by: current_user, reviewed_at: Time.zone.now)
format.html { redirect_to semester_process_volunteers_path, notice: 'Semester Prozess quittiert.' }
format.json do
render json: { link: url_for(@spv.reviewed_by), at: I18n.l(@spv.reviewed_at.to_date),
email: @spv.reviewed_by.email }, status: :ok
end
else
format.html { redirect_to semester_process_volunteers_path, notice: 'Fehler: Quittieren fehlgeschlagen.' }
format.json { render json: { errors: @spv.errors.messages }, status: :unprocessable_entity }
end
end
end
def update_notes
updated_notes = semester_process_volunteer_params[:notes]
@spv.update_attribute(:notes, updated_notes)
end
private
def prepare_review
@semester_process_volunteer = SemesterProcessVolunteer.find(params[:id])
authorize @semester_process_volunteer
@volunteer = @semester_process_volunteer.volunteer
@missions = @semester_process_volunteer.missions
end
def review_params
params.require(:semester_process_volunteer).permit(
volunteer_attributes: [:id, :waive, :iban, :bank],
semester_feedbacks_attributes: [[semester_feedback: [:mission, :goals, :achievements, :future, :comments, :conversation, :spv_mission_id]],
[hour: [:hours, :spv_mission_id, :activity]]]
)
end
def set_semester_process_volunteer
@spv = SemesterProcessVolunteer.find(params[:id])
authorize @spv
@semester_process = @spv.semester_process
@volunteer = @spv.volunteer
end
def set_semester
@semester = Semester.new
if params[:semester]
@selected_semester = Semester.parse(params[:semester])
else
@selected_semester = @semester.previous
params[:semester] = Semester.to_s(@selected_semester)
end
end
def set_responsibles
@responsibles = SemesterProcessVolunteer.joins(responsible: [profile: [:contact]])
.distinct
.select('users.id, contacts.full_name')
.map do |responsible|
{
q: :responsible_id_eq,
text: "Übernommen von #{responsible.full_name}",
value: responsible.id
}
end
end
def set_reviewers
@reviewers = SemesterProcessVolunteer.joins(reviewed_by: [profile: [:contact]])
.distinct
.select('users.id, contacts.full_name')
.map do |reviewed_by|
{
q: :reviewed_by_id_eq,
text: "Quittiert von #{reviewed_by.full_name}",
value: reviewed_by.id
}
end
end
def semester_process_volunteer_params
params.require(:semester_process_volunteer).permit(:semester, :notes)
end
end
class SemesterProcessesController < ApplicationController
before_action :set_semester_process, only: [:show, :edit, :update, :overdue]
before_action :set_semester, only: [:new, :create]
include SemesterProcessHelper
def index
authorize SemesterProcess
@semester_processes = SemesterProcess.all.paginate(page: params[:page])
end
def show; end
def new
@semester_process = SemesterProcess.new(semester: @selected_semester, kind: :mail )
new_or_edit
end
def edit
@semester_process.kind = :mail
new_or_edit
end
def create
@semester_process = SemesterProcess.new(semester_process_params.slice(:kind, :semester))
update_or_create
end
def update
@save = params[:save_records]
update_or_create
end
def overdue
@semester_process.kind = :reminder
@volunteers = Volunteer.feedback_overdue(@semester_process.semester)
@semester_process.build_semester_volunteers(@volunteers, preselect: true)
@spvs_sorted = sort_volunteers
params[:semester] = Semester.to_s(@semester_process.semester.begin)
if EmailTemplate.half_year_process_overdue.active.any?
template = EmailTemplate.half_year_process_overdue.active.first.slice(:subject, :body)
@semester_process.assign_attributes(reminder_mail_body_template: template[:body], reminder_mail_subject_template: template[:subject])
else
redirect_to new_email_template_path,
notice: 'Sie müssen eine aktive E-Mailvorlage haben,
bevor Sie eine Halbjahres Erinnerung erstellen können.'
end
end
private
def new_or_edit
authorize @semester_process
@volunteers = Volunteer.semester_process_eligible(@semester_process.semester)
@semester_process.build_semester_volunteers(@volunteers)
@spvs_sorted = sort_volunteers
if EmailTemplate.half_year_process_email.active.any?
template = EmailTemplate.half_year_process_email.active.first.slice(:subject, :body)
@semester_process.assign_attributes(mail_body_template: template[:body], mail_subject_template: template[:subject])
else
redirect_to new_email_template_path,
notice: 'Sie müssen eine aktive E-Mailvorlage haben,
bevor Sie eine Halbjahres Erinnerung erstellen können.'
end
end
def update_or_create
authorize @semester_process
@semester_process.kind = semester_process_params[:kind]
@semester_process.creator = current_user
if @semester_process.kind == "mail"
@semester_process.assign_attributes(
mail_body_template: semester_process_params[:body],
mail_subject_template: semester_process_params[:subject]
)
@volunteers = Volunteer.semester_process_eligible(@semester_process.semester)
@semester_process.build_semester_volunteers(@volunteers, selected: selected_volunteers, save_records: true)
@semester_process.build_volunteers_feedbacks_and_mails
else
@semester_process.update_attributes(
reminder_mail_body_template: semester_process_params[:body],
reminder_mail_subject_template: semester_process_params[:subject]
)
@volunteers = Volunteer.feedback_overdue(@semester_process.semester)
@semester_process.build_volunteers_feedbacks_and_mails(selected_volunteers)
end
if @semester_process.save
redirect_to semester_process_volunteers_path, notice: 'Semester process was successfully created and emails delivered.'
else