Skip to content

Commit

Permalink
Classification user groups authorization policies (#27)
Browse files Browse the repository at this point in the history
* individual stats breakdown per group. add session time to user group projects breakdown.

* update sort of group member stats breakdown

* Update user_group_member_stats_breakdown_serializer.rb

* add specs user group classification count controller for individual stats breakdown stats

* add specs for group member breakdown query stats

* add spec for serializer

* update session time to be included with top contributors

* update staging credentials to include staging panoptes client credentials. add initial logic for queried user group context policy

* add comment to show reference of where to find diff types of user group stats visibilities

* show stats if panoptes admin

* Update queried_user_group_context_policy.rb

* update group admin check to check for group_admin

* update user group controller specs

* add queried user group context policy spec

* Update user_group_classification_count_controller.rb

* update validations to allow non logged in users to view publicly visible stats and update specs

* fix accidental spacing issue

* Update staging.yml.enc

* Update spec/support/authentication_helpers.rb

Co-authored-by: Zach Wolfenbarger <[email protected]>

* Update authentication_helpers.rb

---------

Co-authored-by: Zach Wolfenbarger <[email protected]>
  • Loading branch information
yuenmichelle1 and zwolf authored Sep 7, 2023
1 parent d0ec241 commit da72ace
Show file tree
Hide file tree
Showing 8 changed files with 735 additions and 36 deletions.
43 changes: 36 additions & 7 deletions app/controllers/user_group_classification_count_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
class UserGroupClassificationCountController < ApplicationController
before_action :validate_params
before_action :sanitize_params
# before_action :require_login
before_action :group_require_login

def query
# TODO: Skipping Auth for now, Will introduce this in a separate PR
# pundit policy for user groups, will probably look something like below:
# current_user['queried_user_group_id'] = params[:id]
# authorize :queried_user_group_context, :show?
skip_authorization
if authorization_required_for_group?
authorize_user_to_query_group_stats
else
skip_authorization
end

if params[:individual_stats_breakdown]
group_member_classification_counts = CountGroupMemberBreakdown.new.call(group_classification_count_params)

Expand All @@ -23,12 +24,40 @@ def query
project_contributions = CountGroupProjectContributions.new.call(group_classification_count_params) unless params[:project_id] || params[:workflow_id]
render json: UserGroupClassificationCountsSerializer.new(group_classification_counts, group_active_user_classification_counts, project_contributions),
serializer_options: serializer_opts_from_params

end
end

private

def authorize_user_to_query_group_stats
current_user['user_group_stats_visibility'] = group_stats_visibility
current_user['individual_stats_breakdown'] = params[:individual_stats_breakdown]
current_user['user_membership'] = current_user_membership
authorize :queried_user_group_context, :show?
end

def authorization_required_for_group?
(params[:individual_stats_breakdown] && group_stats_visibility != 'public_show_all') || group_stats_visibility.include?('private')
end

def group_require_login
require_login if authorization_required_for_group?
end

def current_user_membership
url = "/memberships?user_id=#{current_user['id']}&user_group_id=#{params[:id]}"
client.panoptes.get(url)['memberships'][0]
end

def queried_user_group
url = "/user_groups/#{params[:id]}"
panoptes_application_client.panoptes.get(url)['user_groups'][0]
end

def group_stats_visibility
queried_user_group['stats_visibility']
end

def validate_params
super
raise ValidationError, 'Cannot query individual stats breakdown with anything else EXCEPT start_date and end_date' if params[:individual_stats_breakdown] && non_date_range_params
Expand Down
70 changes: 70 additions & 0 deletions app/policies/queried_user_group_context_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# frozen_string_literal: true

class QueriedUserGroupContextPolicy < ApplicationPolicy
attr_reader :user

def initialize(user, _record)
super
@user = user
end

def show?
return true if panoptes_admin?

if individual_stats_breakdown_requested?
show_ind_stats_breakdown?
else
show_group_aggregate_stats?
end
end

def show_group_aggregate_stats?
# For types of group stats visibilities see: https://github.com/zooniverse/eras/wiki/(Panoptes)-User-Groups-Stats-Visibilities

case group_stats_visibility
when 'public_show_all', 'public_agg_show_ind_if_member', 'public_agg_only'
true
when 'private_show_agg_and_ind', 'private_agg_only'
group_member?
else
false
end
end

def show_ind_stats_breakdown?
case group_stats_visibility
when 'public_show_all'
true
when 'public_agg_show_ind_if_member', 'private_show_agg_and_ind'
group_member?
when 'public_agg_only', 'private_agg_only'
group_admin?
else
false
end
end

def group_member?
current_user_membership && !current_user_roles.empty?
end

def group_admin?
group_member? && current_user_roles.include?('group_admin')
end

def current_user_roles
current_user_membership['roles']
end

def current_user_membership
user['user_membership']
end

def individual_stats_breakdown_requested?
user['individual_stats_breakdown'] || false
end

def group_stats_visibility
user['user_group_stats_visibility']
end
end
2 changes: 1 addition & 1 deletion config/credentials/staging.yml.enc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
DE7jRIWwMnbmRiQRJ0SmsOae9uRB5sniKrwXf7F8ZuvfmLeo16iJbHLX+QtRkTG3hsBdJtjYA1fek7cfsLi78ThSon8Ovzaw+opS6h+mMBOT2takrxtlD1kYDYjupHbsTt5zb3MJEzLYXy+8utpy2wOunq/e8jXg28i0asWONbevnd0ieq/E8aVpSmNLNPlE6b4JeQA0Gk+aa1gKVnNPK9ByqWxaXieDimNiBQa90rmO6hdpvIVcDl6FbbZC3+SqOTab5yOdkZudiRvrcHnDc4fdb03V/hvPbk0vXSoL0dr1SsLlCjTgzkciU56NzJ75z7k9pd8GJ5qQnmJnNIgtOjJyK85t8jcVOhqARI3UihE6QXXbHS5BmhB2ssJ7gi031qpLtM6Iax60zhg9TgWU8mothUE3/b8IONQgEGnLwnnF5KoW4QXkQe50vM+ar0Os6bWEh4adfmjXV5MJGknZ+kBa4tWifDXMWS38+uLDaPmtaB4uWx+iQB0UAxYn/+wFlXWi59nOFf+s+85iIuVX6wHyUNSMdnnMZrGhhfBqQ7GC82Jmelu9dVA9TkuMz6UY8Ts1NATn6HYOVu9VWYcxqLpynbIdbNClKNO4w/lGLw==--P8SvT9334PWTh9EK--oeM/Hj0aEswh7ipr+Rv2QQ==
PGbmdbmi4qGqkpAPoEEdruRtfzTdqrFUuxKZyKkHogeNKi3V3XRYY7xCIpiVzaOk9x2P88UnPSi3uQJX00YFC5g11ta00WuH9WmPEjr9zSrpXTQ5Vou+dKoTszP2nPauNwUPkrYTM2q3Ew2691GspeXK7D6I+t0Oi0uVckI2C7RJknpcaqxDUwOVV4idGczyenMKPYPoOQ9rBogwG2JvG1YBsS6xul87lHyYqmVB7a2KmAxMLPNFbTwT3ASuwreDZyrG6e2oyXMBG1tFtnyX3wcPkj9A02oTN4mLxoaBVRVQS4T43sFqbGawlDPUdHZbI5B6+ekWpqgMIBQXkvqORyUTmfMGhbs3TEuNYEfKBkO1fo3+B2XtGNOknJPIavwVvaUFt2KYRh2Pmdk2ew7VA9FTt6mzTy6QewA6lA4vPfs01flrRzGDx/+DJCydL+UXX04izUzyH2eul0NWAPTKJ0btocok0GCcJb5mXktgECJXBKWO9j/90UVeupaxetpGp/SsfMjtjildK9M0X33ehmfzeWTqmFp+2mnfQo5R8p9XPsX/eVpvGwogSS6dDXIjYixlM0lhOeRq6loWguGRPLY5Fv7Uir7iMoc5vh/mk/Ivaqm+Xf7MkWCZ5QRj+FM9UYczp8C5nX3ndL7WJyfUDRPZR8gRLRZoIIKKznC/icw05IqysCcLBI8wQpl7FGLN760IrlWHWwz4lT4DbeIn7sZ7OoLimYkw/x7QGmOZzpSLGed589D3BsERsHhNXPBVKVaWhReenYgME/u/nfV+dwmE0cPJVxmYGllDdZKEeqtPOSwWK5vEksvCAVowwwADjZNCDVaeEdQ6c+y1--MUB9zAKbMkjYaijP--jfzUVjic0hyW9gGZ6Wv58g==
17 changes: 4 additions & 13 deletions spec/controllers/user_classification_count_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,19 +69,10 @@
end

context 'missing token' do
it 'returns a 403 missing authorization header' do
get :query, params: { id: classification_event.user_id.to_s }
expected_response = { error: 'Missing Authorization header' }
expect(response.status).to eq(403)
expect(response.body).to eq(expected_response.to_json)
end

it 'returns a 403 missing when missing bearer token' do
request.headers['Authorization'] = 'asjdhaskdhsa'
get :query, params: { id: classification_event.user_id.to_s }
expected_response = { error: 'Missing Bearer token' }
expect(response.status).to eq(403)
expect(response.body).to eq(expected_response.to_json)
it_behaves_like 'returns 403 when authorization header is invalid' do
before(:each) {
get :query, params: { id: classification_event.user_id.to_s }
}
end
end

Expand Down
Loading

0 comments on commit da72ace

Please sign in to comment.