Skip to content
Draft
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
3 changes: 3 additions & 0 deletions api/base/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,3 +477,6 @@ def get_response_dict_deprecated(self, data, url):
]),
),
])

class MapCoreGroupPagination(JSONAPIPagination):
page_size = 5
2 changes: 2 additions & 0 deletions api/base/settings/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,3 +501,5 @@
BASE_FOR_METRIC_PREFIX = 1000
SIZE_UNIT_GB = BASE_FOR_METRIC_PREFIX ** 3
NII_STORAGE_REGION_ID = 1

MAP_GATEWAY_ISMEMBEROF_PREFIX = osf_settings.MAP_GATEWAY_ISMEMBEROF_PREFIX
1 change: 1 addition & 0 deletions api/base/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
url(r'^view_only_links/', include('api.view_only_links.urls', namespace='view-only-links')),
url(r'^wikis/', include('api.wikis.urls', namespace='wikis')),
url(r'^_waffle/', include(('api.waffle.urls', 'waffle'), namespace='waffle')),
url(r'^map_core/', include('api.mapcore.urls', namespace='mapcore')),
],
),
),
Expand Down
55 changes: 55 additions & 0 deletions api/institutions/authentication.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import json
from urllib.parse import unquote
import uuid
import logging

import jwe
import jwt
from osf.models.mapcore_group import MapCoreGroup
from osf.models.mapcore_user_group import MapCoreUserGroup
import waffle

#from django.utils import timezone
Expand All @@ -23,6 +26,8 @@
from website.mails import send_mail, WELCOME_OSF4I
from website.settings import OSF_SUPPORT_EMAIL, DOMAIN, to_bool
from website.util.quota import update_default_storage
from django_bulk_update.helper import bulk_update
from django.utils import timezone

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -466,6 +471,7 @@ def get_next(obj, *args):

# update every login. (for mAP API v1)
init_cloud_gateway_groups(user, provider)
update_mapcore_groups(user, provider)

return user, None

Expand Down Expand Up @@ -521,3 +527,52 @@ def init_cloud_gateway_groups(user, provider):
else:
user.add_group(groupname)
user.save()

def update_mapcore_groups(user, provider):
prefix = settings.MAP_GATEWAY_ISMEMBEROF_PREFIX
if not prefix:
return
groups_str = provider['user'].get('groups', '')
groups_error = provider['user'].get('groupsError')
# if get mapcore groups error, do not update groups.
if not groups_str and groups_error:
try:
groups_error = unquote(groups_error)
logger.warning('MAP Core groups retrieval error for user {}: {}'.format(user.username, groups_error))
except Exception:
logger.warning('Failed to URL-decode groups_error: %s', groups_error)
return
import re
patt_prefix = re.compile('^' + prefix)
patt_admin = re.compile('(.+)/admin$')
groups_str_set = set()
for group in groups_str.split(';'):
if patt_prefix.match(group):
groupname = patt_prefix.sub('', group)
if groupname is None or groupname == '':
continue
m = patt_admin.search(groupname)
if m: # is admin
groups_str_set.add(m.group(1))
else:
groups_str_set.add(groupname)
mapcore_user_groups = MapCoreUserGroup.objects.filter(user=user, is_deleted=False)
to_delete = []
for mapcore_user_group in mapcore_user_groups:
groupname = mapcore_user_group.mapcore_group._id
if groupname not in groups_str_set:
mapcore_user_group.is_deleted = True
mapcore_user_group.modified = timezone.now()
to_delete.append(mapcore_user_group)
else:
# keep
groups_str_set.remove(groupname)
if to_delete:
bulk_update(to_delete, update_fields=['is_deleted', 'modified'])
# add new groups
for groupname in groups_str_set:
mapcore_group, created = MapCoreGroup.objects.get_or_create(_id=groupname)
MapCoreUserGroup.objects.create(
user=user,
mapcore_group=mapcore_group,
)
25 changes: 25 additions & 0 deletions api/logs/serializers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from past.builtins import basestring
from osf.models.mapcore_group import MapCoreGroup
from rest_framework import serializers as ser

from addons.osfstorage.models import Region
Expand Down Expand Up @@ -101,6 +102,7 @@ class NodeLogParamsSerializer(RestrictedDictSerializer):
institution = NodeLogInstitutionSerializer(read_only=True)
anonymous_link = ser.BooleanField(read_only=True)
file_format = ser.CharField(read_only=True)
mapcore_groups = ser.SerializerMethodField(read_only=True)

