Skip to content

Commit

Permalink
Merge pull request #8405 from CitizenLabDotCo/TAN-2209-volunteering-p…
Browse files Browse the repository at this point in the history
…ermissions

TAN-2209 Volunteering permissions
  • Loading branch information
luucvanderzee authored Jul 29, 2024
2 parents cdb6718 + 24a23ac commit 7555810
Show file tree
Hide file tree
Showing 23 changed files with 202 additions and 46 deletions.
2 changes: 1 addition & 1 deletion back/app/models/permission.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class Permission < ApplicationRecord
'survey' => %w[taking_survey attending_event],
'poll' => %w[taking_poll attending_event],
'voting' => %w[voting commenting_idea attending_event],
'volunteering' => %w[attending_event],
'volunteering' => %w[volunteering attending_event],
'document_annotation' => %w[annotating_document attending_event]
}
SCOPE_TYPES = [nil, 'Phase'].freeze
Expand Down
5 changes: 5 additions & 0 deletions back/app/services/permissions/base_permissions_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class BasePermissionsService
taking_survey
taking_poll
attending_event
volunteering
].freeze

USER_DENIED_REASONS = {
Expand Down Expand Up @@ -81,5 +82,9 @@ def user_denied_reason(permission, scope = nil)
def denied_when_permitted_by_groups?(permission)
permission.permitted_by == 'groups' && permission.groups && !user.in_any_groups?(permission.groups)
end

def user_requirements_service
@user_requirements_service ||= Permissions::UserRequirementsService.new(check_groups: false)
end
end
end
12 changes: 12 additions & 0 deletions back/app/services/permissions/phase_permissions_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class PhasePermissionsService < BasePermissionsService
already_responded: 'already_responded'
}.freeze

VOLUNTEERING_DENIED_REASONS = {
not_volunteering: 'not_volunteering'
}.freeze

def initialize(phase, user, user_requirements_service: nil)
super(user, user_requirements_service: user_requirements_service)
@phase ||= phase
Expand All @@ -63,6 +67,8 @@ def denied_reason_for_action(action, reaction_mode: nil)
taking_survey_denied_reason_for_action
when 'taking_poll'
taking_poll_denied_reason_for_action
when 'volunteering'
volunteering_denied_reason_for_phase
else
raise "Unsupported action: #{action}" unless SUPPORTED_ACTIONS.include?(action)
end
Expand Down Expand Up @@ -136,6 +142,12 @@ def voting_denied_reason_for_action
end
end

def volunteering_denied_reason_for_phase
unless phase.volunteering?
VOLUNTEERING_DENIED_REASONS[:not_volunteering]
end
end

# Helper methods

def posting_limit_reached?
Expand Down
6 changes: 6 additions & 0 deletions back/app/services/permissions/project_permissions_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ def action_descriptors
taking_poll_disabled_reason = denied_reason_for_action 'taking_poll'
voting_disabled_reason = denied_reason_for_action 'voting'
attending_event_disabled_reason = denied_reason_for_action 'attending_event'
volunteering_disabled_reason = denied_reason_for_action 'volunteering'

{
posting_idea: {
enabled: !posting_disabled_reason,
Expand Down Expand Up @@ -81,6 +83,10 @@ def action_descriptors
attending_event: {
enabled: !attending_event_disabled_reason,
disabled_reason: attending_event_disabled_reason
},
volunteering: {
enabled: !volunteering_disabled_reason,
disabled_reason: volunteering_disabled_reason
}
}
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@
before_all do
# 2020
past_project = create(:project)
create(:phase, project: past_project, start_at: Date.new(2020, 2, 1), end_at: Date.new(2020, 3, 1))
create(
:phase,
project: past_project,
start_at: Date.new(2020, 2, 1),
end_at: Date.new(2020, 3, 1),
with_permissions: true
)

# 2021
@project1 = create(:project)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ def index_xlsx?
end

def create?
user&.active? &&
(record.user_id == user.id) &&
ProjectPolicy.new(user, record.cause.phase.project).show?
return false unless user&.active?
return false unless record.user_id == user.id

reason = Permissions::ProjectPermissionsService.new.denied_reason_for_action 'volunteering', user, record.cause.phase.project
return false if reason

ProjectPolicy.new(user, record.cause.phase.project).show?
end

def destroy?
Expand Down
56 changes: 54 additions & 2 deletions back/engines/free/volunteering/spec/acceptance/volunteers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,17 @@
post 'web_api/v1/causes/:cause_id/volunteers' do
ValidationErrorHelper.new.error_fields(self, Volunteering::Volunteer)

let(:cause) { create(:cause) }
let(:cause) do
create(
:cause,
phase: create(
:volunteering_phase,
start_at: 6.months.ago,
end_at: nil
)
)
end

let(:cause_id) { cause.id }

example_request 'Create a volunteer with the current user' do
Expand All @@ -31,10 +41,52 @@
do_request
assert_status 422
end

context 'when the phase has granular permissions' do
let(:group) { create(:group) }

let(:project) do
create(
:single_phase_volunteering_project,
phase_attrs: { with_permissions: true }
)
end

let(:cause) do
cause = create(:cause, phase: project.phases.first)
permission = cause.phase.permissions.find_by(action: 'volunteering')
permission.update!(permitted_by: 'groups', groups: [group])

cause
end

let(:cause_id) { cause.id }

example 'Try to volunteer for a cause, not as a group member', document: false do
do_request
assert_status 401
end

example 'Try to volunteer for a cause, as a group member', document: false do
group.add_member(@user).save!
do_request
assert_status 201
end
end
end

delete 'web_api/v1/causes/:cause_id/volunteers' do
let(:cause) { create(:cause) }
let(:cause) do
create(
:cause,
phase: create(
:volunteering_phase,
start_at: 6.months.ago,
end_at: nil
)
)
end

let(:cause_id) { cause.id }
let!(:volunteer) { create(:volunteer, user: @user, cause: cause) }

Expand Down
3 changes: 2 additions & 1 deletion back/spec/acceptance/projects_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@
taking_survey: { enabled: false, disabled_reason: 'project_inactive' },
taking_poll: { enabled: false, disabled_reason: 'project_inactive' },
voting: { enabled: false, disabled_reason: 'project_inactive' },
attending_event: { enabled: false, disabled_reason: 'project_inactive' }
attending_event: { enabled: false, disabled_reason: 'project_inactive' },
volunteering: { enabled: false, disabled_reason: 'project_inactive' }
}
)
expect(json_response.dig(:data, :relationships)).to include(
Expand Down
3 changes: 2 additions & 1 deletion front/app/api/permissions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export type IPhasePermissionAction =
| 'taking_poll'
| 'voting'
| 'annotating_document'
| 'attending_event';
| 'attending_event'
| 'volunteering';

export interface IPhasePermissionData {
id: string;
Expand Down
12 changes: 12 additions & 0 deletions front/app/api/projects/__mocks__/_mockServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export const project1: IProjectData = {
enabled: true,
disabled_reason: null,
},
volunteering: {
enabled: false,
disabled_reason: 'not_volunteering',
},
},
avatars_count: 8,
participants_count: 8,
Expand Down Expand Up @@ -211,6 +215,10 @@ export const project2: IProjectData = {
enabled: true,
disabled_reason: null,
},
volunteering: {
enabled: false,
disabled_reason: 'not_volunteering',
},
},
avatars_count: 6,
participants_count: 6,
Expand Down Expand Up @@ -345,6 +353,10 @@ const votingProject: IProject = {
enabled: false,
disabled_reason: 'not_poll',
},
volunteering: {
enabled: false,
disabled_reason: 'not_volunteering',
},
},
avatars_count: 2,
participants_count: 2,
Expand Down
2 changes: 2 additions & 0 deletions front/app/api/projects/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
ProjectReactingDisabledReason,
ProjectSurveyDisabledReason,
ProjectVotingDisabledReason,
ProjectVolunteeringDisabledReason,
} from 'utils/actionDescriptors/types';
import { Keys } from 'utils/cl-react-query/types';

