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

Jkmarx/extend group api to delete #3307

Merged
24 changes: 23 additions & 1 deletion refinery/core/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,35 @@ def partial_update(self, instance, validated_data):


class ExtendedGroupSerializer(serializers.ModelSerializer):
member_list = serializers.SerializerMethodField()
perm_list = serializers.SerializerMethodField()
can_edit = serializers.SerializerMethodField()
uuid = serializers.SerializerMethodField()
name = serializers.CharField(
min_length=3,
validators=[UniqueValidator(queryset=ExtendedGroup.objects.all())]
)

def get_can_edit(self, group):
user = self.context.get('user')
if user is None:
return ''

if group.is_manager_group():
return user in group.user_set.all()
else:
return user in group.manager_group.user_set.all()

def get_member_list(self, group):
# only needed to support dashboard client request
data_set = self.context.get('data_set')
if data_set is None:
users = group.user_set.all().filter(is_active=True).exclude(
username=settings.ANONYMOUS_USER_NAME
)
return UserSerializer(users, many=True).data
return []

def get_perm_list(self, group):
data_set = self.context.get('data_set')
if data_set is None:
Expand All @@ -140,7 +162,7 @@ def get_uuid(self, group):

class Meta:
model = ExtendedGroup
fields = ('name', 'id', 'uuid', 'perm_list')
fields = ('can_edit', 'name', 'id', 'uuid', 'member_list', 'perm_list')


class SiteVideoSerializer(serializers.ModelSerializer):
Expand Down
97 changes: 97 additions & 0 deletions refinery/core/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -854,14 +854,93 @@ def setUp(self):
)
self.patch_view = GroupViewSet.as_view({'patch': 'partial_update'})
self.post_view = GroupViewSet.as_view({'post': 'create'})
self.delete_view = GroupViewSet.as_view({'delete': 'destroy'})
self.data_set = create_dataset_with_necessary_models(user=self.user)
self.group = ExtendedGroup.objects.create(name="Test Group")
self.group.manager_group.user_set.add(self.user)
self.group_2 = ExtendedGroup.objects.create(name="Test Group 2")
self.group_2.manager_group.user_set.add(self.user)
self.group.user_set.add(self.user)
self.group_2.user_set.add(self.user)
self.data_set.share(self.group)
self.data_set.share(self.group_2)

def test_delete_group_returns_403_for_non_managers(self):
non_manager = User.objects.create_user('Non-owner',
'user@example.com',
self.password)
self.group.user_set.add(non_manager)
delete_request = self.factory.delete(urljoin(self.url_root,
self.group.uuid))
force_authenticate(delete_request, user=non_manager)
delete_response = self.delete_view(delete_request, self.group.uuid)
self.assertEqual(delete_response.status_code, 403)

def test_delete_group_returns_200(self):
delete_request = self.factory.delete(urljoin(self.url_root,
self.group.uuid))
force_authenticate(delete_request, user=self.user)
delete_response = self.delete_view(delete_request, self.group.uuid)
self.assertEqual(delete_response.status_code, 200)

def test_delete_group_deletes_group(self):
public_group = ExtendedGroup.objects.public_group()
delete_request = self.factory.delete(urljoin(self.url_root,
self.group.uuid))
force_authenticate(delete_request, user=self.user)
delete_response = self.delete_view(delete_request, self.group.uuid)
remaining_group_uuids = [self.group_2.uuid, public_group.uuid]
self.assertNotIn(delete_response.data, remaining_group_uuids)

def test_get_groups_no_params_returns_all_user_groups(self):
public_group = ExtendedGroup.objects.public_group()
get_request = self.factory.get(self.url_root)
force_authenticate(get_request, user=self.user)
get_response = self.view(get_request)
group_uuid_list = [get_response.data[0].get('id'),
get_response.data[1].get('id'),
get_response.data[2].get('id')]
self.assertIn(public_group.id, group_uuid_list)
self.assertIn(self.group.id, group_uuid_list)
self.assertIn(self.group_2.id, group_uuid_list)

def test_get_groups_no_params_returns_member_list(self):
new_user = User.objects.create_user('Non-owner',
'user@example.com',
self.password)
get_request = self.factory.get(self.url_root)
force_authenticate(get_request, user=new_user)
get_response = self.view(get_request)
user_ids = [self.user.profile.uuid, new_user.profile.uuid]
self.assertEqual(len(get_response.data[0].get('member_list')), 2)
member_list = get_response.data[0].get('member_list')
self.assertIn(member_list[0].get('profile').get('uuid'), user_ids)
self.assertIn(member_list[1].get('profile').get('uuid'), user_ids)

def test_get_groups_no_params_has_can_edit_true(self):
# remove user from public group for testing can_edit
public_group = ExtendedGroup.objects.public_group()
public_group.user_set.remove(self.user)
get_request = self.factory.get(self.url_root)
force_authenticate(get_request, user=self.user)
get_response = self.view(get_request)
self.assertEqual(get_response.data[0].get('can_edit'), True)

