diff --git a/debian/settings.py b/debian/settings.py index a7a2c6f..9a397d3 100644 --- a/debian/settings.py +++ b/debian/settings.py @@ -16,15 +16,15 @@ DEBUG = False TEMPLATE_DEBUG = False -#ADMINS = ( +# ADMINS = ( # # ('User 1', 'watchdog@example.net'), # # ('User 2', 'janitor@example.net'), -#) +# ) # ALLOWED_HOSTS must be correct in production! # See https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts ALLOWED_HOSTS = [ - '*', + '*', ] # Databases diff --git a/setup.py b/setup.py index 1567303..30cd11c 100644 --- a/setup.py +++ b/setup.py @@ -25,16 +25,18 @@ class eo_sdist(sdist): def get_version(): - '''Use the VERSION, if absent generates a version with git describe, if not - tag exists, take 0.0- and add the length of the commit log. - ''' + """Use the VERSION, if absent generates a version with git describe, if not + tag exists, take 0.0- and add the length of the commit log. + """ if os.path.exists('VERSION'): with open('VERSION', 'r') as v: return v.read() if os.path.exists('.git'): p = subprocess.Popen( ['git', 'describe', '--dirty=.dirty', '--match=v*'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) result = p.communicate()[0] if p.returncode == 0: result = result.decode('ascii').strip()[1:] # strip spaces/newlines and initial v @@ -45,9 +47,7 @@ def get_version(): version = result return version else: - return '0.0.post%s' % len( - subprocess.check_output( - ['git', 'rev-list', 'HEAD']).splitlines()) + return '0.0.post%s' % len(subprocess.check_output(['git', 'rev-list', 'HEAD']).splitlines()) return '0.0' @@ -65,6 +65,7 @@ class compile_translations(Command): curdir = os.getcwd() try: from django.core.management import call_command + for path, dirs, files in os.walk('welco'): if 'locale' not in dirs: continue @@ -108,7 +109,8 @@ setup( 'Programming Language :: Python', 'Programming Language :: Python :: 2', ], - install_requires=['django>=1.11,<2.3', + install_requires=[ + 'django>=1.11,<2.3', 'gadjo', 'django-ckeditor<4.5.4', 'django-haystack<2.8', @@ -118,7 +120,7 @@ setup( 'whoosh', 'XStatic-Select2', 'python-dateutil', - ], + ], zip_safe=False, cmdclass={ 'build': build, diff --git a/tests/test_contacts_manager.py b/tests/test_contacts_manager.py index ad72049..db8e8c2 100644 --- a/tests/test_contacts_manager.py +++ b/tests/test_contacts_manager.py @@ -29,14 +29,9 @@ def test_get_contacts_zone_view(app, db): resp = app.get('/ajax/contacts', status=200) assert resp.html.find('button')['data-url'] == '/contacts/add/' - mail = Mail.objects.create( - content=ContentFile('foo', name='bar.txt'), - contact_id='42') + mail = Mail.objects.create(content=ContentFile('foo', name='bar.txt'), contact_id='42') source_type = ContentType.objects.get_for_model(Mail).pk - resp = app.get( - '/ajax/contacts', - params={'source_type': source_type, 'source_pk': mail.pk}, - status=200) + resp = app.get('/ajax/contacts', params={'source_type': source_type, 'source_pk': mail.pk}, status=200) assert resp.html.find('a').text == '...' assert resp.html.find('a')['data-page-slug'] == '42' @@ -46,9 +41,8 @@ def test_post_contacts_zone_view(app, db): assert not mail.contact_id source_type = ContentType.objects.get_for_model(Mail).pk resp = app.post( - '/ajax/contacts', - params={'source_type': source_type, 'source_pk': mail.pk, 'user_id': 42}, - status=200) + '/ajax/contacts', params={'source_type': source_type, 'source_pk': mail.pk, 'user_id': 42}, status=200 + ) assert resp.text == 'ok' assert Mail.objects.get(id=mail.pk).contact_id == '42' @@ -90,20 +84,24 @@ def test_search_json_view(settings, app, user, mail_group): def response(url, request): headers = {'content-type': 'application/json'} content = { - 'data': [{ - 'user_display_name': 'John Doe', - 'user_email': 'john@example.net', - 'user_var_phone': '0123456789', - 'user_var_mobile': '0612345789', - 'user_id': '42', - 'user_roles': [{ - 'name': 'Agent', - 'text': 'Agent', - 'slug': 'agent', - 'id': '8d73434814484aa0b8555ac9c68a9300' - }], - }], - 'err': 0 + 'data': [ + { + 'user_display_name': 'John Doe', + 'user_email': 'john@example.net', + 'user_var_phone': '0123456789', + 'user_var_mobile': '0612345789', + 'user_id': '42', + 'user_roles': [ + { + 'name': 'Agent', + 'text': 'Agent', + 'slug': 'agent', + 'id': '8d73434814484aa0b8555ac9c68a9300', + } + ], + } + ], + 'err': 0, } return httmock.response(200, content, headers) @@ -123,6 +121,7 @@ def test_contact_detail_fragment_view(settings, app, db): } } } + @httmock.urlmatch(netloc='wcs.example.net', path='/api/users/42/', method='GET') def response(url, request): headers = {'content-type': 'application/json'} @@ -132,12 +131,9 @@ def test_contact_detail_fragment_view(settings, app, db): 'user_var_phone': '0123456789', 'user_var_mobile': '0612345789', 'user_id': '42', - 'user_roles': [{ - 'name': 'Agent', - 'text': 'Agent', - 'slug': 'agent', - 'id': '8d73434814484aa0b8555ac9c68a9300' - }], + 'user_roles': [ + {'name': 'Agent', 'text': 'Agent', 'slug': 'agent', 'id': '8d73434814484aa0b8555ac9c68a9300'} + ], } return httmock.response(200, content, headers) @@ -148,15 +144,12 @@ def test_contact_detail_fragment_view(settings, app, db): assert resp.html.find('li').text == 'Phone: 0123456789' # unused 'is_pinned_user' context - mail = Mail.objects.create( - content=ContentFile('foo', name='bar.txt'), - contact_id='42') + mail = Mail.objects.create(content=ContentFile('foo', name='bar.txt'), contact_id='42') source_type = ContentType.objects.get_for_model(Mail).pk with httmock.HTTMock(response): resp = app.get( - '/ajax/contacts/42/', - params={'source_type': source_type, 'source_pk': mail.pk}, - status=200) + '/ajax/contacts/42/', params={'source_type': source_type, 'source_pk': mail.pk}, status=200 + ) assert resp.html.find('h3').text == 'John Doe' @@ -183,7 +176,7 @@ def test_post_contact_add_view(mocked_sleep, settings, app, db): 'orig': 'http://welco.example.net/', 'secret': 'xxx', } - } + }, } # normal case @@ -210,7 +203,8 @@ def test_post_contact_add_view(mocked_sleep, settings, app, db): 'first_name': 'John', 'last_name': 'Doe', }, - status=200) + status=200, + ) assert resp.content_type == 'application/json' assert resp.json['data']['user_id'] == '43' diff --git a/tests/test_mail_manager.py b/tests/test_mail_manager.py index 242102a..d4b04c9 100644 --- a/tests/test_mail_manager.py +++ b/tests/test_mail_manager.py @@ -46,10 +46,7 @@ def test_get_feeder_view(app, user): def test_post_feeder_view(app, user): app.set_user(user.username) - resp = app.post( - '/mail/feeder/', - params={'mail': Upload('filename.txt', b'contents')}, - status=302) + resp = app.post('/mail/feeder/', params={'mail': Upload('filename.txt', b'contents')}, status=302) assert resp.location == '/mail/feeder/' resp = resp.follow() assert resp.html.find('li', {'class': 'info'}).text == '1 files uploaded successfully.' @@ -63,27 +60,28 @@ def test_qualification_save_view(settings, app, db): } } } - mail = Mail.objects.create( - content=ContentFile('foo', name='bar.txt'), - subject='spam') + mail = Mail.objects.create(content=ContentFile('foo', name='bar.txt'), subject='spam') assert not mail.contact_id source_type = ContentType.objects.get_for_model(Mail).pk resp = app.post( '/ajax/qualification-mail-save', params={'source_type': source_type, 'source_pk': mail.pk, 'subject': 'eggs'}, - status=302) - assert resp.location == '/ajax/qualification?source_type=%s&source_pk=%s' % ( - source_type, mail.pk) + status=302, + ) + assert resp.location == '/ajax/qualification?source_type=%s&source_pk=%s' % (source_type, mail.pk) @httmock.urlmatch(netloc='wcs.example.net', path='/api/formdefs/', method='GET') def response_get(url, request): headers = {'content-type': 'application/json'} content = { "err": 0, - "data": [{ - "title": "Foo", - "slug": "foo", - }]} + "data": [ + { + "title": "Foo", + "slug": "foo", + } + ], + } return httmock.response(200, content, headers) with httmock.HTTMock(response_get): @@ -97,9 +95,7 @@ def test_edit_note_view(app, user): assert resp.location.startswith('/login/?next=') app.set_user(user.username) - mail = Mail.objects.create( - content=ContentFile('foo', name='bar.txt'), - note='spam') + mail = Mail.objects.create(content=ContentFile('foo', name='bar.txt'), note='spam') resp = app.get('/ajax/mail/edit-note/', params={'mail': mail.pk}, status=200) assert resp.html.find('h2').text == 'Note' assert resp.html.find('textarea', {'name': 'note'}).text == 'spam' @@ -123,7 +119,7 @@ def test_note_view(app, user): def test_reject_view(settings, app, user): - settings.MAARCH_FEED= { + settings.MAARCH_FEED = { 'URL': 'http://maarch.example.net', 'ENABLE': True, 'USERNAME': 'xxx', @@ -134,9 +130,7 @@ def test_reject_view(settings, app, user): assert resp.location.startswith('/login/?next=') app.set_user(user.username) - mail = Mail.objects.create( - content=ContentFile('foo', name='bar.txt'), - external_id='maarch-42') + mail = Mail.objects.create(content=ContentFile('foo', name='bar.txt'), external_id='maarch-42') @httmock.urlmatch(netloc='maarch.example.net', path='/rest/res/resource/status', method='PUT') def response_ok(url, request): @@ -150,9 +144,7 @@ def test_reject_view(settings, app, user): assert Mail.objects.count() == 0 # errors - mail = Mail.objects.create( - content=ContentFile('foo', name='bar.txt'), - external_id='maarch-42') + mail = Mail.objects.create(content=ContentFile('foo', name='bar.txt'), external_id='maarch-42') @httmock.urlmatch(netloc='maarch.example.net', path='/rest/res/resource/status', method='PUT') def response_error1(url, request): diff --git a/tests/test_manager.py b/tests/test_manager.py index 259011a..b760643 100644 --- a/tests/test_manager.py +++ b/tests/test_manager.py @@ -112,15 +112,11 @@ def test_wcs_summary_view(app, mail_group, user): mail = Mail.objects.create(content=ContentFile('foo', name='bar.txt')) source_type = ContentType.objects.get_for_model(Mail).pk - resp = app.get( - '/ajax/summary/%s/%s/?callback=spam' % (source_type, mail.pk), - status=302) + resp = app.get('/ajax/summary/%s/%s/?callback=spam' % (source_type, mail.pk), status=302) assert resp.location.startswith('/login/?next=') app.set_user(user.username) - resp = app.get( - '/ajax/summary/%s/%s/?callback=spam' % (source_type, mail.pk), - status=200) + resp = app.get('/ajax/summary/%s/%s/?callback=spam' % (source_type, mail.pk), status=200) assert resp.content_type == 'application/javascript' assert 'bar' in resp.text assert resp.text.startswith('spam({') @@ -130,8 +126,8 @@ def test_remove_association_view(app, mail_group, user): mail = Mail.objects.create(content=ContentFile('foo', name='bar.txt')) source_type = ContentType.objects.get_for_model(Mail).pk association = Association.objects.create( - source_type=ContentType.objects.get(id=source_type), - source_pk=mail.pk) + source_type=ContentType.objects.get(id=source_type), source_pk=mail.pk + ) assert Association.objects.filter(id=association.pk).count() == 1 resp = app.get('/ajax/remove-association/%s' % association.pk, status=302) @@ -154,8 +150,8 @@ def test_create_formdata_view(settings, app, mail_group, user): mail = Mail.objects.create(content=ContentFile('foo', name='bar.txt')) source_type = ContentType.objects.get_for_model(Mail).pk association = Association.objects.create( - source_type=ContentType.objects.get(id=source_type), - source_pk=mail.pk) + source_type=ContentType.objects.get(id=source_type), source_pk=mail.pk + ) resp = app.get('/ajax/create-formdata/%s' % association.pk, status=302) assert resp.location.startswith('/login/?next=') @@ -185,7 +181,8 @@ def test_create_formdata_view(settings, app, mail_group, user): 'data': { 'id': 42, 'backoffice_url': 'http://example.net', - }} + }, + } return httmock.response(200, content, headers) with httmock.HTTMock(response_get, response_post): @@ -204,8 +201,7 @@ def test_menu_json_view(app, user, mail_group, phone_group, counter_group, kb_gr app.set_user(user.username) resp = app.get('/menu.json', status=200) assert resp.content_type == 'application/json' - assert sorted([x['label'] for x in resp.json]) == [ - 'Call Center', 'Counter', 'Knowledge Base', 'Mails'] + assert sorted([x['label'] for x in resp.json]) == ['Call Center', 'Counter', 'Knowledge Base', 'Mails'] resp = app.get('/menu.json?callback=foo', status=200) assert resp.content_type == 'application/javascript' diff --git a/tests/test_qualification.py b/tests/test_qualification.py index e9ef4df..b46091c 100644 --- a/tests/test_qualification.py +++ b/tests/test_qualification.py @@ -23,27 +23,25 @@ from welco.forms import QualificationForm pytestmark = pytest.mark.django_db -KNOWN_SERVICES = { - 'wcs': { - 'eservices': { - 'url': 'http://localhost/', - 'title': 'Eservices', - 'orig': 'welco' - } - } -} +KNOWN_SERVICES = {'wcs': {'eservices': {'url': 'http://localhost/', 'title': 'Eservices', 'orig': 'welco'}}} @mock.patch('welco.utils.requests.get') def test_get_qualification(mocked_get, client): with override_settings(KNOWN_SERVICES=KNOWN_SERVICES): forms = mock.Mock() - forms.json.return_value = {'data': [{'category': 'Test', - 'authentication_required': False, - 'description': '', - 'title': 'Test form', - 'slug': 'test-form'}], - 'err': 0} + forms.json.return_value = { + 'data': [ + { + 'category': 'Test', + 'authentication_required': False, + 'description': '', + 'title': 'Test form', + 'slug': 'test-form', + } + ], + 'err': 0, + } mocked_get.return_value = forms user = mock.Mock() diff --git a/tests/test_source_maarch.py b/tests/test_source_maarch.py index 231f1c6..c323122 100644 --- a/tests/test_source_maarch.py +++ b/tests/test_source_maarch.py @@ -59,11 +59,13 @@ class MaarchMock(BaseMock): }, 'status_code': 200, } + list_endpoint.path = '^/rest/res/list$' def update_external_infos(self, url, request): self.requests.append(('update_external_infos', url, request, json.loads(force_text(request.body)))) return json.dumps({}) + update_external_infos.path = '^/rest/res/externalInfos$' def update_status(self, url, request): @@ -75,10 +77,12 @@ class MaarchMock(BaseMock): }, 'status_code': 200, } + update_status.path = '^/rest/res/resource/status$' def post_courrier(self, url, request): self.requests.append(('post_courrier', url, request, json.loads(force_text(request.body)))) + post_courrier.path = '^/rest/res$' @@ -96,37 +100,50 @@ def maarch(settings, mail_group): class WcsMock(BaseMock): def api_formdefs(self, url, request): - return json.dumps({ - 'data': [{ - 'slug': 'slug1', - 'title': 'title1', - }] - }) + return json.dumps( + { + 'data': [ + { + 'slug': 'slug1', + 'title': 'title1', + } + ] + } + ) + api_formdefs.path = '^/api/formdefs/$' def json(self, url, request): - return json.dumps({ - 'data': [{ - 'slug': 'slug1', - 'title': 'title1', - 'category': 'category1', - }] - }) + return json.dumps( + { + 'data': [ + { + 'slug': 'slug1', + 'title': 'title1', + 'category': 'category1', + } + ] + } + ) + json.path = '^/json$' def api_formdefs_slug1_schema(self, url, request): - return json.dumps({ - }) + return json.dumps({}) + api_formdefs_slug1_schema.path = '^/api/formdefs/slug-1/schema$' def api_formdefs_slug1_submit(self, url, request): - return json.dumps({ - 'err': 0, - 'data': { - 'id': 1, - 'backoffice_url': 'http://wcs.example.net/slug-1/1', - }, - }) + return json.dumps( + { + 'err': 0, + 'data': { + 'id': 1, + 'backoffice_url': 'http://wcs.example.net/slug-1/1', + }, + } + ) + api_formdefs_slug1_submit.path = '^/api/formdefs/slug-1/submit$' @@ -172,14 +189,16 @@ def test_feed(settings, app, maarch, wcs, user): # feed mails from maarch with maarch.ctx_manager: # list request - maarch.responses.append({ - 'resources': [ - { - 'res_id': 1, - 'fileBase64Content': force_text(base64.b64encode(PDF_MOCK)), - } - ], - }) + maarch.responses.append( + { + 'resources': [ + { + 'res_id': 1, + 'fileBase64Content': force_text(base64.b64encode(PDF_MOCK)), + } + ], + } + ) # update status request maarch.responses.append({}) # last list request @@ -214,20 +233,26 @@ def test_feed(settings, app, maarch, wcs, user): maarch.clear() pk = Mail.objects.get().pk with wcs.ctx_manager, maarch.ctx_manager: - source_type = str(ContentType.objects.get_for_model(Mail).pk), + source_type = (str(ContentType.objects.get_for_model(Mail).pk),) source_pk = str(pk) - response = app.get('/ajax/qualification', params={ - 'source_type': source_type, - 'source_pk': source_pk, - }) + response = app.get( + '/ajax/qualification', + params={ + 'source_type': source_type, + 'source_pk': source_pk, + }, + ) assert len(response.pyquery('a[data-association-pk]')) == 0 - response = app.post('/ajax/qualification', params={ - 'source_type': source_type, - 'source_pk': str(pk), - 'formdef_reference': 'demarches:slug-1', - }) + response = app.post( + '/ajax/qualification', + params={ + 'source_type': source_type, + 'source_pk': str(pk), + 'formdef_reference': 'demarches:slug-1', + }, + ) # verify qualification was done assert len(response.pyquery('a[data-association-pk]')) == 1 @@ -243,7 +268,7 @@ def test_feed(settings, app, maarch, wcs, user): 'external_link': 'http://wcs.example.net/slug-1/1', 'res_id': 1, } - ] + ], } # verify we can answer @@ -260,24 +285,24 @@ def test_feed(settings, app, maarch, wcs, user): assert response.json['err'] == 1 # verify error when maarch feed is not configured settings.MAARCH_FEED['ENABLE'] = False - response = app.post_json('/api/mail/response/', - params={'mail_id': 'maarch-1', 'content': 'coucou'}, - status=200) + response = app.post_json( + '/api/mail/response/', params={'mail_id': 'maarch-1', 'content': 'coucou'}, status=200 + ) assert response.json['err'] == 1 assert response.json['err_desc'] == 'maarch is unconfigured' settings.MAARCH_FEED['ENABLE'] = True # verify error when mail_id is unknown - response = app.post_json('/api/mail/response/', - params={'mail_id': 'maarch-231', 'content': 'coucou'}, - status=404) + response = app.post_json( + '/api/mail/response/', params={'mail_id': 'maarch-231', 'content': 'coucou'}, status=404 + ) assert response.json['err'] == 1 # successfull call maarch.responses.append({}) with maarch.ctx_manager: - response = app.post_json('/api/mail/response/', - params={'mail_id': 'maarch-1', 'content': 'coucou'}, - status=200) + response = app.post_json( + '/api/mail/response/', params={'mail_id': 'maarch-1', 'content': 'coucou'}, status=200 + ) assert maarch.requests[0][3] == { 'historyMessage': 'coucou', 'resId': [1], diff --git a/tests/test_source_phone.py b/tests/test_source_phone.py index 954c797..4f9415d 100644 --- a/tests/test_source_phone.py +++ b/tests/test_source_phone.py @@ -38,95 +38,104 @@ def test_call_start_stop(client): 'callee': '102', 'data': { 'user': 'boby.lapointe', - } + }, } - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post(reverse('phone-call-event'), json.dumps(payload), content_type='application/json') assert response.status_code == 200 assert response['content-type'] == 'application/json' assert response.json() == {'err': 0} assert models.PhoneCall.objects.count() == 1 - assert models.PhoneCall.objects.filter( - caller='0033699999999', - callee='102', - data=json.dumps(payload['data']), stop__isnull=True).count() == 1 + assert ( + models.PhoneCall.objects.filter( + caller='0033699999999', callee='102', data=json.dumps(payload['data']), stop__isnull=True + ).count() + == 1 + ) # new start event - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post(reverse('phone-call-event'), json.dumps(payload), content_type='application/json') assert response.status_code == 200 assert response['content-type'] == 'application/json' assert response.json() == {'err': 0} assert models.PhoneCall.objects.count() == 2 - assert models.PhoneCall.objects.filter( - caller='0033699999999', - callee='102', - data=json.dumps(payload['data']), stop__isnull=True).count() == 1 + assert ( + models.PhoneCall.objects.filter( + caller='0033699999999', callee='102', data=json.dumps(payload['data']), stop__isnull=True + ).count() + == 1 + ) # first call has been closed - assert models.PhoneCall.objects.filter( - caller='0033699999999', - callee='102', - data=json.dumps(payload['data']), stop__isnull=False).count() == 1 + assert ( + models.PhoneCall.objects.filter( + caller='0033699999999', callee='102', data=json.dumps(payload['data']), stop__isnull=False + ).count() + == 1 + ) payload['event'] = 'stop' - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post(reverse('phone-call-event'), json.dumps(payload), content_type='application/json') assert response.status_code == 200 assert response['content-type'] == 'application/json' assert response.json() == {'err': 0} assert models.PhoneCall.objects.count() == 2 - assert models.PhoneCall.objects.filter( - caller='0033699999999', - callee='102', - data=json.dumps(payload['data']), stop__isnull=False).count() == 2 + assert ( + models.PhoneCall.objects.filter( + caller='0033699999999', callee='102', data=json.dumps(payload['data']), stop__isnull=False + ).count() + == 2 + ) # stop is idempotent - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post(reverse('phone-call-event'), json.dumps(payload), content_type='application/json') assert response.status_code == 200 assert response['content-type'] == 'application/json' assert response.json() == {'err': 0} assert models.PhoneCall.objects.count() == 2 - assert models.PhoneCall.objects.filter( - caller='0033699999999', - callee='102', - data=json.dumps(payload['data']), stop__isnull=False).count() == 2 + assert ( + models.PhoneCall.objects.filter( + caller='0033699999999', callee='102', data=json.dumps(payload['data']), stop__isnull=False + ).count() + == 2 + ) def test_one_call_per_callee(user, client): assert models.PhoneCall.objects.count() == 0 payload = {'event': 'start', 'caller': '0033699999999', 'callee': '102'} - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post(reverse('phone-call-event'), json.dumps(payload), content_type='application/json') assert response.status_code == 200 assert models.PhoneCall.objects.filter(callee='102', stop__isnull=True).count() == 1 # active - assert models.PhoneCall.objects.filter(callee='102', stop__isnull=False).count() == 0 # inactive + assert models.PhoneCall.objects.filter(callee='102', stop__isnull=False).count() == 0 # inactive # new caller, same callee: stops the last call, start a new one payload['caller'] = '00337123456789' - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post(reverse('phone-call-event'), json.dumps(payload), content_type='application/json') assert response.status_code == 200 assert models.PhoneCall.objects.count() == 2 - assert models.PhoneCall.objects.filter( - caller='00337123456789', callee='102', stop__isnull=True).count() == 1 - assert models.PhoneCall.objects.filter( - caller='0033699999999', callee='102', stop__isnull=False).count() == 1 + assert ( + models.PhoneCall.objects.filter(caller='00337123456789', callee='102', stop__isnull=True).count() == 1 + ) + assert ( + models.PhoneCall.objects.filter(caller='0033699999999', callee='102', stop__isnull=False).count() == 1 + ) with override_settings(PHONE_ONE_CALL_PER_CALLEE=False): # accept multiple call: start a new one, don't stop anything payload['caller'] = '00221774261500' - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post( + reverse('phone-call-event'), json.dumps(payload), content_type='application/json' + ) assert response.status_code == 200 assert models.PhoneCall.objects.count() == 3 assert models.PhoneCall.objects.filter(callee='102', stop__isnull=True).count() == 2 assert models.PhoneCall.objects.filter(callee='102', stop__isnull=False).count() == 1 # same caller: stop his last call, add a new one - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post( + reverse('phone-call-event'), json.dumps(payload), content_type='application/json' + ) assert response.status_code == 200 assert models.PhoneCall.objects.count() == 4 assert models.PhoneCall.objects.filter(callee='102', stop__isnull=True).count() == 2 assert models.PhoneCall.objects.filter(callee='102', stop__isnull=False).count() == 2 + def test_current_calls(user, client): # create some calls for number in range(0, 10): @@ -136,10 +145,11 @@ def test_current_calls(user, client): 'callee': '1%02d' % number, 'data': { 'user': 'boby.lapointe', - } + }, } - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post( + reverse('phone-call-event'), json.dumps(payload), content_type='application/json' + ) assert response.status_code == 200 assert response['content-type'] == 'application/json' assert response.json() == {'err': 0} @@ -199,22 +209,20 @@ def test_take_release_line(user, client): payload = { 'callee': '102', } - response = client.post(reverse('phone-take-line'), json.dumps(payload), - content_type='application/json') + response = client.post(reverse('phone-take-line'), json.dumps(payload), content_type='application/json') assert response.status_code == 200 assert response['content-type'] == 'application/json' assert response.json() == {'err': 0} assert models.PhoneLine.objects.count() == 1 - assert models.PhoneLine.objects.filter( - users=user, callee='102').count() == 1 - response = client.post(reverse('phone-release-line'), json.dumps(payload), - content_type='application/json') + assert models.PhoneLine.objects.filter(users=user, callee='102').count() == 1 + response = client.post( + reverse('phone-release-line'), json.dumps(payload), content_type='application/json' + ) assert response.status_code == 200 assert response['content-type'] == 'application/json' assert response.json() == {'err': 0} assert models.PhoneLine.objects.count() == 1 - assert models.PhoneLine.objects.filter( - users=user, callee='102').count() == 0 + assert models.PhoneLine.objects.filter(users=user, callee='102').count() == 0 def test_phone_zone(user, client): @@ -230,15 +238,16 @@ def test_phone_zone(user, client): assert 'You do not have a phoneline configured' not in force_text(response.content) assert '
  • 102' in force_text(response.content) assert 'data-callee="102"' in force_text(response.content) - currents = re.search('
    ' - '(.*?)
    ', force_text(response.content), flags=re.DOTALL) + currents = re.search( + '
    ' '(.*?)
    ', + force_text(response.content), + flags=re.DOTALL, + ) assert currents.group(1).strip() == '' # create a call payload = {'event': 'start', 'caller': '003369999999', 'callee': '102'} - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post(reverse('phone-call-event'), json.dumps(payload), content_type='application/json') assert response.status_code == 200 response = client.get(reverse('phone-zone')) assert response.status_code == 200 @@ -269,8 +278,7 @@ def test_call_expiration(user, client): assert models.PhoneCall.objects.count() == 0 # create a call payload = {'event': 'start', 'caller': '003369999999', 'callee': '102'} - response = client.post(reverse('phone-call-event'), json.dumps(payload), - content_type='application/json') + response = client.post(reverse('phone-call-event'), json.dumps(payload), content_type='application/json') assert response.status_code == 200 assert models.PhoneCall.objects.filter(stop__isnull=True).count() == 1 @@ -284,15 +292,14 @@ def test_call_expiration(user, client): assert len(payload['data']['calls']) == 1 # start call 10 minutes ago - models.PhoneCall.objects.filter(stop__isnull=True).update( - start=now()-timedelta(minutes=10)) + models.PhoneCall.objects.filter(stop__isnull=True).update(start=now() - timedelta(minutes=10)) # get list of calls without expiration response = client.get(reverse('phone-current-calls')) assert response.status_code == 200 payload = response.json() assert payload['err'] == 0 - assert len(payload['data']['calls']) == 1 # still here + assert len(payload['data']['calls']) == 1 # still here # get list of calls with an expiration of 2 minutes (< 10 minutes) with override_settings(PHONE_MAX_CALL_DURATION=2): @@ -300,7 +307,7 @@ def test_call_expiration(user, client): assert response.status_code == 200 payload = response.json() assert payload['err'] == 0 - assert len(payload['data']['calls']) == 0 # call is expired + assert len(payload['data']['calls']) == 0 # call is expired assert models.PhoneCall.objects.filter(stop__isnull=True).count() == 0 # active calls - assert models.PhoneCall.objects.filter(stop__isnull=False).count() == 1 # stopped calls + assert models.PhoneCall.objects.filter(stop__isnull=False).count() == 1 # stopped calls diff --git a/welco/apps.py b/welco/apps.py index d6b79b3..6a6c832 100644 --- a/welco/apps.py +++ b/welco/apps.py @@ -17,6 +17,7 @@ from django.apps import apps from django.conf.urls import include, url + def register_urls(urlpatterns): pre_urls = [] post_urls = [] diff --git a/welco/contacts/forms.py b/welco/contacts/forms.py index a903201..e9d890a 100644 --- a/welco/contacts/forms.py +++ b/welco/contacts/forms.py @@ -24,14 +24,15 @@ DEFAULT_TITLE_CHOICES = ( (pgettext_lazy('title', 'Mr'), pgettext_lazy('title', 'Mr')), ) + class ContactAddForm(forms.Form): - title = forms.CharField(label=_('Title'), - required=False, - widget=forms.Select(choices=DEFAULT_TITLE_CHOICES)) + title = forms.CharField( + label=_('Title'), required=False, widget=forms.Select(choices=DEFAULT_TITLE_CHOICES) + ) first_name = forms.CharField(label=_('First Name'), required=False) - last_name = forms.CharField(label=_('Last Name'), - required=True, - widget=forms.TextInput(attrs={'required': 'required'})) + last_name = forms.CharField( + label=_('Last Name'), required=True, widget=forms.TextInput(attrs={'required': 'required'}) + ) email = forms.CharField(label=_('Email'), required=False) address = forms.CharField(label=_('Address'), required=False) zipcode = forms.CharField(label=_('Zip Code'), required=False) diff --git a/welco/contacts/views.py b/welco/contacts/views.py index 956ae19..331195b 100644 --- a/welco/contacts/views.py +++ b/welco/contacts/views.py @@ -33,6 +33,7 @@ from welco.utils import get_wcs_data, sign_url from .forms import ContactAddForm + class HomeZone(object): def __init__(self, request): self.request = request @@ -49,21 +50,20 @@ class ContactsZone(TemplateView): context = super(ContactsZone, self).get_context_data(**kwargs) context['source_pk'] = self.request.GET.get('source_pk') if 'source_pk' in self.request.GET: - source_class = ContentType.objects.get( - id=self.request.GET['source_type']).model_class() + source_class = ContentType.objects.get(id=self.request.GET['source_type']).model_class() source_object = source_class.objects.get(id=self.request.GET['source_pk']) context['contact_user_id'] = source_object.contact_id return context def post(self, request, *args, **kwargs): if 'user_id' in request.POST: - source_class = ContentType.objects.get( - id=self.request.POST['source_type']).model_class() + source_class = ContentType.objects.get(id=self.request.POST['source_type']).model_class() source_object = source_class.objects.get(id=self.request.POST['source_pk']) source_object.contact_id = request.POST['user_id'] source_object.save() return HttpResponse('ok') + zone = csrf_exempt(ContactsZone.as_view()) @@ -83,8 +83,12 @@ def search_json(request): raise Exception('error %r' % result) for user in result.get('data'): user['title'] = user['user_display_name'] - more = [user.get('user_var_address'), user.get('user_var_phone'), - user.get('user_var_mobile'), user.get('user_var_email')] + more = [ + user.get('user_var_address'), + user.get('user_var_phone'), + user.get('user_var_mobile'), + user.get('user_var_email'), + ] user['more'] = ' / '.join([x for x in more if x]) if user.get('user_roles'): user['roles'] = ' / '.join([r['text'] for r in user['user_roles']]) @@ -109,13 +113,13 @@ class ContactDetailFragmentView(TemplateView): context['user_id'] = user_id if 'source_pk' in self.request.GET: - source_class = ContentType.objects.get( - id=self.request.GET['source_type']).model_class() + source_class = ContentType.objects.get(id=self.request.GET['source_type']).model_class() source_object = source_class.objects.get(id=self.request.GET['source_pk']) context['is_pinned_user'] = bool(source_object.contact_id == user_id) return context + contact_detail_fragment = ContactDetailFragmentView.as_view() @@ -144,9 +148,8 @@ class ContactAdd(FormView): logger = logging.getLogger(__name__) logger.info('POST to authentic (%r)', json.dumps(msg)) authentic_response = requests.post( - signed_url, - data=json.dumps(msg), - headers={'Content-type': 'application/json'}) + signed_url, data=json.dumps(msg), headers={'Content-type': 'application/json'} + ) logger.info('Got authentic response (%r)', authentic_response.text) user_uuid = authentic_response.json().get('uuid') @@ -165,4 +168,5 @@ class ContactAdd(FormView): json.dump(result, response, indent=2) return response + contact_add = csrf_exempt(ContactAdd.as_view()) diff --git a/welco/kb/apps.py b/welco/kb/apps.py index 4aebdc0..e19126d 100644 --- a/welco/kb/apps.py +++ b/welco/kb/apps.py @@ -16,6 +16,7 @@ from django.apps import AppConfig + class KbAppConfig(AppConfig): name = 'welco.kb' diff --git a/welco/kb/forms.py b/welco/kb/forms.py index e185821..9e0feef 100644 --- a/welco/kb/forms.py +++ b/welco/kb/forms.py @@ -19,6 +19,7 @@ from django.utils.text import slugify from .models import Page + class PageForm(forms.ModelForm): class Meta: model = Page diff --git a/welco/kb/migrations/0001_initial.py b/welco/kb/migrations/0001_initial.py index 05b359c..10fdb7b 100644 --- a/welco/kb/migrations/0001_initial.py +++ b/welco/kb/migrations/0001_initial.py @@ -7,14 +7,16 @@ import ckeditor.fields class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( name='Page', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + 'id', + models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True), + ), ('title', models.CharField(max_length=200, verbose_name='Title')), ('slug', models.SlugField(verbose_name='Slug')), ('content', ckeditor.fields.RichTextField(verbose_name='Text')), diff --git a/welco/kb/migrations/0003_page_tags.py b/welco/kb/migrations/0003_page_tags.py index d91559d..0f76b13 100644 --- a/welco/kb/migrations/0003_page_tags.py +++ b/welco/kb/migrations/0003_page_tags.py @@ -16,7 +16,13 @@ class Migration(migrations.Migration): migrations.AddField( model_name='page', name='tags', - field=taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', blank=True, help_text='A comma-separated list of tags.', verbose_name='Keywords'), + field=taggit.managers.TaggableManager( + to='taggit.Tag', + through='taggit.TaggedItem', + blank=True, + help_text='A comma-separated list of tags.', + verbose_name='Keywords', + ), preserve_default=True, ), ] diff --git a/welco/kb/models.py b/welco/kb/models.py index 1e3b817..7c40dfa 100644 --- a/welco/kb/models.py +++ b/welco/kb/models.py @@ -26,8 +26,7 @@ class Page(models.Model): title = models.CharField(_('Title'), max_length=200) slug = models.SlugField(_('Slug')) content = RichTextField(_('Text')) - tags = TaggableManager(_('Keywords'), blank=True, - help_text=_('A comma-separated list of tags.')) + tags = TaggableManager(_('Keywords'), blank=True, help_text=_('A comma-separated list of tags.')) class Meta: ordering = ['title'] diff --git a/welco/kb/search_indexes.py b/welco/kb/search_indexes.py index f4f388b..ec24f70 100644 --- a/welco/kb/search_indexes.py +++ b/welco/kb/search_indexes.py @@ -21,6 +21,7 @@ from haystack import indexes from .models import Page + class PageIndex(indexes.SearchIndex, indexes.Indexable): title = indexes.CharField(model_attr='title', boost=3) text = indexes.CharField(document=True) diff --git a/welco/kb/views.py b/welco/kb/views.py index b2010d2..64366c4 100644 --- a/welco/kb/views.py +++ b/welco/kb/views.py @@ -25,8 +25,7 @@ from django.db.models import Count from django.http import HttpResponse, HttpResponseRedirect from django.template import RequestContext from django.views.decorators.csrf import csrf_exempt -from django.views.generic import (DetailView, CreateView, UpdateView, - ListView, DeleteView, TemplateView) +from django.views.generic import DetailView, CreateView, UpdateView, ListView, DeleteView, TemplateView from haystack.forms import SearchForm from haystack.generic_views import SearchView @@ -36,15 +35,17 @@ from taggit.models import Tag from .models import Page from .forms import PageForm + def check_user_perms(user, access=False): allowed_roles = settings.KB_MANAGE_ROLES[:] if access: allowed_roles.extend(settings.KB_ACCESS_ROLES) if settings.KB_ROLE: - allowed_roles.append(settings.KB_ROLE) # legacy + allowed_roles.append(settings.KB_ROLE) # legacy user_groups = set([x.name for x in user.groups.all()]) return user_groups.intersection(allowed_roles) + def check_request_perms(request, access=False): if not check_user_perms(request.user, access=access): raise PermissionDenied() @@ -63,6 +64,7 @@ class PageListView(ListView): context['can_manage'] = check_user_perms(self.request.user) return context + page_list = login_required(PageListView.as_view()) @@ -74,6 +76,7 @@ class PageAddView(CreateView): check_request_perms(request) return super(PageAddView, self).dispatch(request, *args, **kwargs) + page_add = login_required(PageAddView.as_view()) @@ -85,6 +88,7 @@ class PageEditView(UpdateView): check_request_perms(request) return super(PageEditView, self).dispatch(request, *args, **kwargs) + page_edit = login_required(PageEditView.as_view()) @@ -108,6 +112,7 @@ class PageDetailFragmentView(DetailView): model = Page template_name = 'kb/page_detail_fragment.html' + page_detail_fragment = PageDetailFragmentView.as_view() @@ -119,6 +124,7 @@ class PageDeleteView(DeleteView): check_request_perms(request) return super(PageDeleteView, self).dispatch(request, *args, **kwargs) + page_delete = login_required(PageDeleteView.as_view()) @@ -130,6 +136,7 @@ class PageSearchView(SearchView): check_request_perms(request, access=True) return super(PageSearchView, self).dispatch(request, *args, **kwargs) + page_search = login_required(PageSearchView.as_view()) @@ -140,8 +147,9 @@ class KbZone(TemplateView): context = super(KbZone, self).get_context_data(**kwargs) context['source_pk'] = self.request.GET.get('source_pk') context['form'] = SearchForm() - context['tags'] = Tag.objects.all().annotate( - num_times=Count('taggit_taggeditem_items')).filter(num_times__gt=0) + context['tags'] = ( + Tag.objects.all().annotate(num_times=Count('taggit_taggeditem_items')).filter(num_times__gt=0) + ) num_times = context['tags'].values_list('num_times', flat=True) if not num_times: num_times = [0] @@ -163,6 +171,7 @@ class KbZone(TemplateView): tag.font_size = 'x-large' return context + zone = csrf_exempt(KbZone.as_view()) diff --git a/welco/monkeypatch.py b/welco/monkeypatch.py index bf80fa0..63116a0 100644 --- a/welco/monkeypatch.py +++ b/welco/monkeypatch.py @@ -24,6 +24,7 @@ from django.utils.translation import get_language import ckeditor.widgets + def ckeditor_render(self, name, value, attrs=None): if value is None: value = '' @@ -40,14 +41,22 @@ def ckeditor_render(self, name, value, attrs=None): self.config['language'] = get_language() # Force to text to evaluate possible lazy objects - external_plugin_resources = [[force_text(a), force_text(b), force_text(c)] for a, b, c in self.external_plugin_resources] + external_plugin_resources = [ + [force_text(a), force_text(b), force_text(c)] for a, b, c in self.external_plugin_resources + ] + + return mark_safe( + render_to_string( + 'ckeditor/widget.html', + { + 'final_attrs': flatatt(final_attrs), + 'value': conditional_escape(force_text(value)), + 'id': final_attrs['id'], + 'config': ckeditor.widgets.json_encode(self.config), + 'external_plugin_resources': ckeditor.widgets.json_encode(external_plugin_resources), + }, + ) + ) - return mark_safe(render_to_string('ckeditor/widget.html', { - 'final_attrs': flatatt(final_attrs), - 'value': conditional_escape(force_text(value)), - 'id': final_attrs['id'], - 'config': ckeditor.widgets.json_encode(self.config), - 'external_plugin_resources' : ckeditor.widgets.json_encode(external_plugin_resources) - })) ckeditor.widgets.CKEditorWidget.render = ckeditor_render diff --git a/welco/qualif/migrations/0001_initial.py b/welco/qualif/migrations/0001_initial.py index 0606fdd..61c9943 100644 --- a/welco/qualif/migrations/0001_initial.py +++ b/welco/qualif/migrations/0001_initial.py @@ -14,31 +14,37 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Association', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + 'id', + models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True), + ), ('source_pk', models.PositiveIntegerField()), ], - options={ - }, + options={}, bases=(models.Model,), ), migrations.CreateModel( name='FormdataReference', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + 'id', + models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True), + ), ('reference', models.CharField(max_length=250)), ], - options={ - }, + options={}, bases=(models.Model,), ), migrations.CreateModel( name='FormdefReference', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + 'id', + models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True), + ), ('reference', models.CharField(max_length=250)), ], - options={ - }, + options={}, bases=(models.Model,), ), migrations.AddField( diff --git a/welco/qualif/models.py b/welco/qualif/models.py index 8f092ad..6eaa6b5 100644 --- a/welco/qualif/models.py +++ b/welco/qualif/models.py @@ -38,10 +38,12 @@ class Association(models.Model): if self.source.contact_id: context['user_id'] = self.source.contact_id context['summary_url'] = request.build_absolute_uri( - reverse('wcs-summary', kwargs={'source_type': self.source_type_id, - 'source_pk': self.source_pk})) + reverse('wcs-summary', kwargs={'source_type': self.source_type_id, 'source_pk': self.source_pk}) + ) context.update(self.source.get_source_context(request)) - self.formdata_id, self.formdata_url_backoffice = push_wcs_formdata(request, self.formdef_reference, context) + self.formdata_id, self.formdata_url_backoffice = push_wcs_formdata( + request, self.formdef_reference, context + ) self.save() @property diff --git a/welco/settings.py b/welco/settings.py index 03f93d1..9bc97ff 100644 --- a/welco/settings.py +++ b/welco/settings.py @@ -90,7 +90,7 @@ USE_L10N = True USE_TZ = True -LOCALE_PATHS = (os.path.join(BASE_DIR, 'welco', 'locale'), ) +LOCALE_PATHS = (os.path.join(BASE_DIR, 'welco', 'locale'),) # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/1.7/howto/static-files/ @@ -99,9 +99,7 @@ STATIC_URL = '/static/' STATICFILES_FINDERS = tuple(global_settings.STATICFILES_FINDERS) + ('gadjo.finders.XStaticFinder',) -STATICFILES_DIRS = ( - os.path.join(BASE_DIR, 'welco', 'static'), -) +STATICFILES_DIRS = (os.path.join(BASE_DIR, 'welco', 'static'),) MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/' @@ -131,12 +129,18 @@ CKEDITOR_UPLOAD_PATH = 'uploads/' CKEDITOR_CONFIGS = { 'default': { - 'toolbar_Own': [['Source', 'Format', '-', 'Bold', 'Italic'], - ['NumberedList', 'BulletedList'], - ['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'], - ['Link', 'Unlink'], - ['Image',], - ['RemoveFormat',]], + 'toolbar_Own': [ + ['Source', 'Format', '-', 'Bold', 'Italic'], + ['NumberedList', 'BulletedList'], + ['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'], + ['Link', 'Unlink'], + [ + 'Image', + ], + [ + 'RemoveFormat', + ], + ], 'toolbar': 'Own', }, } @@ -190,7 +194,7 @@ CHANNEL_ROLES = { } # role allowed to manage knowledge base -KB_ROLE = None # deprecated +KB_ROLE = None # deprecated KB_MANAGE_ROLES = [] # roles allowed to visit knowledge base @@ -200,9 +204,7 @@ KB_ACCESS_ROLES = [] SCREEN_PANELS = ['contacts', 'qualif'] # useful links for counter -COUNTER_LINKS = [ - {'label': 'Wikipedia', 'url': 'https://fr.wikipedia.org'} -] +COUNTER_LINKS = [{'label': 'Wikipedia', 'url': 'https://fr.wikipedia.org'}] # phone system PHONE_ONE_CALL_PER_CALLEE = True @@ -214,7 +216,8 @@ PHONE_AUTOTAKE_MELLON_USERNAME = False REST_FRAMEWORK = {} REST_FRAMEWORK['DEFAULT_AUTHENTICATION_CLASSES'] = ['rest_framework.authentication.BasicAuthentication'] -local_settings_file = os.environ.get('WELCO_SETTINGS_FILE', - os.path.join(os.path.dirname(__file__), 'local_settings.py')) +local_settings_file = os.environ.get( + 'WELCO_SETTINGS_FILE', os.path.join(os.path.dirname(__file__), 'local_settings.py') +) if os.path.exists(local_settings_file): exec(open(local_settings_file).read()) diff --git a/welco/sources/counter/migrations/0001_initial.py b/welco/sources/counter/migrations/0001_initial.py index 286755e..d154133 100644 --- a/welco/sources/counter/migrations/0001_initial.py +++ b/welco/sources/counter/migrations/0001_initial.py @@ -6,14 +6,16 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( name='CounterPresence', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + 'id', + models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True), + ), ('status', models.CharField(max_length=50, verbose_name='Status', blank=True)), ('contact_id', models.CharField(max_length=50, null=True)), ('creation_timestamp', models.DateTimeField(auto_now_add=True)), diff --git a/welco/sources/counter/models.py b/welco/sources/counter/models.py index 10b956c..5048d1e 100644 --- a/welco/sources/counter/models.py +++ b/welco/sources/counter/models.py @@ -20,16 +20,15 @@ from django.utils.translation import ugettext_lazy as _ from welco.qualif.models import Association -class CounterPresence(models.Model): +class CounterPresence(models.Model): class Meta: verbose_name = _('Counter Presence') # common to all source types: status = models.CharField(_('Status'), blank=True, max_length=50) contact_id = models.CharField(max_length=50, null=True) - associations = GenericRelation(Association, - content_type_field='source_type', object_id_field='source_pk') + associations = GenericRelation(Association, content_type_field='source_type', object_id_field='source_pk') creation_timestamp = models.DateTimeField(auto_now_add=True) last_update_timestamp = models.DateTimeField(auto_now=True) diff --git a/welco/sources/counter/views.py b/welco/sources/counter/views.py index 040ea3d..6138f90 100644 --- a/welco/sources/counter/views.py +++ b/welco/sources/counter/views.py @@ -54,6 +54,7 @@ class CounterZone(TemplateView): context['useful_links'] = settings.COUNTER_LINKS return context + zone = csrf_exempt(CounterZone.as_view()) diff --git a/welco/sources/mail/__init__.py b/welco/sources/mail/__init__.py index 0304d62..5a86f3f 100644 --- a/welco/sources/mail/__init__.py +++ b/welco/sources/mail/__init__.py @@ -22,14 +22,14 @@ class AppConfig(django.apps.AppConfig): def get_before_urls(self): from . import urls + return urls.urlpatterns def ready(self): from welco.qualif.models import Association from django.db.models import signals - signals.post_save.connect(self.association_post_save, - sender=Association) + signals.post_save.connect(self.association_post_save, sender=Association) def association_post_save(self, sender, instance, **kwargs): from .utils import get_maarch @@ -47,6 +47,8 @@ class AppConfig(django.apps.AppConfig): maarch.set_grc_sent_status( mail_pk=maarch_pk, formdata_id=instance.formdata_id, - formdata_url_backoffice=instance.formdata_url_backoffice) + formdata_url_backoffice=instance.formdata_url_backoffice, + ) + default_app_config = 'welco.sources.mail.AppConfig' diff --git a/welco/sources/mail/forms.py b/welco/sources/mail/forms.py index b49e766..fd4136a 100644 --- a/welco/sources/mail/forms.py +++ b/welco/sources/mail/forms.py @@ -18,6 +18,7 @@ from django import forms from django.utils.translation import ugettext_lazy as _ from django.conf import settings + class MailQualificationForm(forms.Form): post_date = forms.DateTimeField(label=_('Post Date (*)'), required=False) registered_mail_number = forms.CharField(label=_('Registered Mail Number'), required=False) diff --git a/welco/sources/mail/maarch.py b/welco/sources/mail/maarch.py index 11283fa..f84f46a 100644 --- a/welco/sources/mail/maarch.py +++ b/welco/sources/mail/maarch.py @@ -125,7 +125,7 @@ class MaarchCourrier(object): read=self.max_retries, connect=self.max_retries, backoff_factor=0.5, - status_forcelist=(500, 502, 504) + status_forcelist=(500, 502, 504), ) adapter = HTTPAdapter(max_retries=retry) s.mount('http://', adapter) @@ -175,13 +175,16 @@ class MaarchCourrier(object): fields = ','.join(fields) if fields else '*' limit = limit or self.default_limit order_by = order_by or [] - response = self.post_json(self.list_url, { - 'select': fields, - 'clause': clause, - 'limit': limit, - 'withFile': include_file, - 'orderBy': order_by, - }) + response = self.post_json( + self.list_url, + { + 'select': fields, + 'clause': clause, + 'limit': limit, + 'withFile': include_file, + 'orderBy': order_by, + }, + ) if not hasattr(response.get('resources'), 'append'): raise MaarchError('missing resources field or bad type', response) return [self.Courrier(self, **resource) for resource in response['resources']] diff --git a/welco/sources/mail/management/commands/feed_mail.py b/welco/sources/mail/management/commands/feed_mail.py index fc36f2f..baef5ea 100644 --- a/welco/sources/mail/management/commands/feed_mail.py +++ b/welco/sources/mail/management/commands/feed_mail.py @@ -22,10 +22,10 @@ from django.core.management.base import BaseCommand, CommandError from ...models import Mail + class Command(BaseCommand): def add_arguments(self, parser): - parser.add_argument( - '--category', metavar='CATEGORY', default=None) + parser.add_argument('--category', metavar='CATEGORY', default=None) parser.add_argument('filenames', metavar='FILENAME', nargs='+') def handle(self, filenames, *args, **kwargs): diff --git a/welco/sources/mail/management/commands/feed_mail_maarch.py b/welco/sources/mail/management/commands/feed_mail_maarch.py index 6166600..88631c3 100644 --- a/welco/sources/mail/management/commands/feed_mail_maarch.py +++ b/welco/sources/mail/management/commands/feed_mail_maarch.py @@ -25,14 +25,15 @@ from django.db import transaction from ...models import Mail from ...utils import get_maarch + class Command(BaseCommand): """Inject mail coming from Maarch into welco. - Only mail with a status "GRC" are injected, - After injection, their status is immediately changed to "GRC_TRT". - After injection in w.c.s., their status is changed to "GRCSENT" and an - id and an URL of the request in w.c.s. is attached to the mail in - Maarch. + Only mail with a status "GRC" are injected, + After injection, their status is immediately changed to "GRC_TRT". + After injection in w.c.s., their status is changed to "GRCSENT" and an + id and an URL of the request in w.c.s. is attached to the mail in + Maarch. """ def handle(self, *args, **kwargs): diff --git a/welco/sources/mail/migrations/0001_initial.py b/welco/sources/mail/migrations/0001_initial.py index b140b74..b6ef78c 100644 --- a/welco/sources/mail/migrations/0001_initial.py +++ b/welco/sources/mail/migrations/0001_initial.py @@ -6,14 +6,16 @@ from django.db import models, migrations class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( name='Mail', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + 'id', + models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True), + ), ('content', models.FileField(upload_to=b'', verbose_name='Content')), ('triaged', models.BooleanField(default=False)), ('creation_timestamp', models.DateTimeField(auto_now_add=True)), diff --git a/welco/sources/mail/migrations/0011_mail_reference.py b/welco/sources/mail/migrations/0011_mail_reference.py index 96347aa..a1af01e 100644 --- a/welco/sources/mail/migrations/0011_mail_reference.py +++ b/welco/sources/mail/migrations/0011_mail_reference.py @@ -18,7 +18,6 @@ class Migration(migrations.Migration): ), migrations.AlterModelOptions( name='mail', - options={'ordering': ['post_date', 'creation_timestamp'], - 'verbose_name': 'Mail'}, + options={'ordering': ['post_date', 'creation_timestamp'], 'verbose_name': 'Mail'}, ), ] diff --git a/welco/sources/mail/models.py b/welco/sources/mail/models.py index da62f9c..365847e 100644 --- a/welco/sources/mail/models.py +++ b/welco/sources/mail/models.py @@ -32,15 +32,13 @@ from welco.utils import get_wcs_data class Mail(models.Model): - class Meta: verbose_name = _('Mail') ordering = ['post_date', 'creation_timestamp'] content = models.FileField(_('Content')) post_date = models.DateField(_('Post Date'), null=True) - registered_mail_number = models.CharField(_('Registered Mail Number'), - null=True, max_length=50) + registered_mail_number = models.CharField(_('Registered Mail Number'), null=True, max_length=50) note = models.TextField(_('Note'), null=True) external_id = models.CharField(_('External Id'), null=True, max_length=32) @@ -52,8 +50,7 @@ class Mail(models.Model): # common to all source types: status = models.CharField(_('Status'), blank=True, max_length=50) contact_id = models.CharField(max_length=50, null=True) - associations = GenericRelation(Association, - content_type_field='source_type', object_id_field='source_pk') + associations = GenericRelation(Association, content_type_field='source_type', object_id_field='source_pk') creation_timestamp = models.DateTimeField(auto_now_add=True) last_update_timestamp = models.DateTimeField(auto_now=True) @@ -61,6 +58,7 @@ class Mail(models.Model): @classmethod def get_qualification_form_class(cls): from .forms import MailQualificationForm + return MailQualificationForm def get_qualification_form(self): @@ -111,5 +109,13 @@ class Mail(models.Model): def create_thumbnail(sender, instance, created, **kwargs): if not created: return - subprocess.call(['gm', 'convert', '-geometry', '200x', - instance.content.file.name, instance.content.file.name + '.png']) + subprocess.call( + [ + 'gm', + 'convert', + '-geometry', + '200x', + instance.content.file.name, + instance.content.file.name + '.png', + ] + ) diff --git a/welco/sources/mail/urls.py b/welco/sources/mail/urls.py index 272c250..5df4848 100644 --- a/welco/sources/mail/urls.py +++ b/welco/sources/mail/urls.py @@ -16,8 +16,7 @@ from django.conf.urls import url -from .views import (viewer, feeder, qualification_save, edit_note, note, - reject, mail_count, mail_response) +from .views import viewer, feeder, qualification_save, edit_note, note, reject, mail_count, mail_response urlpatterns = [ url('viewer/$', viewer, name='mail-viewer'), diff --git a/welco/sources/mail/utils.py b/welco/sources/mail/utils.py index 953e73a..2d9b1a0 100644 --- a/welco/sources/mail/utils.py +++ b/welco/sources/mail/utils.py @@ -20,9 +20,18 @@ from .maarch import MaarchCourrier, MaarchError class WelcoMaarchCourrier(MaarchCourrier): - def __init__(self, url, username, password, grc_status, - grc_received_status, grc_send_status, grc_refused_status, - grc_response_status, batch_size=10): + def __init__( + self, + url, + username, + password, + grc_status, + grc_received_status, + grc_send_status, + grc_refused_status, + grc_response_status, + batch_size=10, + ): super(WelcoMaarchCourrier, self).__init__(url, username, password) self.grc_status = grc_status self.grc_received_status = grc_received_status @@ -36,7 +45,8 @@ class WelcoMaarchCourrier(MaarchCourrier): clause="status='%s'" % self.grc_status, include_file=True, order_by=['res_id'], - limit=self.batch_size) + limit=self.batch_size, + ) def get_mail(self, mail_id): return self.get_courriers(clause="res_id=%s" % mail_id)[0] @@ -74,5 +84,5 @@ def get_maarch(): grc_received_status=config.get('STATUS_RECEIVED', 'GRC_TRT'), grc_send_status=config.get('STATUS_SEND', 'GRCSENT'), grc_refused_status=config.get('STATUS_REFUSED', 'GRCREFUSED'), - grc_response_status=config.get('STATUS_RESPONSE', 'GRC_RESPONSE')) - + grc_response_status=config.get('STATUS_RESPONSE', 'GRC_RESPONSE'), + ) diff --git a/welco/sources/mail/views.py b/welco/sources/mail/views.py index 67e2e2a..64979a3 100644 --- a/welco/sources/mail/views.py +++ b/welco/sources/mail/views.py @@ -42,11 +42,11 @@ from .utils import get_maarch, MaarchError logger = logging.getLogger(__name__) + def viewer(request, *args, **kwargs): if not 'file' in request.GET: return HttpResponseRedirect('?file=') - body = template.loader.get_template('welco/mail_viewer.html').render( - request=request) + body = template.loader.get_template('welco/mail_viewer.html').render(request=request) return HttpResponse(body) @@ -57,12 +57,13 @@ class Feeder(TemplateView): for upload in request.FILES.getlist('mail'): mail = Mail(content=upload) mail.save() - messages.info(request, _('%d files uploaded successfully.') % - len(request.FILES.getlist('mail'))) + messages.info(request, _('%d files uploaded successfully.') % len(request.FILES.getlist('mail'))) return HttpResponseRedirect(reverse('mail-feeder')) + feeder = login_required(csrf_exempt(Feeder.as_view())) + class Home(object): source_key = 'mail' display_filter = True @@ -101,9 +102,10 @@ def qualification_save(request, *args, **kwargs): mail.reference = form.cleaned_data['reference'] mail.subject = form.cleaned_data['subject'] mail.save() - return HttpResponseRedirect(reverse('qualif-zone') + - '?source_type=%s&source_pk=%s' % (request.POST['source_type'], - request.POST['source_pk'])) + return HttpResponseRedirect( + reverse('qualif-zone') + + '?source_type=%s&source_pk=%s' % (request.POST['source_type'], request.POST['source_pk']) + ) class EditNote(TemplateView): @@ -120,6 +122,7 @@ class EditNote(TemplateView): mail.save() return HttpResponse(json.dumps({'result': 'ok'})) + edit_note = login_required(csrf_exempt(EditNote.as_view())) @@ -192,4 +195,5 @@ class MailResponseAPIView(GenericAPIView): return Response({'err': 1, 'err_desc': str(e)}) return Response({'err': 0}) + mail_response = MailResponseAPIView.as_view() diff --git a/welco/sources/phone/migrations/0001_initial.py b/welco/sources/phone/migrations/0001_initial.py index c64f164..6072cd7 100644 --- a/welco/sources/phone/migrations/0001_initial.py +++ b/welco/sources/phone/migrations/0001_initial.py @@ -6,14 +6,16 @@ from django.db import migrations, models class Migration(migrations.Migration): - dependencies = [ - ] + dependencies = [] operations = [ migrations.CreateModel( name='PhoneCall', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + 'id', + models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True), + ), ('number', models.CharField(max_length=20, verbose_name='Number')), ('creation_timestamp', models.DateTimeField(auto_now_add=True)), ('last_update_timestamp', models.DateTimeField(auto_now=True)), diff --git a/welco/sources/phone/migrations/0002_auto_20151028_1635.py b/welco/sources/phone/migrations/0002_auto_20151028_1635.py index 332b4e3..4c1dd3d 100644 --- a/welco/sources/phone/migrations/0002_auto_20151028_1635.py +++ b/welco/sources/phone/migrations/0002_auto_20151028_1635.py @@ -19,7 +19,10 @@ class Migration(migrations.Migration): migrations.CreateModel( name='PhoneLine', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ( + 'id', + models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True), + ), ('callee', models.CharField(unique=True, max_length=20, verbose_name='Callee')), ('users', models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name='User')), ], diff --git a/welco/sources/phone/models.py b/welco/sources/phone/models.py index 387bc20..7d152cd 100644 --- a/welco/sources/phone/models.py +++ b/welco/sources/phone/models.py @@ -25,8 +25,8 @@ from django.utils.timezone import now, timedelta from welco.qualif.models import Association -class PhoneCall(models.Model): +class PhoneCall(models.Model): class Meta: verbose_name = _('Phone Call') @@ -39,8 +39,7 @@ class PhoneCall(models.Model): # common to all source types: status = models.CharField(_('Status'), blank=True, max_length=50) contact_id = models.CharField(max_length=50, null=True) - associations = GenericRelation(Association, - content_type_field='source_type', object_id_field='source_pk') + associations = GenericRelation(Association, content_type_field='source_type', object_id_field='source_pk') creation_timestamp = models.DateTimeField(auto_now_add=True) last_update_timestamp = models.DateTimeField(auto_now=True) @@ -61,14 +60,13 @@ class PhoneCall(models.Model): if settings.PHONE_MAX_CALL_DURATION: logger = logging.getLogger(__name__) start_after = now() - timedelta(minutes=settings.PHONE_MAX_CALL_DURATION) - for call in cls.objects.filter(callee__in=PhoneLine.get_callees(user), - stop__isnull=True, - start__lt=start_after): + for call in cls.objects.filter( + callee__in=PhoneLine.get_callees(user), stop__isnull=True, start__lt=start_after + ): logger.info('stop expired call from %s to %s', call.caller, call.callee) call.stop = now() call.save() - return cls.objects.filter(callee__in=PhoneLine.get_callees(user), - stop__isnull=True).order_by('start') + return cls.objects.filter(callee__in=PhoneLine.get_callees(user), stop__isnull=True).order_by('start') @classmethod def get_all_callees(cls): @@ -80,15 +78,15 @@ class PhoneCall(models.Model): } def previous_calls(self): - return PhoneCall.objects.filter(caller=self.caller).exclude( - id=self.id).order_by('-start')[:5] + return PhoneCall.objects.filter(caller=self.caller).exclude(id=self.id).order_by('-start')[:5] @property def duration(self): if not self.stop: return 'n.a.' seconds = (self.stop - self.start).seconds - return '%02d:%02d' % (seconds//60, seconds%60) + return '%02d:%02d' % (seconds // 60, seconds % 60) + class PhoneLine(models.Model): callee = models.CharField(_('Callee'), unique=True, max_length=80) diff --git a/welco/sources/phone/views.py b/welco/sources/phone/views.py index 9093273..dc50404 100644 --- a/welco/sources/phone/views.py +++ b/welco/sources/phone/views.py @@ -57,7 +57,7 @@ class PhoneZone(TemplateView): username = self.request.session.get('mellon_session', {}).get('username') if username: # user is from SSO, username is a phone line (callee), create a link to it - username = username[0].split('@', 1)[0][:80] # remove realm + username = username[0].split('@', 1)[0][:80] # remove realm if username: PhoneLine.take(callee=username, user=self.request.user) context = super(PhoneZone, self).get_context_data(**kwargs) @@ -66,50 +66,51 @@ class PhoneZone(TemplateView): context['phonecalls'] = PhoneCall.get_current_calls(self.request.user) return context -zone = csrf_exempt(PhoneZone.as_view()) +zone = csrf_exempt(PhoneZone.as_view()) @csrf_exempt def call_event(request): - '''Log a new call start or stop, input is JSON: + """Log a new call start or stop, input is JSON: - { - 'event': 'start' or 'stop', - 'caller': '003399999999', - 'callee': '102', - 'data': { - 'user': 'zozo', - }, - } - ''' + { + 'event': 'start' or 'stop', + 'caller': '003399999999', + 'callee': '102', + 'data': { + 'user': 'zozo', + }, + } + """ logger = logging.getLogger(__name__) try: payload = json.loads(force_text(request.body)) assert isinstance(payload, dict), 'payload is not a JSON object' - assert set(payload.keys()) <= set(['event', 'caller', 'callee', 'data']), \ - 'payload keys must be "event", "caller", "callee" and optionnaly "data"' - assert set(['event', 'caller', 'callee']) <= set(payload.keys()), \ - 'payload keys must be "event", "caller", "callee" and optionnaly "data"' + assert set(payload.keys()) <= set( + ['event', 'caller', 'callee', 'data'] + ), 'payload keys must be "event", "caller", "callee" and optionnaly "data"' + assert set(['event', 'caller', 'callee']) <= set( + payload.keys() + ), 'payload keys must be "event", "caller", "callee" and optionnaly "data"' assert payload['event'] in ('start', 'stop'), 'event must be "start" or "stop"' assert isinstance(payload['caller'], six.string_types), 'caller must be a string' assert isinstance(payload['callee'], six.string_types), 'callee must be a string' if 'data' in payload: assert isinstance(payload['data'], dict), 'data must be a JSON object' except (TypeError, ValueError, AssertionError) as e: - return HttpResponseBadRequest(json.dumps({'err': 1, 'msg': - force_text(e)}), - content_type='application/json') + return HttpResponseBadRequest( + json.dumps({'err': 1, 'msg': force_text(e)}), content_type='application/json' + ) # janitoring: stop active calls to the callee if settings.PHONE_ONE_CALL_PER_CALLEE: logger.info('stop all calls to %s', payload['callee']) - PhoneCall.objects.filter(callee=payload['callee'], - stop__isnull=True).update(stop=now()) + PhoneCall.objects.filter(callee=payload['callee'], stop__isnull=True).update(stop=now()) else: logger.info('stop call from %s to %s', payload['caller'], payload['callee']) - PhoneCall.objects.filter(caller=payload['caller'], - callee=payload['callee'], - stop__isnull=True).update(stop=now()) + PhoneCall.objects.filter( + caller=payload['caller'], callee=payload['callee'], stop__isnull=True + ).update(stop=now()) if payload['event'] == 'start': # start a new call kwargs = { @@ -129,40 +130,39 @@ def active_call(request, *args, **kwargs): result = { 'caller': call.caller, 'callee': call.callee, - 'active': not(bool(call.stop)), + 'active': not (bool(call.stop)), 'start_timestamp': call.start.strftime('%Y-%m-%dT%H:%M:%S'), - } - return HttpResponse(json.dumps(result, indent=2), - content_type='application/json') + } + return HttpResponse(json.dumps(result, indent=2), content_type='application/json') @login_required def current_calls(request): - '''Returns the list of current calls for current user as JSON: + """Returns the list of current calls for current user as JSON: - { - 'err': 0, - 'data': { - 'calls': [ - { - 'caller': '00334545445', - 'callee': '102', - 'data': { ... }, - }, - ... - ], - 'lines': [ - '102', - ], - 'all-lines': [ - '102', - ], - } - } + { + 'err': 0, + 'data': { + 'calls': [ + { + 'caller': '00334545445', + 'callee': '102', + 'data': { ... }, + }, + ... + ], + 'lines': [ + '102', + ], + 'all-lines': [ + '102', + ], + } + } - lines are number the user is currently watching, all-lines is all - registered numbers. - ''' + lines are number the user is currently watching, all-lines is all + registered numbers. + """ all_callees = PhoneCall.get_all_callees() callees = PhoneLine.get_callees(request.user) phonecalls = PhoneCall.get_current_calls(request.user) @@ -177,11 +177,13 @@ def current_calls(request): }, } for call in phonecalls: - calls.append({ - 'caller': call.caller, - 'callee': call.callee, - 'start': call.start.isoformat('T').split('.')[0], - }) + calls.append( + { + 'caller': call.caller, + 'callee': call.callee, + 'start': call.start.isoformat('T').split('.')[0], + } + ) if call.data: calls[-1]['data'] = json.loads(call.data) response = HttpResponse(content_type='application/json') @@ -192,19 +194,19 @@ def current_calls(request): @csrf_exempt @login_required def take_line(request): - '''Take a line, input is JSON: + """Take a line, input is JSON: - { 'callee': '003369999999' } - ''' + { 'callee': '003369999999' } + """ logger = logging.getLogger(__name__) try: payload = json.loads(force_text(request.body)) assert isinstance(payload, dict), 'payload is not a JSON object' assert list(payload.keys()) == ['callee'], 'payload must have only one key: callee' except (TypeError, ValueError, AssertionError) as e: - return HttpResponseBadRequest(json.dumps({'err': 1, 'msg': - force_text(e)}), - content_type='application/json') + return HttpResponseBadRequest( + json.dumps({'err': 1, 'msg': force_text(e)}), content_type='application/json' + ) PhoneLine.take(payload['callee'], request.user) logger.info(u'user %s took line %s', request.user, payload['callee']) return HttpResponse(json.dumps({'err': 0}), content_type='application/json') @@ -213,19 +215,19 @@ def take_line(request): @csrf_exempt @login_required def release_line(request): - '''Release a line, input is JSON: + """Release a line, input is JSON: - { 'callee': '003369999999' } - ''' + { 'callee': '003369999999' } + """ logger = logging.getLogger(__name__) try: payload = json.loads(force_text(request.body)) assert isinstance(payload, dict), 'payload is not a JSON object' assert list(payload.keys()) == ['callee'], 'payload must have only one key: callee' except (TypeError, ValueError, AssertionError) as e: - return HttpResponseBadRequest(json.dumps({'err': 1, 'msg': - force_text(e)}), - content_type='application/json') + return HttpResponseBadRequest( + json.dumps({'err': 1, 'msg': force_text(e)}), content_type='application/json' + ) PhoneLine.release(payload['callee'], request.user) logger.info(u'user %s released line %s', request.user, payload['callee']) return HttpResponse(json.dumps({'err': 0}), content_type='application/json') diff --git a/welco/urls.py b/welco/urls.py index 0ea3085..fc9fc5b 100644 --- a/welco/urls.py +++ b/welco/urls.py @@ -39,11 +39,12 @@ urlpatterns = [ url(r'^', include('welco.sources.phone.urls')), url(r'^', include('welco.sources.counter.urls')), url(r'^ajax/qualification$', welco.views.qualification, name='qualif-zone'), - url(r'^ajax/remove-association/(?P\w+)$', - welco.views.remove_association, name='ajax-remove-association'), - url(r'^ajax/create-formdata/(?P\w+)$', - welco.views.create_formdata, name='ajax-create-formdata'), - + url( + r'^ajax/remove-association/(?P\w+)$', + welco.views.remove_association, + name='ajax-remove-association', + ), + url(r'^ajax/create-formdata/(?P\w+)$', welco.views.create_formdata, name='ajax-create-formdata'), url(r'^ajax/kb$', welco.kb.views.zone, name='kb-zone'), url(r'^kb/$', welco.kb.views.page_list, name='kb-home'), url(r'^kb/add/$', welco.kb.views.page_add, name='kb-page-add'), @@ -53,23 +54,27 @@ urlpatterns = [ url(r'^ajax/kb/(?P[\w-]+)/$', welco.kb.views.page_detail_fragment, name='kb-page-fragment'), url(r'^kb/(?P[\w-]+)/edit$', welco.kb.views.page_edit, name='kb-page-edit'), url(r'^kb/(?P[\w-]+)/delete$', welco.kb.views.page_delete, name='kb-page-delete'), - url(r'^ajax/contacts$', welco.contacts.views.zone, name='contacts-zone'), url(r'^contacts/search/json/$', welco.contacts.views.search_json, name='contacts-search-json'), - url(r'^ajax/contacts/(?P[\w-]+)/$', - welco.contacts.views.contact_detail_fragment, name='contact-page-fragment'), + url( + r'^ajax/contacts/(?P[\w-]+)/$', + welco.contacts.views.contact_detail_fragment, + name='contact-page-fragment', + ), url(r'^contacts/add/$', welco.contacts.views.contact_add, name='contacts-add'), - - url(r'^ajax/summary/(?P\w+)/(?P\w+)/$', - welco.views.wcs_summary, name='wcs-summary'), - + url( + r'^ajax/summary/(?P\w+)/(?P\w+)/$', + welco.views.wcs_summary, + name='wcs-summary', + ), url(r'^admin/', admin.site.urls), url(r'^logout/$', welco.views.logout, name='auth_logout'), url(r'^login/$', welco.views.login, name='auth_login'), url(r'^menu.json$', welco.views.menu_json, name='menu_json'), - url(r'^ckeditor/upload/', kb_manager_required(ckeditor_views.upload), name='ckeditor_upload'), - url(r'^ckeditor/browse/', never_cache(kb_manager_required(ckeditor_views.browse)), name='ckeditor_browse'), + url( + r'^ckeditor/browse/', never_cache(kb_manager_required(ckeditor_views.browse)), name='ckeditor_browse' + ), ] if 'mellon' in settings.INSTALLED_APPS: diff --git a/welco/utils.py b/welco/utils.py index ada12d9..b179003 100644 --- a/welco/utils.py +++ b/welco/utils.py @@ -36,6 +36,7 @@ def sign_url(url, key, algo='sha256', timestamp=None, nonce=None): new_query = sign_query(parsed.query, key, algo, timestamp, nonce) return urlparse.urlunparse(parsed[:4] + (new_query,) + parsed[5:]) + def sign_query(query, key, algo='sha256', timestamp=None, nonce=None): if timestamp is None: timestamp = datetime.datetime.utcnow() @@ -45,22 +46,22 @@ def sign_query(query, key, algo='sha256', timestamp=None, nonce=None): new_query = query if new_query: new_query += '&' - new_query += urlencode(( - ('algo', algo), - ('timestamp', timestamp), - ('nonce', nonce))) + new_query += urlencode((('algo', algo), ('timestamp', timestamp), ('nonce', nonce))) signature = base64.b64encode(sign_string(new_query, key, algo=algo)) new_query += '&signature=' + quote(signature) return new_query + def sign_string(s, key, algo='sha256', timedelta=30): digestmod = getattr(hashlib, algo) hash = hmac.HMAC(smart_bytes(key), digestmod=digestmod, msg=smart_bytes(s)) return hash.digest() + def get_wcs_services(): return settings.KNOWN_SERVICES.get('wcs') + def get_wcs_json(wcs_url, path, wcs_site, params={}): if not wcs_url.endswith('/'): wcs_url += '/' @@ -70,13 +71,13 @@ def get_wcs_json(wcs_url, path, wcs_site, params={}): response_json = cache.get(url) if response_json is None: signed_url = sign_url(url, wcs_site.get('secret')) - response_json = requests.get(signed_url, headers={'accept': 'application/json'}, - timeout=10).json() + response_json = requests.get(signed_url, headers={'accept': 'application/json'}, timeout=10).json() if not isinstance(response_json, dict): response_json = {'data': response_json} cache.set(url, response_json) return response_json + def get_wcs_options(url, condition=None, params={}): categories = {} for wcs_key, wcs_site in get_wcs_services().items(): @@ -103,6 +104,7 @@ def get_wcs_options(url, condition=None, params={}): options.append((category, sorted(categories[category], key=lambda x: x[1]))) return options + def get_wcs_formdef_details(formdef_reference): wcs_key, form_slug = formdef_reference.split(':') wcs_site = get_wcs_services()[wcs_key] @@ -113,6 +115,7 @@ def get_wcs_formdef_details(formdef_reference): return form return None + def push_wcs_formdata(request, formdef_reference, context=None): wcs_key, form_slug = formdef_reference.split(':') wcs_site = get_wcs_services()[wcs_key] @@ -121,7 +124,7 @@ def push_wcs_formdata(request, formdef_reference, context=None): wcs_site_url += '/' url = wcs_site_url + 'api/formdefs/%s/schema' % form_slug response = requests.get(url) - create_draft = not(bool('welco-direct' in (response.json().get('keywords') or ''))) + create_draft = not (bool('welco-direct' in (response.json().get('keywords') or ''))) url = wcs_site_url + 'api/formdefs/%s/submit?' % form_slug data = { @@ -139,8 +142,7 @@ def push_wcs_formdata(request, formdef_reference, context=None): url = sign_url(url, wcs_site.get('secret')) - response = requests.post(url, data=json.dumps(data), - headers={'Content-type': 'application/json'}) + response = requests.post(url, data=json.dumps(data), headers={'Content-type': 'application/json'}) if response.json().get('err') != 0: raise Exception('error %r' % response.content) data = response.json()['data'] @@ -169,6 +171,7 @@ def get_wcs_data(endpoint, params=None): json_response = {'data': json_response} return json_response + def response_for_json(request, data): json_str = json.dumps(data) for variable in ('jsonpCallback', 'callback'): diff --git a/welco/views.py b/welco/views.py index 7fc6f95..0e69fa8 100644 --- a/welco/views.py +++ b/welco/views.py @@ -88,19 +88,22 @@ class Qualification(TemplateView): context['source_pk'] = self.request.GET['source_pk'] if self.request.GET.get('source_pk'): context['associations'] = Association.objects.filter( - source_type=ContentType.objects.get(id=self.request.GET['source_type']), - source_pk=self.request.GET['source_pk']).order_by('id') + source_type=ContentType.objects.get(id=self.request.GET['source_type']), + source_pk=self.request.GET['source_pk'], + ).order_by('id') return context def post(self, request, *args, **kwargs): association = Association( - source_type=ContentType.objects.get(id=request.POST['source_type']), - source_pk=request.POST['source_pk']) + source_type=ContentType.objects.get(id=request.POST['source_type']), + source_pk=request.POST['source_pk'], + ) association.formdef_reference = request.POST['formdef_reference'] association.save() request.GET = request.POST return self.get(request) + qualification = csrf_exempt(Qualification.as_view()) @@ -117,8 +120,7 @@ class ChannelHome(TemplateView): if not self.check_user_ok(): raise PermissionDenied() context = super(ChannelHome, self).get_context_data(**kwargs) - context['panels'] = [ - {'key': x, 'zone_url': x + '-zone'} for x in settings.SCREEN_PANELS] + context['panels'] = [{'key': x, 'zone_url': x + '-zone'} for x in settings.SCREEN_PANELS] context['source'] = self.source_klass(self.request, **kwargs) context['kb'] = KbHomeZone(self.request) context['contacts'] = ContactsHomeZone(self.request) @@ -141,20 +143,25 @@ def home(request): return HttpResponseRedirect('%s/' % channel) raise PermissionDenied() + class HomePhone(ChannelHome): source_klass = PhoneHome + home_phone = login_required(HomePhone.as_view()) class HomeMail(ChannelHome): source_klass = MailHome + home_mail = login_required(HomeMail.as_view()) + class HomeCounter(ChannelHome): source_klass = CounterHome + home_counter = login_required(HomeCounter.as_view()) @@ -174,11 +181,13 @@ def wcs_summary(request, *args, **kwargs): break return HttpResponse(json_str, content_type='application/javascript') + @login_required def remove_association(request, *args, **kwargs): Association.objects.filter(id=kwargs.get('pk')).delete() return HttpResponseRedirect(resolve_url('home')) + @login_required @csrf_exempt def create_formdata(request, *args, **kwargs): @@ -196,6 +205,7 @@ def create_formdata(request, *args, **kwargs): json.dump({'result': 'ok', 'url': qualif.formdata_url}, response) return response + @login_required def menu_json(request): response = HttpResponse(content_type='application/json') @@ -209,17 +219,21 @@ def menu_json(request): for channel in settings.CHANNEL_ROLES: channel_groups = set(settings.CHANNEL_ROLES[channel]) if user_groups.intersection(channel_groups): - menu.append({ - 'label': force_text(labels.get(channel)), - 'slug': channel, - 'url': request.build_absolute_uri(reverse('home-%s' % channel)), - }) + menu.append( + { + 'label': force_text(labels.get(channel)), + 'slug': channel, + 'url': request.build_absolute_uri(reverse('home-%s' % channel)), + } + ) if check_kb_user_perms(request.user, access=True): - menu.append({ - 'label': force_text(_('Knowledge Base')), - 'slug': 'book', - 'url': request.build_absolute_uri(reverse('kb-home')) - }) + menu.append( + { + 'label': force_text(_('Knowledge Base')), + 'slug': 'book', + 'url': request.build_absolute_uri(reverse('kb-home')), + } + ) json_str = json.dumps(menu) for variable in ('jsonpCallback', 'callback'): if variable in request.GET: diff --git a/welco/wsgi.py b/welco/wsgi.py index 59a1867..4498d92 100644 --- a/welco/wsgi.py +++ b/welco/wsgi.py @@ -8,7 +8,9 @@ https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/ """ import os + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "welco.settings") from django.core.wsgi import get_wsgi_application + application = get_wsgi_application()