Expand Down Expand Up @@ -99,6 +100,7 @@ export interface IProjectAttributes {
annotating_document: ActionDescriptor<ProjectDocumentAnnotationDisabledReason>;
voting: ActionDescriptor<ProjectVotingDisabledReason>;
attending_event: ActionDescriptor<ProjectDisabledReason>;
volunteering: ActionDescriptor<ProjectVolunteeringDisabledReason>;
};
uses_content_builder: boolean;
}
Expand Down
2 changes: 0 additions & 2 deletions front/app/components/FormBuilder/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ export const getIsPostingEnabled = (
return false;
};



export function generateTempId() {
return `TEMP-ID-${uuid4()}`;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ const PagesMenu = () => {
return null;
}

const disabledAddProjectToNavbarButton = navbarItems.data.length >= MAX_NAVBAR_ITEMS;
const disabledAddProjectToNavbarButton =
navbarItems.data.length >= MAX_NAVBAR_ITEMS;

return (
<SectionFormWrapper
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ export const ideationConfig: FormBuilderConfig = {
},
};


export const proposalsConfig: FormBuilderConfig = {
formBuilderTitle: messages.inputForm,
viewFormLinkCopy: messages.viewFormLinkCopy,
Expand All @@ -55,7 +54,7 @@ export const proposalsConfig: FormBuilderConfig = {

toolboxFieldsToExclude: ['page', 'file_upload', 'point'],
displayBuiltInFields: true,
builtInFields:[
builtInFields: [
'title_multiloc',
'body_multiloc',
'topic_ids',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ export default defineMessages({
id: 'app.containers.AdminPage.groups.permissions.permissionAction_attending_event_subtitle',
defaultMessage: 'Who can sign up to attend an event?',
},
permissionAction_volunteering_subtitle: {
id: 'app.containers.AdminPage.groups.permissions.permissionAction_volunteering_subtitle',
defaultMessage: 'Who can volunteer?',
},
phase: {
id: 'app.containers.AdminPage.groups.permissions.phase',
defaultMessage: 'Phase ',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const getPermissionActionSectionSubtitle = ({
annotating_document:
messages.permissionAction_annotating_document_subtitle,
attending_event: messages.permissionAction_attending_event_subtitle,
volunteering: messages.permissionAction_volunteering_subtitle,
};
return participationContextPermissionActionMessages[permissionAction];
}
Expand Down
4 changes: 4 additions & 0 deletions front/app/containers/Admin/projects/project/phase/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ export default defineMessages({
id: 'app.components.app.containers.AdminPage.ProjectEdit.phaseHeader.attendingEvent',
defaultMessage: '<b>Attending event:</b> {participants}',
},
volunteering: {
id: 'app.components.app.containers.AdminPage.ProjectEdit.phaseHeader.volunteering',
defaultMessage: '<b>Volunteering:</b> {participants}',
},
and: {
id: 'app.components.app.containers.AdminPage.ProjectEdit.phaseHeader.and',
defaultMessage: 'and',
Expand Down
2 changes: 2 additions & 0 deletions front/app/containers/Admin/projects/project/phase/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ export const getParticipationActionLabel = (action: IPhasePermissionAction) => {
return messages.annotatingDocument;
case 'attending_event':
return messages.attendingEvent;
case 'volunteering':
return messages.volunteering;
}
};

Expand Down
Loading

0 comments on commit 7555810

Please sign in to comment.