Skip to content

Commit

Permalink
Merge branch 'master' into TAN-449-data-for-reports
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-cit committed Nov 16, 2023
2 parents 6035eb5 + 11f8c37 commit 721b340
Show file tree
Hide file tree
Showing 111 changed files with 1,083 additions and 316 deletions.
37 changes: 28 additions & 9 deletions back/app/services/activities_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,60 @@ def create_periodic_activities(now: Time.zone.now, since: 1.hour)
def create_phase_started_activities(now, last_time)
return unless now.to_date != last_time.to_date

Phase.published.starting_on(now.to_date).each do |phase|
start_date = now.to_date
starting_phases = Phase.published.starting_on(start_date)

# Phases that already have a started activity for *this starting date* are excluded
# to avoid creating duplicate activities (and, consequently, duplicate
# notifications). We still allow the creation of new activities when the start date
# is different (which can occur if the phase is edited).
excluded_phases = Activity
.where(item_id: starting_phases, action: 'started', acted_at: start_date)
.select(:item_id)

starting_phases.where.not(id: excluded_phases).each do |phase|
if phase.ends_before?(now + 1.day)
raise "Invalid phase started event would have been generated for phase\
#{phase.id} with now=#{now} and last_time=#{last_time}"
end

LogActivityJob.perform_later(phase, 'started', nil, phase.start_at.to_time.to_i)
LogActivityJob.perform_later(phase, 'started', nil, start_date.to_time)
end
end

def create_phase_upcoming_activities(now, last_time)
return unless now.to_date != last_time.to_date
today = now.to_date
return unless today != last_time.to_date

upcoming_phases = Phase.published.starting_on(today..(today + 1.week))
# Exclude phases for which an upcoming activity has already been created to avoid
# duplicate notifications.
excluded_phases = Activity
.where(item_id: upcoming_phases, action: 'upcoming')
.select(:item_id)

Phase.published.starting_on(now.to_date + 1.week).each do |phase|
upcoming_phases.where.not(id: excluded_phases).each do |phase|
if phase.ends_before?(now + 1.day)
raise "Invalid phase upcoming event would have been generated for phase\
#{phase.id} with now=#{now} and last_time=#{last_time}"
end

LogActivityJob.perform_later(phase, 'upcoming', nil, now.to_i)
LogActivityJob.perform_later(phase, 'upcoming', nil, now)
end
end

def create_invite_not_accepted_since_3_days_activities(now, last_time)
Invite.where(accepted_at: nil)
.where(created_at: (last_time - 3.days)..(now - 3.days)).each do |invite|
LogActivityJob.perform_later(invite, 'not_accepted_since_3_days', nil, now.to_i)
LogActivityJob.perform_later(invite, 'not_accepted_since_3_days', nil, now)
end
end

def create_phase_ending_soon_activities(now)
if now.hour >= 8 && now.hour <= 20 # Only log activities during day time so they emails are more likely to be noticed
Phase.published.where(end_at: now..now + 2.days).each do |phase|
if Activity.find_by(item: phase, action: 'ending_soon').nil?
LogActivityJob.perform_later(phase, 'ending_soon', nil, now.to_i)
LogActivityJob.perform_later(phase, 'ending_soon', nil, now)
end
end
end
Expand All @@ -62,15 +81,15 @@ def create_phase_ending_soon_activities(now)
def create_basket_not_submitted_activities(now)
Basket.not_submitted.each do |basket|
if Activity.find_by(item: basket, action: 'not_submitted').nil? && basket.baskets_ideas.present? && basket.baskets_ideas.order(:updated_at).last.updated_at <= now - 1.day
LogActivityJob.perform_later(basket, 'not_submitted', nil, now.to_i)
LogActivityJob.perform_later(basket, 'not_submitted', nil, now)
end
end
end

def create_phase_ended_activities(now)
Phase.published.where(end_at: ..now).each do |phase|
if Activity.find_by(item: phase, action: 'ended').nil?
LogActivityJob.perform_later(phase, 'ended', nil, now.to_i)
LogActivityJob.perform_later(phase, 'ended', nil, now)
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions back/app/services/idea_custom_fields_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ def submittable_fields
enabled_fields.reject { |field| unsubbmittable_input_types.include? field.input_type }
end

def printable_fields
ignore_field_types = %w[section date files image_files point linear_scale file_upload]
enabled_fields.reject { |field| ignore_field_types.include? field.input_type }
end

