Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Classification user groups authorization policies #27

Merged
merged 24 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
761f2a8
individual stats breakdown per group. add session time to user group …
yuenmichelle1 Aug 10, 2023
8df82f1
update sort of group member stats breakdown
yuenmichelle1 Aug 10, 2023
08ab8a1
Update user_group_member_stats_breakdown_serializer.rb
yuenmichelle1 Aug 10, 2023
9cf117e
add specs user group classification count controller for individual s…
yuenmichelle1 Aug 10, 2023
34eb2b1
add specs for group member breakdown query stats
yuenmichelle1 Aug 10, 2023
459445c
add spec for serializer
yuenmichelle1 Aug 10, 2023
6fd8cd4
update session time to be included with top contributors
yuenmichelle1 Aug 10, 2023
981e251
update staging credentials to include staging panoptes client credent…
yuenmichelle1 Aug 22, 2023
802870a
add comment to show reference of where to find diff types of user gro…
yuenmichelle1 Aug 22, 2023
51961e6
show stats if panoptes admin
yuenmichelle1 Aug 22, 2023
536ef9b
Update queried_user_group_context_policy.rb
yuenmichelle1 Aug 22, 2023
9741349
update group admin check to check for group_admin
yuenmichelle1 Aug 23, 2023
b8b1291
update user group controller specs
yuenmichelle1 Aug 24, 2023
874b5f0
add queried user group context policy spec
yuenmichelle1 Aug 24, 2023
c6b3276
Update user_group_classification_count_controller.rb
yuenmichelle1 Aug 25, 2023
87b22b9
update validations to allow non logged in users to view publicly visi…
yuenmichelle1 Aug 25, 2023
6c5c679
fix accidental spacing issue
yuenmichelle1 Aug 25, 2023
3fbcb52
Merge branch 'main' into classification-user-groups-authorization-pol…
yuenmichelle1 Aug 28, 2023
fedfefe
Update staging.yml.enc
yuenmichelle1 Aug 28, 2023
73d6185
Merge branch 'main' into classification-user-groups-authorization-pol…
yuenmichelle1 Aug 28, 2023
75623ab
Merge branch 'main' into classification-user-groups-authorization-pol…
yuenmichelle1 Aug 30, 2023
ec92878
Merge branch 'main' into classification-user-groups-authorization-pol…
yuenmichelle1 Sep 6, 2023
4708b5d
Update spec/support/authentication_helpers.rb
yuenmichelle1 Sep 7, 2023
dc93510
Update authentication_helpers.rb
yuenmichelle1 Sep 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These calls out to panoptes can be memoized in order to prevent repeats by adding @queried_user_group ||= to the return line. It doesn't seem like either one of these get called more than once intentionally, but it's something to keep in mind so that you don't repeat API requests unnecessarily.

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