def test_get_groups_no_params_has_can_edit_false(self):
new_user = User.objects.create_user('Non-owner',
'user@example.com',
self.password)
self.group.user_set.add(new_user)
get_request = self.factory.get(self.url_root)
force_authenticate(get_request, user=new_user)
get_response = self.view(get_request)
self.assertEqual(get_response.data[0].get('can_edit'), False)

def test_get_groups_no_params_returns_401_for_anon(self):
get_request = self.factory.get(self.url_root)
get_response = self.view(get_request)
self.assertEqual(get_response.status_code, 401)

def test_get_groups_with_data_set_uuid_returns_403_for_anon(self):
get_request = self.factory.get(self.url_root,
{'dataSetUuid': self.data_set.uuid})
Expand Down Expand Up @@ -921,6 +1000,24 @@ def test_get_groups_with_data_set_uuid_has_uuid(self):
get_response = self.view(get_request)
self.assertEqual(self.group.uuid, get_response.data[0].get('uuid'))

def test_get_groups_with_data_set_uuid_has_can_edit_true(self):
get_request = self.factory.get(self.url_root,
{'dataSetUuid': self.data_set.uuid})
force_authenticate(get_request, user=self.user)
get_response = self.view(get_request)
self.assertEqual(get_response.data[0].get('can_edit'), True)

def test_get_groups_with_data_set_uuid_has_can_edit_false(self):
new_user = User.objects.create_user('Non-owner',
'user@example.com',
self.password)
self.group.user_set.add(new_user)
get_request = self.factory.get(self.url_root,
{'dataSetUuid': self.data_set.uuid})
force_authenticate(get_request, user=new_user)
get_response = self.view(get_request)
self.assertEqual(get_response.data[0].get('can_edit'), False)

def test_get_groups_with_data_set_uuid_has_correct_perms_field(self):
self.data_set.unshare(self.group_2)
get_request = self.factory.get(self.url_root,
Expand Down
61 changes: 44 additions & 17 deletions refinery/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,7 @@ def delete(self, request, uuid):

class GroupViewSet(viewsets.ViewSet):
"""API endpoint for viewing groups."""
http_method_names = ['get', 'patch', 'post']
http_method_names = ['get', 'delete', 'patch', 'post']
lookup_field = 'uuid'

def get_object(self, uuid):
Expand Down Expand Up @@ -939,34 +939,54 @@ def create(self, request):
serializer.errors, status=status.HTTP_400_BAD_REQUEST
)

def destroy(self, request, uuid):
user = request.user
group = self.get_object(uuid)
if not self.is_user_a_group_manager(user, group):
return Response('Only managers may delete groups',
status=status.HTTP_403_FORBIDDEN)
group.delete()
return Response(uuid)

def list(self, request):
data_set_uuid = request.query_params.get('dataSetUuid')
all_perms_flag = request.query_params.get('allPerms', False)

data_set = get_data_set_for_view_set(data_set_uuid)
if data_set_uuid is None:
# returns member list, so must be logged in
if request.user.is_anonymous():
return Response(
self.request.user, status=status.HTTP_401_UNAUTHORIZED
)
query_set = ExtendedGroup.objects.all()
context = {'data_set': None, 'user': request.user}
else:
data_set = get_data_set_for_view_set(data_set_uuid)
context = {'data_set': data_set, 'user': request.user}

public_group = ExtendedGroup.objects.public_group()
if not ('read_meta_dataset' in get_perms(public_group, data_set) or
request.user.has_perm('core.read_meta_dataset', data_set)):
return Response(data_set_uuid, status=status.HTTP_403_FORBIDDEN)
public_group = ExtendedGroup.objects.public_group()
if not ('read_meta_dataset' in get_perms(public_group, data_set) or
request.user.has_perm('core.read_meta_dataset', data_set)):
return Response(data_set_uuid,
status=status.HTTP_403_FORBIDDEN)

if all_perms_flag:
# all groups user is member of
query_set = ExtendedGroup.objects.all()
if all_perms_flag:
# all groups user is member of
query_set = ExtendedGroup.objects.all()

else:
# all groups associated with data set and user is a member of
query_set = ExtendedGroup.objects.filter(
group_ptr__in=get_groups_with_perms(data_set)
)
else:
# all groups associated with data set and user is a member of
query_set = ExtendedGroup.objects.filter(
group_ptr__in=get_groups_with_perms(data_set)
)

member_groups = [group for group in query_set
if request.user in group.user_set.all() and
not group.is_manager_group()]

serializer = ExtendedGroupSerializer(member_groups,
many=True,
context={'data_set': data_set})
context=context)
return Response(serializer.data)

def partial_update(self, request, uuid, format=None):
Expand All @@ -989,9 +1009,16 @@ def partial_update(self, request, uuid, format=None):
data_set.share(group, False, True)

serializer = ExtendedGroupSerializer(group,
context={'data_set': data_set})
context={'data_set': data_set,
'user': request.user})

return Response(serializer.data, status=status.HTTP_200_OK)
return Response(serializer.data)

def is_user_a_group_manager(self, user, group):
if group.is_manager_group():
return user in group.user_set.all()
else:
return user in group.manager_group.user_set.all()