def importable_fields
ignore_field_types = %w[page section date files image_files point linear_scale file_upload]
enabled_fields.reject { |field| ignore_field_types.include? field.input_type }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def create
# The validations and hooks on the user model don't allow us to set
# confirm before save on creation, they'll get reset. So we're forced to
# do a 2nd save operation.
if [true, 'TRUE', 'true', '1', 1].include?(params[:confirm_email])
if confirm_user?
@user.confirm
@user.save
end
Expand All @@ -53,6 +53,8 @@ def create

def update
@user.assign_attributes user_params
@user.confirm if confirm_user?

if @user.save
SideFxUserService.new.after_update(@user, nil)
# This uses default model serialization
Expand Down Expand Up @@ -83,5 +85,9 @@ def user_params
.require(:user)
.permit(:first_name, :last_name, :email, :password, :remote_avatar_url, roles: %i[type project_id], custom_field_values: allowed_custom_field_keys)
end

def confirm_user?
params[:confirm_email].to_s.downcase.in?(%w[true 1])
end
end
end
23 changes: 23 additions & 0 deletions back/engines/commercial/admin_api/spec/acceptance/users_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@
parameter :remote_avatar_url, 'The user avatar'
parameter :custom_field_values, 'All custom field values, if given overwrites the existing values'
end
parameter :confirm_email, 'Should the email already be verified?', required: false, default: false

ValidationErrorHelper.new.error_fields(self, User)

let(:id) { user.id }
Expand All @@ -149,5 +151,26 @@
expect(json_response[:custom_field_values]).to eq({ favourite_drink: 'wine' })
end
end

describe do
before do
SettingsService.new.activate_feature!('user_confirmation')
end

let(:confirm_email) { true }
let(:password) { 'new-password' }
let(:roles) { [{ type: 'admin' }] }

example 'Update a user and confirm email' do
expect { do_request }.to change { user.reload.password_digest }

expect(status).to be 200

user.reload
expect(user.email_confirmed_at).to be_present
expect(user.confirmation_required?).to be false
expect(user.roles).to eq [{ 'type' => 'admin' }]
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ def merge_pdf_rows(parsed_ideas)

form_parsed_ideas.each_with_index.map do |idea, index|
idea[:custom_field_values] = text_parsed_ideas[index][:custom_field_values].merge(idea[:custom_field_values])
idea[:pdf_pages] = complete_page_range(idea[:pdf_pages], text_parsed_ideas[index][:pdf_pages])
text_parsed_ideas[index].merge(idea)
end
end
Expand Down Expand Up @@ -313,10 +314,17 @@ def process_user_details(doc, idea_row)
idea_row
end

def complete_page_range(pages1, pages2)
min = [pages1.min, pages2.min].min
max = [pages1.max, pages2.max].max
(min..max).to_a
end

# Return the fields and page count to import data to
def import_form_data(personal_data_enabled)
# NOTE: It calls this form an xlsx import too - one side effect currently - proposed budget does not import
PrintCustomFieldsService.new(@phase || @project, @form_fields, @locale, personal_data_enabled).importer_data
printable_fields = IdeaCustomFieldsService.new(@participation_method.custom_form).printable_fields
PrintCustomFieldsService.new(@phase || @project, printable_fields, @locale, personal_data_enabled).importer_data
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -577,5 +577,19 @@
end
end
end

describe 'complete_page_range' do
it 'returns the full range of page numbers from two arrays' do
array1 = [1, 3, 4]
array2 = [2, 6, 7]
range = service.send(:complete_page_range, array1, array2)
expect(range).to eq [1, 2, 3, 4, 5, 6, 7]

array3 = [7, 10, 12]
array4 = [7, 8, 9]
range = service.send(:complete_page_range, array3, array4)
expect(range).to eq [7, 8, 9, 10, 11, 12]
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,27 @@

describe BulkImportIdeas::PrintCustomFieldsService do
let(:project) { create(:continuous_project) }
let(:custom_form) { create(:custom_form, participation_context: project) }
let(:service) { described_class.new project, custom_form.custom_fields, 'en', false }
let(:custom_form) { create(:custom_form, :with_default_fields, participation_context: project) }

before do
# Custom fields
create(:custom_field, resource: custom_form, key: 'a_text_field', title_multiloc: { 'en' => 'A text field' }, enabled: true)