def get_view_url(self, obj):
urls = obj.get('urls', None)
Expand Down Expand Up @@ -225,6 +227,29 @@ def get_storage_name(self, obj):
return 'Institutional Storage'
return None

def get_mapcore_groups(self, obj):
mapcore_group_info = []

if is_anonymized(self.context['request']):
return mapcore_group_info

mapcore_group_data = obj.get('mapcore_groups', None)

if mapcore_group_data:
mapcore_group_ids = [each for each in mapcore_group_data if isinstance(each, int)]
mapcore_groups = (
MapCoreGroup.objects.filter(id__in=mapcore_group_ids)
.only('id', '_id')
.order_by('_id')
)
for mapcore_group in mapcore_groups:
mapcore_group_info.append({
'id': mapcore_group.id,
'name': mapcore_group._id,
})
return mapcore_group_info


class NodeLogSerializer(JSONAPISerializer):

filterable_fields = frozenset(['action', 'date', 'user'])
Expand Down
28 changes: 28 additions & 0 deletions api/mapcore/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from django.apps import apps
from rest_framework import serializers as ser
from api.base.serializers import JSONAPISerializer, LinksField, TypeField, VersionedDateTimeField
from website.settings import MAPCORE_GROUP_HOSTNAME, MAPCORE_GROUP_API_PATH


MapCoreGroup = apps.get_model('osf.MapCoreGroup')

class MapCoreGroupSerializer(JSONAPISerializer):
"""
JSONAPI serializer for MapCoreGroup model.
Keep fields minimal — expand if the model exposes more attributes that should be surfaced.
"""
id = ser.IntegerField(read_only=True)
mapcore_group_id = ser.IntegerField(source='id', read_only=True)
name = ser.CharField(source='_id', read_only=True)
created = VersionedDateTimeField(read_only=True)
modified = VersionedDateTimeField(read_only=True)
links = LinksField({
'self': 'get_absolute_url',
})
type = TypeField()

class Meta:
type_ = 'mapcore-groups'

def get_absolute_url(self, obj):
return f'{MAPCORE_GROUP_HOSTNAME}{MAPCORE_GROUP_API_PATH}{obj._id}/'
12 changes: 12 additions & 0 deletions api/mapcore/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from django.conf.urls import url

from api.mapcore import views

app_name = 'osf'

urlpatterns = [
# Examples:
# url(r'^$', 'api.views.home', name='home'),
# url(r'^blog/', include('blog.urls')),
url(r'^groups/$', views.MapCoreGroupList.as_view(), name=views.MapCoreGroupList.view_name),
]
46 changes: 46 additions & 0 deletions api/mapcore/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from django.apps import apps
from rest_framework import generics
from rest_framework import permissions as drf_permissions
from api.base.views import JSONAPIBaseView
from framework.auth.oauth_scopes import CoreScopes
from api.mapcore.serializers import MapCoreGroupSerializer
from api.base import permissions as base_permissions
from api.base.utils import get_user_auth
from api.base.pagination import MapCoreGroupPagination


class MapCoreGroupList(JSONAPIBaseView, generics.ListAPIView):
"""
List of MapCoreGroups
"""
permission_classes = (
drf_permissions.IsAuthenticated,
base_permissions.TokenHasScope,
)
required_read_scopes = [CoreScopes.NODE_CONTRIBUTORS_READ]
model_class = apps.get_model('osf.MapCoreGroup')

serializer_class = MapCoreGroupSerializer
view_category = 'mapcore_groups'
view_name = 'mapcore-group-list'

ordering = ('_id', ) # default ordering
pagination_class = MapCoreGroupPagination

def get_queryset(self):
auth = get_user_auth(self.request)
if not auth or not auth.user or not auth.user.is_authenticated:
return self.model_class.objects.none()

qs = self.model_class.objects.filter(mapcore_user_groups__user=auth.user, mapcore_user_groups__is_deleted=False)
q = self.request.GET.get('search') or self.request.query_params.get('search')
if q:
q = q.strip()
if q:
qs = qs.filter(_id__icontains=q)

return qs

def get(self, request, *args, **kwargs):
result = super().get(request, *args, **kwargs)
return result
Loading