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

Add actions to pods #126

Merged
merged 114 commits into from
Aug 15, 2016
Merged
Show file tree
Hide file tree
Changes from 110 commits
Commits
Show all changes
114 commits
Select commit Hold shift + click to select a range
86c7186
Add action support to PodApi angular service
justinvdm Jul 20, 2016
40dbd13
Add commas for separating object properties in PodApi service and its…
justinvdm Jul 20, 2016
b901c3f
Change base pod directive to draw actions
justinvdm Jul 20, 2016
526afad
Fix padding for items in pod body
justinvdm Jul 20, 2016
f0a00d4
Fix multi-line attribute spacing for pod template
justinvdm Jul 20, 2016
054db41
Don't call action trigger function with case ids in pod directive
justinvdm Jul 21, 2016
a5e7be4
Update PodApi service sending of actions request to match api change
justinvdm Jul 21, 2016
c715570
Refactor base pod controller's updating of pod data into its own method
justinvdm Jul 21, 2016
ddc1210
Update base pod directive's action tests to instantiate directive as …
justinvdm Jul 21, 2016
c59d79f
Merge branch 'EPIC-OPENHELPD-21' into EPIC-OPENHELPD-23
justinvdm Jul 21, 2016
aafcd49
Update base pod controller to trigger actions
justinvdm Jul 21, 2016
713ec63
Fix action request body in PodApi service
justinvdm Jul 21, 2016
a4fabac
Fix pod action anchor tags to not make the page jump
justinvdm Jul 21, 2016
459cac8
Update case timeline after pod action trigger
justinvdm Jul 21, 2016
38ceb6d
Change case field to case_id in error message
Jul 22, 2016
fd88660
Add docstring for pod read_data format
Jul 21, 2016
eda494a
Add docstring to pod perform_action to describe format
Jul 21, 2016
47d7a4a
Create case action note if action was successful
Jul 21, 2016
21903d1
Update tests for pod action changes
Jul 21, 2016
477bcbc
Fix expected error message in test
Jul 22, 2016
e73cba4
Use [[s for angular templates
justinvdm Jul 22, 2016
37c08a5
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-49-update-podapi-…
justinvdm Jul 22, 2016
00dcaa8
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-52-update-base-po…
justinvdm Jul 22, 2016
f5eb1c1
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-53-update-case-ac…
justinvdm Jul 22, 2016
3451969
Add notifications directive
justinvdm Jul 22, 2016
779c6a7
Change pod controller to emit event on pod action failure
justinvdm Jul 22, 2016
542b5a7
Change CaseController to add a notification on pod action failure
justinvdm Jul 22, 2016
085b469
Parse fetched pod data in pod controller to add busy flags to action …
justinvdm Jul 22, 2016
d2a7816
Change pod controller to set actions to busy when triggered
justinvdm Jul 22, 2016
3ed98b6
Merge branch 'feature/issue-48-draw-actions-from-pod-data' into featu…
justinvdm Jul 22, 2016
8a8d797
Change pod controller to set actions to not be busy when triggers com…
justinvdm Jul 25, 2016
d38f15d
Change pod controller to support using custom busy text for actions
justinvdm Jul 25, 2016
bb06575
Minor cleanup for pod controller
justinvdm Jul 25, 2016
e28738e
Change pod directive to draw busy actions differently
justinvdm Jul 25, 2016
9fad273
More consistent callback names in pod controller
justinvdm Jul 25, 2016
2581f7f
Merge pull request #55 from praekelt/feature-issue-51-backend-changes…
Jul 25, 2016
3990069
Refactor PodApi to avoid needing to repeat logic for handling responses
justinvdm Jul 25, 2016
7af3be6
Reject PodApi errors as PodApiErrors
justinvdm Jul 25, 2016
61cfa15
Add trap utility
justinvdm Jul 25, 2016
1b82c41
Emit an event if pod api calls fail in pod controller
justinvdm Jul 25, 2016
7ff8f88
Merge branch 'feature/issue-56-notify-on-pod-action-failure' into fea…
justinvdm Jul 25, 2016
787fa0f
Emit timelineChanged events from pod controller on pod action success…
justinvdm Jul 26, 2016
093620c
Merge branch 'develop' into EPIC-OPENHELPD-23
justinvdm Jul 26, 2016
bcb4cdb
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-53-update-case-ac…
justinvdm Jul 26, 2016
26f4247
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-57-provide-visual…
justinvdm Jul 26, 2016
1179973
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-48-draw-actions-f…
justinvdm Jul 26, 2016
477bd0d
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-56-notify-on-pod-…
justinvdm Jul 26, 2016
098e1d1
Change case notifications approach to keep notification content insid…
justinvdm Jul 26, 2016
94f891e
Remove accidental change to pod action trigger success callback in po…
justinvdm Jul 26, 2016
01bfa9d
Merge branch 'feature/issue-56-notify-on-pod-action-failure' into fea…
justinvdm Jul 26, 2016
26369ba
Emit notification for trigger api failures in pod controller
justinvdm Jul 26, 2016
7955092
Add notification for pod action api failures
justinvdm Jul 26, 2016
4be1e28
Merge branch 'develop' into EPIC-OPENHELPD-23
justinvdm Jul 27, 2016
33a92cb
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-56-notify-on-pod-…
justinvdm Jul 27, 2016
849af1e
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-53-update-case-ac…
justinvdm Jul 27, 2016
798b8f9
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-48-draw-actions-f…
justinvdm Jul 27, 2016
01bff59
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-57-provide-visual…
justinvdm Jul 27, 2016
2284cbb
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-59-handle-pod-err…
justinvdm Jul 27, 2016
804ef03
Change pod controller and directive to show when pod is loading
justinvdm Jul 27, 2016
1507722
Change pod controller and directive to show when loading pod fails
justinvdm Jul 27, 2016
2fc6862
Display a notification if loading pods fails
justinvdm Jul 27, 2016
0acacff
Only set actions to not be busy once success or failure callback has …
justinvdm Jul 27, 2016
fe267dd
Merge branch 'feature/issue-57-provide-visual-feedback-when-pod-actio…
justinvdm Jul 27, 2016
4e54077
Fix scope soup in cp-case-notifications directive
justinvdm Jul 27, 2016
82ecd13
Merge branch 'feature/issue-56-notify-on-pod-action-failure' into fea…
justinvdm Jul 27, 2016
4afda00
Fix failing test after merging in updates to #56
justinvdm Jul 27, 2016
a6ff38b
Merge branch 'feature/issue-59-handle-pod-error-responses-in-ui' into…
justinvdm Jul 27, 2016
658938d
More consistent naming convention for pod status scope property
justinvdm Jul 27, 2016
b94a1cf
Merge branch 'develop' into EPIC-OPENHELPD-23
justinvdm Jul 28, 2016
072e2c8
Merge branch 'develop' into feature/issue-53-update-case-actions-afte…
justinvdm Jul 28, 2016
162188d
Merge branch 'develop' into feature/issue-48-draw-actions-from-pod-data
justinvdm Jul 28, 2016
6104f65
Merge branch 'develop' into feature/issue-56-notify-on-pod-action-fai…
justinvdm Jul 28, 2016
9056cdc
Merge branch 'develop' into feature/issue-57-provide-visual-feedback-…
justinvdm Jul 28, 2016
9ad8bd1
Merge branch 'develop' into feature/issue-59-handle-pod-error-respons…
justinvdm Jul 28, 2016
30a20d0
Merge branch 'develop' into feature/issue-60-show-when-pods-load-or-f…
justinvdm Jul 28, 2016
bf6ea66
Merge branch 'feature/issue-48-draw-actions-from-pod-data' into EPIC-…
justinvdm Jul 28, 2016
1f8ff75
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-57-provide-visual…
justinvdm Jul 28, 2016
65e3bfa
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-53-update-case-ac…
justinvdm Jul 28, 2016
a4ebc33
Add pod action confirm modal
justinvdm Jul 28, 2016
bbd9d49
Change PodController to support showing confirmation modal for actions
justinvdm Jul 28, 2016
341e95c
Clean up PodController tests
justinvdm Jul 28, 2016
d50c77f
Merge branch 'develop' into EPIC-OPENHELPD-23
justinvdm Jul 29, 2016
b684ae9
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-56-notify-on-pod-…
justinvdm Jul 29, 2016
7436b23
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-57-provide-visual…
justinvdm Jul 29, 2016
8b23672
Merge branch 'feature/issue-56-notify-on-pod-action-failure' into fea…
justinvdm Jul 29, 2016
f9e1ecf
Merge branch 'feature/issue-57-provide-visual-feedback-when-pod-actio…
justinvdm Jul 29, 2016
ed26df5
Merge branch 'feature/issue-59-handle-pod-error-responses-in-ui' into…
justinvdm Jul 29, 2016
764bc24
Merge branch 'feature/issue-60-show-when-pods-load-or-fail-to-load' i…
justinvdm Jul 29, 2016
f0064a5
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-57-provide-visual…
justinvdm Jul 29, 2016
b39cd36
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-59-handle-pod-err…
justinvdm Jul 29, 2016
255bd0d
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-60-show-when-pods…
justinvdm Jul 29, 2016
f8b8405
Merge branch 'feature/issue-60-show-when-pods-load-or-fail-to-load' i…
justinvdm Aug 1, 2016
dd5aaaf
Merge branch 'develop' into feature/issue-58-pod-confirm-modal
justinvdm Aug 1, 2016
f689f48
Fix pod action confirm modal template to only include title in header
justinvdm Aug 1, 2016
ca19784
Fix timelineChanged event proxying and related false positive test (t…
justinvdm Aug 1, 2016
f3e51f1
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-58-pod-confirm-modal
justinvdm Aug 1, 2016
7b7d1e2
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-62-change-pod-mod…
justinvdm Aug 1, 2016
c682b52
Add basic ModalService with confirm() method for generic confirm modals
justinvdm Aug 1, 2016
9eb52e4
Add PodUIService.confirmAction() for drawing pod action confirm modals
justinvdm Aug 1, 2016
a7860da
Use PodUIService.confirmAction() in pod controller
justinvdm Aug 1, 2016
a3693f0
Move modal templates into subdirectory
justinvdm Aug 1, 2016
d4cb017
Rename notifications to alerts
justinvdm Aug 1, 2016
2c828bb
Remove stray template url in pod controller
justinvdm Aug 1, 2016
4a622be
Change alerts approach to display alerts that have their own markup u…
justinvdm Aug 1, 2016
a894215
Undisable pod actions after error
justinvdm Aug 1, 2016
5e5f824
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-62-change-pod-mod…
justinvdm Aug 2, 2016
d48c4c3
Include user's name on case action when pod action is triggered
justinvdm Aug 2, 2016
e1d3209
Merge branch 'master' of https://github.com/rapidpro/casepro into EPI…
Aug 5, 2016
147e2b1
Merge branch 'feature/issue-66-include-users-name-on-pod-action-case-…
justinvdm Aug 5, 2016
89b2cb3
Update pod docstrings
justinvdm Aug 5, 2016
b92c1ab
Fix bad search-and-replace for notification -> alert (thanks @rudigie…
justinvdm Aug 5, 2016
52d6c3e
Move dummy templates to karma directory
justinvdm Aug 5, 2016
b7e7792
Restrict access for case views
justinvdm Aug 5, 2016
8990707
Merge branch 'EPIC-OPENHELPD-23' into feature/issue-71-restrict-acces…
justinvdm Aug 8, 2016
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
55 changes: 51 additions & 4 deletions casepro/pods/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,59 @@ def config_json(self):
return json.dumps(self.config._config_data)

def read_data(self, params):
"""Should return the data that should be used to create the display for the pod."""
"""
Should return the data that should be used to create the display for the pod.

For the base implementation, the data should be an object with 'items' and 'actions' keys.

The items key should be a list of objects, that have 'name' and 'value' keys, with the value of the keys being
what will be displayed.

The 'actions' key should be a list of objects, that have 'type', 'name' and 'payload' keys, where type and
payload is what is sent to the 'perform_action' function to determine which button has been pressed, and 'name'
is the text that is displayed on the button.

Each action may include the following optional fields:
- ``busy_text``: used as the action's corresponding
button's text while waiting on a response from the pod's api side
when the action is triggered. Defaults to the value of the ``name``
field.
- ``confirm``: whether a confirmation modal should be shown to
confirm whether the user would like to perform the action. Defaults
to ``false``.

Example:
{
'items': [
{
'name': 'EDD',
'value': '2015-07-18',
},
],
'actions': [
{
'type': 'remove_edd',
'name': 'Remove EDD',
'payload': {},
'busy_text': 'Removing EDD',
'confirm': True
},
],
}
"""
return {}

def perform_action(self, params):
"""Should perform the action specified by params."""
return {}
def perform_action(self, type_, params):
"""
Should perform the action specified by the type and params (which are specified in the read function).

Returns a tuple (success, payload), where 'success' is a boolean value indicating whether the action was
successful or not. If true, a case action note will be created.

For the base implementation, payload is an object with a 'message' key, which is the error message if success
is false, or the message to place in the case action note if success is true.
"""
return (False, {'message': ''})


class PodPlugin(AppConfig):
Expand Down
72 changes: 70 additions & 2 deletions casepro/pods/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.core.urlresolvers import reverse
from django.test import modify_settings

from casepro.cases.models import CaseAction
from casepro.test import BaseCasesTest


Expand Down Expand Up @@ -100,14 +101,81 @@ def test_invalid_json(self):
'details': 'No JSON object could be decoded'
})

def test_case_id_required(self):
'''
If the case id is not present in the request, an error response should be returned.
'''
with self.settings(PODS=[{'label': 'base_pod'}]):
from casepro.pods import registry
reload(registry)

response = self.url_post_json(
'unicef', reverse('perform_pod_action', args=('0',)), {})
self.assertEqual(response.status_code, 400)
self.assertEqual(response.json, {
'reason': 'Request object needs to have a "case_id" field'
})

def test_pod_valid_request(self):
"""
If it is a valid post request, the action should be performed.
"""
with self.settings(PODS=[{'label': 'base_pod'}]):
from casepro.pods import registry
reload(registry)

contact = self.create_contact(self.unicef, 'contact-uuid', 'contact_name')
msg = self.create_message(self.unicef, 0, contact, 'Test message')
case = self.create_case(self.unicef, contact, self.moh, msg)

response = self.url_post_json(
'unicef', reverse('perform_pod_action', args=('0',)), {})
'unicef', reverse('perform_pod_action', args=('0',)), {'case_id': case.id})
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json, {})
self.assertEqual(response.json, {
'success': False,
'payload': {
'message': '',
}
})