create(:custom_field, resource: custom_form, key: 'number_field', title_multiloc: { 'en' => 'Number field' }, input_type: 'number', enabled: true)

select_field = create(:custom_field, resource: custom_form, key: 'select_field', title_multiloc: { 'en' => 'Select field' }, input_type: 'select', enabled: true)
create(:custom_field_option, custom_field: select_field, key: 'yes', title_multiloc: { 'en' => 'Yes' })
create(:custom_field_option, custom_field: select_field, key: 'no', title_multiloc: { 'en' => 'No' })

create(:custom_field, resource: custom_form, key: 'page', input_type: 'page', enabled: true)

multiselect_field = create(:custom_field, resource: custom_form, key: 'multiselect_field', title_multiloc: { 'en' => 'Multi select field' }, input_type: 'multiselect', enabled: true)
create(:custom_field_option, custom_field: multiselect_field, key: 'this', title_multiloc: { 'en' => 'This' })
create(:custom_field_option, custom_field: multiselect_field, key: 'that', title_multiloc: { 'en' => 'That' })

create(:custom_field, resource: custom_form, key: 'page', input_type: 'page', enabled: true)

another_select_field = create(:custom_field, resource: custom_form, key: 'another_select_field', title_multiloc: { 'en' => 'Another select field' }, input_type: 'select', enabled: true)
create(:custom_field_option, custom_field: another_select_field, key: 'yes', title_multiloc: { 'en' => 'Yes' })
create(:custom_field_option, custom_field: another_select_field, key: 'no', title_multiloc: { 'en' => 'No' })
Expand All @@ -30,11 +38,9 @@

