Skip to content
This repository was archived by the owner on Mar 15, 2018. It is now read-only.

Commit 2343467

Browse files
committed
create API endpoint for posting comm emails (bug 896044)
1 parent 939e6ee commit 2343467

File tree

5 files changed

+76
-5
lines changed

5 files changed

+76
-5
lines changed

apps/comm/tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99

1010
@task
11-
def consume_email(email_text):
11+
def consume_email(email_text, **kwargs):
1212
"""Parse emails and save notes."""
1313
res = save_from_email_reply(email_text)
1414
if not res:

lib/settings_base.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1564,3 +1564,7 @@ def read_only_mode(env):
15641564

15651565
# Cache timeout on the /search/featured API.
15661566
CACHE_SEARCH_FEATURED_API_TIMEOUT = 60 * 60 # 1 hour.
1567+
1568+
# Whitelist IP addresses of the allowed clients that can post email
1569+
# through the API.
1570+
WHITELISTED_CLIENTS_EMAIL_API = []

mkt/comm/api.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
from django.conf import settings
12
from django.db.models import Q
23
from django.http import Http404
34
from django.shortcuts import get_object_or_404
45

5-
from rest_framework.exceptions import PermissionDenied
6+
from rest_framework.decorators import api_view, permission_classes
7+
from rest_framework.exceptions import PermissionDenied, ParseError
68
from rest_framework.fields import CharField
79
from rest_framework.filters import OrderingFilter
810
from rest_framework.mixins import (CreateModelMixin, DestroyModelMixin,
@@ -14,11 +16,13 @@
1416
from addons.models import Addon
1517
from users.models import UserProfile
1618
from comm.models import CommunicationNote, CommunicationThread
19+
from comm.tasks import consume_email
1720
from comm.utils import ThreadObjectPermission
1821
from mkt.api.authentication import (RestOAuthAuthentication,
1922
RestSharedSecretAuthentication)
2023
from mkt.api.base import CORSViewSet
2124
from mkt.webpay.forms import PrepareForm
25+
from rest_framework.response import Response
2226

2327

2428
class AuthorSerializer(ModelSerializer):
@@ -190,3 +194,22 @@ def get_serializer(self, instance=None, data=None,
190194

191195
return super(NoteViewSet, self).get_serializer(data=data_dict,
192196
files=files, instance=instance, many=many, partial=partial)
197+
198+
199+
class EmailCreationPermission(object):
200+
def has_permission(self, request, view):
201+
remote_ip = request.META.get('REMOTE_ADDR')
202+
return remote_ip and (
203+
remote_ip in settings.WHITELISTED_CLIENTS_EMAIL_API)
204+
205+
206+
@api_view(['POST'])
207+
@permission_classes((EmailCreationPermission,))
208+
def post_email(request):
209+
email_body = request.POST.get('email_body')
210+
if not email_body:
211+
raise ParseError(
212+
detail='email_body not present in the POST data.')
213+
214+
consume_email.apply_async((email_body,))
215+
return Response(status=201)

mkt/comm/tests/test_api.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import json
22

3+
from django.conf import settings
34
from django.core.urlresolvers import reverse
45

6+
import mock
57
from nose.tools import eq_
68
from test_utils import RequestFactory
79

810
from amo.tests import addon_factory
911
from comm.models import (CommunicationNote, CommunicationThread,
1012
CommunicationThreadCC)
1113
from mkt.api.tests.test_oauth import RestOAuth
12-
from mkt.comm.api import ThreadPermission
14+
from mkt.comm.api import ThreadPermission, EmailCreationPermission, post_email
1315
from mkt.site.fixtures import fixture
1416
from mkt.webapps.models import Webapp
1517

@@ -185,3 +187,44 @@ def test_creation_denied(self):
185187
def test_cors_allowed(self):
186188
res = self.client.get(self.list_url)
187189
self.assertCORS(res, 'get', 'post', 'delete')
190+
191+
192+
class TestEmailApi(RestOAuth):
193+
194+
def setUp(self):
195+
super(TestEmailApi, self).setUp()
196+
settings.WHITELISTED_CLIENTS_EMAIL_API = ['10.10.10.10']
197+
self.mock_request = RequestFactory().get(reverse('post-email-api'))
198+
mock.patch.object(settings, 'WHITELISTED_CLIENTS_EMAIL_API',
199+
['10.10.10.10'])
200+
201+
def get_request(self, data):
202+
req = self.mock_request
203+
req.META['REMOTE_ADDR'] = '10.10.10.10'
204+
req.POST = dict(data)
205+
req.method = 'POST'
206+
req.user = self.user
207+
req.amo_user = self.profile
208+
req.groups = req.amo_user.groups.all()
209+
return req
210+
211+
def test_allowed(self):
212+
self.mock_request.META['REMOTE_ADDR'] = '10.10.10.10'
213+
assert EmailCreationPermission().has_permission(self.mock_request,
214+
None)
215+
216+
def test_denied(self):
217+
self.mock_request.META['REMOTE_ADDR'] = '10.10.10.1'
218+
assert not EmailCreationPermission().has_permission(self.mock_request,
219+
None)
220+
221+
@mock.patch('comm.tasks.consume_email.apply_async')
222+
def test_response(self, _mock):
223+
res = post_email(self.get_request({'email_body': 'something'}))
224+
_mock.assert_called_with(('something',))
225+
eq_(res.status_code, 201)
226+
227+
def test_bad_request(self):
228+
"""Test with no email body."""
229+
res = post_email(self.get_request({}))
230+
eq_(res.status_code, 400)

mkt/comm/urls.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from rest_framework.routers import DefaultRouter
44

5-
from mkt.comm.api import NoteViewSet, ThreadViewSet
5+
from mkt.comm.api import NoteViewSet, ThreadViewSet, post_email
66

77

88
api_thread = DefaultRouter()
@@ -11,5 +11,6 @@
1111
base_name='comm-note')
1212

1313
api_patterns = patterns('',
14-
url(r'^comm/', include(api_thread.urls))
14+
url(r'^comm/', include(api_thread.urls)),
15+
url(r'^comm/email/', post_email, name='post-email-api')
1516
)

0 commit comments

Comments
 (0)