Skip to content

Commit

Permalink
Merge branch 'master' into TAN-814-survey-ui-improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
EdwinKato committed Mar 11, 2024
2 parents b5aeb3b + d53d990 commit 4720e58
Show file tree
Hide file tree
Showing 249 changed files with 4,087 additions and 1,846 deletions.
50 changes: 50 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ parameters:
type: boolean
default: false

chromatic:
type: boolean
default: false

executors:
cl2-back:
parameters:
Expand Down Expand Up @@ -668,6 +672,30 @@ jobs:
path: /tmp/report.html
destination: lighthouse

front-chromatic:
docker:
- image: citizenlabdotco/cl2-devops-front-buildenv
resource_class: medium
working_directory: ~/citizenlab/front
steps:
# Non-shallow clone (required for chromatic)
- run: mkdir -p ~/.ssh
- run: ssh-keyscan github.com >> ~/.ssh/known_hosts
- run: |
cd ~
rm -rf ~/$(echo $CIRCLE_REPOSITORY_URL | cut -d '/' -f 2 | cut -d '.' -f 1)
git clone -b "$CIRCLE_BRANCH" "$CIRCLE_REPOSITORY_URL"
- restore_cache:
keys:
- v2-npm-cache-{{ checksum "package-lock.json" }}
- <<: *install-front-dependencies
- save_cache:
paths:
- /root/.npm
key: v2-npm-cache-{{ checksum "package-lock.json" }}
- run: npm run chromatic

# E2E TESTS
e2e-tests:
docker:
Expand Down Expand Up @@ -1293,3 +1321,25 @@ workflows:
- "Canada"
- "US West"
# - "UK"

manual-chromatic:
when: << pipeline.parameters.chromatic >>
jobs:
- front-chromatic:
context:
- docker-hub-access
- chromatic

weekly-chromatic:
triggers:
- schedule:
cron: 0 5 * * 1 # Every Monday at 5am: https://crontab.guru/
filters:
branches:
only:
- master
jobs:
- front-chromatic:
context:
- docker-hub-access
- chromatic
6 changes: 3 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ reset-dev-env:
docker-compose run --rm -e RAILS_ENV=test web bin/rails db:drop db:create db:schema:load

migrate:
docker-compose run --rm web bin/rails db:migrate
docker-compose run --rm web bin/rails db:migrate cl2back:clean_tenant_settings email_campaigns:assure_campaign_records fix_existing_tenants:update_permissions cl2back:clear_cache_store email_campaigns:remove_deprecated

be-up:
docker-compose up
Expand Down Expand Up @@ -61,12 +61,12 @@ add-campaign-and-notification:
blint back-lint-autocorrect:
docker compose run web bundle exec rubocop -P --format simple --autocorrect

# Usage example:
# Usage example:
# make r file=spec/models/idea_spec.rb
r rspec:
docker-compose run --rm web bin/rspec ${file}

# Usage example:
# Usage example:
# make feature-toggle feature=initiative_cosponsors enabled=true
feature-toggle:
docker-compose run web "bin/rails runner \"enabled = ${enabled}; feature = '${feature}'; Tenant.find_by(host: 'localhost').switch!; c = AppConfiguration.first; c.settings['${feature}'] ||= {}; c.settings['${feature}']['allowed'] = ${enabled}; c.settings['${feature}']['enabled'] = ${enabled}; c.save!\""
Expand Down
14 changes: 9 additions & 5 deletions back/app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,15 @@ def default_from_email
end

def raw_from_email
app_settings.core.from_email.presence || default_from_email
app_settings.core['from_email'].presence || default_from_email
end

def to_email
email_address_with_name(recipient.email, "#{recipient.first_name} #{recipient.last_name}")
end

def reply_to_email
app_settings.core.reply_to_email.presence || default_from_email
app_settings.core['reply_to_email'].presence || default_from_email
end

def domain
Expand Down Expand Up @@ -203,9 +203,13 @@ def text_direction

def to_deep_struct(obj)
case obj
when Hash then OpenStruct.new(obj.transform_values { |nested_object| to_deep_struct(nested_object) })
when Array then obj.map { |nested_object| to_deep_struct(nested_object) }
else obj
when Hash
struct_obj = obj.transform_values { |nested_object| to_deep_struct(nested_object) }
WhinyOpenStruct.new(struct_obj, raise_exception: false)
when Array
obj.map { |nested_object| to_deep_struct(nested_object) }
else
obj
end
end
end
27 changes: 27 additions & 0 deletions back/app/services/whiny_open_struct.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

# rubocop:disable Style/OpenStructUse

# Latest OpenStruct implementation doesn't define `respond_to_missing?` method
# https://github.com/ruby/ruby/blob/v3_2_0/lib/ostruct.rb
# rubocop:disable Style/MissingRespondToMissing

# Inspired by https://stackoverflow.com/a/16905766
class WhinyOpenStruct < OpenStruct
def initialize(hash, raise_exception: true)
@raise_exception = raise_exception
super(hash)
end

# See https://github.com/ruby/ruby/blob/v2_7_6/lib/ostruct.rb#L99
def method_missing(meth, *args)
if !meth.to_s.end_with?('=') && !@table.key?(meth)
msg = "No '#{meth}' member set yet"
@raise_exception ? raise(NoMethodError, msg) : ErrorReporter.report_msg(msg)
end