class CustomRegistrationView(RegistrationView):
Expand Down
15 changes: 4 additions & 11 deletions refinery/ui/source/js/analysis-monitor/ctrls/ctrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ function AnalysisMonitorCtrl (
vm.initializedFlag = {};
vm.openAnalysisDeleteModal = openAnalysisDeleteModal;

vm.$onDestroy = function () {
$timeout.cancel(vm.timerList);
};

// On data set browser analysis tab, method set timer and refreshes the
// analysis list and refreshes details for running analyses.
vm.updateAnalysesList = function () {
Expand All @@ -34,10 +38,6 @@ function AnalysisMonitorCtrl (
};

vm.timerList = $timeout(vm.updateAnalysesList, 15000);
// Cancels timer when away from analyses tab
$scope.$on('refinery/analyze-tab-inactive', function () {
$timeout.cancel(vm.timerList);
});

return analysisMonitorFactory.getAnalysesList(param)
.then(function (response) {
Expand All @@ -57,7 +57,6 @@ function AnalysisMonitorCtrl (
$timeout.cancel(vm.timerList);

vm.updateAnalysesList().then(function () {
$rootScope.$broadcast('rf/cancelAnalysis');
// Removes flag because list is updated
vm.setCancelAnalysisFlag(false, uuid);
});
Expand All @@ -75,12 +74,6 @@ function AnalysisMonitorCtrl (
}
};

vm.cancelTimerRunningList = function () {
if (typeof vm.timerRunList !== 'undefined') {
$timeout.cancel(vm.timerRunList);
}
};

/**
* @name getRunningAnalyses
* @desc Helper function to update running analyses with details
Expand Down
18 changes: 2 additions & 16 deletions refinery/ui/source/js/analysis-monitor/ctrls/ctrl.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ describe('Controller: AnalysisMonitorCtrl', function () {
var factory;
var fakeUuid = 'x508x83x-x9xx-4740-x9x7-x7x0x631280x';
var fakeInvalidUuid = 'xxxxx';
var timeout;

beforeEach(module('refineryApp'));
beforeEach(module('refineryAnalysisMonitor'));
beforeEach(inject(function (
$controller, $rootScope, $timeout, $window, analysisMonitorFactory
$controller, $rootScope, $window, analysisMonitorFactory
) {
ctrl = $controller('AnalysisMonitorCtrl', {
$scope: $rootScope.$new()
Expand Down Expand Up @@ -111,9 +110,7 @@ describe('Controller: AnalysisMonitorCtrl', function () {
});

describe('Helper functions', function () {
beforeEach(inject(function ($timeout) {
timeout = $timeout;

beforeEach(inject(function () {
ctrl.analysesDetail[fakeUuid] = {
refineryImport: [{
status: 'PROGRESS',
Expand Down Expand Up @@ -161,17 +158,6 @@ describe('Controller: AnalysisMonitorCtrl', function () {
.toEqual(ctrl.analysesList.length);
});

it('cancelTimerRunningList method is function', function () {
expect(angular.isFunction(ctrl.cancelTimerRunningList)).toBe(true);
});

it('cancelTimerRunningList method cancel timerRunList', function () {
ctrl.timerRunList = timeout(10);
expect(typeof ctrl.timerRunList.$$state.value).toEqual('undefined');
ctrl.cancelTimerRunningList();
expect(ctrl.timerRunList.$$state.value).toEqual('canceled');
});

it('setAnalysesLoadingFlag method is function', function () {
expect(angular.isFunction(ctrl.setAnalysesLoadingFlag)).toBe(true);
});
Expand Down
6 changes: 3 additions & 3 deletions refinery/ui/source/js/commons/ctrls/group-add-modal-ctrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@

GroupAddModalCtrl.$inject = [
'$log',
'groupExtendedService'
'groupService'
];

function GroupAddModalCtrl (
$log,
groupExtendedService
groupService
) {
var vm = this;

Expand Down Expand Up @@ -50,7 +50,7 @@
**/
function createGroup () {
vm.isLoading = true;
groupExtendedService.create({ name: vm.groupName }).$promise
groupService.save({ name: vm.groupName }).$promise
.then(function () {
vm.isLoading = false;
generateAlertMessage('success', vm.groupName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ describe('Controller: GroupAddModalCtrl', function () {
beforeEach(inject(function (
$rootScope,
$controller,
groupExtendedService,
groupService,
_$q_
) {
scope = $rootScope.$new();
service = groupExtendedService;
service = groupService;
$q = _$q_;
ctrl = $controller('GroupAddModalCtrl', {
$scope: scope
Expand Down Expand Up @@ -43,7 +43,7 @@ describe('Controller: GroupAddModalCtrl', function () {
ctrl.groupName = 'Test Group 1';
var successResponse = true;
var groupNameAccepted = false;
spyOn(service, 'create').and.callFake(function () {
spyOn(service, 'save').and.callFake(function () {
var deferred = $q.defer();
deferred.resolve(successResponse);
groupNameAccepted = true;
Expand Down