Skip to content

Commit

Permalink
Add unhide annotation endpoint
Browse files Browse the repository at this point in the history
This adds the `DELETE /api/annotations/<annid>/hide` endpoint, which
removes the moderation of the given annotation, effectively showing the
annotation to all group readers again.
  • Loading branch information
chdorner committed Apr 5, 2017
1 parent c4b2bfc commit af68c9c
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 24 deletions.
14 changes: 14 additions & 0 deletions h/services/annotation_moderation.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ def hide(self, annotation):
mod = models.AnnotationModeration(annotation=annotation)
self.session.add(mod)

def unhide(self, annotation):
"""
Show a hidden annotation again to other users.
In case the given annotation is not moderated, this method is a no-op.
:param annotation: The annotation to unhide.
:type annotation: h.models.Annotation
"""

self.session.query(models.AnnotationModeration) \
.filter_by(annotation=annotation) \
.delete()


def annotation_moderation_service_factory(context, request):
return AnnotationModerationService(request.db)
18 changes: 18 additions & 0 deletions h/views/api_moderation.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,21 @@ def create(context, request):
request.notify_after_commit(event)

return HTTPNoContent()


@api_config(route_name='api.annotation_hide',
request_method='DELETE',
link_name='annotation.unhide',
description='Unhide an annotation as a group moderator.',
effective_principals=security.Authenticated)
def delete(context, request):
if not request.has_permission('admin', context.group):
raise HTTPNotFound()

svc = request.find_service(name='annotation_moderation')
svc.unhide(context.annotation)

event = events.AnnotationEvent(request, context.annotation.id, 'update')
request.notify_after_commit(event)

return HTTPNoContent()
24 changes: 24 additions & 0 deletions tests/h/services/annotation_moderation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,30 @@ def test_it_skips_creating_moderation_when_already_exists(self, svc, factories,
assert count == 1


class TestAnnotationModerationServiceUnhide(object):
def test_it_unhides_given_annotation(self, svc, factories, db_session):
mod = factories.AnnotationModeration()
annotation = mod.annotation

svc.unhide(annotation)

assert svc.hidden(annotation.id) is False

def test_it_leaves_othes_annotations_hidden(self, svc, factories, db_session):
mod1, mod2 = factories.AnnotationModeration(), factories.AnnotationModeration()

svc.unhide(mod1.annotation)

assert svc.hidden(mod2.annotation.id) is True

def test_it_skips_hiding_annotation_when_not_hidden(self, svc, factories, db_session):
annotation = factories.Annotation()

svc.unhide(annotation)

assert svc.hidden(annotation.id) is False


class TestAnnotationNipsaServiceFactory(object):
def test_it_returns_service(self, pyramid_request):
svc = annotation_moderation_service_factory(None, pyramid_request)
Expand Down
83 changes: 59 additions & 24 deletions tests/h/views/api_moderation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,62 @@ def test_it_responds_with_not_found_when_no_admin_access_in_group(self, pyramid_
with pytest.raises(HTTPNotFound):
views.create(resource, pyramid_request)

@pytest.fixture
def resource(self):
return mock.Mock(spec_set=['annotation', 'group'])

@pytest.fixture
def moderation_service(self, pyramid_config):
svc = mock.Mock(spec_set=['hide'])
pyramid_config.register_service(svc, name='annotation_moderation')
return svc

@pytest.fixture
def has_permission(self, pyramid_request):
func = mock.Mock(return_value=True)
pyramid_request.has_permission = func
return func

@pytest.fixture
def events(self, patch):
return patch('h.views.api_moderation.events')

@pytest.fixture
def pyramid_request(self, pyramid_request):
pyramid_request.notify_after_commit = mock.Mock()
return pyramid_request

@pytest.mark.usefixtures('moderation_service', 'has_permission')
class TestDelete(object):
def test_it_unhides_the_annotation(self, pyramid_request, resource, moderation_service):
views.delete(resource, pyramid_request)

moderation_service.unhide.assert_called_once_with(resource.annotation)

def test_it_publishes_update_event(self, pyramid_request, resource, events):
views.delete(resource, pyramid_request)

events.AnnotationEvent.assert_called_once_with(
pyramid_request, resource.annotation.id, 'update')

pyramid_request.notify_after_commit.assert_called_once_with(
events.AnnotationEvent.return_value)

def test_it_renders_no_content(self, pyramid_request, resource):
response = views.delete(resource, pyramid_request)
assert isinstance(response, HTTPNoContent)

def test_it_checks_for_group_admin_permission(self, pyramid_request, resource):
views.delete(resource, pyramid_request)
pyramid_request.has_permission.assert_called_once_with('admin', resource.group)

def test_it_responds_with_not_found_when_no_admin_access_in_group(self, pyramid_request, resource):
pyramid_request.has_permission.return_value = False
with pytest.raises(HTTPNotFound):
views.delete(resource, pyramid_request)


@pytest.fixture
def resource():
return mock.Mock(spec_set=['annotation', 'group'])


@pytest.fixture
def moderation_service(pyramid_config):
svc = mock.Mock(spec_set=['hide', 'unhide'])
pyramid_config.register_service(svc, name='annotation_moderation')
return svc


@pytest.fixture
def has_permission(pyramid_request):
func = mock.Mock(return_value=True)
pyramid_request.has_permission = func
return func


@pytest.fixture
def events(patch):
return patch('h.views.api_moderation.events')


@pytest.fixture
def pyramid_request(pyramid_request):
pyramid_request.notify_after_commit = mock.Mock()
return pyramid_request

0 comments on commit af68c9c

Please sign in to comment.