@modify_settings(INSTALLED_APPS={
'append': 'casepro.pods.tests.utils.SuccessActionPlugin',
})
def test_case_action_note_created_on_successful_action(self):
'''
If the action is successful, a case action note should be created.
'''
CaseAction.objects.all().delete()
self.login(self.admin)

with self.settings(PODS=[{'label': 'success_pod'}]):
from casepro.pods import registry
reload(registry)

contact = self.create_contact(self.unicef, 'contact-uuid', 'contact_name')
msg = self.create_message(self.unicef, 0, contact, 'Test message')
case = self.create_case(self.unicef, contact, self.moh, msg)

response = self.url_post_json(
'unicef', reverse('perform_pod_action', args=('0',)), {
'case_id': case.id,
'action': {
'type': 'foo',
'payload': {'foo': 'bar'},
},
})

self.assertEqual(response.status_code, 200)

message = "Type foo Params {u'foo': u'bar'}"
self.assertEqual(response.json, {
'success': True,
'payload': {
'message': message
}
})

[caseaction] = CaseAction.objects.all()
self.assertEqual(
caseaction.note,
"%s %s" % (self.admin.username, message))
13 changes: 13 additions & 0 deletions casepro/pods/tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,16 @@ class DummyPodPlugin(PodPlugin):
directive = 'dummy-pod'
scripts = ('dummy-script.js',)
styles = ('dummy-style.css',)