describe 'importer_data' do
it 'returns form meta data for importer - page count, fields, options and positions' do
expect(service.importer_data[:fields].pluck(:key)).to eq %w[
title_multiloc
body_multiloc
location_description
proposed_budget
importer_data = service.importer_data
expect(importer_data[:page_count]).to eq 3
expect(importer_data[:fields].pluck(:key)).to eq %w[
a_text_field
number_field
select_field
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ def municipality_code(cpr_number)
headers: headers,
basic_auth: { username: api_config['username'], password: api_config['password'] }
)
unless response.success?
ErrorReporter.report_msg('Error in KKI Location API', extra: { status_code: response.code })
end
response['cprMunicipalityCode']
end

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true

require 'rails_helper'
require 'savon/mock/spec_helper'

describe IdNemlogIn::KkiLocationApi do
let(:cpr_number) { '1234567890' }
let(:base_uri) { 'http://api.example.com/' }
let(:full_uri) { base_uri + cpr_number }

before do
configuration = AppConfiguration.instance
settings = configuration.settings
settings['kki_location_api'] = {
allowed: true,
enabled: true,
uri: base_uri,
username: 'username',
password: 'password',
custom_headers: 'h1: value1, h2: value2'
}
configuration.save!
end

it 'returns municipality code' do
stub_request(:get, full_uri).to_return(
body: '{"cprMunicipalityCode": "123"}',
headers: { 'Content-Type' => 'application/json' }
)

result = described_class.new.municipality_code(cpr_number)
expect(result).to eq('123')
end

it 'logs error if response is not successful' do
stub_request(:get, full_uri).to_return(status: 500)

expect(ErrorReporter).to receive(:report_msg).and_call_original
result = described_class.new.municipality_code(cpr_number)
expect(result).to be_nil
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@ class DeliveryService
Campaigns::AssigneeDigest,
Campaigns::CommentDeletedByAdmin,
Campaigns::CommentMarkedAsSpam,
Campaigns::CommentOnYourComment,
Campaigns::CommentOnIdeaYouFollow,
Campaigns::CommentOnInitiativeYouFollow,
Campaigns::CommentOnYourComment,
Campaigns::CosponsorOfYourInitiative,
Campaigns::EventRegistrationConfirmation,
Campaigns::IdeaMarkedAsSpam,
Campaigns::IdeaPublished,
Campaigns::InitiativeAssignedToYou,
Campaigns::InitiativeMarkedAsSpam,
Campaigns::InitiativePublished,
Campaigns::InvitationToCosponsorInitiative,
Campaigns::InitiativeResubmittedForReview,
Campaigns::InternalCommentOnIdeaAssignedToYou,
Campaigns::InternalCommentOnIdeaYouCommentedInternallyOn,
Expand All @@ -28,6 +27,7 @@ class DeliveryService
Campaigns::InternalCommentOnUnassignedInitiative,
Campaigns::InternalCommentOnUnassignedUnmoderatedIdea,
Campaigns::InternalCommentOnYourInternalComment,
Campaigns::InvitationToCosponsorInitiative,
Campaigns::InviteReceived,
Campaigns::InviteReminder,
Campaigns::Manual,
Expand All @@ -48,6 +48,8 @@ class DeliveryService
Campaigns::StatusChangeOnInitiativeYouFollow,
Campaigns::ThresholdReachedForAdmin,
Campaigns::UserDigest,
Campaigns::VotingPhaseStarted,
Campaigns::VotingResults,
Campaigns::Welcome,
Campaigns::YourProposedInitiativesDigest
].freeze
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ ach:
"voting_basket_submitted": crwdns777337:0crwdne777337:0
"voting_basket_not_submitted": crwdns777339:0crwdne777339:0
"voting_last_chance": crwdns777341:0crwdne777341:0
"voting_phase_started": crwdns1336704:0crwdne1336704:0
"voting_results": crwdns777343:0crwdne777343:0
"your_proposed_initiatives_digest": crwdns208148:0crwdne208148:0
general:
Expand Down
1 change: 1 addition & 0 deletions back/engines/free/email_campaigns/config/locales/ar-MA.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ ar-MA:
"voting_basket_submitted": تأكيد التصويت
"voting_basket_not_submitted": لم يتم تقديم الأصوات
"voting_last_chance": آخر فرصة للتصويت
"voting_phase_started": مرحلة المشروع الجديد مع التصويت
"voting_results": نتائج التصويت
"your_proposed_initiatives_digest": نظرة عامة أسبوعية على مُقترحاتك
general:
Expand Down
1 change: 1 addition & 0 deletions back/engines/free/email_campaigns/config/locales/ar-SA.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ ar:
"voting_basket_submitted": تأكيد التصويت
"voting_basket_not_submitted": لم يتم تقديم الأصوات
"voting_last_chance": آخر فرصة للتصويت
"voting_phase_started": مرحلة المشروع الجديد مع التصويت
"voting_results": نتائج التصويت
"your_proposed_initiatives_digest": نظرة عامة أسبوعية على مُقترحاتك
general:
Expand Down
1 change: 1 addition & 0 deletions back/engines/free/email_campaigns/config/locales/ca-ES.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ ca:
"voting_basket_submitted": Confirmació de la votació
"voting_basket_not_submitted": Vots no enviats
"voting_last_chance": Última oportunitat per votar
"voting_phase_started": Nova fase del projecte amb votació
"voting_results": Resultats de les votacions
"your_proposed_initiatives_digest": Resum setmanal de les vostres propostes
general:
Expand Down
1 change: 1 addition & 0 deletions back/engines/free/email_campaigns/config/locales/da-DK.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ da:
"voting_basket_submitted": Bekræftelse af afstemning
"voting_basket_not_submitted": Stemmer ikke afgivet
"voting_last_chance": Sidste chance for at stemme
"voting_phase_started": Ny projektfase med afstemning
"voting_results": Afstemningsresultater
"your_proposed_initiatives_digest": Ugentlig oversigt over dine forslag
general:
Expand Down
1 change: 1 addition & 0 deletions back/engines/free/email_campaigns/config/locales/de-DE.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ de:
"voting_basket_submitted": Bestätigung der Abstimmung
"voting_basket_not_submitted": Nicht abgegebene Stimmen
"voting_last_chance": Letzte Chance zur Abstimmung
"voting_phase_started": Neue Projektphase mit Abstimmung
"voting_results": Abstimmungsergebnisse
"your_proposed_initiatives_digest": Wöchentliche Übersicht eigener Vorschläge
general:
Expand Down
1 change: 1 addition & 0 deletions back/engines/free/email_campaigns/config/locales/el-GR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ el:
"voting_basket_submitted": Επιβεβαίωση της ψηφοφορίας
"voting_basket_not_submitted": Ψήφοι που δεν υποβλήθηκαν
"voting_last_chance": Τελευταία ευκαιρία να ψηφίσετε
"voting_phase_started": Νέα φάση έργου με ψηφοφορία
"voting_results": Αποτελέσματα ψηφοφορίας
"your_proposed_initiatives_digest": Εβδομαδιαία επισκόπηση των προτάσεών σας
general:
Expand Down
Loading

0 comments on commit 721b340

Please sign in to comment.