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

[WIP] content surveys #1974

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
44 changes: 44 additions & 0 deletions galaxy_ng/app/access_control/access_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ def get_pulp_access_policy(self, name, default=None):
Converts the statement list into the full pulp access policy.
"""

print(f'GET_PULP_ACCESS_POLICY {name}')
statements = self._get_statements().get(name, default)
print(f'STATEMENTS: {statements}')

if not statements and default is None:
return None
Expand Down Expand Up @@ -123,6 +125,7 @@ class AccessPolicyBase(AccessPolicyFromDB):

@classmethod
def get_access_policy(cls, view):

statements = GALAXY_STATEMENTS

# If this is a galaxy access policy, load from the statement file
Expand Down Expand Up @@ -820,3 +823,44 @@ def is_namespace_owner(self, request, viewset, action):
return True

return False


class SurveyAccessPolicy(AccessPolicyBase):
NAME = "SurveyAccessPolicy"

@classmethod
def get_access_policy(cls, view):

print(f'GET ACCESS POLICY {cls} {cls.NAME} {view}')

statements = [
{
"action": [
"get",
"list",
"retrieve",
],
"principal": "*",
"effect": "allow",
},
{
"action": [
"create",
"update",
],
"principal": "authenticated",
"effect": "allow",
"condition": "is_survey_user",
},
]
# As a last resort, require admin rights
print('USE DEFAULT ... FUCK.')
return MockPulpAccessPolicy(
{
"statements": statements,
}
)

def is_survey_user(self, request, viewset, action):
print(f'IS_SURVEY_USER ... {viewset} {action}')
return True
4 changes: 3 additions & 1 deletion galaxy_ng/app/access_control/statements/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
from .insights import INSIGHTS_STATEMENTS
from .pulp import PULP_VIEWSETS
from .roles import LOCKED_ROLES
from .survey import SURVEY_STATEMENTS

__all__ = (
STANDALONE_STATEMENTS,
INSIGHTS_STATEMENTS,
PULP_VIEWSETS,
LOCKED_ROLES
LOCKED_ROLES,
SURVEY_STATEMENTS,
)
22 changes: 22 additions & 0 deletions galaxy_ng/app/access_control/statements/survey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
SURVEY_STATEMENTS = {
"SurveyAccessPolicy": [
{
"action": [
"get",
"list",
"retrieve",
],
"principal": "*",
"effect": "allow",
},
{
"action": [
"create",
"update",
],
"principal": "authenticated",
"effect": "allow",
"condition": "is_survey_user",
},
]
}
14 changes: 14 additions & 0 deletions galaxy_ng/app/api/v1/filtersets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from .namespace import LegacyNamespaceFilter
from .role import LegacyRoleFilterOrdering
from .role import LegacyRoleFilter
from .role import LegacyRoleImportFilter
from .user import LegacyUserFilter


__all__ = [
'LegacyNamespaceFilter',
'LegacyRoleFilterOrdering',
'LegacyRoleFilter',
'LegacyRoleImportFilter',
'LegacyUserFilter',
]
53 changes: 53 additions & 0 deletions galaxy_ng/app/api/v1/filtersets/namespace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from django.db.models import Q
from django.db.models import Case, Value, When
from django_filters import filters
from django_filters.rest_framework import filterset

from galaxy_ng.app.models.auth import User
from galaxy_ng.app.api.v1.models import LegacyNamespace
from galaxy_ng.app.api.v1.models import LegacyRole
from galaxy_ng.app.api.v1.models import LegacyRoleImport
from galaxy_ng.app.utils.rbac import get_v3_namespace_owners


class LegacyNamespaceFilter(filterset.FilterSet):

keywords = filters.CharFilter(method='keywords_filter')
owner = filters.CharFilter(method='owner_filter')

sort = filters.OrderingFilter(
fields=(
('created', 'created'),
('name', 'name')
)
)

class Meta:
model = LegacyNamespace
fields = ['created', 'name']

def keywords_filter(self, queryset, name, value):

keywords = self.request.query_params.getlist('keywords')

for keyword in keywords:
queryset = queryset.filter(Q(name__icontains=keyword))

return queryset

def owner_filter(self, queryset, name, value):
# find the owner on the linked v3 namespace

# FIXME - this is terribly slow
pks = []
for ns1 in LegacyNamespace.objects.all():
if not ns1.namespace:
continue
ns3 = ns1.namespace
owners = get_v3_namespace_owners(ns3)
if value in [x.username for x in owners]:
pks.append(ns1.id)

queryset = queryset.filter(id__in=pks)

return queryset
Original file line number Diff line number Diff line change
Expand Up @@ -10,70 +10,6 @@
from galaxy_ng.app.utils.rbac import get_v3_namespace_owners


class LegacyNamespaceFilter(filterset.FilterSet):

keywords = filters.CharFilter(method='keywords_filter')
owner = filters.CharFilter(method='owner_filter')

sort = filters.OrderingFilter(
fields=(
('created', 'created'),
('name', 'name')
)
)

class Meta:
model = LegacyNamespace
fields = ['created', 'name']

def keywords_filter(self, queryset, name, value):

keywords = self.request.query_params.getlist('keywords')

for keyword in keywords:
queryset = queryset.filter(Q(name__icontains=keyword))

return queryset

def owner_filter(self, queryset, name, value):
# find the owner on the linked v3 namespace

# FIXME - this is terribly slow
pks = []
for ns1 in LegacyNamespace.objects.all():
if not ns1.namespace:
continue
ns3 = ns1.namespace
owners = get_v3_namespace_owners(ns3)
if value in [x.username for x in owners]:
pks.append(ns1.id)

queryset = queryset.filter(id__in=pks)

return queryset


class LegacyUserFilter(filterset.FilterSet):

username = filters.CharFilter(method='username_filter')

sort = filters.OrderingFilter(
fields=(
# ('created', 'created'),
('username', 'username')
)
)

class Meta:
model = User
# fields = ['created', 'username']
fields = ['username']

def username_filter(self, queryset, name, value):
username = self.request.query_params.get('username')
return queryset.filter(username=username)


class LegacyRoleFilterOrdering(filters.OrderingFilter):
def filter(self, qs, value):
if value is not None and any(v in ["download_count", "-download_count"] for v in value):
Expand Down
31 changes: 31 additions & 0 deletions galaxy_ng/app/api/v1/filtersets/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from django.db.models import Q
from django.db.models import Case, Value, When
from django_filters import filters
from django_filters.rest_framework import filterset

from galaxy_ng.app.models.auth import User
from galaxy_ng.app.api.v1.models import LegacyNamespace
from galaxy_ng.app.api.v1.models import LegacyRole
from galaxy_ng.app.api.v1.models import LegacyRoleImport
from galaxy_ng.app.utils.rbac import get_v3_namespace_owners


class LegacyUserFilter(filterset.FilterSet):

username = filters.CharFilter(method='username_filter')

sort = filters.OrderingFilter(
fields=(
# ('created', 'created'),
('username', 'username')
)
)

class Meta:
model = User
# fields = ['created', 'username']
fields = ['username']

def username_filter(self, queryset, name, value):
username = self.request.query_params.get('username')
return queryset.filter(username=username)
14 changes: 14 additions & 0 deletions galaxy_ng/app/api/v1/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from .legacy_namespace import LegacyNamespace
from .legacy_role import LegacyRoleTag
from .legacy_role import LegacyRole
from .legacy_role import LegacyRoleDownloadCount
from .legacy_role import LegacyRoleImport


__all__ = [
'LegacyNamespace',
'LegacyRoleTag',
'LegacyRole',
'LegacyRoleDownloadCount',
'LegacyRoleImport',
]
54 changes: 54 additions & 0 deletions galaxy_ng/app/api/v1/models/legacy_namespace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from django.db import models

from galaxy_ng.app.models import Namespace
from galaxy_ng.app.models.auth import User

from pulpcore.plugin.models import Task


class LegacyNamespace(models.Model):
"""
A legacy namespace, aka a github username.

Namespaces in the galaxy_ng sense are very restrictive
with their character sets. This is primarily due to how
collection namespaces and names must be pythonic and
importable module names. Legacy roles had no such
restrictions and were 1:1 with whatever github allowed
for a username.

This model exists for a few reasons:
1) enable an endpoint for v1/users with no sql hacks
2) enable the ui to list namespaces with avatar icons
3) to map the legacy namespace to a new namespace
which can have galaxy_ng style permission management
4) to define what users aside from the creator can
"own" the roles under the namespace.
"""

created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)

name = models.CharField(max_length=64, unique=True, blank=False)
company = models.CharField(max_length=64, blank=True)
email = models.CharField(max_length=256, blank=True)
avatar_url = models.URLField(max_length=256, blank=True)
description = models.CharField(max_length=256, blank=True)

namespace = models.ForeignKey(
Namespace,
null=True,
on_delete=models.SET_NULL,
related_name="namespace",
)

owners = models.ManyToManyField(
User,
editable=True
)

def __repr__(self):
return f'<LegacyNamespace: {self.name}>'

def __str__(self):
return self.name
Loading