class SuccessActionPod(Pod):
def perform_action(self, type_, params):
'''
Returns a successful action result with a message containing the type and params.
'''
return (True, {'message': 'Type %s Params %r' % (type_, params)})


class SuccessActionPlugin(DummyPodPlugin):
pod_class = SuccessActionPod
label = 'success_pod'
26 changes: 24 additions & 2 deletions casepro/pods/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
import json
from django.http import JsonResponse

from casepro.cases.models import Case, CaseAction
from casepro.pods import registry


ACTION_NOTE_CONTENT = "%(username)s %(message)s"


def read_pod_data(request, index):
"""Delegates to the `read_data` function of the correct pod."""
if request.method != 'GET':
Expand All @@ -20,7 +24,10 @@ def read_pod_data(request, index):


def perform_pod_action(request, index):
"""Deletegates to the `perform_action` function of the correct pod."""
"""
Delegates to the `perform_action` function of the correct pod. If the action completes successfully, a new case
action note is created with the success message.
"""
if request.method != 'POST':
return JsonResponse({'reason': 'Method not allowed'}, status=405)

Expand All @@ -34,4 +41,19 @@ def perform_pod_action(request, index):
except ValueError as e:
return JsonResponse({'reason': 'JSON decode error', 'details': e.message}, status=400)

return JsonResponse(pod.perform_action(data))
case_id = data.get('case_id')
if case_id is None:
return JsonResponse(
{'reason': 'Request object needs to have a "case_id" field'}, status=400)

action_data = data.get('action', {})
success, payload = pod.perform_action(action_data.get('type'), action_data.get('payload', {}))
if success is True:
case = Case.objects.get(id=case_id)
Copy link
Contributor

Choose a reason for hiding this comment

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

For security, filter by org too to make sure a user can never act on a case outside of their org

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually come to think of it, it should actually be checking Case.access_level(user) to make sure this user has correct access rights to this case.

Obviously this applies to anywhere requests can access or modify cases.

note = ACTION_NOTE_CONTENT % {
'username': request.user.username,
'message': payload.get('message'),
}
CaseAction.create(case, request.user, CaseAction.ADD_NOTE, note=note)

return JsonResponse({'success': success, 'payload': payload})
Loading