super
end
end
# rubocop:enable Style/OpenStructUse
# rubocop:enable Style/MissingRespondToMissing
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@

RSpec.describe FlagInappropriateContent::EmailCampaigns::InappropriateContentFlaggedMailer do
describe 'campaign_mail' do
let!(:recipient) { create(:user, locale: 'en') }
let!(:campaign) { FlagInappropriateContent::EmailCampaigns::Campaigns::InappropriateContentFlagged.create! }
let(:mail) { described_class.with(command: command, campaign: campaign).campaign_mail.deliver_now }

let(:flaggable) { create(:idea) }

let(:command) do
let_it_be(:recipient) { create(:user, locale: 'en') }
let_it_be(:campaign) { FlagInappropriateContent::EmailCampaigns::Campaigns::InappropriateContentFlagged.create! }
let_it_be(:flaggable) { create(:idea) }
let_it_be(:command) do
{
recipient: recipient,
event_payload: {
Expand All @@ -24,6 +21,8 @@
}
end

let_it_be(:mail) { described_class.with(command: command, campaign: campaign).campaign_mail.deliver_now }

before do
EmailCampaigns::UnsubscriptionToken.create!(user_id: recipient.id)
end
Expand Down Expand Up @@ -58,6 +57,8 @@
command[:event_payload][:flag_automatically_detected] = true
end

let(:mail) { described_class.with(command: command, campaign: campaign).campaign_mail.deliver_now }

it 'includes the explanation note about automatic flagging' do
expect(mail.body.encoded).to include('This post was automatically detected')
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module ReportBuilder
class PublishedGraphDataUnitPolicy < ::ApplicationPolicy
def published?
record.report.phase.started? && PhasePolicy.new(user, record.report.phase).show?
ReportPolicy.new(user, record.report).layout?
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -3,92 +3,24 @@
require 'rails_helper'

RSpec.describe ReportBuilder::PublishedGraphDataUnitPolicy do
subject { described_class.new(user, data_unit) }
subject { described_class.new(instance_double(User), data_unit) }

shared_examples 'permits if phase started' do
context 'phase started' do
let_it_be(:phase) { build(:phase, project: project, start_at: 1.day.ago) }
let_it_be(:report) { build(:report, phase: phase) }
let_it_be(:data_unit) { build(:published_graph_data_unit, report: report) }

it { is_expected.to permit(:published) }
end
end

shared_examples 'does not permit if phase not started' do
context 'phase not started' do
let_it_be(:phase) { build(:phase, project: project, start_at: 1.day.from_now) }
let_it_be(:report) { build(:report, phase: phase) }
let_it_be(:data_unit) { build(:published_graph_data_unit, report: report) }

it { is_expected.not_to permit(:published) }
end
end

let_it_be(:project) { create(:project) }
let_it_be(:phase) { create(:phase, project: project) }
let_it_be(:report) { create(:report, phase: phase) }
let_it_be(:report) { create(:report, phase: build(:phase)) }
let_it_be(:data_unit) { create(:published_graph_data_unit, report: report) }

context 'when user is admin' do
let_it_be(:user) { build(:admin) }

it { is_expected.to permit(:published) }
before do
allow(ReportBuilder::ReportPolicy).to receive(:new).and_return(report_policy)
end

context 'when user is moderator' do
context 'when user can moderate project' do
let_it_be(:user) { build(:project_moderator, projects: [project]) }
it { is_expected.to permit(:published) }
end
context 'when ReportPolicy#layout? returns true' do
let(:report_policy) { instance_double(ReportBuilder::ReportPolicy, layout?: true) }

context 'when user cannot moderate project' do
let_it_be(:user) { build(:project_moderator) }

include_examples 'permits if phase started'
include_examples 'does not permit if phase not started'
end
end

context 'when user is normal user' do
let_it_be(:user) { build(:user) }

context 'when user is not project member' do
before do
allow(PhasePolicy).to receive(:new).and_return(instance_double(PhasePolicy, show?: false))
end

it { is_expected.not_to permit(:published) }
end

context 'when user is project member' do
before do
allow(PhasePolicy).to receive(:new).and_return(instance_double(PhasePolicy, show?: true))
end

include_examples 'permits if phase started'
include_examples 'does not permit if phase not started'
end
it { is_expected.to permit(:published) }
end

context 'when user is visitor' do
let_it_be(:user) { nil }

context 'when user is not project member' do
before do
allow(PhasePolicy).to receive(:new).and_return(instance_double(PhasePolicy, show?: false))
end

it { is_expected.not_to permit(:published) }
end

context 'when user is project member' do
before do
allow(PhasePolicy).to receive(:new).and_return(instance_double(PhasePolicy, show?: true))
end
context 'when ReportPolicy#layout? returns false' do
let(:report_policy) { instance_double(ReportBuilder::ReportPolicy, layout?: false) }

include_examples 'permits if phase started'
include_examples 'does not permit if phase not started'
end
it { is_expected.not_to permit(:published) }
end
end
Loading

0 comments on commit 4720e58

Please sign in to comment.