From 19bca067b20ba623841d48f7dc0eed715635ee0f Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Wed, 14 Aug 2019 13:35:20 -0700 Subject: [PATCH 01/19] PWL-773: Add unit test for API end points in operation. Add unit test cases for metering API end point /meters/ Add unit test cases for apiKey API end point /apiKey/. Add unit test cases for null service API end point /nullservice/. Add unit test cases for ip ranges API end points /ipranges/. Add unit test cases for session logs API end point /session-logs/. Add unit test cases for party API end point /parties/. Add unit test cases for partner API end point /partners/. Add unit test cases for authentication API end point /credentials/. Add unit test cases for authorization API end points /authorizations/. Add unit test cases for subscription API end points /subscriptions/. Add warning message print for all manual test cases and when HOSTNAME is not defined in settings.py. --- apikey/pyTests.py | 39 - apikey/testSamples.py | 16 +- apikey/tests.py | 35 +- authentication/manualTests.py | 37 + authentication/testSamples.py | 108 +++ authentication/tests.py | 236 ++++- authorization/pyTests.py | 235 ----- authorization/testSamples.py | 78 +- authorization/tests.py | 471 +++++++++- authorization/views.py | 2 +- common/permissions.py | 3 +- common/pyTests.py | 138 --- common/testSamples.py | 83 ++ common/tests.py | 229 +++++ ipranges/tests.py | 67 ++ loggingapp/pyTests.py | 103 --- loggingapp/testSamples.py | 41 +- loggingapp/tests.py | 102 ++- metering/pyTests.py | 130 --- metering/testSamples.py | 109 ++- metering/tests.py | 285 +++--- nullservice/manualTests.py | 30 + nullservice/tests.py | 5 +- .../0015_partner_forgotusernametext.py | 5 - partner/pyTests.py | 74 -- partner/testSamples.py | 57 +- partner/tests.py | 87 +- party/manualTests.py | 47 + party/pyTests.py | 69 -- party/testSamples.py | 229 ++++- party/tests.py | 520 ++++++++++- party/views.py | 21 +- paywall2/settings.py.template.prod | 2 + paywall2/settings.py.template.test | 2 + ...PartyCountry.py => runTestPartyCountry.py} | 0 subscription/pyTests.py | 174 ---- ...dualEmail.py => runTestIndividualEmail.py} | 0 subscription/testSamples.py | 124 ++- subscription/tests.py | 841 +++++++++++++++++- subscription/views.py | 4 +- 40 files changed, 3544 insertions(+), 1294 deletions(-) delete mode 100644 apikey/pyTests.py create mode 100644 authentication/manualTests.py create mode 100644 authentication/testSamples.py delete mode 100644 authorization/pyTests.py delete mode 100644 common/pyTests.py create mode 100644 common/tests.py delete mode 100644 loggingapp/pyTests.py delete mode 100644 metering/pyTests.py create mode 100644 nullservice/manualTests.py delete mode 100644 partner/pyTests.py create mode 100644 party/manualTests.py delete mode 100644 party/pyTests.py rename scripts/{testPartyCountry.py => runTestPartyCountry.py} (100%) delete mode 100644 subscription/pyTests.py rename subscription/{testIndividualEmail.py => runTestIndividualEmail.py} (100%) diff --git a/apikey/pyTests.py b/apikey/pyTests.py deleted file mode 100644 index ad43442d..00000000 --- a/apikey/pyTests.py +++ /dev/null @@ -1,39 +0,0 @@ -#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. - -import django -import unittest -import sys, getopt -from unittest import TestCase -import requests -import json -from models import ApiKey -from testSamples import ApiKeySample -from common.pyTests import PyTestGenerics, GenericCRUDTest - -# Create your tests here. -django.setup() -serverUrl = PyTestGenerics.initPyTest() -print "using server url %s" % serverUrl - -# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- - -class ApiKeyCRUD(GenericCRUDTest, TestCase): - sample = ApiKeySample(serverUrl) - - def setUp(self): -# super(ApiKeyCRUD, self).setUp() - ApiKey.objects.filter(apiKey=self.sample.data['apiKey']).delete() - ApiKey.objects.filter(apiKey=self.sample.updateData['apiKey']).delete() - - # overrides parent class teardown. - def tearDown(self): - pass -# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- - -print "Running unit tests on party web services API........." - -if __name__ == '__main__': - sys.argv[1:] = [] - unittest.main() - ret = not runner.run(suite).wasSuccessful() - sys.exit(ret) diff --git a/apikey/testSamples.py b/apikey/testSamples.py index 14270b0b..1079f50a 100644 --- a/apikey/testSamples.py +++ b/apikey/testSamples.py @@ -1,12 +1,10 @@ import django -import unittest -import sys, getopt -from unittest import TestCase +import sys +from django.test import TestCase from models import ApiKey +from common.tests import TestGenericInterfaces -from common.pyTests import PyTestGenerics - -genericForcePost = PyTestGenerics.forcePost +genericForcePost = TestGenericInterfaces.forcePost class ApiKeySample(): path = 'apikeys/' @@ -15,13 +13,13 @@ class ApiKeySample(): 'apiKey':'proxyKey', } updateData = { - 'apiKey':'proxy2Key', + 'apiKey':'proxyKey2', } pkName = 'apiKeyId' model = ApiKey def __init__(self, serverUrl): - self.url = serverUrl+self.path + self.url = serverUrl + self.path - def forcePost(self,data): + def forcePost(self, data): return genericForcePost(self.model, self.pkName, data) diff --git a/apikey/tests.py b/apikey/tests.py index 7ce503c2..2ba88d48 100644 --- a/apikey/tests.py +++ b/apikey/tests.py @@ -1,3 +1,36 @@ +#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. + +import django +import unittest +import sys +import requests +import json from django.test import TestCase +from models import ApiKey +from testSamples import ApiKeySample +from common.tests import TestGenericInterfaces, GenericCRUDTest +# Python 3: module Cookie -> http.cookies +from Cookie import SimpleCookie + +# Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() + +# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- + +class ApiKeyCRUD(GenericCRUDTest, TestCase): + sample = ApiKeySample(serverUrl) + + def test_for_get_all(self): + url = self.getUrl(self.sample.url) + self.getAllHelper(url, 'apiKey', self.apiKey) + +# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- + +print "Running unit tests on API key web services API........." -# Create your tests here. +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) diff --git a/authentication/manualTests.py b/authentication/manualTests.py new file mode 100644 index 00000000..ba46d38a --- /dev/null +++ b/authentication/manualTests.py @@ -0,0 +1,37 @@ +#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. + +import django +import unittest +import sys +import json +from django.test import TestCase, Client +from partner.testSamples import PartnerSample +from party.testSamples import UserPartySample +from common.tests import TestGenericInterfaces, GenericTest +from testSamples import CredentialSample +from tests import CredentialGenericTest +# Python 3: module Cookie -> http.cookies +from Cookie import SimpleCookie + +# Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() + +# test for API endpoint /credentials/resetPwd/ +class ResetPasswordTest(CredentialGenericTest): + + def test_for_reset_password(self): + url = '%scredentials/resetPwd/?user=%s&partnerId=%s' % (serverUrl, self.sample.getUsername(), self.partnerId) + + # the default content type for put is 'application/octet-stream' + # does not test for partyId update + res = self.client.put(url, None, content_type='application/json') + self.assertEqual(res.status_code, 200) + +print "Running unit tests on authentication/credential reset password web services API........." + +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) \ No newline at end of file diff --git a/authentication/testSamples.py b/authentication/testSamples.py new file mode 100644 index 00000000..87c43593 --- /dev/null +++ b/authentication/testSamples.py @@ -0,0 +1,108 @@ +import django +import hashlib +import copy +from authentication.models import Credential +from partner.models import Partner +from party.models import Party +from common.tests import TestGenericInterfaces +from authentication.views import generateSecretKey + +genericForcePost = TestGenericInterfaces.forcePost + +class CredentialSample(): + path = 'credentials/' + loginPath = 'credentials/login/' + serverUrl = None + url = None + USERNAME = 'test_user' + FIRSTNAME = 'Phoenix' + LASTNAME = 'Bioinformatics' + PASSWORD = 'phoenix123' + PASSWORD_UPDATE = 'phoenix456' + EMAIL = 'techteam@arabidopsis.org' + EMAIL_UPDATE = 'techteam@phoenixbioinformatics.org' + INSTITUTION = 'Phoenix Bioinformatics' + USER_IDENTIFIER = 123 + USER_IDENTIFIER_UPDATE = 124 + data = { + 'username': USERNAME, + 'firstName': FIRSTNAME, + 'lastName': LASTNAME, + 'password': PASSWORD, + 'email': EMAIL, + 'institution': INSTITUTION, + 'partyId': None, + 'partnerId': None, + 'userIdentifier': USER_IDENTIFIER + } + updateData = { + 'username': USERNAME + '_update', + 'firstName': FIRSTNAME + '_update', + 'lastName': LASTNAME + '_update', + 'password': PASSWORD_UPDATE, + 'email': EMAIL_UPDATE, + 'institution': INSTITUTION + ' Update', + 'partyId': None, + 'partnerId': None, + 'userIdentifier': USER_IDENTIFIER_UPDATE + } + pkName = 'id' + model = Credential + + def __init__(self, serverUrl): + self.serverUrl = serverUrl + self.url = serverUrl + self.path + self.data = copy.deepcopy(self.data) + + def setAsUpdateExample(self): + for key in self.data: + if self.updateData[key]: + self.data[key] = self.updateData[key] + + def setPartnerId(self, partnerId): + self.data['partnerId'] = partnerId + + def setPartyId(self, partyId): + self.data['partyId'] = partyId + + def getUserIdentifier(self): + return self.data['userIdentifier'] + + def getUsername(self): + return self.data['username'] + + def getEmail(self): + return self.data['email'] + + def getPartyId(self): + return self.data['partyId'] + + # data to submit to POST API to create credential without party + def getDataForCreate(self): + dataForCreate = copy.deepcopy(self.data) + del dataForCreate['partyId'] + dataForCreate['name'] = '%s %s' % (self.data['firstName'], self.data['lastName']) + return dataForCreate + + def forcePost(self,data): + postData = copy.deepcopy(data) + postData['partyId'] = Party.objects.get(partyId=self.data['partyId']) + postData['partnerId'] = Partner.objects.get(partnerId=self.data['partnerId']) + postData['password'] = self.hashPassword(self.data['password']) + return genericForcePost(self.model, self.pkName, postData) + + def hashPassword(self, password): + return hashlib.sha1(password).hexdigest() + + def getLoginUrl(self): + return self.serverUrl + self.loginPath + '?partnerId=%s' % self.data['partnerId'] + + def getLoginData(self): + return { + 'user': self.data['username'], + 'password': self.data['password'] + } + + def getSecretKey(self): + # this has dependency on authentication.views regarding argument + return generateSecretKey(self.data['partyId'], self.hashPassword(self.data['password'])) \ No newline at end of file diff --git a/authentication/tests.py b/authentication/tests.py index 7ce503c2..fb3a5631 100644 --- a/authentication/tests.py +++ b/authentication/tests.py @@ -1,3 +1,235 @@ -from django.test import TestCase +#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. -# Create your tests here. +import django +import unittest +import sys +import json +import copy +# Python 3: library urllib -> urllib.parse +import urllib +from django.test import TestCase, Client +from partner.testSamples import PartnerSample +from party.testSamples import UserPartySample +from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest, ManualTest, checkMatch +from testSamples import CredentialSample +# Python 3: module Cookie -> http.cookies +from Cookie import SimpleCookie + +# Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() + +# test for API endpoint /credentials/ and /credentials/profile/ +# does not extend GenericCRUDTest class since all methods need override +class CredentialCRUDTest(GenericTest, TestCase): + sample = CredentialSample(serverUrl) + partnerId = None + + def setUp(self): + super(CredentialCRUDTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId + + userPartySample = UserPartySample(serverUrl) + partyId = userPartySample.forcePost(userPartySample.data) + self.sample.data['partyId']=self.sample.updateData['partyId']=partyId + + def test_for_create_with_party_id(self): + sample = self.sample + url = sample.url + if self.apiKey: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + + res = self.client.post(url, sample.data) + + self.assertEqual(res.status_code, 201) + # note the returned credential object do not contain credential table primary key "id" + # but always contains party id instead + self.assertIsNotNone(TestGenericInterfaces.forceGet(self.sample.model,'partyId',sample.getPartyId())) + + def test_for_create_without_party_id(self): + sample = self.sample + url = sample.url + if self.apiKey: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + + res = self.client.post(url, sample.getDataForCreate()) + + self.assertEqual(res.status_code, 201) + # note the returned credential object do not contain credential table primary key "id" + # but always contains party id instead + self.assertIsNotNone(TestGenericInterfaces.forceGet(self.sample.model,'partyId',json.loads(res.content)['partyId'])) + + def test_for_get(self): + sample = self.sample + pk = sample.forcePost(sample.data) + partnerId = self.partnerId + + # test get by user identifier + queryByUserIdentifier = 'userIdentifier=%s&partnerId=%s' % (sample.getUserIdentifier(), partnerId) + self.assertGetRequestByQueryParam(queryByUserIdentifier) + + # test get by username + queryByUsername = 'username=%s&partnerId=%s' % (sample.getUsername(), partnerId) + self.assertGetRequestByQueryParam(queryByUsername) + + # test get by partyId + queryByPartyId = 'partyId=%s' % sample.getPartyId() + self.assertGetRequestByQueryParam(queryByPartyId) + + def assertGetRequestByQueryParam(self, queryParam): + url = '%s?%s' % (self.sample.url, queryParam) + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + # remove password from comparison since it is not returned in GET API + data = copy.deepcopy(self.sample.data) + del data['password'] + # note the returned credential object do not contain credential table primary key "id" + # but always contains party id instead + self.assertEqual(checkMatch(data, resObj, 'partyId', self.sample.getPartyId()), True) + + def test_for_update_by_party_id(self): + queryParam = 'partyId=%s' % self.sample.getPartyId() + self.runUpdateTestByQueryParam(queryParam) + + def test_for_update_by_user_identifier(self): + queryParam = 'userIdentifier=%s&partnerId=%s' % (self.sample.getUserIdentifier(), self.partnerId) + self.runUpdateTestByQueryParam(queryParam) + + def test_for_update_by_username(self): + queryParam = 'username=%s&partnerId=%s' % (self.sample.getUsername(), self.partnerId) + self.runUpdateTestByQueryParam(queryParam) + + def runUpdateTestByQueryParam(self, queryParam): + sample = self.sample + sample.forcePost(sample.data) + partnerId = self.partnerId + loginCredential = self.getUserLoginCredential(); + + url = '%s?%s&%s' % (sample.url, loginCredential, queryParam) + + # the default content type for put is 'application/octet-stream' + # does not test for partyId update + res = self.client.put(url, json.dumps(sample.updateData), content_type='application/json') + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + + # hash password for comparison + updateData = {} + for key in sample.updateData: + if key == 'password': + updateData[key] = sample.hashPassword(sample.updateData[key]) + else: + updateData[key] = sample.updateData[key] + # manipulate sample data to match the test condition + self.assertEqual(checkMatch(updateData, resObj, 'partyId', sample.getPartyId()), True) + + # test for API endpoint /credentials/profile/ + # this is smiliar to the UPDATE methods above except that it only accepts + # pratyId as query param and returns status code 201 when succeed + def test_for_update_profile(self): + sample = self.sample + sample.forcePost(sample.data) + partnerId = self.partnerId + loginCredential = self.getUserLoginCredential(); + + url = '%scredentials/profile/?%s&partyId=%s' % (serverUrl, loginCredential, sample.getPartyId()) + # the default content type for put is 'application/octet-stream' + # does not test for partyId update + res = self.client.put(url, json.dumps(sample.updateData), content_type='application/json') + # API should return 200 for an update but returns 201 + self.assertEqual(res.status_code, 201) + resObj = json.loads(res.content) + + # hash password for comparison + updateData = {} + for key in sample.updateData: + if key == 'password': + updateData[key] = sample.hashPassword(sample.updateData[key]) + else: + updateData[key] = sample.updateData[key] + # manipulate sample data to match the test condition + self.assertEqual(checkMatch(updateData, resObj, 'partyId', sample.getPartyId()), True) + + def getUserLoginCredential(self): + sample = self.sample + secretKey = urllib.quote(sample.getSecretKey()) + return 'credentialId=%s&secretKey=%s' % (sample.getPartyId(), secretKey) + +class CredentialGenericTest(TestCase): + sample = CredentialSample(serverUrl) + partnerId = None + + def setUp(self): + super(CredentialGenericTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + self.sample.data['partnerId']=self.partnerId + + userPartySample = UserPartySample(serverUrl) + partyId = userPartySample.forcePost(userPartySample.data) + self.sample.data['partyId']=partyId + + self.sample.forcePost(self.sample.data) + +# test for API endpoint /crendetials/login/ +class CredentialLoginTest(CredentialGenericTest): + + def test_for_login(self): + loginUrl = self.sample.getLoginUrl() + loginData = self.sample.getLoginData() + res = self.client.post(loginUrl, loginData) + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + self.assertIsNotNone(resObj['credentialId']) + self.assertIsNotNone(resObj['secretKey']) + +# test for API endpoint /credentials/getUsernames/ +class GetUsernamesTest(CredentialGenericTest): + + def test_for_get_usernames(self): + url = '%scredentials/getUsernames/?email=%s&partnerId=%s' % (serverUrl, self.sample.getEmail(), self.partnerId) + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + # remove password from comparison since it is not returned + data = copy.deepcopy(self.sample.data) + del data['password'] + # note the returned credential object do not contain credential table primary key "id" + # but always contains party id instead + self.assertEqual(checkMatch(data, resObj, 'partyId', self.sample.getPartyId()), True) + +# test for API endpoint /credentials/checkAccountExists/ +class CheckAccountExistsTest(CredentialGenericTest): + + def test_for_check_account_exists(self): + self.assertGetRequestByType('email', self.sample.getEmail()) + self.assertGetRequestByType('username', self.sample.getUsername()) + + def assertGetRequestByType(self, keyName, value): + url = '%scredentials/checkAccountExists?%s=%s&partnerId=%s' % (serverUrl, keyName, value, self.partnerId) + checkKey = '%sExist' % keyName + + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + # remove password from comparison since it is not returned + self.assertEqual(resObj[checkKey], True) + +# test for API endpoint /credentials/resetPwd/ +# test in manualTests.py +class ResetPasswordTest(ManualTest, TestCase): + path = "/credentials/resetPwd/" + testMethodStr = "running ./manage.py test authentication.manualTests" + +print "Running unit tests on authentication/credential web services API........." + +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) diff --git a/authorization/pyTests.py b/authorization/pyTests.py deleted file mode 100644 index f03c1cb2..00000000 --- a/authorization/pyTests.py +++ /dev/null @@ -1,235 +0,0 @@ -#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. - -import django -import unittest -import sys, getopt -import requests -from unittest import TestCase -from common.pyTests import PyTestGenerics, GenericCRUDTest, GenericTest - -from subscription.testSamples import SubscriptionSample -from party.testSamples import IpRangeSample, PartySample -from partner.testSamples import PartnerSample -from partner.models import Partner -from authorization.models import Status - -from testSamples import UriPatternSample, AccessRuleSample, AccessTypeSample, CredentialSample - -from authentication.views import generateSecretKey - -# Create your tests here. -django.setup() -serverUrl = PyTestGenerics.initPyTest() -print "using server url %s" % serverUrl - - -# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- - -class UriPatternCRUD(GenericCRUDTest, TestCase): - sample = UriPatternSample(serverUrl) - -class AccessRuleCRUD(GenericCRUDTest, TestCase): - sample = AccessRuleSample(serverUrl) - partnerSample = PartnerSample(serverUrl) - patternSample = UriPatternSample(serverUrl) - accessTypeSample = AccessTypeSample(serverUrl) - def setUp(self): - super(AccessRuleCRUD,self).setUp() - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.patternId = self.patternSample.forcePost(self.patternSample.data) - self.accessTypeId = self.accessTypeSample.forcePost(self.accessTypeSample.data) - self.sample.partnerId=self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId - self.sample.data['patternId']=self.sample.updateData['patternId']=self.patternId - self.sample.data['accessTypeId']=self.sample.updateData['accessTypeId']=self.accessTypeId - - def tearDown(self): - super(AccessRuleCRUD,self).tearDown() - PyTestGenerics.forceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - PyTestGenerics.forceDelete(self.patternSample.model, self.patternSample.pkName, self.patternId) - PyTestGenerics.forceDelete(self.accessTypeSample.model, self.accessTypeSample.pkName, self.accessTypeId) - -class AccessTypesCRUD(GenericCRUDTest, TestCase): - sample = AccessTypeSample(serverUrl) - -# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- - - -# Base class for sample management for access, subscription, and authorization access tests. -class AuthorizationTestBase(GenericTest, TestCase): - - # should be consistent with IpRangeSample object - successIp = '120.1.0.0' - failIp = '12.2.3.4' - - # should be consistent with SubscriptionSample object - successSubscriptionData = { - 'startDate':'2012-04-12T00:00:00Z', - 'endDate':'2018-04-12T00:00:00Z', - 'partnerId':None, # To be populated after Partner is created - 'partyId':None, # To be populated after Party is created - } - failSubscriptionData = { - 'startDate':'2012-04-12T00:00:00Z', - 'endDate':'2014-04-12T00:00:00Z', - 'partnerId':None, - 'partyId':None, - } - - def initSamples(self): - self.partnerSample = PartnerSample(serverUrl) - self.partySample = PartySample(serverUrl) - self.subscriptionSample = SubscriptionSample(serverUrl) - self.ipRangeSample = IpRangeSample(serverUrl) - self.uriPatternSample = UriPatternSample(serverUrl) - self.accessTypeSample = AccessTypeSample(serverUrl) - self.accessRuleSample = AccessRuleSample(serverUrl) - self.credentialSample = CredentialSample() - - def createSamples(self): - # create independent objects - self.accessTypeId = self.accessTypeSample.forcePost(self.accessTypeSample.data) - self.uriPatternId = self.uriPatternSample.forcePost(self.uriPatternSample.data) - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.partyId = self.partySample.forcePost(self.partySample.data) - - # create AccessRule based on AccessType, Pattern, and Partner objects created - self.accessRuleSample.data['accessTypeId']=self.accessTypeId - self.accessRuleSample.data['patternId']=self.uriPatternId - self.accessRuleSample.data['partnerId'] = self.partnerId - self.accessRuleId = self.accessRuleSample.forcePost(self.accessRuleSample.data) - - # create Subscription object based on Party and Partner objects created - self.subscriptionSample.data['partyId'] = self.partyId - self.subscriptionSample.data['partnerId'] = self.partnerId - self.subscriptionId = self.subscriptionSample.forcePost(self.subscriptionSample.data) - - # create IpRange object based on data Party created - self.ipRangeSample.data['partyId'] = self.partyId - self.ipRangeId = self.ipRangeSample.forcePost(self.ipRangeSample.data) - - # create Credential object based on Party created - PyTestGenerics.forceDelete(self.credentialSample.model, 'username', self.credentialSample.data['username']) - self.credentialSample.data['partyId'] = self.partyId - self.credentialSample.data['partnerId'] = self.partnerId - self.credentialId = self.credentialSample.forcePost(self.credentialSample.data) - - def deleteSamples(self): - PyTestGenerics.forceDelete(self.subscriptionSample.model, self.subscriptionSample.pkName, self.subscriptionId) - PyTestGenerics.forceDelete(self.ipRangeSample.model, self.ipRangeSample.pkName, self.ipRangeId) - PyTestGenerics.forceDelete(self.partySample.model, self.partySample.pkName, self.partyId) - PyTestGenerics.forceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - PyTestGenerics.forceDelete(self.accessTypeSample.model, self.accessTypeSample.pkName, self.accessTypeId) - PyTestGenerics.forceDelete(self.uriPatternSample.model, self.uriPatternSample.pkName, self.uriPatternId) - PyTestGenerics.forceDelete(self.accessRuleSample.model, self.accessRuleSample.pkName, self.accessRuleId) - PyTestGenerics.forceDelete(self.credentialSample.model, self.credentialSample.pkName, self.credentialId) - -class AuthenticationTest(AuthorizationTestBase): - url = serverUrl+'authorizations/authentications/' - - def runTest(self, urlType, expectedStatus): - #initialize samples - self.initSamples() - - # setting up data - self.accessTypeSample.data['name'] = urlType - - # create sample models in database - self.createSamples() - - # run the system test - loginKey = generateSecretKey(self.partyId, self.credentialSample.data['password']) - url = self.url + '?url=%s&partnerId=%s' % (self.uriPatternSample.data['pattern'], self.partnerId) - cookies = {'credentialId':str(self.partyId), 'secretKey':loginKey, 'apiKey':self.apiKey} - req = requests.get(url,cookies=cookies) - self.assertEqual(req.status_code, 200) - self.assertEqual(req.json()['access'], expectedStatus) - - # delete samples in database - self.deleteSamples() - - def test_for_authentication(self): - self.runTest("Login", True) - -class SubscriptionTest(AuthorizationTestBase): - url = serverUrl+'authorizations/subscriptions/' - - def runTest(self, subscriptionData, usePartyId, ip, urlType, expectedStatus): - #initialize samples - self.initSamples() - - # setting up data - self.subscriptionSample.data = subscriptionData - self.accessTypeSample.data['name'] = urlType - - # create sample models in database - self.createSamples() - - # run the system test - url = self.url + '?partnerId=%s&url=%s&apiKey=%s' % (self.partnerId, self.uriPatternSample.data['pattern'], self.apiKey) - if not ip == None: - url = url+'&ip=%s' % (ip) - if usePartyId: - url = url+'&partyId=%s' % (self.partyId) - - cookies = {'apiKey':self.apiKey} - req = requests.get(url,cookies=cookies) - self.assertEqual(req.status_code, 200) - self.assertEqual(req.json()['access'], expectedStatus) - - # delete samples in database - self.deleteSamples() - - def test_for_subscription(self): - # valid subscription based on partyId, Paid url. access should be True - self.runTest(self.successSubscriptionData, True, None, 'Paid', True) - # invalid subscription, Paid url. access should be False - self.runTest(self.failSubscriptionData, True, None, 'Paid', False) - # invalid subscription, not Paid url. access should be True - self.runTest(self.failSubscriptionData, True, None, 'Free', True) - # valid subscription based on IP, Paid url, access should be True - self.runTest(self.successSubscriptionData, False, self.successIp, 'Paid', True) - -class AccessTest(AuthorizationTestBase): - url = serverUrl+'authorizations/access/' - - def runTest(self, subscriptionData, usePartyId, ip, urlType, expectedStatus): - # initialize samples - self.initSamples() - - # setting up data - self.subscriptionSample.data = subscriptionData - self.accessTypeSample.data['name'] = urlType - - # create sample models in database - self.createSamples() - - # run the system test - url = self.url + '?partnerId=%s&url=%s&apiKey=%s' % (self.partnerId, self.uriPatternSample.data['pattern'], self.apiKey) - if not ip == None: - url = url+'&ip=%s' % (ip) - cookies = {'apiKey':self.apiKey} - if usePartyId: - cookies['partyId'] = str(self.partyId) - req = requests.get(url, cookies=cookies) - self.assertEqual(req.status_code, 200) - self.assertEqual(req.json()['status'], expectedStatus) - - # delete samples in database - self.deleteSamples() - - def test_for_access(self): - # valid subscription, paid url, status should be OK - self.runTest(self.successSubscriptionData, True, None, 'Paid', Status.ok) - # invalid subscription, paid url, status should be need subscription - self.runTest(self.failSubscriptionData, True, None, 'Paid', Status.needSubscription) - #self.runAccessTest(self.successSubscriptionData, False, self.successIp, self.paidUrl, Status.ok) - -print "Running unit tests on authorization web services API........." - -if __name__ == '__main__': - sys.argv[1:] = [] - unittest.main() - ret = not runner.run(suite).wasSuccessful() - sys.exit(ret) diff --git a/authorization/testSamples.py b/authorization/testSamples.py index 28040b93..622b7b6f 100644 --- a/authorization/testSamples.py +++ b/authorization/testSamples.py @@ -1,23 +1,13 @@ #Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. -import django -import unittest -import sys, getopt -import requests -from unittest import TestCase from authorization.models import UriPattern, AccessRule, AccessType -from authentication.models import Credential from partner.models import Partner from party.models import Party -from common.pyTests import PyTestGenerics - -from authorization.models import Status +from common.tests import TestGenericInterfaces import copy - import hashlib -genericForcePost = PyTestGenerics.forcePost - +genericForcePost = TestGenericInterfaces.forcePost class UriPatternSample(): url = None @@ -34,25 +24,23 @@ class UriPatternSample(): def __init__(self, serverUrl): self.url = serverUrl+self.path - def forcePost(self,data): - return genericForcePost(self.model, self.pkName, data) + def forcePost(self,postData): + return genericForcePost(self.model, self.pkName, postData) class AccessRuleSample(): partnerId = 'tair' url = None path = 'authorizations/accessRules/' data = { - 'accessRuleId':1, - 'patternId':1, - 'accessTypeId':1, - 'partnerId':'tair', + 'partnerId':None, + 'patternId':None, + 'accessTypeId':None, } updateData = { - 'accessRuleId':1, - 'patternId':7, - 'accessTypeId':1, - 'partnerId':'cdiff', + 'partnerId':None, + 'patternId':None, + 'accessTypeId':None, } pkName = 'accessRuleId' model = AccessRule @@ -60,22 +48,23 @@ class AccessRuleSample(): def __init__(self, serverUrl): self.url = serverUrl+self.path - def forcePost(self,data): - postData = copy.deepcopy(data) - postData['patternId'] = UriPattern.objects.get(patternId=data['patternId']) - postData['accessTypeId'] = AccessType.objects.get(accessTypeId=data['accessTypeId']) - postData['partnerId'] = Partner.objects.get(partnerId=data['partnerId']) - return genericForcePost(self.model, self.pkName, postData) + def forcePost(self,postData): + processedData = copy.deepcopy(postData) + processedData['patternId'] = UriPattern.objects.get(patternId=postData['patternId']) + processedData['accessTypeId'] = AccessType.objects.get(accessTypeId=postData['accessTypeId']) + processedData['partnerId'] = Partner.objects.get(partnerId=postData['partnerId']) + return genericForcePost(self.model, self.pkName, processedData) class AccessTypeSample(): url = None path = 'authorizations/accessTypes/' + TYPE_LOGIN = 'Login' + TYPE_PAID = 'Paid' data = { - 'name':'test1', + 'name':TYPE_LOGIN, } - updateData = { - 'name':'test2', + 'name':TYPE_PAID, } pkName = 'accessTypeId' model = AccessType @@ -83,26 +72,11 @@ class AccessTypeSample(): def __init__(self, serverUrl): self.url = serverUrl+self.path - def forcePost(self,data): - return genericForcePost(self.model, self.pkName, data) - + def setAsLoginType(self): + self.data['name'] = self.TYPE_LOGIN -class CredentialSample(): - data = { - 'username':'steve', - 'password':hashlib.sha1('stevepass').hexdigest(), - 'email':'steve@getexp.com', - 'institution':'test organization', - 'partyId':None, - 'partnerId':None, - 'userIdentifier':'1234536', - } - pkName = 'id' - model = Credential - - def forcePost(self,data): - postData = copy.deepcopy(data) - postData['partyId'] = Party.objects.get(partyId=data['partyId']) - postData['partnerId'] = Partner.objects.get(partnerId=data['partnerId']) - return genericForcePost(self.model, self.pkName, postData) + def setAsPaidType(self): + self.data['name'] = self.TYPE_PAID + def forcePost(self,postData): + return genericForcePost(self.model, self.pkName, postData) \ No newline at end of file diff --git a/authorization/tests.py b/authorization/tests.py index 7ce503c2..29513283 100644 --- a/authorization/tests.py +++ b/authorization/tests.py @@ -1,3 +1,472 @@ +#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. + +import django +import unittest +import sys +import json from django.test import TestCase +from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest +from party.testSamples import UserPartySample, OrganizationPartySample, IpRangeSample, CountrySample, ConsortiumPartySample, InstitutionPartySample, PartyAffiliationSample +from partner.testSamples import PartnerSample +from authentication.testSamples import CredentialSample +from subscription.testSamples import SubscriptionSample +from testSamples import UriPatternSample, AccessRuleSample, AccessTypeSample +from authorization.models import Status +# Python 3: module Cookie -> http.cookies +from Cookie import SimpleCookie + +# Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() + +# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- + +# Test for API end point /authorizations/patterns/ +class UriPatternCRUDTest(GenericCRUDTest, TestCase): + sample = UriPatternSample(serverUrl) + +# Test for API end point /authorizations/accessTypes/ +class AccessTypesCRUDTest(GenericCRUDTest, TestCase): + sample = AccessTypeSample(serverUrl) + +# Test for API end point /authorizations/accessRules/ +class AccessRuleCRUDTest(GenericCRUDTest, TestCase): + sample = AccessRuleSample(serverUrl) + + def setUp(self): + super(AccessRuleCRUDTest,self).setUp() + partnerSample = PartnerSample(serverUrl) + partnerId = partnerSample.forcePost(partnerSample.data) + self.sample.data['partnerId']=self.sample.updateData['partnerId']=partnerId + + patternSample = UriPatternSample(serverUrl) + patternId = patternSample.forcePost(patternSample.data) + self.sample.data['patternId']=patternId + + accessTypeSample = AccessTypeSample(serverUrl) + accessTypeId = accessTypeSample.forcePost(accessTypeSample.data) + self.sample.data['accessTypeId']=accessTypeId + + def test_for_update(self): + # set different pattern for update data + patternSample = UriPatternSample(serverUrl) + updatePatternId = patternSample.forcePost(patternSample.updateData) + self.sample.updateData['patternId']=updatePatternId + + # set different access type for update data + accessTypeSample = AccessTypeSample(serverUrl) + updateAccessTypeId = accessTypeSample.forcePost(accessTypeSample.updateData) + self.sample.updateData['accessTypeId']=updateAccessTypeId + + super(AccessRuleCRUDTest, self).test_for_update() + +# # ----------------- END OF BASIC CRUD OPERATIONS ---------------------- + +# Base class for sample management for access, subscription, and authorization access tests. +class GenericAuthorizationTest(GenericTest, TestCase): + partnerId = None + patternId = None + patternSample = UriPatternSample(serverUrl) + accessRuleSample = AccessRuleSample(serverUrl) + + def setUp(self): + super(GenericAuthorizationTest, self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + self.accessRuleSample.data['partnerId'] = self.partnerId + + patternId = self.patternSample.forcePost(self.patternSample.data) + self.accessRuleSample.data['patternId'] = patternId + + def setUpLoginAccessRule(self): + accessTypeSample = AccessTypeSample(serverUrl) + accessTypeSample.setAsLoginType() + accessTypeId = accessTypeSample.forcePost(accessTypeSample.data) + + self.accessRuleSample.data['accessTypeId'] = accessTypeId + self.accessRuleSample.forcePost(self.accessRuleSample.data) + + def setUpPaidAccessRule(self): + accessTypeSample = AccessTypeSample(serverUrl) + accessTypeSample.setAsPaidType() + accessTypeId = accessTypeSample.forcePost(accessTypeSample.data) + + self.accessRuleSample.data['accessTypeId'] = accessTypeId + self.accessRuleSample.forcePost(self.accessRuleSample.data) + + def setUpSubscribedUser(self): + credentialSample = self.setUpCredentialSample() + + individualSubscriptionSample = SubscriptionSample(serverUrl) + individualSubscriptionSample.setPartnerId(self.partnerId) + individualSubscriptionSample.setPartyId(credentialSample.getPartyId()) + individualSubscriptionSample.forcePost(individualSubscriptionSample.data) + + return credentialSample + + def setUpCredentialSample(self): + userPartySample = UserPartySample(serverUrl) + userPartyId = userPartySample.forcePost(userPartySample.data) + + credentialSample = CredentialSample(serverUrl) + + credentialSample.setPartnerId(self.partnerId) + credentialSample.setPartyId(userPartyId) + credentialSample.forcePost(credentialSample.data) + + return credentialSample + + def setUpSubscribedOrganization(self): + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + + organizationPartySample = OrganizationPartySample(serverUrl) + organizationPartySample.setCountry(countryId) + organizationPartyId = organizationPartySample.forcePost(organizationPartySample.data) + + orgIpRangeSample = IpRangeSample(serverUrl) + orgIpRangeSample.setPartyId(organizationPartyId) + orgIpRangeSample.forcePost(orgIpRangeSample.data) + + organizationSubscriptionSample = SubscriptionSample(serverUrl) + organizationSubscriptionSample.setPartnerId(self.partnerId) + organizationSubscriptionSample.setPartyId(organizationPartyId) + organizationSubscriptionSample.forcePost(organizationSubscriptionSample.data) + + return orgIpRangeSample + + def setUpSubscribedConsortium(self): + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + + # create subscribed consortium + consortiumPartySample = ConsortiumPartySample(serverUrl) + consortiumPartySample.setCountry(countryId) + consortiumPartyId = consortiumPartySample.forcePost(consortiumPartySample.data) + + consortiumSubscriptionSample = SubscriptionSample(serverUrl) + consortiumSubscriptionSample.setPartnerId(self.partnerId) + consortiumSubscriptionSample.setPartyId(consortiumPartyId) + consortiumSubscriptionSample.forcePost(consortiumSubscriptionSample.data) + + # create institution that is a subsidy of consortium + institutionPartySample = InstitutionPartySample(serverUrl) + institutionPartySample.setCountry(countryId) + institutionPartyId = institutionPartySample.forcePost(institutionPartySample.data) + + institutionIpRangeSample = IpRangeSample(serverUrl) + institutionIpRangeSample.setPartyId(institutionPartyId) + institutionIpRangeSample.forcePost(institutionIpRangeSample.data) + + affiliationSample = PartyAffiliationSample(serverUrl) + affiliationSample.setParentId(consortiumPartyId) + affiliationSample.setChildId(institutionPartyId) + affiliationSample.forcePost(affiliationSample.data) + + return institutionIpRangeSample + +# Test for API end point /authorizations/authentications/ +# Checks if user can access a Login type pattern +# End point returns true if url to check does not require login or user already logins +# Returns false when url requires login and user is not logged in +# ApiKey, credentialId and secretKey are required and need to be passed in by cookie +class AuthenticationTest(GenericAuthorizationTest): + url = serverUrl+'authorizations/authentications/' + loginPattern = None + nonLoginPattern = None + credentialSample = None + + def setUp(self): + super(AuthenticationTest,self).setUp() + + self.setUpLoginAccessRule() + self.loginPattern = self.patternSample.data['pattern'] + self.nonLoginPattern = self.patternSample.updateData['pattern'] + + # create user credential and its subscription + self.credentialSample = self.setUpCredentialSample() + + def test_for_authentication(self): + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + + # test login not required pattern when user is not logged in + self.runAuthenticationTest(self.nonLoginPattern, True) + + # test login required pattern when user is not logged in + self.runAuthenticationTest(self.loginPattern, False) + + # test login required pattern when user is logged in + credentialSample = self.credentialSample + cookies = SimpleCookie({'apiKey':self.apiKey, 'credentialId':credentialSample.getPartyId(), 'secretKey':credentialSample.getSecretKey()}) + self.runAuthenticationTest(self.loginPattern, True, cookies) + + def runAuthenticationTest(self, urlToCheck, expectedStatus, cookies = None): + url = '%s?partnerId=%s&url=%s' % (self.url, self.partnerId, urlToCheck) + if cookies: + self.client.cookies = cookies + else: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + self.assertEqual(json.loads(res.content)['access'], expectedStatus) + +# Test for API end point /authorizations/subscriptions/ +# Checks if an user (by partyId) or an IP address can access a Paid (subsription required) +# type pattern +# End point returns true if url to check does not require subscription or if user +# or ip address belongs to a subscribed entity +# Returns false when url requires subscription and no subscribed entity detected +class SubscriptionTest(GenericAuthorizationTest): + url = serverUrl + 'authorizations/subscriptions/' + paidPattern = None + nonPaidPattern = None + + def setUp(self): + super(SubscriptionTest,self).setUp() + + self.setUpPaidAccessRule() + self.paidPattern = self.patternSample.data['pattern'] + self.nonPaidPattern = self.patternSample.updateData['pattern'] + + def test_for_subscription(self): + credentialSample = self.setUpSubscribedUser() + userPartyId = credentialSample.getPartyId() + + orgIpRangeSample = self.setUpSubscribedOrganization() + + # User with subscription, Paid url. access should be True + # Note if a non-exist partyId is passed in an error will be thrown + authParam = 'partyId=%s' % userPartyId + self.runSubscriptionTest(self.paidPattern, authParam , True) + + # IP of organization with subscription, Paid url, access should be True + subscribedIP = orgIpRangeSample.getInRangeIp() + authParam = 'ip=%s' % subscribedIP + self.runSubscriptionTest(self.paidPattern, authParam, True) + + # IP outside of organization with subscription, Paid url, access should be False + # Note that if an invalid format IP is passed in, error will be thrown + unsubscribedIP = orgIpRangeSample.getOutRangeIp() + authParam = 'ip=%s' % unsubscribedIP + self.runSubscriptionTest(self.paidPattern, authParam, False) + + # No identity info, Paid url. access should be False + self.runSubscriptionTest(self.paidPattern, None, False) + + # Not Paid url. access should be True + self.runSubscriptionTest(self.nonPaidPattern, None, True) + + def test_for_consortium_subscription(self): + consOrgIpRangeSample = self.setUpSubscribedConsortium() + + # Institution whose parent consortium has subscription, Paid url. Passed in institution party id + # Access should be True + # Note if a non-exist partyId is passed in an error will be thrown + authParam = 'partyId=%s' % consOrgIpRangeSample.getPartyId() + self.runSubscriptionTest(self.paidPattern, authParam , True) + + # IP of institution whose parent consortium has subscription, Paid url, access should be True + subscribedIP = consOrgIpRangeSample.getInRangeIp() + authParam = 'ip=%s' % subscribedIP + self.runSubscriptionTest(self.paidPattern, authParam, True) + + # IP outside of organization with subscription, Paid url, access should be False + # Note that if an invalid format IP is passed in, error will be thrown + unsubscribedIP = consOrgIpRangeSample.getOutRangeIp() + authParam = 'ip=%s' % unsubscribedIP + self.runSubscriptionTest(self.paidPattern, authParam, False) + + def runSubscriptionTest(self, urlToCheck, authParam, expectedStatus): + url = '%s?partnerId=%s&url=%s' % (self.url, self.partnerId, urlToCheck) + if authParam: + url = '%s&%s' % (url, authParam) + + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + self.assertEqual(json.loads(res.content)['access'], expectedStatus) + +# Test for API end point /authorizations/access/ +# Checks if a url pattern requires subscription and if an IP address or a list of IP addresses +# can access this pattern +# End point returns a JSON object, which includes but not limited to +# (1) status as either "NeedLogin" (for pattern that requires login, this checks before subscription status) +# or "OK" (for free pattern or paid pattern + subscribed IP) or "NeedSubscription" (paid pattern + +# unsubscribed IP) +# (2) isPaidContent as "T" (paid pattern) or "F" (free pattern) +# (3) userIdentifier for the passed in credentialId and secretKey +# ApiKey, credentialId and secretKey are required and need to be passed in by cookie +class AccessTest(GenericAuthorizationTest): + url = serverUrl + 'authorizations/access/' + + def setUp(self): + super(AccessTest, self).setUp() + + def test_for_login_only_access(self): + self.setUpLoginAccessRule() + loginPattern = self.patternSample.data['pattern'] + nonLoginPattern = self.patternSample.updateData['pattern'] + + credentialSample = self.setUpCredentialSample() + + # test login not required & free pattern when user is not logged in, status should be OK + self.runAccessTest(urlToCheck=nonLoginPattern, expectedUrlPaidStatus=False, + authParam=None, ipList=None, expectedNeedLoginStatus=False, + expectedAccessStatus=True, expectedUserIdentifier=None, cookies=None) + + # test login required & free pattern when user is not logged in, status should be NeedLogin + self.runAccessTest(urlToCheck=loginPattern, expectedUrlPaidStatus=False, + authParam=None, ipList=None, expectedNeedLoginStatus=True, + expectedAccessStatus=None, expectedUserIdentifier=None, cookies=None) + + # test valid credential + login required & free url, status should be OK + partyId = credentialSample.getPartyId() + # note this partyId can be different from the credentialId we passed in cookies, and the user identifier + # returned is in accordance with this partyId. For the sake of consistency we use same id in the test + authParam = 'partyId=%s' % partyId + cookies = SimpleCookie({'apiKey':self.apiKey, 'credentialId':partyId, 'secretKey':credentialSample.getSecretKey()}) + self.runAccessTest(urlToCheck=loginPattern, expectedUrlPaidStatus=False, + authParam=authParam, ipList=None, expectedNeedLoginStatus=False, + expectedAccessStatus=True, expectedUserIdentifier=credentialSample.getUserIdentifier(), cookies=cookies) + + def test_for_subscription_only_access(self): + orgIpRangeSample = self.setUpSubscribedOrganization() + + self.runSubscriptionOnlyAccessTest(orgIpRangeSample) + + def test_for_subscription_only_access_for_consortium(self): + orgIpRangeSample = self.setUpSubscribedConsortium() + + self.runSubscriptionOnlyAccessTest(orgIpRangeSample) + + def runSubscriptionOnlyAccessTest(self, orgIpRangeSample): + self.setUpPaidAccessRule() + paidPattern = self.patternSample.data['pattern'] + nonPaidPattern = self.patternSample.updateData['pattern'] + + credentialSample = self.setUpSubscribedUser() + + # test no credential & ip for paid url, status should be NeedSubscription + self.runAccessTest(urlToCheck=paidPattern, expectedUrlPaidStatus=True, + authParam=None, ipList=None, expectedNeedLoginStatus=False, + expectedAccessStatus=False, expectedUserIdentifier=None, cookies=None) + + # test no credential & ip for free url, status should be OK + self.runAccessTest(urlToCheck=nonPaidPattern, expectedUrlPaidStatus=False, + authParam=None, ipList=None, expectedNeedLoginStatus=False, + expectedAccessStatus=True, expectedUserIdentifier=None, cookies=None) + + # test valid subscription for individual, paid url, status should be OK + partyId = credentialSample.getPartyId() + authParam = 'partyId=%s' % partyId + cookies = SimpleCookie({'apiKey':self.apiKey, 'credentialId':partyId, 'secretKey':credentialSample.getSecretKey()}) + self.runAccessTest(urlToCheck=paidPattern, expectedUrlPaidStatus=True, + authParam=authParam, ipList=None, expectedNeedLoginStatus=False, + expectedAccessStatus=True, expectedUserIdentifier=credentialSample.getUserIdentifier(), cookies=cookies) + + # test valid subscription for organization, paid url, status should be OK + subscribedIP = orgIpRangeSample.getInRangeIp() + self.runAccessTest(urlToCheck=paidPattern, expectedUrlPaidStatus=True, + authParam=None, ipList=subscribedIP, expectedNeedLoginStatus=False, + expectedAccessStatus=True, expectedUserIdentifier=None, cookies=None) + + # test IP outside of subscribed organization subscription, paid url, status should be NeedSubscription + unsubscribedIP = orgIpRangeSample.getOutRangeIp() + self.runAccessTest(urlToCheck=paidPattern, expectedUrlPaidStatus=True, + authParam=None, ipList=unsubscribedIP, expectedNeedLoginStatus=False, + expectedAccessStatus=False, expectedUserIdentifier=None, cookies=None) + + def test_for_login_and_subscription_access(self): + orgIpRangeSample = self.setUpSubscribedOrganization() + + self.runLoginAndSubscriptionAccessTest(orgIpRangeSample) + + def test_for_login_and_subscription_access_for_consortium(self): + orgIpRangeSample = self.setUpSubscribedConsortium() + + self.runLoginAndSubscriptionAccessTest(orgIpRangeSample) + + def runLoginAndSubscriptionAccessTest(self, orgIpRangeSample): + self.setUpLoginAccessRule() + self.setUpPaidAccessRule() + loginPaidPattern = self.patternSample.data['pattern'] + + # test login required & paid pattern when no user nor IP provided, status should be NeedLogin + self.runAccessTest(urlToCheck=loginPaidPattern, expectedUrlPaidStatus=True, + authParam=None, ipList=None, expectedNeedLoginStatus=True, + expectedAccessStatus=None, expectedUserIdentifier=None, cookies=None) + + # test login required & paid pattern when only IP provided, status should be NeedLogin + subscribedIP = orgIpRangeSample.getInRangeIp() + self.runAccessTest(urlToCheck=loginPaidPattern, expectedUrlPaidStatus=True, + authParam=None, ipList=subscribedIP, expectedNeedLoginStatus=True, + expectedAccessStatus=None, expectedUserIdentifier=None, cookies=None) + + # test login required & paid pattern with subscribed user, status should be OK + credentialSample = self.setUpSubscribedUser() + partyId = credentialSample.getPartyId() + authParam = 'partyId=%s' % partyId + cookies = SimpleCookie({'apiKey':self.apiKey, 'credentialId':partyId, 'secretKey':credentialSample.getSecretKey()}) + self.runAccessTest(urlToCheck=loginPaidPattern, expectedUrlPaidStatus=True, + authParam=authParam, ipList=None, expectedNeedLoginStatus=False, + expectedAccessStatus=True, expectedUserIdentifier=credentialSample.getUserIdentifier(), cookies=cookies) + + # create additional credential that is not subscribed + nonSubUserPartySample = UserPartySample(serverUrl) + nonSubUserPartyId = nonSubUserPartySample.forcePost(nonSubUserPartySample.updateData) + + nonSubCredentialSample = CredentialSample(serverUrl) + nonSubCredentialSample.setAsUpdateExample() + nonSubCredentialSample.setPartnerId(self.partnerId) + nonSubCredentialSample.setPartyId(nonSubUserPartyId) + nonSubCredentialSample.forcePost(nonSubCredentialSample.data) + + # test login required & paid pattern with unsubscribed user , status should be NeedSubscription + partyId = nonSubCredentialSample.getPartyId() + authParam = 'partyId=%s' % partyId + cookies = SimpleCookie({'apiKey':self.apiKey, 'credentialId':partyId, 'secretKey':nonSubCredentialSample.getSecretKey()}) + self.runAccessTest(urlToCheck=loginPaidPattern, expectedUrlPaidStatus=True, + authParam=authParam, ipList=None, expectedNeedLoginStatus=False, + expectedAccessStatus=False, expectedUserIdentifier=nonSubCredentialSample.getUserIdentifier(), cookies=cookies) + + # Note ipList param always need to add to end point call even when no value for it + def runAccessTest(self, urlToCheck, expectedUrlPaidStatus, authParam = None, ipList = None, + expectedNeedLoginStatus = None, expectedAccessStatus = None, expectedUserIdentifier = None, cookies = None): + if not ipList: + ipList = '' + url = '%s?partnerId=%s&url=%s&ipList=%s' % (self.url, self.partnerId, urlToCheck, ipList) + if authParam: + url = '%s&%s' % (url, authParam) + + if cookies: + self.client.cookies = cookies + else: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + res = json.loads(res.content) + status = '' + if expectedNeedLoginStatus is not None and expectedNeedLoginStatus: + status = Status.needLogin + if expectedAccessStatus is not None: + if expectedAccessStatus: + status = Status.ok + else: + status = Status.needSubscription + self.assertEqual(res['status'], status) + if expectedUrlPaidStatus: + isPaidContent = 'T' + else: + isPaidContent = 'F' + self.assertEqual(res['isPaidContent'], isPaidContent) + if expectedUserIdentifier: + self.assertEqual(res['userIdentifier'], str(expectedUserIdentifier)) + +print "Running unit tests on authorization web services API........." -# Create your tests here. +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) diff --git a/authorization/views.py b/authorization/views.py index f092c4c1..55aa51c5 100644 --- a/authorization/views.py +++ b/authorization/views.py @@ -118,7 +118,7 @@ def get(self, request, format=None): requestPatternId = request.GET.get('patternId') if UriPattern.objects.filter(patternId = requestPatternId).exists(): obj = UriPattern.objects.get(patternId = requestPatternId) - serializer = UriPatternSerializer(obj, many=True) + serializer = UriPatternSerializer(obj) logger.info("Authorization URIAccess %s%s %s%s %s%s" % ("requestPatternId:",requestPatternId,"serializer.data:",serializer.data,"status:",status.HTTP_200_OK)) return Response(serializer.data, status=status.HTTP_200_OK) else: diff --git a/common/permissions.py b/common/permissions.py index b6743813..602943bc 100644 --- a/common/permissions.py +++ b/common/permissions.py @@ -1,4 +1,5 @@ from apikey.models import ApiKey +from authentication.models import Credential class ApiKeyPermission(): @staticmethod @@ -20,7 +21,6 @@ def has_object_permission(self, request, view, obj): return True def isPhoenix(request): - from authentication.models import Credential credentialId = request.GET.get('credentialId') secretKey = request.GET.get('secretKey') if credentialId and secretKey and Credential.validate(credentialId, secretKey): @@ -28,7 +28,6 @@ def isPhoenix(request): return False def isLoggedIn(request): - from authentication.models import Credential credentialId = request.GET.get('credentialId') secretKey = request.GET.get('secretKey') if credentialId and secretKey and Credential.validate(credentialId, secretKey):# and Credential.objects.get(partyId=credentialId).partyId.partyType=='phoenix': diff --git a/common/pyTests.py b/common/pyTests.py deleted file mode 100644 index 71d48bf3..00000000 --- a/common/pyTests.py +++ /dev/null @@ -1,138 +0,0 @@ -import requests -import json -import sys, getopt - -from testSamples import CommonApiKeySample -from partner.models import Partner -from apikey.models import ApiKey - -class GenericTest(object): - apiKeySample = CommonApiKeySample() - apiKey = None - def setUp(self): - #delete possible entries that we use as test case - ApiKey.objects.filter(apiKey=self.apiKeySample.data['apiKey']).delete() - self.apiKeyId = self.apiKeySample.forcePost(self.apiKeySample.data) - self.apiKey = self.apiKeySample.data['apiKey'] - - def tearDown(self): - PyTestGenerics.forceDelete(self.apiKeySample.model, self.apiKeySample.pkName, self.apiKeyId) - -# This function checks if sampleData is within the array of data retrieved -# from API call. -def checkMatch(sampleData, retrievedDataArray, pkName, pk): - hasMatch = False - for item in retrievedDataArray: - # find the entry from dataArray that has the same PK - # as the entry created - if item[pkName] == pk: - hasMatch = True - for key in sampleData: - # makes sure that all contents from sample is the - # same as content retrieved from request - if not (item[key] == sampleData[key] or float(item[key])==float(sampleData[key])): - hasMatch = False - break - return hasMatch - -class GenericCRUDTest(GenericTest): - def test_for_create(self): - sample = self.sample - url = sample.url - if self.apiKey: - url = url+'?apiKey=%s' % (self.apiKey) - cookies = {'apiKey':self.apiKey} - req = requests.post(url, data=sample.data, cookies=cookies) - - self.assertEqual(req.status_code, 201) - self.assertIsNotNone(PyTestGenerics.forceGet(sample.model,sample.pkName,req.json()[sample.pkName])) - PyTestGenerics.forceDelete(sample.model,sample.pkName,req.json()[sample.pkName]) - - def test_for_get_all(self): - sample = self.sample - pk = sample.forcePost(sample.data) - url = sample.url - if self.apiKey: - url = url+'?apiKey=%s' % (self.apiKey) - cookies = {'apiKey':self.apiKey} - req = requests.get(url, cookies=cookies) - self.assertEqual(req.status_code, 200) - self.assertEqual(checkMatch(sample.data, req.json(), sample.pkName, pk), True) - - PyTestGenerics.forceDelete(sample.model,sample.pkName,pk) - - def test_for_update(self): - sample = self.sample - pk = sample.forcePost(sample.data) - url = sample.url + '?%s=%s' % (sample.pkName, str(pk)) - if self.apiKey: - url = url+'&apiKey=%s' % (self.apiKey) - cookies = {'apiKey':self.apiKey} - req = requests.put(url, data=sample.updateData,cookies=cookies) - if sample.pkName in sample.updateData: - pk = sample.updateData[sample.pkName] - self.assertEqual(req.status_code, 200) - self.assertEqual(checkMatch(sample.updateData, req.json(), sample.pkName, pk), True) - PyTestGenerics.forceDelete(sample.model,sample.pkName,pk) - - def test_for_delete(self): - sample = self.sample - pk = sample.forcePost(sample.data) - url = sample.url + '?%s=%s' % (sample.pkName, str(pk)) - if self.apiKey: - url = url+'&apiKey=%s' % (self.apiKey) - cookies = {'apiKey':self.apiKey} - req = requests.delete(url, cookies=cookies) - self.assertIsNone(PyTestGenerics.forceGet(sample.model,sample.pkName,pk)) - - def test_for_get(self): - sample = self.sample - pk = sample.forcePost(sample.data) - url = sample.url + '?%s=%s' % (sample.pkName, str(pk)) - if self.apiKey: - url = url+'&apiKey=%s' % (self.apiKey) - cookies = {'apiKey':self.apiKey} - req = requests.get(url, cookies=cookies) - self.assertEqual(req.status_code, 200) - self.assertEqual(checkMatch(sample.data, req.json(), sample.pkName, pk), True) - PyTestGenerics.forceDelete(sample.model,sample.pkName,pk) - -class PyTestGenerics: - @staticmethod - def initPyTest(): - try: - opts, args = getopt.getopt(sys.argv[1:], "h:" , ["host="]) - except getopt.GetoptError: - print "Usage: python -m metering.pyTests --host \n\rExample hostname: 'http://pb.steveatgetexp.com:8080/'" - sys.exit(1) - serverUrl = "" - for opt, arg in opts: - if opt=='--host' or opt=='-h': - serverUrl = arg - if serverUrl=="": - print "hostname is required" - sys.exit(1) - return serverUrl - - - @staticmethod - def forceGet(model, pkName, pk): - try: - filters = {pkName:pk} - return model.objects.get(**filters) - except: - return None - - @staticmethod - def forceDelete(model, pkName,pk): - try: - filters = {pkName:pk} - model.objects.get(**filters).delete() - except: - pass - - @staticmethod - def forcePost(model, pkName, data): - u = model(**data) - u.save() - return u.__dict__[pkName] diff --git a/common/testSamples.py b/common/testSamples.py index 88e7c827..40f55f50 100644 --- a/common/testSamples.py +++ b/common/testSamples.py @@ -1,6 +1,10 @@ from apikey.models import ApiKey from partner.models import Partner +from party.models import Party +from authentication.models import Credential +from authentication.views import generateSecretKey import copy +import hashlib def forcePost(model, pkName, data): u = model(**data) @@ -16,3 +20,82 @@ class CommonApiKeySample(): def forcePost(self,data): return forcePost(self.model, self.pkName, data) + +class CommonPartnerSample(): + url = None + path = 'partners/' + data = { + 'partnerId':'phoenix', + 'name':'PhoenixBio', + } + pkName = 'partnerId' + model = Partner + + def __init__(self, serverUrl): + self.url = serverUrl + self.path + + def forcePost(self,data): + return forcePost(self.model, self.pkName, data) + +class CommonUserPartySample(): + path = 'parties/' + url = None + data = { + 'partyType':'user', + 'name':'phoenix_admin', + } + pkName = 'partyId' + model = Party + + def __init__(self, serverUrl): + self.url = serverUrl+self.path + + def forcePost(self,data): + return forcePost(self.model, self.pkName, data) + +class CommonCredentialSample(): + url = None + path = 'credentials/' + USERNAME = 'phoenix_admin' + FIRSTNAME = 'Phoenix' + LASTNAME = 'Bioinformatics' + PASSWORD = 'phoenix123' + EMAIL = 'info@phoenixbioinformatics.org' + INSTITUTION = 'Phoenix Bioinformatics' + USER_IDENTIFIER = 123 + data = { + 'username': USERNAME, + 'firstName': FIRSTNAME, + 'lastName': LASTNAME, + 'password': PASSWORD, + 'email': EMAIL, + 'institution': INSTITUTION, + 'userIdentifier': USER_IDENTIFIER, + 'partnerId': None, + 'partyId': None + } + pkName = 'id' + model = Credential + + def __init__(self, serverUrl): + self.url = serverUrl + self.path + + def setPartnerId(self, partnerId): + self.data['partnerId'] = partnerId + + def setPartyId(self, partyId): + self.data['partyId'] = partyId + + def forcePost(self,data): + postData = copy.deepcopy(data) + postData['partyId'] = Party.objects.get(partyId=self.data['partyId']) + postData['partnerId'] = Partner.objects.get(partnerId=self.data['partnerId']) + postData['password'] = self.hashPassword(self.data['password']) + return forcePost(self.model, self.pkName, postData) + + def hashPassword(self, password): + return hashlib.sha1(password).hexdigest() + + def getSecretKey(self): + # this has dependency on authentication.views regarding argument + return generateSecretKey(self.data['partyId'], self.hashPassword(self.data['password'])) diff --git a/common/tests.py b/common/tests.py new file mode 100644 index 00000000..5d581fe1 --- /dev/null +++ b/common/tests.py @@ -0,0 +1,229 @@ +import json +import sys +import time +# Python 3: library urllib -> urllib.parse +import urllib +from testSamples import CommonApiKeySample, CommonPartnerSample, CommonUserPartySample, CommonCredentialSample +from partner.models import Partner +from apikey.models import ApiKey +from django.test import Client +from django.conf import settings +# Python 3: module Cookie -> http.cookies +from Cookie import SimpleCookie + +class TestGenericInterfaces: + @staticmethod + def getHost(): + if TestGenericInterfaces.hasHost(): + return settings.HOSTNAME + # default connection to localhost + return "http://localhost/" + + @staticmethod + def hasHost(): + return hasattr(settings, 'HOSTNAME') + + @staticmethod + def forceGet(model, pkName, pk): + try: + filters = {pkName:pk} + return model.objects.get(**filters) + except: + return None + + @staticmethod + def forceDelete(model, pkName,pk): + try: + filters = {pkName:pk} + model.objects.get(**filters).delete() + except: + pass + + @staticmethod + def forcePost(model, pkName, data): + u = model(**data) + u.save() + return u.__dict__[pkName] + +class GenericTest(object): + apiKeySample = CommonApiKeySample() + apiKey = None + + def setUp(self): + self.apiKeyId = self.apiKeySample.forcePost(self.apiKeySample.data) + self.apiKey = self.apiKeySample.data['apiKey'] + + def getUrl(self, url, pkName = None, pk = None): + fullUrl = url + if pkName and pk: + fullUrl = url + '?%s=%s' % (pkName, str(pk)) + return fullUrl + +# create a credential record to login for every test +class LoginRequiredTest(GenericTest): + credentialId = None + secretKey = None + + def setUp(self): + super(LoginRequiredTest, self).setUp() + serverUrl = TestGenericInterfaces.getHost() + credentialSample = CommonCredentialSample(serverUrl) + + partnerSample = CommonPartnerSample(serverUrl) + partnerId = partnerSample.forcePost(partnerSample.data) + credentialSample.setPartnerId(partnerId) + + userPartySample = CommonUserPartySample(serverUrl) + partyId = userPartySample.forcePost(userPartySample.data) + credentialSample.setPartyId(partyId) + + credentialSample.forcePost(credentialSample.data) + + self.credentialId = partyId + self.secretKey = credentialSample.getSecretKey() + + def getUrl(self, url, pkName = None, pk = None): + secretKey = urllib.quote(self.secretKey) + fullUrl = url + '?credentialId=%s&secretKey=%s' % (self.credentialId, secretKey) + if pkName and pk: + fullUrl = '%s&%s=%s' % (fullUrl, pkName, str(pk)) + return fullUrl + +# This function checks if sampleData is within the array of data retrieved +# from API call. +def checkMatch(sampleData, retrievedData, pkName, pk): + hasMatch = False + if not isinstance(retrievedData, list): + retrievedData = [retrievedData] + for item in retrievedData: + # find the entry from dataArray that has the same PK + # as the entry created + if item[pkName] == pk: + hasMatch = True + for key in sampleData: + # makes sure that all contents from sample is the + # same as content retrieved from request + if not key in item or not (item[key] == sampleData[key] or compareDateTime(sampleData[key], item[key]) + or float(item[key]) == float(sampleData[key])): + hasMatch = False + break + if not hasMatch: + print "\nERROR: sample data %s and retrieved data %s does not match" % (sampleData, retrievedData) + return hasMatch + +## This function checks if sampleData is within the array of data retrieved +# from API call, and skip common key we use for authentication, such as apiKey, +# credential, party etc. +def filterAndCheckMatch(sampleData, retrievedDataArray, pkName, pk, commonKeyName, commonKeyValue): + filteredArray = [] + for item in retrievedDataArray: + if item[commonKeyName] == commonKeyValue: + continue; + else: + filteredArray.append(item) + return checkMatch(sampleData, filteredArray, pkName, pk) + +def compareDateTime(sampleTime, retrievedTime): + retrievedTime = retrievedTime.replace('T', ' ').replace('Z', '') + return sampleTime == retrievedTime + +class GenericGETOnlyTest(GenericTest): + + def test_for_get_all(self): + sample = self.sample + url = self.getUrl(sample.url) + self.getAllHelper(url) + + def test_for_get(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = self.getUrl(sample.url, sample.pkName, pk) + if self.apiKey: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + self.assertEqual(checkMatch(sample.data, json.loads(res.content), sample.pkName, pk), True) + + def getAllHelper(self, url, commonKeyName = None, commonKeyValue = None): + sample = self.sample + pk = sample.forcePost(sample.data) + if self.apiKey: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + if commonKeyName and commonKeyValue: + self.assertEqual(filterAndCheckMatch(sample.data, json.loads(res.content), sample.pkName, pk, commonKeyName, commonKeyValue), True) + else: + self.assertEqual(checkMatch(sample.data, json.loads(res.content), sample.pkName, pk), True) + +class GenericCRUDTest(GenericGETOnlyTest): + + # GET tests defined in GenericGETOnlyTest class + + def test_for_create(self): + sample = self.sample + url = self.getUrl(sample.url) + if self.apiKey: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + + res = self.client.post(url, sample.data) + + self.assertEqual(res.status_code, 201) + self.assertIsNotNone(TestGenericInterfaces.forceGet(sample.model,sample.pkName,json.loads(res.content)[sample.pkName])) + + def test_for_update(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = self.getUrl(sample.url, sample.pkName, pk) + if sample.pkName in sample.updateData: + pk = sample.updateData[sample.pkName] + if self.apiKey: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + + # the default content type for put is 'application/octet-stream' + res = self.client.put(url, json.dumps(sample.updateData), content_type='application/json') + + self.assertEqual(res.status_code, 200) + self.assertEqual(checkMatch(sample.updateData, json.loads(res.content), sample.pkName, pk), True) + + def test_for_delete(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = self.getUrl(sample.url, sample.pkName, pk) + if self.apiKey: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + + res = self.client.delete(url) + + self.assertIsNone(TestGenericInterfaces.forceGet(sample.model,sample.pkName,pk)) + +class LoginRequiredGETOnlyTest(LoginRequiredTest, GenericGETOnlyTest): + # just inherit methods from two parent classes + pass + +class LoginRequiredCRUDTest(LoginRequiredTest, GenericCRUDTest): + # just inherit methods from two parent classes + pass + +class ManualTest(object): + path = "" + testMethodStr = "" + + def test_warning(self): + print "\n----------------------------------------------------------------------" + print "\nWARNING: Please manually test API end point %s if necessary.\n\ + If you've \n\ + (1) upgraded Python version or\n\ + (2) upgraded Django version or\n\ + (3) updated module or setting params related to this end point\n\ + Please make sure you test this end point by %s" % (self.path, self.testMethodStr) + print "\n----------------------------------------------------------------------" + +if not TestGenericInterfaces.hasHost(): + print "WARNING: No HOSTNAME detected in settings.py." + +print "Using server url %s" % TestGenericInterfaces.getHost() + diff --git a/ipranges/tests.py b/ipranges/tests.py index 7ce503c2..5f9af36d 100644 --- a/ipranges/tests.py +++ b/ipranges/tests.py @@ -1,3 +1,70 @@ +import django +import unittest +import sys +import json + from django.test import TestCase +from common.tests import TestGenericInterfaces, GenericTest +from Cookie import SimpleCookie # Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() + +# test for API end point /ipranges/validateip +class ValidateIpTest(GenericTest, TestCase): + VALID_PUBLIC_IPV4 = '74.9.8.38' + VALID_PRIVATE_IPV4 = '172.16.5.0' + VALID_IPV6_FULL = '2001:0db8:0000:0000:0000:8a2e:0370:7334' + VALID_IPV6_SIMPLIFIED = '2001:db8::8a2e:370:7334' + INVALID_IP_I = '67.2.6' + INVALID_IP_II = '123.276.4.1' + INVALID_IP_III = '124.89.7.65.1' + INVALID_IP_IV = 'random_string' + INVALID_IP_V = 99999 + + def test_for_get(self): + self.assert_for_valid_ip(self.VALID_PUBLIC_IPV4, 4) + self.assert_for_valid_ip(self.VALID_PRIVATE_IPV4, 4) + self.assert_for_valid_ip(self.VALID_IPV6_FULL, 6) + self.assert_for_valid_ip(self.VALID_IPV6_SIMPLIFIED, 6) + self.assert_for_invalid_ip(self.INVALID_IP_I) + self.assert_for_invalid_ip(self.INVALID_IP_II) + self.assert_for_invalid_ip(self.INVALID_IP_III) + self.assert_for_invalid_ip(self.INVALID_IP_IV) + self.assert_for_invalid_ip(self.INVALID_IP_V) + + def assert_for_valid_ip(self, ip, ipVersion): + res = self.get_response(ip) + + self.assertEqual(res.status_code, 200) + self.assertEqual(res.content, '{"ip version": %s}' % ipVersion) + + def assert_for_invalid_ip(self, ip): + res = self.get_response(ip) + + self.assertEqual(res.status_code, 200) + self.assertEqual(res.content, '{"ip": "invalid"}') + + # TODO: find example that can trigger this response + def assert_for_error_input(self, ip): + res = self.get_response(ip) + + self.assertEqual(res.status_code, 200) + self.assertEqual(res.content, '{"ip": "error"}') + + def get_response(self, ip): + url = '%sipranges/validateip/?ip=%s' % (serverUrl, ip) + + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + res = self.client.get(url) + + return res + +print "Running unit tests on IP range web services API........." + +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) \ No newline at end of file diff --git a/loggingapp/pyTests.py b/loggingapp/pyTests.py deleted file mode 100644 index 7b272afc..00000000 --- a/loggingapp/pyTests.py +++ /dev/null @@ -1,103 +0,0 @@ -#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. - -import django -import unittest -import sys, getopt -from unittest import TestCase -from party.models import Party -from partner.models import Partner -from loggingapp.models import PageView - -from loggingapp.testSamples import PageViewSample -from party.testSamples import PartySample -from partner.testSamples import PartnerSample -import requests -import json -from common.pyTests import PyTestGenerics, GenericCRUDTest, GenericTest - -from rest_framework import status - - -# Create your tests here. -django.setup() -serverUrl = PyTestGenerics.initPyTest() -print "using server url %s" % serverUrl - -# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- - -class PageViewCRUD(GenericCRUDTest, TestCase): - sample = PageViewSample(serverUrl) - partySample = PartySample(serverUrl) - - def setUp(self): - super(PageViewCRUD, self).setUp() - self.partyId = self.partySample.forcePost(self.partySample.data) - self.sample.data['partyId']=self.sample.updateData['partyId']=self.partyId - - # update and delete are not allowed in this CRUD - def test_for_update(self): - pass - - def test_for_delete(self): - pass - - def tearDown(self): - super(PageViewCRUD, self).tearDown() - PyTestGenerics.forceDelete(self.partySample.model, self.partySample.pkName, self.sample.data['partyId']) - -# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- - -class SessionCountViewTest(GenericTest, TestCase): - url = serverUrl + 'session-logs/sessions/counts/' - # sessionId, pageViewDate - sampleData = [ - (1, '1979-01-01T00:00:00Z'), - (1, '1980-01-01T00:00:00Z'), - (1, '1981-01-01T00:00:00Z'), - (1, '1982-01-01T00:00:00Z'), - (2, '1980-01-01T00:00:00Z'), - (3, '1980-01-01T00:00:00Z'), - (3, '1981-01-01T00:00:00Z'), - ] - pageViewIdList = [] - sample = PageViewSample(serverUrl) - partySample = PartySample(serverUrl) - def setUp(self): - super(SessionCountViewTest, self).setUp() - self.partyId = self.partySample.forcePost(self.partySample.data) - self.sample.data['partyId']=self.sample.updateData['partyId']=self.partyId - for entry in self.sampleData: - self.sample.data['sessionId'] = str(entry[0]) - self.sample.data['pageViewDate'] = entry[1] - self.pageViewIdList.append(self.sample.forcePost(self.sample.data)) - - def runTest(self, startDate, endDate, expectedCount): - url = self.url + '?apiKey=%s' % self.apiKey - if startDate: - url += '&startDate=%s' % startDate - if endDate: - url += '&endDate=%s' % endDate - cookies = {'apiKey':self.apiKey} - req = requests.get(url,cookies=cookies) - self.assertEqual(req.status_code, 200) - count = req.json()['count'] - self.assertEqual(count, expectedCount) - - def test_for_get(self): - self.runTest('1978-05-01T00:00:00Z', '1979-05-01T00:00:00Z', 1) #only sessionId 1 - self.runTest('1980-05-01T00:00:00Z', '1981-05-01T00:00:00Z', 2) #sessionId 1, 3 - self.runTest('1979-05-01T00:00:00Z', '1980-05-01T00:00:00Z', 3) #sessionId 1, 2, and 3 - - def tearDown(self): - super(SessionCountViewTest, self).setUp() - PyTestGenerics.forceDelete(self.partySample.model, self.partySample.pkName, self.sample.data['partyId']) - for entry in self.pageViewIdList: - PyTestGenerics.forceDelete(self.sample.model, self.sample.pkName, entry) - -print "Running unit tests on party web services API........." - -if __name__ == '__main__': - sys.argv[1:] = [] - unittest.main() - ret = not runner.run(suite).wasSuccessful() - sys.exit(ret) diff --git a/loggingapp/testSamples.py b/loggingapp/testSamples.py index 0f14c699..4b0fed5f 100644 --- a/loggingapp/testSamples.py +++ b/loggingapp/testSamples.py @@ -1,35 +1,45 @@ import django import unittest -import sys, getopt -from unittest import TestCase -from subscription.models import Subscription, SubscriptionTransaction +import sys +import copy from loggingapp.models import PageView from party.models import Party from partner.models import Partner -import requests -import json - -import copy -from common.pyTests import PyTestGenerics +from django.test import TestCase +from common.tests import TestGenericInterfaces -genericForcePost = PyTestGenerics.forcePost +genericForcePost = TestGenericInterfaces.forcePost class PageViewSample(): + SESSION_ID_I = '9A417B49536A8395936C4717E80E005C' + SESSION_ID_II = 'BC71B65BF137AD7924600A00D3F03C1C' + SESSION_ID_III = '51AD64E5EDEF1C59CAF5C30EFA2F4783' path = 'session-logs/page-views/' url = None + data = { - 'uri':'test123', + 'uri':'test_url_1', 'partyId':None, - 'pageViewDate':'2013-08-31T00:00:00Z', - 'sessionId':'abcdefg', + 'partnerId':None, + 'pageViewDate':'2018-08-31T00:00:00Z', + 'sessionId':SESSION_ID_I, 'ip':'123.45.67.8', + 'ipList':'111.11.22.1, 123.45.67.8', + 'isPaidContent':False, + 'meterStatus':PageView.METER_NOT_METERED_STATUS + } updateData = { - 'uri':'test234', + 'uri':'test_url_2', 'partyId':None, - 'pageViewDate':'2020-08-31T00:00:00Z', - 'sessionId':'efghijk', + 'partnerId':None, + 'pageViewDate':'2019-08-31T17:34:26Z', + 'sessionId':SESSION_ID_II, 'ip':'12.34.5.67', + 'ipList':'111.11.22.23, 123.45.67.8, 12.34.5.67', + 'isPaidContent':True, + 'meterStatus':PageView.METER_BLOCK_STATUS + } pkName = 'pageViewId' model = PageView @@ -40,6 +50,7 @@ def __init__(self, serverUrl): def forcePost(self,data): postData = copy.deepcopy(data) postData['partyId'] = Party.objects.get(partyId=data['partyId']) + postData['partnerId'] = Partner.objects.get(partnerId=data['partnerId']) return genericForcePost(self.model, self.pkName, postData) diff --git a/loggingapp/tests.py b/loggingapp/tests.py index 7ce503c2..9f9f386f 100644 --- a/loggingapp/tests.py +++ b/loggingapp/tests.py @@ -1,3 +1,101 @@ -from django.test import TestCase +#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. -# Create your tests here. +import django +import unittest +import sys, getopt +import json +import copy +from django.test import TestCase, Client +from partner.testSamples import PartnerSample +from party.testSamples import UserPartySample +from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest +from testSamples import PageViewSample +# Python 3: module Cookie -> http.cookies +from Cookie import SimpleCookie + +# Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() + +# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- + +# test for API end point /session-logs/page-views/ +class PageViewCRUD(GenericCRUDTest, TestCase): + sample = PageViewSample(serverUrl) + partySample = UserPartySample(serverUrl) + partnerSample = PartnerSample(serverUrl); + + def setUp(self): + super(PageViewCRUD, self).setUp() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + self.partyId = self.partySample.forcePost(self.partySample.data) + self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId + self.sample.data['partyId']=self.sample.updateData['partyId']=self.partyId + + # update and delete are not allowed in this CRUD + def test_for_update(self): + pass + + def test_for_delete(self): + pass + +# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- + +# test for API end point /session-logs/sessions/counts/ +class SessionCountViewTest(GenericTest, TestCase): + url = serverUrl + 'session-logs/sessions/counts/' + + # sessionId, pageViewDate + sampleData = [ + (PageViewSample.SESSION_ID_I, '1980-01-01T00:35:00Z'), + (PageViewSample.SESSION_ID_I, '1980-01-01T00:55:00Z'), + (PageViewSample.SESSION_ID_I, '1980-01-01T00:57:00Z'), + (PageViewSample.SESSION_ID_I, '1980-01-01T01:04:00Z'), + (PageViewSample.SESSION_ID_II, '1981-01-01T00:00:00Z'), + (PageViewSample.SESSION_ID_III, '1982-01-01T00:00:00Z'), + (PageViewSample.SESSION_ID_III, '1982-01-01T00:02:00Z'), + ] + pageViewIdList = [] + sample = PageViewSample(serverUrl) + partySample = UserPartySample(serverUrl) + partnerSample = PartnerSample(serverUrl) + + def setUp(self): + super(SessionCountViewTest, self).setUp() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + self.partyId = self.partySample.forcePost(self.partySample.data) + self.sample.data['partnerId']=self.partnerId + self.sample.data['partyId']=self.partyId + for entry in self.sampleData: + self.sample.data['sessionId'] = entry[0] + self.sample.data['pageViewDate'] = entry[1] + self.pageViewIdList.append(self.sample.forcePost(self.sample.data)) + + def test_for_get(self): + self.runTest('1979-05-01T00:00:00Z', '1980-05-01T00:00:00Z', 1) #only session I + self.runTest('1979-05-01T00:00:00Z', '1981-05-01T00:00:00Z', 2) #session I,II + self.runTest('1979-05-01T00:00:00Z', '1982-05-01T00:00:00Z', 3) #sessionId I, II and III + + def runTest(self, startDate, endDate, expectedCount): + url = self.url + '?apiKey=%s' % self.apiKey + if startDate: + url += '&startDate=%s' % startDate + if endDate: + url += '&endDate=%s' % endDate + + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + count = json.loads(res.content)['count'] + self.assertEqual(count, expectedCount) + +# skipped testing for /session-logs/page-views/csv/ since no external resource uses its + +print "Running unit tests on session logs web services API........." + +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) diff --git a/metering/pyTests.py b/metering/pyTests.py deleted file mode 100644 index f66f0a07..00000000 --- a/metering/pyTests.py +++ /dev/null @@ -1,130 +0,0 @@ -#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. - -import django -import unittest -import sys, getopt -from unittest import TestCase -from metering.models import IpAddressCount, LimitValue -from partner.models import Partner -import requests -import json -from testSamples import LimitValueSample, IpAddressCountSample -from partner.testSamples import PartnerSample -import copy -from common.pyTests import PyTestGenerics, GenericCRUDTest, GenericTest -from rest_framework import status - - -# Create your tests here. -django.setup() -serverUrl = PyTestGenerics.initPyTest() -print "using server url %s" % serverUrl - -# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- - -class IpAddressCountCRUD(GenericCRUDTest, TestCase): - - sample = IpAddressCountSample(serverUrl) - partnerSample = PartnerSample(serverUrl) - - def setUp(self): - super(IpAddressCountCRUD,self).setUp() - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.sample.partnerId=self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId - - def tearDown(self): - super(IpAddressCountCRUD,self).tearDown() - PyTestGenerics.forceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - -class LimitValueCRUD(GenericCRUDTest, TestCase): - - sample = LimitValueSample(serverUrl) - partnerSample = PartnerSample(serverUrl) - - def setUp(self): - super(LimitValueCRUD,self).setUp() - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.sample.partnerId=self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId - - def tearDown(self): - super(LimitValueCRUD,self).tearDown() - PyTestGenerics.forceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - -# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- - -class IncrementMeteringCountTest(GenericTest, TestCase): - ipAddressCountSample = IpAddressCountSample(serverUrl) - limitValueSample = LimitValueSample(serverUrl) - partnerSample = PartnerSample(serverUrl) - def setUp(self): - super(IncrementMeteringCountTest, self).setUp() - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.ipAddressCountSample.data['partnerId'] = self.partnerId - self.ipAddressCountSample.data['count'] = 1 - self.ipAddressCountId = self.ipAddressCountSample.forcePost(self.ipAddressCountSample.data) - self.limitValueSample.data['partnerId'] = self.partnerId - self.limitValueId = self.limitValueSample.forcePost(self.limitValueSample.data) - - def test_for_increment(self): - currentCount = self.ipAddressCountSample.data['count'] - url = '%smeters/ip/%s/increment/?partnerId=%s' % (serverUrl, self.ipAddressCountSample.data['ip'], self.partnerId) - cookies = {'apiKey':self.apiKey} - req = requests.post(url, cookies=cookies) - newCount = IpAddressCount.objects.get(id=self.ipAddressCountId).count - self.assertEqual(currentCount+1, newCount) - - def tearDown(self): - super(IncrementMeteringCountTest,self).tearDown() - PyTestGenerics.forceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - PyTestGenerics.forceDelete(self.ipAddressCountSample.model, self.ipAddressCountSample.pkName, self.ipAddressCountId) - PyTestGenerics.forceDelete(self.limitValueSample.model, self.limitValueSample.pkName, self.limitValueId) - -class CheckLimitTest(GenericTest, TestCase): - successIpAddressCountSample = IpAddressCountSample(serverUrl) - failIpAddressCountSample = IpAddressCountSample(serverUrl) - limitValueSample = LimitValueSample(serverUrl) - partnerSample = PartnerSample(serverUrl) - successIp = '123.45.6.7' - failIp = '123.45.6.8' - - def setUp(self): - super(CheckLimitTest, self).setUp() - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.successIpAddressCountSample.data['partnerId'] = self.partnerId - self.successIpAddressCountSample.data['count'] = 1 - self.successIpAddressCountSample.data['ip'] = self.successIp - self.successIpAddressCountId = self.successIpAddressCountSample.forcePost(self.successIpAddressCountSample.data) - self.failIpAddressCountSample.data['partnerId'] = self.partnerId - self.failIpAddressCountSample.data['ip'] = self.failIp - self.failIpAddressCountSample.data['count'] = 10000 - self.failIpAddressCountId = self.failIpAddressCountSample.forcePost(self.failIpAddressCountSample.data) - self.limitValueSample.data['partnerId'] = self.partnerId - self.limitValueId = self.limitValueSample.forcePost(self.limitValueSample.data) - - def test_for_check_limit(self): - url = '%smeters/ip/%s/limit/?partnerId=%s' % (serverUrl, self.successIp, self.partnerId) - cookies = {'apiKey':self.apiKey} - req = requests.get(url, cookies=cookies) - self.assertEqual(req.json()['status'], 'OK') - url = '%smeters/ip/%s/limit/?partnerId=%s' % (serverUrl, self.failIp, self.partnerId) - req = requests.get(url, cookies=cookies) - self.assertEqual(req.json()['status'], 'Block') - - def tearDown(self): - super(CheckLimitTest,self).tearDown() - PyTestGenerics.forceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - PyTestGenerics.forceDelete(self.successIpAddressCountSample.model, self.successIpAddressCountSample.pkName, self.successIpAddressCountId) - PyTestGenerics.forceDelete(self.failIpAddressCountSample.model, self.failIpAddressCountSample.pkName, self.failIpAddressCountId) - PyTestGenerics.forceDelete(self.limitValueSample.model, self.limitValueSample.pkName, self.limitValueId) - -print "Running unit tests on subscription web services API........." - -if __name__ == '__main__': - sys.argv[1:] = [] - unittest.main() - ret = not runner.run(suite).wasSuccessful() - sys.exit(ret) diff --git a/metering/testSamples.py b/metering/testSamples.py index f17f468b..ba458628 100644 --- a/metering/testSamples.py +++ b/metering/testSamples.py @@ -1,59 +1,118 @@ import django -import unittest -import sys, getopt -from unittest import TestCase -from metering.models import IpAddressCount, LimitValue +import copy +from metering.models import IpAddressCount, LimitValue, MeterBlacklist from partner.models import Partner -import requests -import json +from common.tests import TestGenericInterfaces -import copy -from common.pyTests import PyTestGenerics +genericForcePost = TestGenericInterfaces.forcePost + +class LimitValueSample(): + path = 'meters/limits/' + url = None + UNDER_LIMIT_VAL = 5 + WARNING_LIMIT_VAL = 10 + BLOCKING_LIMIT_VAL = 20 + INCREASE_BLOCKING_LIMIT_VAL = 30 + TYPE_WARNING = 'Warning' + TYPE_EXCEED = 'Block' + data = { + 'val': BLOCKING_LIMIT_VAL, + 'partnerId': None, + } + updateData = { + 'val': INCREASE_BLOCKING_LIMIT_VAL, + 'partnerId': None, + } + pkName = 'limitId' + model = LimitValue + + def __init__(self, serverUrl): + self.url = serverUrl+self.path + # create instance data + self.data = copy.deepcopy(self.data) + + def setLimitVal(self, val): + self.data['val'] = val + + def setPartnerId(self, partnerId): + self.data['partnerId'] = partnerId -genericForcePost = PyTestGenerics.forcePost + def forcePost(self,data): + postData = copy.deepcopy(data) + postData['partnerId'] = Partner.objects.get(partnerId=data['partnerId']) + return genericForcePost(self.model, self.pkName, postData) class IpAddressCountSample(): path = 'meters/' url = None + UNDER_LIMIT_IP = '123.45.6.7' + WARNING_HIT_IP = '123.45.6.8' + BLOCKING_HIT_IP = '123.45.6.9' data = { - 'ip':'123.45.6.7', - 'count':1, - 'partnerId':None, + 'ip': UNDER_LIMIT_IP, + 'count': LimitValueSample.UNDER_LIMIT_VAL, + 'partnerId': None, } updateData = { - 'ip':'123.45.6.7', - 'count':5, - 'partnerId':None, + 'ip': UNDER_LIMIT_IP, + 'count': LimitValueSample.BLOCKING_LIMIT_VAL, + 'partnerId': None, } pkName = 'id' model = IpAddressCount def __init__(self, serverUrl): self.url = serverUrl+self.path + self.data = copy.deepcopy(self.data) + + def setPartnerId(self, partnerId): + self.data['partnerId'] = partnerId + + def setCount(self, count): + self.data['count'] = count + + def setIp(self, ip): + self.data['ip'] = ip + + def getCount(self): + return self.data['count'] + + def getIp(self): + return self.data['ip'] def forcePost(self,data): postData = copy.deepcopy(data) postData['partnerId'] = Partner.objects.get(partnerId=data['partnerId']) return genericForcePost(self.model, self.pkName, postData) - -class LimitValueSample(): - path = 'meters/limits/' + +class MeterBlacklistSample(): + path = 'meters/meterblacklist/' url = None + UNBLOCKED_URI = 'test_uri_unblocked' + BLOCKED_URI = 'test_uri_blocked' + BLOCKED_URI_II = 'test_uri_blocked_II' data = { - 'val':8, - 'partnerId':None, + 'pattern': BLOCKED_URI, + 'partnerId': None } updateData = { - 'val':12, - 'partnerId':None, + 'pattern': BLOCKED_URI_II, + 'partnerId': None } - pkName = 'limitId' - model = LimitValue + pkName = 'meterBlackListId' + model = MeterBlacklist def __init__(self, serverUrl): self.url = serverUrl+self.path + self.data = copy.deepcopy(self.data) + + def setPartnerId(self, partnerId): + self.data['partnerId'] = partnerId + + def setPattern(self, pattern): + self.data['pattern'] = pattern def forcePost(self,data): postData = copy.deepcopy(data) - postData['partnerId'] = Partner.objects.get(partnerId=data['partnerId']) + # partnerId for MeterBlacklist model is not foreign key return genericForcePost(self.model, self.pkName, postData) diff --git a/metering/tests.py b/metering/tests.py index e6ec8d66..431c4151 100644 --- a/metering/tests.py +++ b/metering/tests.py @@ -1,114 +1,173 @@ -#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. - - - - - -from django.test import TestCase - -from .models import ipAddr -import requests -# Create your tests here. -serverUrl = 'http://52.4.106.144:8080/' -testIP = '786.786.786.786' - -class TestForIpAddr(TestCase): -# def test_for_getIPList(self): -# forcePostIP(testIP) -# req = requests.get(serverUrl+'meters/ip/') -# boolean = False -# for ips in req.json(): -# if ips['ip']==testIP: -# boolean = True -# self.assertEqual(boolean, True) -# forceDeleteIP(testIP) -# -# def test_for_getIPDetail(self): -# forcePostIP(testIP) -# req = requests.get(serverUrl+'meters/ip/'+testIP) -# self.assertEqual(req.status_code, 200) -# forceDeleteIP(testIP) - -# def test_for_deleteIP(self): -# forcePostIP(testIP) -# req = requests.delete(serverUrl+'/meters/ip/'+testIP) -# self.assertEqual(req.status_code, 204) - - def test_for_postIP(self): - data = {'ip': testIP} - req = requests.post(serverUrl+'meters/ip/', data=data) - self.assertEqual(req.status_code, 201) - ip = forceGetIP(testIP) - self.assertEqual(ip, not None) - self.assertEqual(ip.ip, testIP) - self.assertEqual(ip.count, 1) - forceDeleteIP(testIP) - -# def test_for_incrementIP(self): -# forcePostIP(testIP) -# req = requests.get(serverUrl+'/meters/ip/'+testIP+'/increment') -# self.assertEqual(req.status_code, 200) -# ip = forceGetIP(testIP) -# self.assertEqual(ip.count, 2) -# forceDeleteIP(testIP) - -# def test_for_atWarningLimit(self): -# forcePostIP(testIP) -# req = requests.get(serverUrl+'/meters/ip/'+testIP+'/atWarningLimit') -# self.assertEqual(req.json()['bool'], False) -# forceSetIP(testIP, 9) -# req = requests.get(serverUrl+'/meters/ip/'+testIP+'/atWarningLimit') -# self.assertEqual(req.json()['bool'],True) -# forceDeleteIP(testIP) -# -# def test_for_atMeteringLimit(self): -# forcePostIP(testIP) -# req = requests.get(serverUrl+'/meters/ip/'+testIP+'/atMeteringLimit') -# self.assertEqual(req.json()['bool'], False) -# forceSetIP(testIP, 11) -# req = requests.get(serverUrl+'/meters/ip/'+testIP+'/atMeteringLimit') -# self.assertEqual(req.json()['bool'],True) -# forceDeleteIP(testIP) - - -class TestForLimits(TestCase): - def test_for_getWarningLimit(self): - pass - - def test_for_getMeteringLimit(self): - pass - - def test_for_setWarningLimit(self): - pass - - def test_for_setMeteringLimit(self): - pass - - -#Auxillary functions -def forcePostIP(ip): - #try: - # ipAddr.objects.get(ip=ip) - #except: - u = ipAddr(ip=ip, count=1) - u.save() - -def forceDeleteIP(ip): - try: - u = ipAddr.objects.get(ip=ip) - u.delete() - except: - pass - -def forceGetIP(ip): - try: - u = ipAddr.objects.get(ip=ip) - return u - except: - return None - -def forceSetIP(ip, count): - u = ipAddr.objects.get(ip=ip) - u.count = count - u.save() +#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. +import django +import unittest +import sys, getopt +import json +import copy +from django.test import TestCase, Client +from metering.models import IpAddressCount, LimitValue +from partner.testSamples import PartnerSample +from partner.models import Partner +from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest +from testSamples import LimitValueSample, IpAddressCountSample, MeterBlacklistSample +# Python 3: module Cookie -> http.cookies +from Cookie import SimpleCookie + +# Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() + +# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- + +# test for API endpoint /meters/ +class IpAddressCountCRUD(GenericCRUDTest, TestCase): + + sample = IpAddressCountSample(serverUrl) + partnerSample = PartnerSample(serverUrl) + + def setUp(self): + super(IpAddressCountCRUD,self).setUp() + Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + self.sample.partnerId=self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId + +# test for API endpoint /meters/limits +class LimitValueCRUD(GenericCRUDTest, TestCase): + + sample = LimitValueSample(serverUrl) + partnerSample = PartnerSample(serverUrl) + + def setUp(self): + super(LimitValueCRUD,self).setUp() + Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + self.sample.partnerId=self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId + +# test for API endpoint /meters/meterblacklist/ +class MeterBlacklistCRUD(GenericCRUDTest, TestCase): + + sample = MeterBlacklistSample(serverUrl) + partnerSample = PartnerSample(serverUrl) + + def setUp(self): + super(MeterBlacklistCRUD,self).setUp() + Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + self.sample.partnerId=self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId + + +# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- + +# test for API endpoint /meters/ip//increment/ +class IncrementMeteringCountTest(GenericTest, TestCase): + client = Client() + + partnerSample = PartnerSample(serverUrl) + limitValueSample = LimitValueSample(serverUrl) + ipAddressCountSample = IpAddressCountSample(serverUrl) + + def setUp(self): + super(IncrementMeteringCountTest, self).setUp() + Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + + self.limitValueSample.setPartnerId(self.partnerId) + self.limitValueId = self.limitValueSample.forcePost(self.limitValueSample.data) + + self.ipAddressCountSample.setPartnerId(self.partnerId) + self.ipAddressCountSample.setIp(IpAddressCountSample.UNDER_LIMIT_IP) + self.ipAddressCountSample.setCount(LimitValueSample.UNDER_LIMIT_VAL) + self.ipAddressCountId = self.ipAddressCountSample.forcePost(self.ipAddressCountSample.data) + + def test_for_increment(self): + currentCount = self.ipAddressCountSample.getCount() + # cannot use reverse method since we have ip value in the middle of uri + url = '%smeters/ip/%s/increment/?partnerId=%s' % (serverUrl, self.ipAddressCountSample.getIp(), self.partnerId) + + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + res = self.client.post(url) + + newCount = IpAddressCount.objects.get(id=self.ipAddressCountId).count + self.assertEqual(currentCount+1, newCount) + +# test for API endpoint /meters/ip//limit/ +class CheckLimitTest(GenericTest, TestCase): + client = Client() + + partnerSample = PartnerSample(serverUrl) + + limitValueSampleWarning = LimitValueSample(serverUrl) + limitValueSampleExceed = LimitValueSample(serverUrl) + + successIpAddressCountSample = IpAddressCountSample(serverUrl) + limitWarningIpAddressCountSample = IpAddressCountSample(serverUrl) + limitBlockedIpAddressCountSample = IpAddressCountSample(serverUrl) + + meterBlacklistSample = MeterBlacklistSample(serverUrl) + + def setUp(self): + super(CheckLimitTest, self).setUp() + Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + + self.limitValueSampleWarning.setPartnerId(self.partnerId) + self.limitValueSampleWarning.setLimitVal(LimitValueSample.WARNING_LIMIT_VAL) + self.limitValueSampleWarning.forcePost(self.limitValueSampleWarning.data) + + self.limitValueSampleExceed.setPartnerId(self.partnerId) + self.limitValueSampleExceed.setLimitVal(LimitValueSample.BLOCKING_LIMIT_VAL) + self.limitValueSampleExceed.forcePost(self.limitValueSampleExceed.data) + + self.successIpAddressCountSample.setPartnerId(self.partnerId) + self.successIpAddressCountSample.setIp(IpAddressCountSample.UNDER_LIMIT_IP) + self.successIpAddressCountSample.setCount(LimitValueSample.UNDER_LIMIT_VAL) + self.successIpAddressCountSample.forcePost(self.successIpAddressCountSample.data) + + self.limitWarningIpAddressCountSample.setPartnerId(self.partnerId) + self.limitWarningIpAddressCountSample.setIp(IpAddressCountSample.WARNING_HIT_IP) + self.limitWarningIpAddressCountSample.setCount(LimitValueSample.WARNING_LIMIT_VAL) + self.limitWarningIpAddressCountSample.forcePost(self.limitWarningIpAddressCountSample.data) + + self.limitBlockedIpAddressCountSample.setPartnerId(self.partnerId) + self.limitBlockedIpAddressCountSample.setIp(IpAddressCountSample.BLOCKING_HIT_IP) + self.limitBlockedIpAddressCountSample.setCount(LimitValueSample.BLOCKING_LIMIT_VAL) + self.limitBlockedIpAddressCountSample.forcePost(self.limitBlockedIpAddressCountSample.data) + + self.meterBlacklistSample.setPartnerId(self.partnerId) + self.meterBlacklistSample.setPattern(MeterBlacklistSample.BLOCKED_URI) + self.meterBlacklistSample.forcePost(self.meterBlacklistSample.data) + + def test_for_check_limit(self): + uri = MeterBlacklistSample.UNBLOCKED_URI + # test for under limit + # cannot use reverse method since we have ip value in the middle of uri + url = '%smeters/ip/%s/limit/?partnerId=%s&uri=%s' % (serverUrl, self.successIpAddressCountSample.getIp(), self.partnerId, uri) + self.assert_check_limit(url, 'OK') + # test for hit limit warning + url = '%smeters/ip/%s/limit/?partnerId=%s&uri=%s' % (serverUrl, self.limitWarningIpAddressCountSample.getIp(), self.partnerId, uri) + self.assert_check_limit(url, 'Warning') + # test for over limit + url = '%smeters/ip/%s/limit/?partnerId=%s&uri=%s' % (serverUrl, self.limitBlockedIpAddressCountSample.getIp(), self.partnerId, uri) + self.assert_check_limit(url, 'Block') + + def assert_check_limit(self, url, status): + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + res = self.client.get(url) + if res.status_code == 200: + self.assertEqual(json.loads(res.content)['status'], status) + else: + self.fail('failed to run test, response code is %s' % res.status_code) + + def test_for_blacklisted_url(self): + uri = MeterBlacklistSample.BLOCKED_URI + url = '%smeters/ip/%s/limit/?partnerId=%s&uri=%s' % (serverUrl, self.successIpAddressCountSample.getIp(), self.partnerId, uri) + self.assert_check_limit(url, 'BlackListBlock') + +print "Running unit tests on metering web services API........." + +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) \ No newline at end of file diff --git a/nullservice/manualTests.py b/nullservice/manualTests.py new file mode 100644 index 00000000..6438616c --- /dev/null +++ b/nullservice/manualTests.py @@ -0,0 +1,30 @@ +import django +import unittest +import sys +import json + +from django.test import TestCase +from common.tests import TestGenericInterfaces, GenericTest +from Cookie import SimpleCookie + +# Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() + +# test for API end point /nullservice +class NullServiceTest(GenericTest, TestCase): + def test_for_get(self): + url = '%snullservice/' % (serverUrl) + + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + +print "Running unit tests on nullservice web services API........." + +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) \ No newline at end of file diff --git a/nullservice/tests.py b/nullservice/tests.py index 7ce503c2..d303c58c 100644 --- a/nullservice/tests.py +++ b/nullservice/tests.py @@ -1,3 +1,6 @@ from django.test import TestCase +from common.tests import ManualTest -# Create your tests here. +class NullServiceTest(ManualTest, TestCase): + path = "/nullservice/" + testMethodStr = "running ./manage.py test nullservice.manualTests" \ No newline at end of file diff --git a/partner/migrations/0015_partner_forgotusernametext.py b/partner/migrations/0015_partner_forgotusernametext.py index ffa6e9ad..50310f75 100644 --- a/partner/migrations/0015_partner_forgotusernametext.py +++ b/partner/migrations/0015_partner_forgotusernametext.py @@ -11,9 +11,4 @@ class Migration(migrations.Migration): ] operations = [ - migrations.AddField( - model_name='partner', - name='forgotUserNameText', - field=models.CharField(max_length=200, null=True), - ), ] diff --git a/partner/pyTests.py b/partner/pyTests.py deleted file mode 100644 index fed0cadd..00000000 --- a/partner/pyTests.py +++ /dev/null @@ -1,74 +0,0 @@ -#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. -import sys -import django -import unittest -from unittest import TestCase -from partner.models import Partner, PartnerPattern, SubscriptionTerm, SubscriptionDescription, SubscriptionDescriptionItem -import copy -from common.pyTests import PyTestGenerics, GenericCRUDTest, GenericTest -from testSamples import PartnerSample, PartnerPatternSample, SubscriptionTermSample, SubscriptionDescriptionSample, SubscriptionDescriptionItemSample -import requests - -initPyTest = PyTestGenerics.initPyTest -genericForceDelete = PyTestGenerics.forceDelete - -# Create your tests here. -django.setup() -serverUrl = initPyTest() - -print "using server url %s" % serverUrl - -class PartnerCRUD(GenericCRUDTest, TestCase): - sample = PartnerSample(serverUrl) - - def test_for_create(self): - Partner.objects.filter(partnerId=self.sample.data['partnerId']).delete() - super(PartnerCRUD, self).test_for_create() - - def test_for_getByUri(self): - partnerSample = PartnerSample(serverUrl) - Partner.objects.filter(partnerId=partnerSample.data['partnerId']).delete() - partnerId = partnerSample.forcePost(partnerSample.data) - - partnerPatternSample = PartnerPatternSample(serverUrl) - partnerPatternSample.data['partnerId'] = partnerId - partnerPatternId = partnerPatternSample.forcePost(partnerPatternSample.data) - url = self.sample.url + "?uri=%s" % (partnerPatternSample.data['sourceUri']) - cookies = {'apiKey':self.apiKey} - req = requests.get(url,cookies=cookies) - self.assertEqual(len(req.json()) > 0, True) - genericForceDelete(partnerPatternSample.model, partnerPatternSample.pkName, partnerPatternId) - genericForceDelete(partnerSample.model, partnerSample.pkName, partnerId) - -class PartnerPatternCRUD(GenericCRUDTest, TestCase): - sample = PartnerPatternSample(serverUrl) - partnerSample = PartnerSample(serverUrl) - def setUp(self): - super(PartnerPatternCRUD,self).setUp() - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.sample.partnerId=self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId - - def tearDown(self): - super(PartnerPatternCRUD,self).tearDown() - genericForceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - -class SubscriptionTermCRUD(GenericCRUDTest, TestCase): - sample = SubscriptionTermSample(serverUrl) - partnerSample = PartnerSample(serverUrl) - def setUp(self): - super(SubscriptionTermCRUD,self).setUp() - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.sample.partnerId=self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId - def tearDown(self): - super(SubscriptionTermCRUD,self).tearDown() - genericForceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - -print "Running unit tests on partner web services API........." - -if __name__ == '__main__': - sys.argv[1:] = [] - unittest.main() - ret = not runner.run(suite).wasSuccessful() - sys.exit(ret) diff --git a/partner/testSamples.py b/partner/testSamples.py index 9ac2132d..079ce852 100644 --- a/partner/testSamples.py +++ b/partner/testSamples.py @@ -1,12 +1,12 @@ import sys import django import unittest -from unittest import TestCase +from django.test import TestCase from partner.models import Partner, PartnerPattern, SubscriptionTerm, SubscriptionDescription, SubscriptionDescriptionItem import copy -from common.pyTests import PyTestGenerics +from common.tests import TestGenericInterfaces -genericForcePost = PyTestGenerics.forcePost +genericForcePost = TestGenericInterfaces.forcePost class PartnerSample(): url = None @@ -17,26 +17,24 @@ class PartnerSample(): 'logoUri':'randomuri.com', 'termOfServiceUri':'anotherrandomuri.com', 'description':'Genome database for the reference plant Arabidopsis thaliana', + 'resetPasswordEmailBody': 'Test Partner username: %s (%s). Your temp password is %s.' } updateData = { 'partnerId':'test', 'name':'testPartner2', - 'logoUri':'randomuri.com', - 'termOfServiceUri':'anotherrandomuri.com', - 'description':'Genome database for the reference plant Arabidopsis thaliana2', + 'logoUri':'randomuri2.com', + 'termOfServiceUri':'anotherrandomuri2.com', + 'description':'Updated description: Genome database for the reference plant Arabidopsis thaliana', } pkName = 'partnerId' model = Partner def __init__(self, serverUrl): self.url = serverUrl+self.path + self.data = copy.deepcopy(self.data) - #delete possible entries that we use as test case - try: - filters={self.pkName:self.data['patternId']} - self.model.objects.get(**filters).delete() - except: - pass + def setDifferentPartnerId(self): + self.data['partnerId'] = 'test2' def forcePost(self,data): return genericForcePost(self.model, self.pkName, data) @@ -46,13 +44,13 @@ class PartnerPatternSample(): path = 'partners/patterns/' data = { 'partnerId':None, - 'sourceUri':'https://paywall2.steveatgetexp.com', - 'targetUri':'https://back-prod.steveatgetexp.com', + 'sourceUri':'https://www.arabidopsis.org', + 'targetUri':'https://back-prod.arabidopsis.org', } updateData = { 'partnerId':None, - 'sourceUri':'https://paywall2a.steveatgetexp.com', - 'targetUri':'https://back-prod.steveatgetexp.com', + 'sourceUri':'https://uat.arabidopsis.org', + 'targetUri':'https://back-uat.arabidopsis.org', } pkName = 'partnerPatternId' model = PartnerPattern @@ -71,15 +69,15 @@ class SubscriptionTermSample(): data = { 'partnerId':None, 'period':180, - 'price':360.00, - 'groupDiscountPercentage':0.7, + 'price':180.00, + 'groupDiscountPercentage': 1.5, 'description':'test' } updateData = { 'partnerId':None, 'period':365, - 'price':180.00, - 'groupDiscountPercentage':0.8, + 'price':360.00, + 'groupDiscountPercentage': 2.5, 'description':'test2' } pkName = 'subscriptionTermId' @@ -88,6 +86,9 @@ class SubscriptionTermSample(): def __init__(self, serverUrl): self.url = serverUrl+self.path + def setPartnerId(self, partnerId): + self.data['partnerId'] = partnerId + def forcePost(self,data): postData = copy.deepcopy(data) postData['partnerId'] = Partner.objects.get(partnerId=data['partnerId']) @@ -97,14 +98,14 @@ class SubscriptionDescriptionSample(): url = None path = 'partners/descriptions/' data = { + 'partnerId':None, 'header':'Commercial Description', 'descriptionType':'Commercial', - 'partnerId':None, } updateData = { - 'header':'Commercial Description2', - 'descriptionType':'Institution', 'partnerId':None, + 'header':'Institution Description', + 'descriptionType':'Institution', } pkName = 'subscriptionDescriptionId' model = SubscriptionDescription @@ -121,10 +122,12 @@ class SubscriptionDescriptionItemSample(): url = None path = 'partners/descriptionItems/' data = { - 'subscriptionDescriptionId':None, + 'subscriptionDescriptionId': None, + 'text': 'Benefit' } updateData = { - 'subscriptionDescriptionId':None, + 'subscriptionDescriptionId': None, + 'text': 'Updated Benefit' } pkName = 'subscriptionDescriptionItemId' model = SubscriptionDescriptionItem @@ -134,5 +137,5 @@ def __init__(self, serverUrl): def forcePost(self,data): postData = copy.deepcopy(data) - postData['subscriptionDescritpionId'] = SubscriptionDescription.objects.get(subscriptionDescriptionId=data['subscriptionDescriptionId']) - return genericForcePost(self.model, self.pkName, postData) + postData['subscriptionDescriptionId'] = SubscriptionDescription.objects.get(subscriptionDescriptionId=data['subscriptionDescriptionId']) + return genericForcePost(self.model, self.pkName, postData) \ No newline at end of file diff --git a/partner/tests.py b/partner/tests.py index 7ce503c2..eb7b2366 100644 --- a/partner/tests.py +++ b/partner/tests.py @@ -1,3 +1,86 @@ -from django.test import TestCase +#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. +import sys +import django +import unittest +import copy +import json +from django.test import TestCase, Client +from partner.models import Partner, PartnerPattern, SubscriptionTerm, SubscriptionDescription, SubscriptionDescriptionItem +from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericGETOnlyTest, checkMatch +from testSamples import PartnerSample, PartnerPatternSample, SubscriptionTermSample, SubscriptionDescriptionSample, SubscriptionDescriptionItemSample -# Create your tests here. +# Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() + +# test for API end point /partners/ +class PartnerCRUD(GenericGETOnlyTest, TestCase): + sample = PartnerSample(serverUrl) + +# test for API end point /partners/patterns/ +class PartnerPatternCRUD(GenericCRUDTest, TestCase): + sample = PartnerPatternSample(serverUrl) + partnerSample = PartnerSample(serverUrl) + + def setUp(self): + super(PartnerPatternCRUD,self).setUp() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId + + # cannot perform get all since for GET action sourceUri is required + def test_for_get_all(self): + pass + + def test_for_get(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = sample.url + '?%s=%s' % ('sourceUri', sample.data['sourceUri']) + + # no cookie needed + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + self.assertEqual(checkMatch(sample.data, json.loads(res.content), sample.pkName, pk), True) + + +# test for API end point /partners/terms/ +class SubscriptionTermCRUD(GenericGETOnlyTest, TestCase): + sample = SubscriptionTermSample(serverUrl) + partnerSample = PartnerSample(serverUrl) + + def setUp(self): + super(SubscriptionTermCRUD,self).setUp() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId + +# test for API end point /partners/descriptions/ +# TODO: test for case when GET request is sent with includeText param +class SubscriptionDescriptionCRUD(GenericGETOnlyTest, TestCase): + sample = SubscriptionDescriptionSample(serverUrl) + partnerSample = PartnerSample(serverUrl) + + def setUp(self): + super(SubscriptionDescriptionCRUD,self).setUp() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId + +# test for API end point /partners/descriptionItems/ +class SubscriptionDescriptionItemCRUD(GenericCRUDTest, TestCase): + sample = SubscriptionDescriptionItemSample(serverUrl) + partnerSample = PartnerSample(serverUrl) + descriptionSample = SubscriptionDescriptionSample(serverUrl) + + def setUp(self): + super(SubscriptionDescriptionItemCRUD,self).setUp() + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + self.descriptionSample.data['partnerId']=self.partnerId + self.descriptionId = self.descriptionSample.forcePost(self.descriptionSample.data) + self.sample.data['subscriptionDescriptionId']=self.sample.updateData['subscriptionDescriptionId']=self.descriptionId + +print "Running unit tests on partner web services API........." + +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) diff --git a/party/manualTests.py b/party/manualTests.py new file mode 100644 index 00000000..7db7287e --- /dev/null +++ b/party/manualTests.py @@ -0,0 +1,47 @@ +import django +import unittest +import sys +import json +from django.test import TestCase +from testSamples import UsageSample +from django.core.mail import send_mail + +# test for API end point /parties/usage/ +# API used for requesting usage for consortiums/institutions +class GetUsageRequestTest(TestCase): + sample = UsageSample() + + def test_for_send_usage_request(self): + self.send_usage_email(self.sample.institutionData) + self.send_usage_email(self.sample.consortiumData) + + # this code is copied from party/views.py implementation + def send_usage_email(self, data): + partyName = '' + partyTypeName = '' + if data['institution']: + partyName = data['institution'] + partyTypeName = 'Institution' + elif data['consortium']: + partyName = data['consortium'] + partyTypeName = 'Consortium' + subject = "%s Usage Request For %s" % (partyTypeName,partyName) + message = "Partner: %s\n" \ + "%s: %s\n" \ + "User: %s\n" \ + "Email: %s\n" \ + "Start date: %s\n" \ + "End date: %s\n" \ + "Comments: %s\n" \ + % (data['partner'], partyTypeName, partyName, data['name'], data['email'], data['startDate'], data['endDate'], data['comments']) + from_email = "subscriptions@phoenixbioinformatics.org" + recipient_list = [self.sample.RECEIPIENT_EMAIL] + self.assertEqual(send_mail(subject=subject, message=message, from_email=from_email, recipient_list=recipient_list, fail_silently=False), 1) + +print "Running unit tests on consortium usage email request........." + +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) \ No newline at end of file diff --git a/party/pyTests.py b/party/pyTests.py deleted file mode 100644 index a2c13631..00000000 --- a/party/pyTests.py +++ /dev/null @@ -1,69 +0,0 @@ -#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. - -import django -import unittest -import sys, getopt -from unittest import TestCase -from models import Party, IpRange -import requests -import json -from testSamples import PartySample, IpRangeSample, PartyAffiliationSample -from common.pyTests import PyTestGenerics, GenericCRUDTest, GenericTest - - -# Create your tests here. -django.setup() -serverUrl = PyTestGenerics.initPyTest() -print "using server url %s" % serverUrl - -# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- - -class PartyCRUD(GenericCRUDTest, TestCase): - sample = PartySample(serverUrl) - -class IpRangeCRUD(GenericCRUDTest, TestCase): - sample = IpRangeSample(serverUrl) - partySample = PartySample(serverUrl) - - def setUp(self): - super(IpRangeCRUD,self).setUp() - partyId = self.partySample.forcePost(self.partySample.data) - self.sample.data['partyId']=self.sample.updateData['partyId']=partyId - - def tearDown(self): - super(IpRangeCRUD,self).tearDown() - PyTestGenerics.forceDelete(self.partySample.model, self.partySample.pkName, self.sample.data['partyId']) - -class PartyAffiliationCRUD(GenericCRUDTest, TestCase): - sample = PartyAffiliationSample(serverUrl) - - def setUp(self): - pass - - def test_for_update(self): - pass - - def test_for_get(self): - pass - - def test_for_get_all(self): - pass - - def test_for_create(self): - pass - - def test_for_delete(self): - pass - - def tearDown(self): - pass - -# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- - -print "Running unit tests on party web services API........." - -if __name__ == '__main__': - sys.argv[1:] = [] - unittest.main() - ret = not runner.run(suite).wasSuccessful() - sys.exit(ret) diff --git a/party/testSamples.py b/party/testSamples.py index 94bb63b2..c5dd7413 100644 --- a/party/testSamples.py +++ b/party/testSamples.py @@ -1,25 +1,49 @@ import django import unittest -import sys, getopt +import sys +import copy from unittest import TestCase -from party.models import Party, IpRange, PartyAffiliation +from party.models import Country, Party, IpRange, PartyAffiliation, ImageInfo from partner.models import Partner +from common.tests import TestGenericInterfaces +from datetime import datetime, timedelta -import copy -from common.pyTests import PyTestGenerics +genericForcePost = TestGenericInterfaces.forcePost + +class CountrySample(): + path = 'parties/countries/' + url = None + data = { + 'name': 'United States' + } + updateData = { + 'name': 'China' + } + pkName = 'countryId' + model = Country + + def __init__(self, serverUrl): + self.url = serverUrl+self.path -genericForcePost = PyTestGenerics.forcePost + def getName(self): + return self.data['name'] -class PartySample(): + def forcePost(self,data): + return genericForcePost(self.model, self.pkName, data) + +class UserPartySample(): path = 'parties/' url = None + PARTY_TYPE_USER = 'user' + PARTY_TYPE_STAFF = 'staff' + PARTY_TYPE_ADMIN = 'admin' data = { - 'partyType':'user', - 'name':'test', + 'partyType':PARTY_TYPE_USER, + 'name':'test_user', } updateData = { - 'partyType':'organization', - 'name':'test1', + 'partyType':PARTY_TYPE_USER, + 'name':'test_user_II', } pkName = 'partyId' model = Party @@ -30,21 +54,102 @@ def __init__(self, serverUrl): def forcePost(self,data): return genericForcePost(self.model, self.pkName, data) -# TODO add sample for IPv6 tests +class OrganizationPartySample(): + path = 'parties/' + url = None + PARTY_TYPE_ORG = 'organization' + data = { + 'partyType':PARTY_TYPE_ORG, + 'name':'test_organization', + 'display': True, + 'country': None, + 'label': 'Test Organization Label' + } + updateData = { + 'partyType':PARTY_TYPE_ORG, + 'name':'test_organization_II', + 'display': False, + 'country': None, + 'label': 'Test Organization Label II' + } + pkName = 'partyId' + model = Party + + def __init__(self, serverUrl): + self.url = serverUrl+self.path + + def getName(self): + return self.data['name'] + + def getPartyType(self): + return self.data['partyType'] + + def setCountry(self, countryId): + self.data['country'] = countryId + + def forcePost(self,data): + postData = copy.deepcopy(data) + postData['country'] = Country.objects.get(countryId=data['country']) + return genericForcePost(self.model, self.pkName, postData) + +class InstitutionPartySample(OrganizationPartySample): + path = 'parties/institutions/' + +class ConsortiumPartySample(): + path = 'parties/consortiums/' + url = None + PARTY_TYPE_CONSORTIUM = 'consortium' + data = { + 'partyType':PARTY_TYPE_CONSORTIUM, + 'name':'test_consortium', + 'display': True, + 'country': None, + 'label': 'Test Consortium Label' + } + updateData = { + 'partyType':PARTY_TYPE_CONSORTIUM, + 'name':'test_consortium_II', + 'display': False, + 'country': None, + 'label': 'Test Consortium Label II' + } + pkName = 'partyId' + model = Party + + def __init__(self, serverUrl): + self.url = serverUrl+self.path + + def setCountry(self, countryId): + self.data['country'] = countryId + + def getName(self): + return self.data['name'] + + def getPartyType(self): + return self.data['partyType'] + + def forcePost(self,data): + postData = copy.deepcopy(data) + postData['country'] = Country.objects.get(countryId=data['country']) + return genericForcePost(self.model, self.pkName, postData) + +# TODO: add sample for IPv6 tests +# TODO: test for 'ip range too large' type of IP ranges - API needs to be +# updated. Should not throw unwrapped error class IpRangeSample(): path = 'parties/ipranges/' url = None data = { - 'start':'120.0.0.0', - 'end':'120.255.255.255', - 'partyId':1, - 'label': 'testlabel', + 'start':'120.10.20.0', + 'end':'120.10.22.255', + 'partyId': None, + 'label': 'test_label', } updateData = { - 'start':'120.0.0.0', - 'end':'120.255.211.200', - 'partyId':1, - 'label': 'labeltest', + 'start':'120.10.20.0', + 'end':'120.10.23.80', + 'partyId': None, + 'label': 'test_label_II', } pkName = 'ipRangeId' model = IpRange @@ -52,6 +157,18 @@ class IpRangeSample(): def __init__(self, serverUrl): self.url = serverUrl+self.path + def setPartyId(self, partyId): + self.data['partyId'] = partyId + + def getPartyId(self): + return self.data['partyId'] + + def getInRangeIp(self): + return '120.10.21.231' + + def getOutRangeIp(self): + return '133.1.8.52' + def forcePost(self,data): postData = copy.deepcopy(data) postData['partyId'] = Party.objects.get(partyId=data['partyId']) @@ -61,14 +178,82 @@ class PartyAffiliationSample(): path = 'parties/affiliations/' url = None data = { - 'parentPartyId': Party.objects.all().get(partyId=33342), - 'childPartyId' : Party.objects.all().get(partyId=33343), + 'parentPartyId': None, + 'childPartyId' : None, } pkName = 'partyAffiliationId'; model = PartyAffiliation + def __init__(self, serverUrl): self.url = serverUrl+self.path + def setParentId(self, parentPartyId): + self.data['parentPartyId'] = parentPartyId + + def getParentId(self): + return self.data['parentPartyId'] + + def setChildId(self, childPartyId): + self.data['childPartyId'] = childPartyId + + def getChildId(self): + return self.data['childPartyId'] + def forcePost(self,data): - return genericForcePost(self.model, self.pkName, data) + postData = copy.deepcopy(data) + postData['parentPartyId'] = Party.objects.get(partyId=data['parentPartyId']) + postData['childPartyId'] = Party.objects.get(partyId=data['childPartyId']) + return genericForcePost(self.model, self.pkName, postData) + +class ImageInfoSample(): + data = { + 'partyId': None, + 'name' : 'Test Organization', + 'imageUrl': 'somerandomurl' + } + pkName = 'imageInfoId'; + model = ImageInfo + + def setPartyId(self, partyId): + self.data['partyId'] = partyId + def getName(self): + return self.data['name'] + + def getImageUrl(self): + return self.data['imageUrl'] + + def forcePost(self,data): + postData = copy.deepcopy(data) + postData['partyId'] = Party.objects.get(partyId=data['partyId']) + return genericForcePost(self.model, self.pkName, postData) + +class UsageSample(): + PARTNER = 'phoenix' + COMMENTS = 'Please send us the usage data' + NUM_DAYS_DELTA = 90 + RECEIPIENT_EMAIL = 'xingguo.chen@arabidopsis.org' + startDateObj = datetime.today() - timedelta(days=NUM_DAYS_DELTA) + startDate = startDateObj.strftime('%b %d, %Y') + endDateObj = datetime.today() + endDate = endDateObj.strftime('%b %d, %Y') + institutionData = { + 'institution': 'University of Mars', + 'consortium': None, + 'name': 'Science Library', + 'partner': PARTNER, + 'email': 'science@umars.edu', + 'startDate': startDate, + 'endDate': endDate, + 'comments': COMMENTS + } + consortiumData = { + 'institution': None, + 'consortium': 'Galaxy University Association', + 'name': 'Central Library', + 'partner': PARTNER, + 'email': 'library@gua.edu', + 'startDate': startDate, + 'endDate': endDate, + 'comments': COMMENTS + } diff --git a/party/tests.py b/party/tests.py index 7ce503c2..2664d2a7 100644 --- a/party/tests.py +++ b/party/tests.py @@ -1,3 +1,519 @@ -from django.test import TestCase +#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. +import django +import unittest +import sys +import json +import copy +from django.test import TestCase, Client +from testSamples import CountrySample, UserPartySample, OrganizationPartySample, InstitutionPartySample, ConsortiumPartySample, IpRangeSample, PartyAffiliationSample +from partner.testSamples import PartnerSample +from subscription.testSamples import SubscriptionSample +from authentication.testSamples import CredentialSample +from common.tests import TestGenericInterfaces, GenericGETOnlyTest, GenericCRUDTest, LoginRequiredGETOnlyTest, LoginRequiredCRUDTest, LoginRequiredTest, ManualTest, checkMatch +# Python 3: module Cookie -> http.cookies +from Cookie import SimpleCookie -# Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() + +# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- + +# test for API end point /parties with party type user +# TODO: test for party type staff, admin as well +class UserPartyCRUDTest(LoginRequiredCRUDTest, TestCase): + sample = UserPartySample(serverUrl) + + def test_for_get_all(self): + # get all by type + url = self.getUrl(self.sample.url, 'partyType', self.sample.PARTY_TYPE_USER) + self.getAllHelper(url, 'partyId', self.credentialId) + +# test for API end point /parties with party type organization +# TODO: test for party type consortium +class OrganizationPartyCRUDTest(LoginRequiredCRUDTest, TestCase): + sample = OrganizationPartySample(serverUrl) + countrySample = CountrySample(serverUrl) + + def setUp(self): + super(OrganizationPartyCRUDTest,self).setUp() + countryId = self.countrySample.forcePost(self.countrySample.data) + self.sample.data['country']=self.sample.updateData['country']=countryId + + def test_for_get_all(self): + # get all by type + url = self.getUrl(self.sample.url, 'partyType', self.sample.PARTY_TYPE_ORG) + self.getAllHelper(url) + +# test for API end point /parties/countries +class CountryGETOnlyTest(GenericGETOnlyTest, TestCase): + sample = CountrySample(serverUrl) + + # only method is test_for_get_all + def test_for_get(self): + pass + +# test for API end point /parties/ipranges/ +class IpRangeCRUDTest(LoginRequiredCRUDTest, TestCase): + sample = IpRangeSample(serverUrl) + partySample = OrganizationPartySample(serverUrl) + countrySample = CountrySample(serverUrl) + partyId = None + + def setUp(self): + super(IpRangeCRUDTest,self).setUp() + countryId = self.countrySample.forcePost(self.countrySample.data) + self.partySample.data['country']=countryId + self.partyId = self.partySample.forcePost(self.partySample.data) + self.sample.data['partyId']=self.sample.updateData['partyId']=self.partyId + + def test_for_get(self): + pass + + def getUrl(self, url, pkName = None, pk = None): + # need partyId for filter + fullUrl = super(IpRangeCRUDTest,self).getUrl(url, pkName, pk) + '&%s=%s' % ('partyId', self.partyId) + return fullUrl + +# test for API end point /parties/consortiums/ +# returns consortium info and associated credential info +class ConsortiumPartyCRUDTest(LoginRequiredCRUDTest, TestCase): + sample = ConsortiumPartySample(serverUrl) + partnerId = None + + def setUp(self): + super(ConsortiumPartyCRUDTest,self).setUp() + + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + self.sample.data['country']=self.sample.updateData['country']=countryId + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + + + def test_for_get(self): + sample = self.sample + # note this should not override the parent credential sample used for login + # so use a different name + consortiumCredentialSample = self.initForcePostConsortiumCredentialSample(serverUrl) + pk = self.forcePostConsortiumItem(consortiumCredentialSample) + + url = self.getUrl(sample.url, sample.pkName, pk) + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + + resObj = json.loads(res.content) + self.assertConsortiumItem(sample.data, consortiumCredentialSample.data, consortiumCredentialSample, resObj, sample.pkName, pk) + self.assertEqual(resObj[0]['hasIpRange'], False) + + # test for case where ip range is associated + ipRangeSample = IpRangeSample(serverUrl) + ipRangeSample.data['partyId'] = pk + ipRangeSample.forcePost(ipRangeSample.data) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + + resObj = json.loads(res.content) + self.assertEqual(resObj[0]['hasIpRange'], True) + + + def test_for_get_all(self): + pass + + # API end point requires to create consortium and its user together + def test_for_create(self): + sample = self.sample + consortiumCredentialSample = CredentialSample(serverUrl) + consortiumCredentialSample.data['partnerId'] = self.partnerId + postData = self.composeConsortiumPostData(sample.data, consortiumCredentialSample.data) + + url = self.getUrl(sample.url) + res = self.client.post(url, postData) + + self.assertEqual(res.status_code, 201) + resObj = json.loads(res.content) + pk = resObj[0][sample.pkName] + # manipulate sample data to match the test condition + consortiumCredentialSample.data['partyId'] = pk + self.assertConsortiumItem(sample.data, consortiumCredentialSample.data, consortiumCredentialSample, resObj, sample.pkName, pk) + + def test_for_update(self): + sample = self.sample + consortiumCredentialSample = self.initForcePostConsortiumCredentialSample(serverUrl) + pk = self.forcePostConsortiumItem(consortiumCredentialSample) + + # create put data with both party update data and credential update data + putData = self.composeConsortiumPostData(sample.updateData, consortiumCredentialSample.updateData) + + url = self.getUrl(sample.url, sample.pkName, pk) + + # the default content type for put is 'application/octet-stream' + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + # manipulate sample update data to match the test condition + self.assertConsortiumItem(sample.updateData, consortiumCredentialSample.updateData, consortiumCredentialSample, resObj, sample.pkName, pk) + + def initForcePostConsortiumCredentialSample(self, serverUrl): + consortiumCredentialSample = CredentialSample(serverUrl) + + consortiumCredentialSample.data['partnerId'] = consortiumCredentialSample.updateData['partnerId'] = self.partnerId + return consortiumCredentialSample + + # alternative method is to post data by call create API + def forcePostConsortiumItem(self, consortiumCredentialSample): + sample = self.sample + pk = sample.forcePost(sample.data) + + consortiumCredentialSample.data['partyId'] = consortiumCredentialSample.updateData['partyId'] = pk + consortiumCredentialSample.forcePost(consortiumCredentialSample.data) + + return pk + + # create post/put data with both consortium data and credential data + def composeConsortiumPostData(self, consortiumSampleData, consortiumCredentialSampleData): + postData = copy.deepcopy(consortiumSampleData) + + for key in consortiumCredentialSampleData: + if consortiumCredentialSampleData[key] is not None: + postData[key] = consortiumCredentialSampleData[key] + + return postData + + def assertConsortiumItem(self, consortiumSampleData, consortiumCredentialSampleData, consortiumCredentialSample, resObj, pkName, pk): + self.assertEqual(checkMatch(consortiumSampleData, resObj[0], pkName, pk), True) + # manipulate sample data to match the test condition + consortiumCredentialSampleData['password'] = consortiumCredentialSample.hashPassword(consortiumCredentialSampleData['password']) + self.assertEqual(checkMatch(consortiumCredentialSampleData, resObj[1], pkName, pk), True) + +# test for API end point /parties/institutions/ +# returns organization info and associated credential info +# difference between this API and /parties API is this API will include +# affliated consortium info and credential info +class InstitutionPartyCRUDTest(LoginRequiredCRUDTest, TestCase): + sample = InstitutionPartySample(serverUrl) + partnerId = None + consortiumPartyId = None + + def setUp(self): + super(InstitutionPartyCRUDTest,self).setUp() + consortiumSample = ConsortiumPartySample(serverUrl) + + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + self.sample.data['country']=self.sample.updateData['country']=countryId + consortiumSample.data['country']=countryId + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + + self.consortiumPartyId = consortiumSample.forcePost(consortiumSample.data) + + def test_for_get(self): + sample = self.sample + # note this should not override the parent credential sample used for login + # so use a different name + institutionCredentialSample = self.initForcePostInstitutionCredentialSample(serverUrl) + pk = self.forcePostInstitutionItem(institutionCredentialSample) + + url = self.getUrl(sample.url, sample.pkName, pk) + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + + resObj = json.loads(res.content) + self.assertInstitutionItem(sample.data, institutionCredentialSample.data, institutionCredentialSample, resObj, sample.pkName, pk) + self.assertEqual(resObj[0]['hasIpRange'], False) + self.assertEqual(resObj[0]['consortiums'][0], self.consortiumPartyId) + + # test for case where ip range is associated + ipRangeSample = IpRangeSample(serverUrl) + ipRangeSample.data['partyId'] = pk + ipRangeSample.forcePost(ipRangeSample.data) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + + resObj = json.loads(res.content) + self.assertEqual(resObj[0]['hasIpRange'], True) + + + def test_for_get_all(self): + pass + + # API end point requires to create consortium and its user together + def test_for_create(self): + sample = self.sample + institutionCredentialSample = CredentialSample(serverUrl) + institutionCredentialSample.data['partnerId'] = self.partnerId + postData = self.composeInstitutionPostData(sample.data, institutionCredentialSample.data) + + url = self.getUrl(sample.url) + res = self.client.post(url, postData) + + self.assertEqual(res.status_code, 201) + resObj = json.loads(res.content) + pk = resObj[0][sample.pkName] + # manipulate sample data to match the test condition + institutionCredentialSample.data['partyId'] = pk + self.assertInstitutionItem(sample.data, institutionCredentialSample.data, institutionCredentialSample, resObj, sample.pkName, pk) + + def test_for_update(self): + sample = self.sample + institutionCredentialSample = self.initForcePostInstitutionCredentialSample(serverUrl) + pk = self.forcePostInstitutionItem(institutionCredentialSample) + + # create put data with both party update data and credential update data + putData = self.composeInstitutionPostData(sample.updateData, institutionCredentialSample.updateData) + + url = self.getUrl(sample.url, sample.pkName, pk) + + # the default content type for put is 'application/octet-stream' + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + self.assertInstitutionItem(sample.updateData, institutionCredentialSample.updateData, institutionCredentialSample, resObj, sample.pkName, pk) + + def initForcePostInstitutionCredentialSample(self, serverUrl): + institutionCredentialSample = CredentialSample(serverUrl) + + institutionCredentialSample.data['partnerId'] = institutionCredentialSample.updateData['partnerId'] = self.partnerId + + return institutionCredentialSample + + # alternative method is to post data by call create API + def forcePostInstitutionItem(self, institutionCredentialSample): + sample = self.sample + pk = sample.forcePost(sample.data) + + institutionCredentialSample.data['partyId'] = institutionCredentialSample.updateData['partyId'] = pk + institutionCredentialSample.forcePost(institutionCredentialSample.data) + + partyAffiliationSample = PartyAffiliationSample(serverUrl) + partyAffiliationSample.setParentId(self.consortiumPartyId) + partyAffiliationSample.setChildId(pk) + partyAffiliationSample.forcePost(partyAffiliationSample.data) + + return pk + + # create post/put data with both consortium data and credential data + def composeInstitutionPostData(self, institutionSampleData, institutionCredentialSampleData): + postData = copy.deepcopy(institutionSampleData) + + for key in institutionCredentialSampleData: + if institutionCredentialSampleData[key] is not None: + postData[key] = institutionCredentialSampleData[key] + + return postData + + def assertInstitutionItem(self, institutionSampleData, institutionCredentialSampleData, institutionCredentialSample, resObj, pkName, pk): + self.assertEqual(checkMatch(institutionSampleData, resObj[0], pkName, pk), True) + # manipulate sample data to match the test condition + institutionCredentialSampleData['password'] = institutionCredentialSample.hashPassword(institutionCredentialSampleData['password']) + self.assertEqual(checkMatch(institutionCredentialSampleData, resObj[1], pkName, pk), True) + +# test for end point /parties/affiliations/ +# get_all and update methods unavailable, all available methods need to be override +# so no need to inherit from LoginRequiredCRUDTest +class PartyAffiliationCRUDTest(LoginRequiredTest, TestCase): + sample = PartyAffiliationSample(serverUrl) + parentPartySample = ConsortiumPartySample(serverUrl) + childPartySample = InstitutionPartySample(serverUrl) + + def setUp(self): + super(PartyAffiliationCRUDTest,self).setUp() + + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + self.parentPartySample.data['country']=self.childPartySample.data['country']=countryId + + parentPartyId = self.parentPartySample.forcePost(self.parentPartySample.data) + childPartyId = self.childPartySample.forcePost(self.childPartySample.data) + + self.sample.setParentId(parentPartyId) + self.sample.setChildId(childPartyId) + + def test_for_get(self): + sample = self.sample + sample.forcePost(sample.data) + + parentPartyId = sample.getParentId() + parentPartyType = self.parentPartySample.getPartyType() + + childPartyId = sample.getChildId() + childPartyType = self.childPartySample.getPartyType() + + # get by consortium (parent organization) + url = self.getUrl(sample.url) + url = '%s&partyId=%s&partyType=%s' % (url, parentPartyId, parentPartyType) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + self.assertEqual(checkMatch(self.childPartySample.data, resObj, 'partyId', childPartyId), True) + self.assertEqual(resObj[0]['consortiums'][0], parentPartyId) + + # get by institution (child organization) + url = self.getUrl(sample.url) + url = '%s&partyId=%s&partyType=%s' % (url, childPartyId, childPartyType) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + self.assertEqual(checkMatch(self.parentPartySample.data, json.loads(res.content), 'partyId', parentPartyId), True) + + def test_for_create(self): + sample = self.sample + parentPartyId = sample.getParentId() + childPartyId = sample.getChildId() + + url = self.getUrl(sample.url) + url = '%s&parentPartyId=%s&childPartyId=%s' % (url, parentPartyId, childPartyId) + + res = self.client.post(url, sample.data) + + self.assertEqual(res.status_code, 201) + # return content is child organization data + # resObj = json.loads(res.content) + # self.assertEqual(checkMatch(self.childPartySample.data, resObj, 'partyId', childPartyId), True) + # self.assertEqual(resObj['consortiums'][0], parentPartyId) + self.assertIsNotNone(TestGenericInterfaces.forceGet(sample.model,'parentPartyId',parentPartyId)) + self.assertIsNotNone(TestGenericInterfaces.forceGet(sample.model,'childPartyId',childPartyId)) + + def test_for_delete(self): + sample = self.sample + pk = sample.forcePost(sample.data) + + parentPartyId = sample.getParentId() + childPartyId = sample.getChildId() + + url = self.getUrl(sample.url) + url = '%s&parentPartyId=%s&childPartyId=%s' % (url, parentPartyId, childPartyId) + + res = self.client.delete(url) + + self.assertIsNone(TestGenericInterfaces.forceGet(sample.model,sample.pkName,pk)) + +# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- + +# test for API end point /parties/org/ +# get organization by ip +class GetOrgByIpTest(TestCase): + sample = IpRangeSample(serverUrl) + partySample = OrganizationPartySample(serverUrl) + countrySample = CountrySample(serverUrl) + url = None + + def setUp(self): + countryId = self.countrySample.forcePost(self.countrySample.data) + self.partySample.data['country']=countryId + self.partyId = self.partySample.forcePost(self.partySample.data) + self.sample.data['partyId']=self.sample.updateData['partyId']=self.partyId + self.sample.forcePost(self.sample.data) + self.url = serverUrl + 'parties/org/?ip=%s' % self.sample.getInRangeIp() + + def test_for_get_by_ip(self): + res = self.client.get(self.url) + + self.assertEqual(res.status_code, 200) + self.assertEqual(res.content, self.partySample.getName()) + +# test for API end point /parties/orgstatus/ +# get organization and its subscription status to partner by ip +class GetOrgAndSubStatusTest(TestCase): + sample = IpRangeSample(serverUrl) + partnerSample = PartnerSample(serverUrl) + partySample = OrganizationPartySample(serverUrl) + countrySample = CountrySample(serverUrl) + subscriptionSample = SubscriptionSample(serverUrl) + url = None + partnerId = None + partyId = None + + def setUp(self): + self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) + countryId = self.countrySample.forcePost(self.countrySample.data) + self.partySample.data['country']=countryId + self.partyId = self.partySample.forcePost(self.partySample.data) + self.sample.data['partyId']=self.partyId + self.sample.forcePost(self.sample.data) + self.url = serverUrl + 'parties/orgstatus/?ip=%s&partnerId=%s' % (self.sample.getInRangeIp(), self.partnerId) + + def test_for_unsubscribed(self): + res = self.client.get(self.url) + + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + self.assertEqual(resObj['name'], self.partySample.getName()) + self.assertEqual(resObj['status'], 'not subscribed') + + def test_for_subscribed(self): + self.subscriptionSample.setPartnerId(self.partnerId) + self.subscriptionSample.setPartyId(self.partyId) + self.subscriptionSample.forcePost(self.subscriptionSample.data) + + res = self.client.get(self.url) + + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + self.assertEqual(resObj['name'], self.partySample.getName()) + self.assertEqual(resObj['status'], 'subscribed') + +# test for API end point /parties/organizations/ +# get subscribed organization list by partner +class GetSubOrgListByPartnerTest(TestCase): + sample = IpRangeSample(serverUrl) + partnerSample = PartnerSample(serverUrl) + partySample = OrganizationPartySample(serverUrl) + countrySample = CountrySample(serverUrl) + subscriptionSample = SubscriptionSample(serverUrl) + url = None + + def setUp(self): + partnerId = self.partnerSample.forcePost(self.partnerSample.data) + + countryId = self.countrySample.forcePost(self.countrySample.data) + + self.partySample.data['country']=countryId + partyId = self.partySample.forcePost(self.partySample.data) + + self.sample.data['partyId']=partyId + self.sample.forcePost(self.sample.data) + + self.subscriptionSample.setPartnerId(partnerId) + self.subscriptionSample.setPartyId(partyId) + self.subscriptionSample.forcePost(self.subscriptionSample.data) + + self.url = serverUrl + 'parties/organizations/?partnerId=%s' % partnerId + + def test_for_list(self): + res = self.client.get(self.url) + + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content)[0] + self.assertEqual(resObj[0], self.partySample.getName()) + self.assertEqual(resObj[1], self.countrySample.getName()) + +# test for API end point /parties/usage/ +# test in manualTests.py +class GetUsageRequestTest(ManualTest, TestCase): + path = "/parties/usage/" + testMethodStr = "running ./manage.py test party.manualTests (the UI invocation from librarians is not public yet)" + +# test for API end point /parties/consortiuminstitutions/{consortiumId} +# this endpoint is not working + +print "Running unit tests on party web services API........." + +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) diff --git a/party/views.py b/party/views.py index 0a0a8a50..aca8e99b 100644 --- a/party/views.py +++ b/party/views.py @@ -641,16 +641,17 @@ def get(self, request, format=None): return Response({'error':'does not allow get without partyType'}) obj = self.get_queryset() out = [] - if params['partyType'] == 'consortium': - for entry in obj.PartyAffiliation.all(): - serializer = serializer_class(entry) - out.append(serializer.data) - elif params['partyType'] == 'organization': - for entry in obj.consortiums.all(): - serializer = serializer_class(entry) - out.append(serializer.data) - else: - return Response({'error':'invalid partyType'}) + if obj: + if params['partyType'] == 'consortium': + for entry in obj.PartyAffiliation.all(): + serializer = serializer_class(entry) + out.append(serializer.data) + elif params['partyType'] == 'organization': + for entry in obj.consortiums.all(): + serializer = serializer_class(entry) + out.append(serializer.data) + else: + return Response({'error':'invalid partyType'}) return HttpResponse(json.dumps(out), content_type="application/json") def post(self, request, format=None): diff --git a/paywall2/settings.py.template.prod b/paywall2/settings.py.template.prod index 50ba2a60..286d9447 100644 --- a/paywall2/settings.py.template.prod +++ b/paywall2/settings.py.template.prod @@ -29,6 +29,8 @@ STRIPE_PUBLIC_KEY = None # ACTION: Add Stripe production public key here STRIPE_PRIVATE_KEY = None # ACTION: Add Stripe production private key here +HOSTNAME = 'http://localhost:9000/' + # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False diff --git a/paywall2/settings.py.template.test b/paywall2/settings.py.template.test index e5f89145..ed1e0f0f 100644 --- a/paywall2/settings.py.template.test +++ b/paywall2/settings.py.template.test @@ -29,6 +29,8 @@ STRIPE_PUBLIC_KEY = 'pk_test_VEu0r74glZkzeT8IXLmXxojP' STRIPE_PRIVATE_KEY = 'sk_test_dXy85QkwH66s64bIWKbikyMt' +HOSTNAME = 'http://localhost:9000/' + # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True diff --git a/scripts/testPartyCountry.py b/scripts/runTestPartyCountry.py similarity index 100% rename from scripts/testPartyCountry.py rename to scripts/runTestPartyCountry.py diff --git a/subscription/pyTests.py b/subscription/pyTests.py deleted file mode 100644 index 347348f8..00000000 --- a/subscription/pyTests.py +++ /dev/null @@ -1,174 +0,0 @@ -#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. - -import django -import unittest -import sys, getopt -from unittest import TestCase -from subscription.models import Subscription, SubscriptionTransaction, ActivationCode -from partner.models import Partner -import requests -import json -from testSamples import SubscriptionSample, SubscriptionTransactionSample, ActivationCodeSample -from party.testSamples import PartySample, IpRangeSample -from partner.testSamples import PartnerSample, SubscriptionTermSample -import copy -from common.pyTests import PyTestGenerics, GenericCRUDTest, GenericTest -from rest_framework import status -from controls import PaymentControl - -# Create your tests here. -django.setup() -serverUrl = PyTestGenerics.initPyTest() -print "using server url %s" % serverUrl - -# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- - -class ActivationCodeCRUD(GenericCRUDTest, TestCase): - sample = ActivationCodeSample(serverUrl) - partnerSample = PartnerSample(serverUrl) - - def setUp(self): - super(ActivationCodeCRUD, self).setUp() - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.sample.data['partnerId'] = self.sample.updateData['partnerId']=self.partnerId - - # delete activationCode entries that will be used for test - ActivationCode.objects.filter(activationCode=self.sample.data['activationCode']).delete() - ActivationCode.objects.filter(activationCode=self.sample.updateData['activationCode']).delete() - - def tearDown(self): - super(ActivationCodeCRUD,self).tearDown() - PyTestGenerics.forceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - - -class SubscriptionCRUD(GenericCRUDTest, TestCase): - - sample = SubscriptionSample(serverUrl) - partySample = PartySample(serverUrl) - partnerSample = PartnerSample(serverUrl) - activationCodeSample = ActivationCodeSample(serverUrl) - - def setUp(self): - super(SubscriptionCRUD,self).setUp() - self.partyId = self.partySample.forcePost(self.partySample.data) - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - ActivationCode.objects.filter(activationCode=self.activationCodeSample.data['activationCode']).delete() - self.activationCodeId = self.activationCodeSample.forcePost(self.activationCodeSample.data) - self.sample.data['partyId']=self.sample.updateData['partyId']=self.partyId - self.sample.partnerId=self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId - - # post request for subscription is not generic. It creates a SubscriptionTransaction - # object in addition to a Subscription object. - def test_for_create(self): - sample = self.sample - url = sample.url - cookies = {'apiKey':self.apiKey} - - # Creation via basic CRUD format - req = requests.post(url, data=sample.data, cookies=cookies) - self.assertEqual(req.status_code, status.HTTP_201_CREATED) - self.assertIsNotNone(PyTestGenerics.forceGet(sample.model,sample.pkName,req.json()[sample.pkName])) - transactionId = req.json()['subscriptionTransactionId'] - self.assertIsNotNone(PyTestGenerics.forceGet(SubscriptionTransaction,'subscriptionTransactionId',transactionId)) - PyTestGenerics.forceDelete(SubscriptionTransaction, 'subscriptionTransactionId', transactionId) - PyTestGenerics.forceDelete(sample.model,sample.pkName,req.json()[sample.pkName]) - - # Creationg via activation code - activationCode = ActivationCode.objects.get(activationCodeId=self.activationCodeId).activationCode - data ={"partyId":self.partyId, "activationCode":activationCode} - req = requests.post(url, data=data, cookies=cookies) - self.assertEqual(req.status_code, status.HTTP_201_CREATED) - self.assertIsNotNone(PyTestGenerics.forceGet(sample.model,sample.pkName,req.json()[sample.pkName])) - transactionId = req.json()['subscriptionTransactionId'] - self.assertIsNotNone(PyTestGenerics.forceGet(SubscriptionTransaction,'subscriptionTransactionId',transactionId)) - PyTestGenerics.forceDelete(SubscriptionTransaction, 'subscriptionTransactionId', transactionId) - PyTestGenerics.forceDelete(sample.model,sample.pkName,req.json()[sample.pkName]) - - def tearDown(self): - super(SubscriptionCRUD,self).tearDown() - PyTestGenerics.forceDelete(self.partySample.model, self.partySample.pkName, self.partyId) - PyTestGenerics.forceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - PyTestGenerics.forceDelete(self.activationCodeSample.model, self.activationCodeSample.pkName, self.activationCodeId) - -class SubscriptionTransactionCRUD(GenericCRUDTest, TestCase): - sample = SubscriptionTransactionSample(serverUrl) - - partySample = PartySample(serverUrl) - partnerSample = PartnerSample(serverUrl) - subscriptionSample = SubscriptionSample(serverUrl) - - def setUp(self): - super(SubscriptionTransactionCRUD,self).setUp() - self.partyId = self.partySample.forcePost(self.partySample.data) - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.subscriptionSample.data['partyId']=self.partyId - self.subscriptionSample.data['partnerId']=self.partnerId - self.subscriptionId = self.subscriptionSample.forcePost(self.subscriptionSample.data) - self.sample.data['subscriptionId']=self.sample.updateData['subscriptionId']=self.subscriptionId - - def tearDown(self): - super(SubscriptionTransactionCRUD,self).tearDown() - PyTestGenerics.forceDelete(self.partySample.model, self.partySample.pkName, self.partyId) - PyTestGenerics.forceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - PyTestGenerics.forceDelete(self.subscriptionSample.model, self.subscriptionSample.pkName, self.subscriptionId) - -# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- - -class SubscriptionRenewalTest(GenericTest, TestCase): - def test_for_update(self): - subscriptionSample = SubscriptionSample(serverUrl) - partnerSample = PartnerSample(serverUrl) - partySample = PartySample(serverUrl) - - Partner.objects.filter(partnerId=partnerSample.data['partnerId']).delete() - partnerId = partnerSample.forcePost(partnerSample.data) - partyId = partySample.forcePost(partySample.data) - - subscriptionSample.data['partnerId']=subscriptionSample.updateData['partnerId']=partnerId - subscriptionSample.data['partyId']=subscriptionSample.updateData['partyId']=partyId - subscriptionId = subscriptionSample.forcePost(subscriptionSample.data) - - url = serverUrl + 'subscriptions/' + str(subscriptionId) + '/renewal?apiKey=%s' % self.apiKey - cookies = {'apiKey':self.apiKey} - req = requests.put(url, data=subscriptionSample.updateData,cookies=cookies) - self.assertEqual(req.status_code, 200) - transactionId = req.json()['subscriptionTransactionId'] - self.assertIsNotNone(PyTestGenerics.forceGet(SubscriptionTransaction,'subscriptionTransactionId',transactionId)) - PyTestGenerics.forceDelete(SubscriptionTransaction, 'subscriptionTransactionId', transactionId) - PyTestGenerics.forceDelete(subscriptionSample.model,subscriptionSample.pkName,subscriptionId) - PyTestGenerics.forceDelete(partnerSample.model,partnerSample.pkName,partnerId) - PyTestGenerics.forceDelete(partySample.model,partySample.pkName,partyId) - -class PostPaymentHandlingTest(GenericTest, TestCase): - - partnerSample = PartnerSample(serverUrl) - subscriptionTermSample = SubscriptionTermSample(serverUrl) - - def setUp(self): - super(PostPaymentHandlingTest, self).setUp() - Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() - self.partnerId = self.partnerSample.forcePost(self.partnerSample.data) - self.subscriptionTermSample.data['partnerId'] = self.partnerId - self.subscriptionTermId = self.subscriptionTermSample.forcePost(self.subscriptionTermSample.data) - - def test_for_postPaymentSubscription(self): - activationCodeArray = PaymentControl.postPaymentHandling(self.subscriptionTermId, 5) - for activationCode in activationCodeArray: - self.assertIsNotNone(PyTestGenerics.forceGet(ActivationCode, 'activationCode', activationCode)) - PyTestGenerics.forceDelete(ActivationCode, 'activationCode', activationCode) - - def tearDown(self): - super(PostPaymentHandlingTest, self).tearDown() - PyTestGenerics.forceDelete(self.partnerSample.model, self.partnerSample.pkName, self.partnerId) - PyTestGenerics.forceDelete(self.subscriptionTermSample.model, self.subscriptionTermSample.pkName, self.subscriptionTermId) - -print "Running unit tests on subscription web services API........." - -if __name__ == '__main__': - sys.argv[1:] = [] - unittest.main() - ret = not runner.run(suite).wasSuccessful() - sys.exit(ret) diff --git a/subscription/testIndividualEmail.py b/subscription/runTestIndividualEmail.py similarity index 100% rename from subscription/testIndividualEmail.py rename to subscription/runTestIndividualEmail.py diff --git a/subscription/testSamples.py b/subscription/testSamples.py index aa1641f8..bd4e850e 100644 --- a/subscription/testSamples.py +++ b/subscription/testSamples.py @@ -1,40 +1,65 @@ -import django -import unittest -import sys, getopt -from unittest import TestCase +import copy from subscription.models import Subscription, SubscriptionTransaction, ActivationCode from party.models import Party from partner.models import Partner -import requests -import json +from datetime import datetime, timedelta +from common.tests import TestGenericInterfaces -import copy -from common.pyTests import PyTestGenerics +genericForcePost = TestGenericInterfaces.forcePost -genericForcePost = PyTestGenerics.forcePost +NUM_DAYS_AFTER_PURCHASE = 2 +NUM_SUBSCRIBED_DAYS = 30 +UPDATE_NUM_DAYS_AFTER_PURCHASE = 1 +UPDATE_NUM_SUBSCRIBED_DAYS = 60 + +def getDateTimeString(dateTimeObj): + return dateTimeObj.strftime("%Y-%m-%d %H:%M:%S.%f") class ActivationCodeSample(): path = 'subscriptions/activationCodes/' url = None + TRANSACTION_TYPE = 'create_free' data = { 'activationCode':'testactivationcode', 'partnerId':None, - 'partyId':None, - 'period':180, - 'purchaseDate':'2001-01-01T00:00:00Z', + # partyId is assigned upon activation not on creation + # 'partyId':None, + 'period':NUM_SUBSCRIBED_DAYS, + 'purchaseDate':None, } updateData = { 'activationCode':'testactivationcode2', 'partnerId':None, - 'partyId':None, - 'period':150, - 'purchaseDate':'2005-01-01T00:00:00Z', + # 'partyId':None, + 'period':UPDATE_NUM_SUBSCRIBED_DAYS, + 'purchaseDate':None, } pkName = 'activationCodeId' model = ActivationCode def __init__(self, serverUrl): self.url = serverUrl+self.path + self.data['purchaseDate'] = getDateTimeString(datetime.today() - timedelta(days=NUM_DAYS_AFTER_PURCHASE)) + self.updateData['purchaseDate'] = getDateTimeString(datetime.today() - timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE)) + + def setPartnerId(self, partnerId): + self.data['partnerId'] = partnerId + + # for get endpoint transactionType is not returned, so we only initialize this param when needed + def initTransctionType(self): + self.data['transactionType'] = self.TRANSACTION_TYPE + + def getActivationCode(self): + return self.data['activationCode'] + + def getPeriod(self): + return self.data['period'] + + def getTransactionType(self): + return self.data['transactionType'] + + def getPartnerId(self): + return self.data['partnerId'] def forcePost(self,data): postData = copy.deepcopy(data) @@ -45,22 +70,43 @@ class SubscriptionSample(): path = 'subscriptions/' url = None data = { - 'startDate':'2012-04-12T00:00:00Z', - 'endDate':'2018-04-12T00:00:00Z', - 'partnerId':'tair', - 'partyId':1, + 'startDate':None, + 'endDate':None, + 'partnerId':None, + 'partyId':None, } updateData = { - 'startDate':'2012-04-12T00:00:00Z', - 'endDate':'2018-04-12T00:00:00Z', - 'partnerId':'cdiff', - 'partyId':1, + 'startDate':None, + 'partnerId':None, + 'partyId':None, } pkName = 'subscriptionId' model = Subscription def __init__(self, serverUrl): self.url = serverUrl+self.path + self.data = copy.deepcopy(self.data) + + startDateObj = datetime.today() - timedelta(days=NUM_DAYS_AFTER_PURCHASE) + self.data['startDate'] = getDateTimeString(startDateObj) + self.data['endDate'] = getDateTimeString(startDateObj + timedelta(days=NUM_SUBSCRIBED_DAYS)) + + updateStartDateObj = datetime.today() - timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE) + self.updateData['startDate'] = getDateTimeString(updateStartDateObj) + self.updateData['endDate'] = getDateTimeString(updateStartDateObj + timedelta(days=UPDATE_NUM_SUBSCRIBED_DAYS)) + + def setPartnerId(self, partnerId): + self.data['partnerId'] = partnerId + + def setPartyId(self, partyId): + self.data['partyId'] = partyId + + def getEndDate(self): + return self.data['endDate'] + + def setAsExpired(self): + self.data['startDate'] = getDateTimeString(datetime.today() - timedelta(days=2 * NUM_SUBSCRIBED_DAYS)) + self.data['endDate'] = getDateTimeString(datetime.today() - timedelta(days=NUM_SUBSCRIBED_DAYS)) def forcePost(self,data): postData = copy.deepcopy(data) @@ -68,22 +114,19 @@ def forcePost(self,data): postData['partnerId'] = Partner.objects.get(partnerId=data['partnerId']) return genericForcePost(self.model, self.pkName, postData) - class SubscriptionTransactionSample(): path = 'subscriptions/transactions/' - url = None + url = None data = { - 'subscriptionId':1, - 'transactionDate':'2012-04-12T00:00:00Z', - 'startDate':'2012-04-12T00:00:00Z', - 'endDate':'2018-04-12T00:00:00Z', + 'transactionDate':None, + 'startDate':None, + 'endDate':None, 'transactionType':'create', } updateData = { - 'subscriptionId':1, - 'transactionDate':'2014-02-12T00:00:00Z', - 'startDate':'2012-04-12T00:00:00Z', - 'endDate':'2018-04-12T00:00:00Z', + 'transactionDate':None, + 'startDate':None, + 'endDate':None, 'transactionType':'renew', } pkName = 'subscriptionTransactionId' @@ -92,8 +135,19 @@ class SubscriptionTransactionSample(): def __init__(self, serverUrl): self.url = serverUrl+self.path + transactionDateObj = datetime.today() - timedelta(days=NUM_DAYS_AFTER_PURCHASE) + self.data['transactionDate'] = getDateTimeString(transactionDateObj) + self.data['startDate'] = self.data['transactionDate'] + self.data['endDate'] = getDateTimeString(transactionDateObj + timedelta(days=NUM_SUBSCRIBED_DAYS)) + + updateTransactionDateObj = datetime.today() - timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE) + self.updateData['transactionDate'] = getDateTimeString(updateTransactionDateObj) + self.updateData['startDate'] = self.updateData['transactionDate'] + self.updateData['endDate'] = getDateTimeString(updateTransactionDateObj + timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE)) + + def forcePost(self,data): postData = copy.deepcopy(data) - postData['subscriptionId'] = Subscription.objects.get(subscriptionId=data['subscriptionId']) + if ('subscriptionId' in postData): + postData['subscriptionId'] = Subscription.objects.get(subscriptionId=postData['subscriptionId']) return genericForcePost(self.model, self.pkName, postData) - diff --git a/subscription/tests.py b/subscription/tests.py index 0c4f009a..0583a0d4 100644 --- a/subscription/tests.py +++ b/subscription/tests.py @@ -1,9 +1,844 @@ -#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. +#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. +import django +import unittest +import sys +import json +import copy +from django.test import TestCase +from subscription.models import Subscription, SubscriptionTransaction, ActivationCode +from testSamples import SubscriptionSample, SubscriptionTransactionSample, ActivationCodeSample +from party.testSamples import UserPartySample, CountrySample, OrganizationPartySample, IpRangeSample, ConsortiumPartySample, InstitutionPartySample, PartyAffiliationSample, ImageInfoSample +from partner.testSamples import PartnerSample, SubscriptionTermSample +from authentication.testSamples import CredentialSample +from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest, LoginRequiredTest, ManualTest, checkMatch +from rest_framework import status +from controls import PaymentControl +# Python 3: module Cookie -> http.cookies +from Cookie import SimpleCookie +# Create your tests here. +django.setup() +serverUrl = TestGenericInterfaces.getHost() +# ---------------------- UNIT TEST FOR BASIC CRUD OPERATIONS ------------- +# test for API end point /subscriptions/ +# except for GET that is explicitly override in end point, all other actions +# (UPDATE and DELETE) queries item by party id instead of subscription id +class SubscriptionCRUDTest(LoginRequiredTest, TestCase): + partyId = None + partnerId = None + sample = SubscriptionSample(serverUrl) -from django.test import TestCase + def setUp(self): + super(SubscriptionCRUDTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + + partySample = UserPartySample(serverUrl) + self.partyId = partySample.forcePost(partySample.data) + + self.sample.data['partyId']=self.sample.updateData['partyId']=self.partyId + self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId + + # post request for subscription is not generic. It creates a SubscriptionTransaction + # object in addition to a Subscription object. + # creation via basic CRUD format + # Need valid phoenix credential + # Potential API end point threat: no role based authorization + def test_for_create(self): + sample = self.sample + url = self.getUrl(sample.url) + + res = self.client.post(url, sample.data) + self.assertEqual(res.status_code, status.HTTP_201_CREATED) + resObj = json.loads(res.content) + self.assertIsNotNone(TestGenericInterfaces.forceGet(sample.model,sample.pkName,resObj[sample.pkName])) + transactionId = resObj['subscriptionTransactionId'] + self.assertIsNotNone(TestGenericInterfaces.forceGet(SubscriptionTransaction,'subscriptionTransactionId',transactionId)) + + # create subscription by activation code + def test_for_create_by_activation(self): + sample = self.sample + # no need for user credential + url = sample.url + + activationCodeSample = ActivationCodeSample(serverUrl) + activationCodeSample.initTransctionType() + activationCodeSample.setPartnerId(self.partnerId) + activationCodeSample.forcePost(activationCodeSample.data) + + activationCode = activationCodeSample.getActivationCode() + data ={"partyId":self.partyId, "activationCode":activationCode} + res = self.client.post(url, data) + self.assertEqual(res.status_code, status.HTTP_201_CREATED) + resObj = json.loads(res.content) + self.assertIsNotNone(TestGenericInterfaces.forceGet(sample.model,sample.pkName,resObj[sample.pkName])) + transactionId = resObj['subscriptionTransactionId'] + self.assertIsNotNone(TestGenericInterfaces.forceGet(SubscriptionTransaction,'subscriptionTransactionId',transactionId)) + + # get by subscriptionId, partyId or userIdentifier + def test_for_get(self): + sample = self.sample + pk = sample.forcePost(sample.data) + + # get by subscriptionId + url = self.getUrl(sample.url, sample.pkName, pk) + self.runGetTestByIdentifier(url, pk) + + # get by partyId + url = self.getUrl(sample.url, 'partyId', self.partyId) + self.runGetTestByIdentifier(url, pk) + + # get by userIdentifier + credentialSample = CredentialSample(serverUrl) + credentialSample.setPartyId(self.partyId) + credentialSample.setPartnerId(self.partnerId) + credentialSample.forcePost(credentialSample.data) + + url = self.getUrl(sample.url, 'userIdentifier', credentialSample.getUserIdentifier()) + # need to pass ipAddress as arg even when not needed + url = '%s&partnerId=%s&ipAddress=' % (url, self.partnerId) + self.runGetTestByIdentifier(url, pk) + + # get by ipAddress + def test_for_get_by_ip_address(self): + # override party setup + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + + partySample = OrganizationPartySample(serverUrl) + partySample.setCountry(countryId) + self.partyId = partySample.forcePost(partySample.data) + + ipRangeSample = IpRangeSample(serverUrl) + ipRangeSample.setPartyId(self.partyId) + ipRangeSample.forcePost(IpRangeSample.data) + + subIp = ipRangeSample.getInRangeIp() + + sample = self.sample + sample.setPartyId(self.partyId) + pk = sample.forcePost(sample.data) + + url = self.getUrl(sample.url, 'ipAddress', subIp) + # need to pass userIdentifier as arg even when not needed + url = '%s&partnerId=%s&userIdentifier=' % (url, self.partnerId) + self.runGetTestByIdentifier(url, pk) + + def runGetTestByIdentifier(self, url, pk): + sample = self.sample + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + self.assertEqual(checkMatch(sample.data, json.loads(res.content), sample.pkName, pk), True) + + # can only update by party id + def test_for_update(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = self.getUrl(sample.url, 'partyId', self.partyId) + + # the default content type for put is 'application/octet-stream' + res = self.client.put(url, json.dumps(sample.updateData), content_type='application/json') + + self.assertEqual(res.status_code, 200) + self.assertEqual(checkMatch(sample.updateData, json.loads(res.content), sample.pkName, pk), True) + + # can only delete by party id + def test_for_delete(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = self.getUrl(sample.url, 'partyId', self.partyId) + + res = self.client.delete(url) + + self.assertIsNone(TestGenericInterfaces.forceGet(sample.model,sample.pkName,pk)) + self.assertIsNone(TestGenericInterfaces.forceGet(sample.model,'partyId',self.partyId)) + +# test for API end point /subscriptions/activationCodes/ for create and update +# need to authenticate user +class ActivationCodeCreateAndUpdateTest(LoginRequiredTest, TestCase): + sample = ActivationCodeSample(serverUrl) + + def setUp(self): + super(ActivationCodeCreateAndUpdateTest, self).setUp() + + self.sample.initTransctionType() + + partnerSample = PartnerSample(serverUrl) + partnerId = partnerSample.forcePost(partnerSample.data) + self.sample.data['partnerId'] = self.sample.updateData['partnerId']=partnerId + + # Potential API end point threat: no role based authorization + def test_for_create(self): + sample = self.sample + url = self.getUrl(sample.url) + url = '%s&quantity=%s&period=%s&partnerId=%s&transactionType=%s' % (url, + 1, sample.getPeriod(), sample.getPartnerId(),sample.getTransactionType()) + res = self.client.post(url) + + self.assertEqual(res.status_code, 200) + self.assertIsNotNone(TestGenericInterfaces.forceGet(sample.model,'activationCode',json.loads(res.content)[0])) + + # update activation code as deleted + def test_for_update(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = self.getUrl(sample.url, sample.pkName, pk) + url += '&deleteMarker=true' + res = self.client.put(url) + + self.assertEqual(res.status_code, 200) + self.assertEqual(TestGenericInterfaces.forceGet(sample.model,sample.pkName,pk).deleteMarker, True) + +# test for API end point /subscriptions/activationCodes/ for get and delete +# returned activation code data does not include transaction type +class ActivationCodeGetAndDeleteTest(GenericCRUDTest, TestCase): + sample = ActivationCodeSample(serverUrl) + + def setUp(self): + super(ActivationCodeGetAndDeleteTest, self).setUp() + + partnerSample = PartnerSample(serverUrl) + partnerId = partnerSample.forcePost(partnerSample.data) + self.sample.data['partnerId'] = self.sample.updateData['partnerId']=partnerId + + + def test_for_get(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = self.getUrl(sample.url, sample.pkName, pk) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + # transaction is not returned in API + data = copy.deepcopy(sample.data) + del data['transactionType'] + self.assertEqual(checkMatch(data, json.loads(res.content), sample.pkName, pk), True) + + def test_for_get_all(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = self.getUrl(sample.url) + + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + # transaction is not returned in API + data = copy.deepcopy(sample.data) + del data['transactionType'] + self.assertEqual(checkMatch(data, json.loads(res.content), sample.pkName, pk), True) + + # Tested in above class + def test_for_create(self): + pass + + # Tested in above class + def test_for_update(self): + pass + + # delete method can be tested but shall not be used. + # should use update method to update delete marker instead + +# test for API end point /subscriptions/transactions/ +class SubscriptionTransactionCRUDTest(GenericCRUDTest, TestCase): + sample = SubscriptionTransactionSample(serverUrl) + + def setUp(self): + super(SubscriptionTransactionCRUDTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + partnerId = partnerSample.forcePost(partnerSample.data) + + partySample = UserPartySample(serverUrl) + partyId = partySample.forcePost(partySample.data) + + subscriptionSample = SubscriptionSample(serverUrl) + subscriptionSample.setPartnerId(partnerId) + subscriptionSample.setPartyId(partyId) + subscriptionId = subscriptionSample.forcePost(subscriptionSample.data) + + self.sample.data['subscriptionId']=self.sample.updateData['subscriptionId']=subscriptionId + +# ----------------- END OF BASIC CRUD OPERATIONS ---------------------- + +# Note that for subscription end points, unless specifically designed (/subscriptions/consortiums/ +# and /subscriptions/consactsubscriptions/), otherwise they only return the subscription record of +# the organization itself; they do not check/return the subscription of its consortium + +# No API end point or method update consortiumId, consortiumStartDate and consortiumEndDate; +# they are updated by scripts/updateConsortiumSubscriptionFields.py on a daily basis by cron job +# on API server. + +# The consortiumStartDate and consortiumEndDate values are for reference only and are not used in validating +# a subscription. Instead, when an institution or an individual that belongs to a consortium is checked for +# authorization, the authorization end points calls method that checks not only their own subscription but +# also the subscription of their consortium. But still, startDate and endDate of the record are used + +# test for API end point /subscriptions/{subscriptionId}/renewal/ +# update subscription duration directly +# will create subscription transaction +class SubscriptionRenewalTest(GenericTest, TestCase): + sample = SubscriptionSample(serverUrl) + + def setUp(self): + super(SubscriptionRenewalTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + partnerId = partnerSample.forcePost(partnerSample.data) + + partySample = UserPartySample(serverUrl) + partyId = partySample.forcePost(partySample.data) + + sample = self.sample + sample.data['partnerId']=sample.updateData['partnerId']=partnerId + sample.data['partyId']=sample.updateData['partyId']=partyId + + def test_for_update(self): + sample = self.sample + subscriptionId = sample.forcePost(sample.data) + + url = serverUrl + 'subscriptions/' + str(subscriptionId) + '/renewal/' + # the default content type for put is 'application/octet-stream' + res = self.client.put(url, json.dumps(sample.updateData), content_type='application/json') + + self.assertEqual(res.status_code, 200) + self.assertEqual(checkMatch(sample.updateData, json.loads(res.content), sample.pkName, subscriptionId), True) + transactionId = json.loads(res.content)['subscriptionTransactionId'] + self.assertIsNotNone(TestGenericInterfaces.forceGet(SubscriptionTransaction,'subscriptionTransactionId',transactionId)) + +# test for API end point /subscriptions/payments/ +# cannot test via POST request to API since not sure how to generate a stripeToken +class PostPaymentHandlingTest(ManualTest, TestCase): + path = "/subscriptions/payments/" + testMethodStr = "by submitting an order on ui.arabidopsis.org" + +# test for API end point /subscriptions/enddate/ +# end point looks for the effective subscription with latest end date that either covers the given IP address +# or belongs to the given party for a given partner +# end point returns the expiration date of the found subscription and 'subscribed' status as True; +# otherwise, the returned expiration date is null and status is False. +# TODO: End point cannot accept ipAddress alone without partyId or userIdentifier, which I do not see a reason to it +class GetSubcriptionEndDateTest(GenericTest, TestCase): + partnerId = None + userPartyId = None + userIdentifier = None + orgPartyId = None + orgInRangeIp = None + USER_SUBSCRIPTION_TYPE = 'individual' + ORG_SUBSCRIPTION_TYPE = 'institutional' + + def setUp(self): + super(GetSubcriptionEndDateTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + + # create individual user + userPartySample = UserPartySample(serverUrl) + self.userPartyId = userPartySample.forcePost(userPartySample.data) + + credentialSample = CredentialSample(serverUrl) + credentialSample.setPartyId(self.userPartyId) + credentialSample.setPartnerId(self.partnerId) + credentialSample.forcePost(credentialSample.data) + self.userIdentifier = credentialSample.getUserIdentifier() + + # create organization and its subscription + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + + orgPartySample = OrganizationPartySample(serverUrl) + orgPartySample.setCountry(countryId) + self.orgPartyId = orgPartySample.forcePost(orgPartySample.data) + + ipRangeSample = IpRangeSample(serverUrl) + ipRangeSample.setPartyId(self.orgPartyId) + ipRangeSample.forcePost(IpRangeSample.data) + + self.orgInRangeIp = ipRangeSample.getInRangeIp() + + def test_for_no_subscription(self): + # test get by userPartyId and ipAddress when neither user nor organization is subscribed + queryParam = 'partyId=%s&ipAddress=%s' % (self.userPartyId, self.orgInRangeIp) + self.runTest(queryParam, False) + + # test get by userIdentifier and ipAddress when neither user nor organization is subscribed + queryParam = 'userIdentifier=%s&ipAddress=%s' % (self.userIdentifier, self.orgInRangeIp) + self.runTest(queryParam, False) + + def test_for_get_individual_subscription(self): + userSubscriptionSample = SubscriptionSample(serverUrl) + userSubscriptionSample.setPartyId(self.userPartyId) + userSubscriptionSample.setPartnerId(self.partnerId) + userSubscriptionSample.forcePost(userSubscriptionSample.data) + + # test get by user partyId when user is subscribed + queryParam = 'partyId=%s' % self.userPartyId + self.runTest(queryParam, True, self.USER_SUBSCRIPTION_TYPE, userSubscriptionSample.getEndDate()) + + # test get by user partyId and ipAddress when only user is subscribed + queryParam = 'partyId=%s&ipAddress=%s' % (self.userPartyId, self.orgInRangeIp) + self.runTest(queryParam, True, self.USER_SUBSCRIPTION_TYPE, userSubscriptionSample.getEndDate()) + + # test get by userIdentifier when user is subscribed + queryParam = 'userIdentifier=%s' % self.userIdentifier + self.runTest(queryParam, True, self.USER_SUBSCRIPTION_TYPE, userSubscriptionSample.getEndDate()) + + # test get by userIdentifier and ipAddress when onlyuser is subscribed + queryParam = 'userIdentifier=%s&ipAddress=%s' % (self.userIdentifier, self.orgInRangeIp) + self.runTest(queryParam, True, self.USER_SUBSCRIPTION_TYPE, userSubscriptionSample.getEndDate()) + + def test_for_get_organization_subscription(self): + # ip address cannot be passed alone. Need to pass individual credential (userIdentifier/partyId) + # as well + orgSubscriptionSample = SubscriptionSample(serverUrl) + orgSubscriptionSample.setPartyId(self.orgPartyId) + orgSubscriptionSample.setPartnerId(self.partnerId) + orgSubscriptionSample.forcePost(orgSubscriptionSample.data) + + # test get when both userIdentifier and ipAddress are provided + queryParam = 'userIdentifier=%s&ipAddress=%s' % (self.userIdentifier, self.orgInRangeIp) + self.runTest(queryParam, True, self.ORG_SUBSCRIPTION_TYPE, orgSubscriptionSample.getEndDate()) + + # test get when both userPartyId and ipAddress are provided + queryParam = 'partyId=%s&ipAddress=%s' % (self.userPartyId, self.orgInRangeIp) + self.runTest(queryParam, True, self.ORG_SUBSCRIPTION_TYPE, orgSubscriptionSample.getEndDate()) + + def test_for_have_both_subscriptions(self): + # create organization subscription before user subscription so user subscription end date is later + orgSubscriptionSample = SubscriptionSample(serverUrl) + orgSubscriptionSample.setPartyId(self.orgPartyId) + orgSubscriptionSample.setPartnerId(self.partnerId) + orgSubscriptionSample.forcePost(orgSubscriptionSample.data) + + userSubscriptionSample = SubscriptionSample(serverUrl) + userSubscriptionSample.setPartyId(self.userPartyId) + userSubscriptionSample.setPartnerId(self.partnerId) + userSubscriptionSample.forcePost(userSubscriptionSample.data) + + # organization (IP based) subscription will shadow individual subscription on subscription type + # but end date will be the latest of both so there could be inconsistency between end date and + # subscription type + + expEndDate = max(orgSubscriptionSample.getEndDate(), userSubscriptionSample.getEndDate()) + + # test get when both userIdentifier and ipAddress are provided + queryParam = 'userIdentifier=%s&ipAddress=%s' % (self.userIdentifier, self.orgInRangeIp) + self.runTest(queryParam, True, self.ORG_SUBSCRIPTION_TYPE, expEndDate) + self.runTest(queryParam, True, self.ORG_SUBSCRIPTION_TYPE, userSubscriptionSample.getEndDate()) + + # test get when both userPartyId and ipAddress are provided + queryParam = 'partyId=%s&ipAddress=%s' % (self.userPartyId, self.orgInRangeIp) + self.runTest(queryParam, True, self.ORG_SUBSCRIPTION_TYPE, expEndDate) + self.runTest(queryParam, True, self.ORG_SUBSCRIPTION_TYPE, userSubscriptionSample.getEndDate()) + + def runTest(self, queryParam, expectedSubscriptionStatus, expectedSubscriptionType = None, expectedExpDate = None): + url = '%ssubscriptions/enddate/?partnerId=%s&%s' % (serverUrl, self.partnerId, queryParam) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + self.assertEqual(expectedSubscriptionStatus, resObj['subscribed']) + if expectedSubscriptionType and resObj['subscriptionType']: + self.assertEqual(expectedSubscriptionType, resObj['subscriptionType']) + if expectedExpDate and resObj['expDate']: + expDate = resObj['expDate'].replace('T', ' ').replace('Z', '') + self.assertEqual(expectedExpDate, expDate) + +# test for API end point /subscriptions/membership/ +# end point looks for the effective subscription with latest end date that covers the given IP address for a given partner +# end point returns the expiration date of the found subscription and 'isMember' status as True, and also +# replies the display name or organization and its logo url queried from ImageInfo table; +# otherwise, it returns 'isMember' status as False and all other fields as None +class CheckMembershipTest(GenericTest, TestCase): + partnerId = None + orgPartyId = None + orgInRangeIp = None + imageInfoSample = ImageInfoSample() + + def setUp(self): + super(CheckMembershipTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + + # create organization and its subscription + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + + orgPartySample = OrganizationPartySample(serverUrl) + orgPartySample.setCountry(countryId) + self.orgPartyId = orgPartySample.forcePost(orgPartySample.data) + + imageInfoSample = self.imageInfoSample + imageInfoSample.setPartyId(self.orgPartyId) + imageInfoSample.forcePost(imageInfoSample.data) + + ipRangeSample = IpRangeSample(serverUrl) + ipRangeSample.setPartyId(self.orgPartyId) + ipRangeSample.forcePost(IpRangeSample.data) + + self.orgInRangeIp = ipRangeSample.getInRangeIp() + + def test_for_get(self): + + # test before organization subscribes + url = '%ssubscriptions/membership/?partnerId=%s&ipAddress=%s' % (serverUrl, self.partnerId, self.orgInRangeIp) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + self.assertEqual(resObj['isMember'], False) + + orgSubscriptionSample = SubscriptionSample(serverUrl) + orgSubscriptionSample.setPartyId(self.orgPartyId) + orgSubscriptionSample.setPartnerId(self.partnerId) + orgSubscriptionSample.forcePost(orgSubscriptionSample.data) + + # test after organization subscribes + imageInfoSample = self.imageInfoSample + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + self.assertEqual(resObj['isMember'], True) + self.assertEqual(resObj['name'], imageInfoSample.getName()) + self.assertEqual(resObj['imageUrl'], imageInfoSample.getImageUrl()) + expDate = resObj['expDate'].replace('T', ' ').replace('Z', '') + self.assertEqual(expDate, orgSubscriptionSample.getEndDate()) + +# test for API end point /subscriptions/subscriptionrequest/ +# this end point seems not working. Will print a warning to ask manual test +class SubscriptionRequestTest(ManualTest, TestCase): + path = "/subscriptions/subscriptionrequest/" + testMethodStr = "clicking Subcription - Download All Requests on ui.arabidopsis.org/adminportal/" + +# test for API end point /subscriptions/active/ +# endpoint returns ALL ACTIVE subscription and party info that covers the given IP address or belongs to the given +# user identifier for a given partner +# ipAddress must be passed in; userIdentifier is optional +class GetActiveSubscriptionTest(GenericTest, TestCase): + partnerId = None + userPartySample = UserPartySample(serverUrl) + userPartyId = None + userIdentifier = None + orgPartySample = OrganizationPartySample(serverUrl) + orgPartyId = None + orgInRangeIp = None + + def setUp(self): + super(GetActiveSubscriptionTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + + # create individual user + self.userPartyId = self.userPartySample.forcePost(self.userPartySample.data) + + credentialSample = CredentialSample(serverUrl) + credentialSample.setPartyId(self.userPartyId) + credentialSample.setPartnerId(self.partnerId) + credentialSample.forcePost(credentialSample.data) + self.userIdentifier = credentialSample.getUserIdentifier() + + # create organization and its subscription + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + + self.orgPartySample.setCountry(countryId) + self.orgPartyId = self.orgPartySample.forcePost(self.orgPartySample.data) + + ipRangeSample = IpRangeSample(serverUrl) + ipRangeSample.setPartyId(self.orgPartyId) + ipRangeSample.forcePost(IpRangeSample.data) + + self.orgInRangeIp = ipRangeSample.getInRangeIp() + + def test_for_no_subscription(self): + self.runTest(partyId = None, expectedPartyData = None, subscriptionId = None, expectSubscriptionData = None) + + def test_for_get_individual_subscription(self): + userSubscriptionSample = SubscriptionSample(serverUrl) + userSubscriptionSample.setPartyId(self.userPartyId) + userSubscriptionSample.setPartnerId(self.partnerId) + subscriptionId = userSubscriptionSample.forcePost(userSubscriptionSample.data) + + self.runTest(self.userPartyId, self.userPartySample.data, subscriptionId, userSubscriptionSample.data) + + def test_for_get_organization_subscription(self): + # ip address cannot be passed alone. Need to pass individual credential (userIdentifier/partyId) + # as well + orgSubscriptionSample = SubscriptionSample(serverUrl) + orgSubscriptionSample.setPartyId(self.orgPartyId) + orgSubscriptionSample.setPartnerId(self.partnerId) + subscriptionId = orgSubscriptionSample.forcePost(orgSubscriptionSample.data) + + self.runTest(self.orgPartyId, self.getOrgDataToCompare(), subscriptionId, orgSubscriptionSample.data) + + def test_for_have_both_subscriptions(self): + orgSubscriptionSample = SubscriptionSample(serverUrl) + orgSubscriptionSample.setPartyId(self.orgPartyId) + orgSubscriptionSample.setPartnerId(self.partnerId) + orgSubId = orgSubscriptionSample.forcePost(orgSubscriptionSample.data) + + userSubscriptionSample = SubscriptionSample(serverUrl) + userSubscriptionSample.setPartyId(self.userPartyId) + userSubscriptionSample.setPartnerId(self.partnerId) + userSubId = userSubscriptionSample.forcePost(userSubscriptionSample.data) + + self.runTest(self.userPartyId, self.userPartySample.data, userSubId, userSubscriptionSample.data) + self.runTest(self.orgPartyId, self.getOrgDataToCompare(), orgSubId, orgSubscriptionSample.data) + + def runTest(self, partyId = None, expectedPartyData = None, subscriptionId = None, expectSubscriptionData = None): + # ipAddress must be passed in; userIdentifier is optional + url = '%ssubscriptions/active/?partnerId=%s&userIdentifier=%s&ipAddress=%s' % (serverUrl, + self.partnerId, self.userIdentifier, self.orgInRangeIp) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + if not partyId and not subscriptionId: + self.assertFalse(resObj) + return + if partyId: + self.assertEqual(checkMatch(expectedPartyData, resObj, 'partyId', partyId), True) + if subscriptionId: + self.assertEqual(checkMatch(expectSubscriptionData, resObj, 'subscriptionId', subscriptionId), True) + + def getOrgDataToCompare(self): + # remove fields that are not returned by API end point + return { + 'name': self.orgPartySample.getName(), + 'partyType': self.orgPartySample.getPartyType() + } + +# test for API end point /subscriptions/activesubscriptions/{partyId}/ +# endpoint returns ALL ACTIVE subscriptions that belongs to a partyId for ALL partners +# end point returns {'partnerId_1':[{subscription detail}], 'partnerId_2':[{subscription detail}]...} +class GetActiveSubscriptionByPartyIdTest(GenericTest, TestCase): + partnerId = None + subscriptionSample = SubscriptionSample(serverUrl) + + def setUp(self): + super(GetActiveSubscriptionByPartyIdTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + + self.subscriptionSample.setPartnerId(self.partnerId) + + def test_for_get_individual_subscription(self): + userPartySample = UserPartySample(serverUrl) + partyId = userPartySample.forcePost(userPartySample.data) + + self.runTest(partyId) + + def test_for_get_organization_subscription(self): + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + + orgPartySample = OrganizationPartySample(serverUrl) + orgPartySample.setCountry(countryId) + partyId = orgPartySample.forcePost(orgPartySample.data) + + self.runTest(partyId) + + def runTest(self, partyId): + subscriptionSample = self.subscriptionSample + subscriptionSample.setPartyId(partyId) + subscriptionId = subscriptionSample.forcePost(subscriptionSample.data) + + url = '%ssubscriptions/activesubscriptions/%s/' % (serverUrl, partyId) + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + self.assertEqual(checkMatch(self.subscriptionSample.data, json.loads(res.content)[self.partnerId], + 'subscriptionId', subscriptionId), True) + +# test for API end point /subscriptions/allsubscriptions/{partyId}/ +# endpoint returns ALL subscriptions that belongs to a partyId for ALL partners, including active ones +# and expired ones. Note that for each partner a party can only have an active subscription or an expired +# subscription +# end point returns {'partnerId_1':[{subscription detail}], 'partnerId_2':[{subscription detail}]...} +class GetSubscriptionHistoryByPartyIdTest(GenericTest, TestCase): + partnerIdWithActiveSubscription = None + partnerIdWithExpiredSubscription = None + subscriptionSample = SubscriptionSample(serverUrl) + expiredSubscriptionSample = SubscriptionSample(serverUrl) + expiredSubscriptionSample.setAsExpired() + + def setUp(self): + super(GetSubscriptionHistoryByPartyIdTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerIdWithActiveSubscription = partnerSample.forcePost(partnerSample.data) + partnerSample.setDifferentPartnerId() + self.partnerIdWithExpiredSubscription = partnerSample.forcePost(partnerSample.data) + + self.subscriptionSample.setPartnerId(self.partnerIdWithActiveSubscription) + self.expiredSubscriptionSample.setPartnerId(self.partnerIdWithExpiredSubscription) + + def test_for_get_individual_subscription(self): + userPartySample = UserPartySample(serverUrl) + partyId = userPartySample.forcePost(userPartySample.data) + + self.runTest(partyId) + + def test_for_get_organization_subscription(self): + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + + orgPartySample = OrganizationPartySample(serverUrl) + orgPartySample.setCountry(countryId) + partyId = orgPartySample.forcePost(orgPartySample.data) + + self.runTest(partyId) + + def runTest(self, partyId): + subscriptionSample = self.subscriptionSample + subscriptionSample.setPartyId(partyId) + subscriptionId = subscriptionSample.forcePost(subscriptionSample.data) + + expiredSubscriptionSample = self.expiredSubscriptionSample + expiredSubscriptionSample.setPartyId(partyId) + expSubscriptionId = expiredSubscriptionSample.forcePost(expiredSubscriptionSample.data) + + url = '%ssubscriptions/allsubscriptions/%s/' % (serverUrl, partyId) + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + resObj = json.loads(res.content) + self.assertEqual(checkMatch(self.subscriptionSample.data, resObj[self.partnerIdWithActiveSubscription], + 'subscriptionId', subscriptionId), True) + self.assertEqual(checkMatch(self.expiredSubscriptionSample.data, resObj[self.partnerIdWithExpiredSubscription], + 'subscriptionId', expSubscriptionId), True) + +# test for API end point /subscriptions/consortiums/ +# check for an institution, for each partner which of its consortium have an active subscription +# passed in partyId is the partyId of the institution +# end point returns {'partnerId_1':[{subscribed consortium data}], 'partnerId_2':[{subscribed consortium data}]...} +# DOES NOT return subscription details +# TODO: to use current API end point we have to pass in param "active" and its value has to be true, which makes +# behavior of this end point to be identical to the end point below: /subscriptions/consactsubscriptions/{partyId} +class GetConsortiumSubcriptionTest(GenericTest, TestCase): + consortiumPartySample = ConsortiumPartySample(serverUrl) + partnerId = None + consortiumPartyId = None + institutionPartyId = None + + def setUp(self): + super(GetConsortiumSubcriptionTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + + parentPartySample = self.consortiumPartySample + parentPartySample.setCountry(countryId) + self.consortiumPartyId = parentPartyId = parentPartySample.forcePost(parentPartySample.data) + + subscriptionSample = SubscriptionSample(serverUrl) + subscriptionSample.setPartnerId(self.partnerId) + subscriptionSample.setPartyId(parentPartyId) + subscriptionSample.forcePost(subscriptionSample.data) + + childPartySample = InstitutionPartySample(serverUrl) + childPartySample.setCountry(countryId) + self.institutionPartyId = childPartyId = childPartySample.forcePost(childPartySample.data) + + affliationSample = PartyAffiliationSample(serverUrl) + affliationSample.setParentId(parentPartyId) + affliationSample.setChildId(childPartyId) + affliationSample.forcePost(affliationSample.data) + + def test_for_get(self): + + url = '%ssubscriptions/consortiums/?active=true&partyId=%s' % (serverUrl, self.institutionPartyId) + + res = self.client.get(url) + + self.assertEqual(res.status_code, 200) + self.assertEqual(checkMatch(self.consortiumPartySample.data, json.loads(res.content)[self.partnerId], 'partyId', self.consortiumPartyId), True) + +# test for API end point /subscriptions/consactsubscriptions/{partyId} for Consortium Active Subscription +# check for an institution, for each partner which of its consortium have an active subscription +# passed in partyId is the partyId of the institution +# end point returns {'partnerId_1':[{subscribed consortium data}], 'partnerId_2':[{subscribed consortium data}]...} +# DOES NOT return subscription details +class GetConsortiumActiveSubscriptionTest(GenericTest, TestCase): + consortiumPartySample = ConsortiumPartySample(serverUrl) + partnerId = None + consortiumPartyId = None + institutionPartyId = None + + def setUp(self): + super(GetConsortiumActiveSubscriptionTest,self).setUp() + + partnerSample = PartnerSample(serverUrl) + self.partnerId = partnerSample.forcePost(partnerSample.data) + + countrySample = CountrySample(serverUrl) + countryId = countrySample.forcePost(countrySample.data) + + parentPartySample = self.consortiumPartySample + parentPartySample.setCountry(countryId) + self.consortiumPartyId = parentPartyId = parentPartySample.forcePost(parentPartySample.data) + + childPartySample = InstitutionPartySample(serverUrl) + childPartySample.setCountry(countryId) + self.institutionPartyId = childPartyId = childPartySample.forcePost(childPartySample.data) + + affliationSample = PartyAffiliationSample(serverUrl) + affliationSample.setParentId(parentPartyId) + affliationSample.setChildId(childPartyId) + affliationSample.forcePost(affliationSample.data) + + def test_for_get(self): + url = '%ssubscriptions/consactsubscriptions/%s/' % (serverUrl, self.institutionPartyId) + + # before consortium has subscription + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + self.assertFalse(json.loads(res.content)) + + subscriptionSample = SubscriptionSample(serverUrl) + subscriptionSample.setPartnerId(self.partnerId) + subscriptionSample.setPartyId(self.consortiumPartyId) + subscriptionSample.forcePost(subscriptionSample.data) + + # after consortium has subcription + res = self.client.get(url) + self.assertEqual(res.status_code, 200) + self.assertEqual(checkMatch(self.consortiumPartySample.data, json.loads(res.content)[self.partnerId], 'partyId', self.consortiumPartyId), True) + +# test for API end point /subscriptions/commercials/ +# Sep/03/2019: this is a dreprecated API, now replaced by SalesForce Campaign + +# test for API end point /subscriptions/institutions/ +# Sep/03/2019: this is a dreprecated API, now replaced by SalesForce Campaign + +# test for API end point /subscriptions/request/ +# Sep/03/2019: this is a dreprecated API, now replaced by SalesForce Campaign + +# test for /subscriptions/templates/block or /subscriptions/templates/warn/ +# no test as no known external resource is using them + +# test for API end point /subscriptions/renew/ +# an end point for sending renewal request email, assume it's deprecated + +print "Running unit tests on subscription web services API........." -# Create your tests here. +if __name__ == '__main__': + sys.argv[1:] = [] + unittest.main() + ret = not runner.run(suite).wasSuccessful() + sys.exit(ret) diff --git a/subscription/views.py b/subscription/views.py index de9e9873..908f33b6 100644 --- a/subscription/views.py +++ b/subscription/views.py @@ -151,7 +151,7 @@ def post(self, request): else: # basic subscription creation if not isPhoenix(self.request): - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + return Response(status=status.HTTP_400_BAD_REQUEST) serializer = self.serializer_class(data=request.data) if serializer.is_valid(): @@ -160,7 +160,7 @@ def post(self, request): returnData = serializer.data returnData['subscriptionTransactionId']=transaction.subscriptionTransactionId return Response(returnData, status=status.HTTP_201_CREATED) - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # /transactions/ class SubscriptionTransactionCRUD(GenericCRUDView): From daad678ccd999ccb2903c0f17dba2a09c8825fab Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Tue, 10 Sep 2019 17:33:36 -0700 Subject: [PATCH 02/19] PWL-742: Code change in accordance with Python upgrade 2.7 -> 3.6, Django upgrade 1.8 -> 2.2 PWL-769: Update mysql dirver engine. PWL-769: Update code syntax by python 2to3 tool. PWL-742: Add on_delete definition as prevent delete for ForeignKey field. PWL-742: Removed urlresolver import since it is deprecated and not used. PWL-742: Remove byte decorator from migration db_column value and default value. PWL-742: Update url pattern syntax. PWL-742: Update middleware configuration. PWL-742: Update TEMPLATES configuration. PWL-742: Update Rest Framework module Pagination configuration. PWL-742: Remove deprecated module SessionAuthenticationMiddleware. PWL-742: Replace NullBooleanField with BooleanField(null=True) as the first is likely to be deprecated in the future. PWL-742: Update get fields method call name. Remove decode method on GET param since it is already decoded by default. PWL-769: Fix database connector datetime field and data parsing issue by updating database configuration. PWL-742: Wrap password hash into a function. Encode password before hashing. PWL-742: Decode raw response from bytes to string before assert in test cases. PWL-742: Refactor code so encode and decode method will use default charset instead of hardcoded. PWL-742: Update all naive datetime object to be timezone aware format. PWL-742: Update TEMPLATES configuration to add loader classes. PWL-742: Override default configuration of django logging to prevent too many error email sent. PWL-773: Override default setting to allow sending email in manual test cases. --- apikey/migrations/0001_initial.py | 2 +- apikey/serializers.py | 2 +- apikey/testSamples.py | 2 +- apikey/tests.py | 9 +- apikey/views.py | 4 +- authentication/manualTests.py | 11 +- authentication/migrations/0001_initial.py | 6 +- .../migrations/0002_auto_20150806_1926.py | 4 +- .../migrations/0003_auto_20150821_2103.py | 2 +- .../migrations/0004_credential_name.py | 2 +- ...5_Credentials_institution_length_64_200.py | 2 +- ..._Credential_tbl_drop_name_column_PW-161.py | 2 +- .../0007_lname_and_fname_in_credential.py | 2 +- .../migrations/0008_auto_20160820_1956.py | 2 +- authentication/models.py | 19 ++- authentication/testSamples.py | 5 +- authentication/tests.py | 12 +- authentication/urls.py | 1 + authentication/views.py | 20 ++- authorization/controls.py | 2 +- authorization/migrations/0001_initial.py | 10 +- .../migrations/0002_uripattern_length.py | 4 +- ...riPattern_RedirectUri_add_column_PWL715.py | 2 +- authorization/models.py | 6 +- authorization/serializers.py | 2 +- authorization/tests.py | 7 +- authorization/views.py | 10 +- common/common.py | 124 +++++++++--------- common/testSamples.py | 5 +- common/tests.py | 31 ++--- common/views.py | 4 +- ipranges/tests.py | 13 +- loggingapp/migrations/0001_initial.py | 4 +- loggingapp/migrations/0002_pageview_ip.py | 2 +- .../0003_PageView_NullableSessionId.py | 2 +- .../0004_increase_pageview_uri_length.py | 2 +- loggingapp/migrations/0005_added_3_fields.py | 6 +- .../0006_pageview_new_fields_PHX-497.py | 2 +- .../0007_choices_meterstatus_PHX-497.py | 4 +- loggingapp/models.py | 6 +- loggingapp/tests.py | 7 +- metering/migrations/0001_initial.py | 6 +- ...imitValue_tbl_add_pattern_column_PW-287.py | 4 +- .../0003_MeterBlacklist_newTable_PW287.py | 6 +- ...imitValue_tbl_drop_patter_columns_PW287.py | 2 +- metering/models.py | 4 +- metering/tests.py | 7 +- metering/views.py | 2 +- nullservice/apps.py | 2 +- nullservice/manualTests.py | 4 +- nullservice/models.py | 2 +- partner/migrations/0001_initial.py | 6 +- ...description_subscriptiondescriptionitem.py | 8 +- .../0003_subscriptiondescriptionitem_text.py | 2 +- .../0004_subscriptionterm_description.py | 2 +- .../0005_partner_termofserviceuri.py | 2 +- partner/migrations/0006_HomePageUri.py | 2 +- ...007_Partner_description_addColumn_PW271.py | 2 +- ...l_add_login_register_link_colums_PW-336.py | 2 +- .../0009_Partner_tbl_rename_colums_PW-336.py | 2 +- ...riptionListDesc_field_to_partner_PW-332.py | 2 +- .../0011_Partner_registerText_column_PW321.py | 2 +- ...012_Partner_ForgotUIEmail_columns_PW342.py | 2 +- ...artner_ForgotUIEmail_body_columns_PW342.py | 2 +- .../0014_PartnerUIDPWDPlaceHoldersPW348.py | 6 +- .../0015_partner_forgotusernametext.py | 2 +- ..._Partner_resetpwdemailbody_column_PW357.py | 2 +- ...17_Partner_loginRedirectErrorText_PW360.py | 2 +- .../0018_added_defaultLoginRedirect_PW-373.py | 2 +- .../0019_added_uiUri_uiMeterUri_PW-376.py | 2 +- .../0020_Partner_GuideURI_columns_PW419.py | 2 +- partner/models.py | 8 +- partner/tests.py | 4 +- partner/views.py | 4 +- party/manualTests.py | 7 +- party/migrations/0001_initial.py | 6 +- party/migrations/0002_auto_20150817_2225.py | 6 +- party/migrations/0003_iprange_label.py | 2 +- party/migrations/0004_auto_20150901_1757.py | 4 +- party/migrations/0004_auto_20150916_2317.py | 6 +- .../0005_remove_party_consortium.py | 2 +- party/migrations/0006_party_consortium.py | 4 +- party/migrations/0007_auto_20150917_0023.py | 4 +- party/migrations/0008_merge.py | 2 +- party/migrations/0009_auto_20150924_0050.py | 4 +- party/migrations/0010_change_party_model.py | 8 +- party/migrations/0011_remove_affiliation.py | 2 +- .../0012_create_partyaffiliation.py | 6 +- ...013_rename_primary_key_partyaffiliation.py | 2 +- .../0014_add_label_field_to_party.py | 2 +- .../0015_label_allow_blank-PWL-749.py | 2 +- .../0016_create_image_info_table.py | 4 +- party/models.py | 16 ++- party/testSamples.py | 2 +- party/tests.py | 10 +- party/views.py | 15 +-- paywall2/settings.py.template.prod | 43 +++++- paywall2/settings.py.template.test | 43 +++++- paywall2/urls.py | 10 +- scripts/IpRangeAddChange.py | 54 ++++---- scripts/LoadCountryIdScript.py | 16 +-- scripts/basicMigrationScript.py | 4 +- scripts/countryMigration.py | 2 +- scripts/createTestAccounts0329.py | 8 +- scripts/ltSetup.py | 2 +- scripts/organizationCountryMigrationScript.py | 14 +- scripts/personSubscriptionMigrationScript.py | 8 +- scripts/removeTestingOrganizationScript.py | 4 +- scripts/runTestPartyCountry.py | 4 +- scripts/subscriptionMigrationScript.py | 22 ++-- scripts/updateConsortiumSubscriptionFields.py | 2 +- scripts/updatePartyPasswordsFromFile.py | 4 +- scripts/userMigrationScript.py | 6 +- subscription/controls.py | 20 +-- subscription/migrations/0001_initial.py | 24 ++-- ...002_unique_constraint_partyId_partnerId.py | 2 +- .../0003_subscriptionrequestmodel.py | 4 +- .../0004_subscriptionrequest_requesttype.py | 2 +- ...ransactionType_to_activationCode_PW-438.py | 2 +- .../0006_cons_fields_subscription_PWL-579.py | 6 +- .../0007_added_delete_marker_POL-20.py | 2 +- subscription/models.py | 16 +-- subscription/testSamples.py | 21 +-- subscription/tests.py | 15 +-- subscription/views.py | 18 +-- 125 files changed, 515 insertions(+), 452 deletions(-) diff --git a/apikey/migrations/0001_initial.py b/apikey/migrations/0001_initial.py index 796ec7ab..ffbdfdfc 100644 --- a/apikey/migrations/0001_initial.py +++ b/apikey/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/apikey/serializers.py b/apikey/serializers.py index 57d20a9a..1f286413 100644 --- a/apikey/serializers.py +++ b/apikey/serializers.py @@ -1,6 +1,6 @@ #Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. -from models import ApiKey +from .models import ApiKey from rest_framework import serializers class ApiKeySerializer(serializers.ModelSerializer): diff --git a/apikey/testSamples.py b/apikey/testSamples.py index 1079f50a..5071cf86 100644 --- a/apikey/testSamples.py +++ b/apikey/testSamples.py @@ -1,7 +1,7 @@ import django import sys from django.test import TestCase -from models import ApiKey +from .models import ApiKey from common.tests import TestGenericInterfaces genericForcePost = TestGenericInterfaces.forcePost diff --git a/apikey/tests.py b/apikey/tests.py index 2ba88d48..b2b48524 100644 --- a/apikey/tests.py +++ b/apikey/tests.py @@ -6,11 +6,10 @@ import requests import json from django.test import TestCase -from models import ApiKey -from testSamples import ApiKeySample +from .models import ApiKey +from .testSamples import ApiKeySample from common.tests import TestGenericInterfaces, GenericCRUDTest -# Python 3: module Cookie -> http.cookies -from Cookie import SimpleCookie +from http.cookies import SimpleCookie # Create your tests here. django.setup() @@ -27,7 +26,7 @@ def test_for_get_all(self): # ----------------- END OF BASIC CRUD OPERATIONS ---------------------- -print "Running unit tests on API key web services API........." +print("Running unit tests on API key web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/apikey/views.py b/apikey/views.py index dbb5458d..48185ff8 100644 --- a/apikey/views.py +++ b/apikey/views.py @@ -3,8 +3,8 @@ from django.http import HttpResponse from rest_framework import generics -from models import ApiKey -from serializers import ApiKeySerializer +from .models import ApiKey +from .serializers import ApiKeySerializer import json diff --git a/authentication/manualTests.py b/authentication/manualTests.py index ba46d38a..b4fd0935 100644 --- a/authentication/manualTests.py +++ b/authentication/manualTests.py @@ -8,16 +8,17 @@ from partner.testSamples import PartnerSample from party.testSamples import UserPartySample from common.tests import TestGenericInterfaces, GenericTest -from testSamples import CredentialSample -from tests import CredentialGenericTest -# Python 3: module Cookie -> http.cookies -from Cookie import SimpleCookie +from .testSamples import CredentialSample +from .tests import CredentialGenericTest +from http.cookies import SimpleCookie +from django.test.utils import override_settings # Create your tests here. django.setup() serverUrl = TestGenericInterfaces.getHost() # test for API endpoint /credentials/resetPwd/ +@override_settings(EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend') class ResetPasswordTest(CredentialGenericTest): def test_for_reset_password(self): @@ -28,7 +29,7 @@ def test_for_reset_password(self): res = self.client.put(url, None, content_type='application/json') self.assertEqual(res.status_code, 200) -print "Running unit tests on authentication/credential reset password web services API........." +print("Running unit tests on authentication/credential reset password web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/authentication/migrations/0001_initial.py b/authentication/migrations/0001_initial.py index 392a8553..c6cb06df 100644 --- a/authentication/migrations/0001_initial.py +++ b/authentication/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -16,7 +16,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('gmail', models.CharField(max_length=128, db_index=True)), - ('partyId', models.ForeignKey(to='party.Party')), + ('partyId', models.ForeignKey(to='party.Party', on_delete=models.PROTECT)), ], options={ 'db_table': 'GoogleEmail', @@ -30,7 +30,7 @@ class Migration(migrations.Migration): ('password', models.CharField(max_length=32)), ('email', models.CharField(max_length=128, null=True)), ('institution', models.CharField(max_length=64, null=True)), - ('partyId', models.ForeignKey(to='party.Party', db_column=b'partyId')), + ('partyId', models.ForeignKey(to='party.Party', db_column='partyId', on_delete=models.PROTECT)), ], options={ 'db_table': 'User', diff --git a/authentication/migrations/0002_auto_20150806_1926.py b/authentication/migrations/0002_auto_20150806_1926.py index 31b10958..a6d6a613 100644 --- a/authentication/migrations/0002_auto_20150806_1926.py +++ b/authentication/migrations/0002_auto_20150806_1926.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -15,7 +15,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='user', name='partnerId', - field=models.ForeignKey(db_column=b'partnerId', default='test', to='partner.Partner'), + field=models.ForeignKey(db_column='partnerId', default='test', to='partner.Partner', on_delete=models.PROTECT), preserve_default=False, ), migrations.AddField( diff --git a/authentication/migrations/0003_auto_20150821_2103.py b/authentication/migrations/0003_auto_20150821_2103.py index 41f8deee..a5f591a2 100644 --- a/authentication/migrations/0003_auto_20150821_2103.py +++ b/authentication/migrations/0003_auto_20150821_2103.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/authentication/migrations/0004_credential_name.py b/authentication/migrations/0004_credential_name.py index ab582d77..52f65532 100644 --- a/authentication/migrations/0004_credential_name.py +++ b/authentication/migrations/0004_credential_name.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/authentication/migrations/0005_Credentials_institution_length_64_200.py b/authentication/migrations/0005_Credentials_institution_length_64_200.py index b1d00662..ea783fab 100644 --- a/authentication/migrations/0005_Credentials_institution_length_64_200.py +++ b/authentication/migrations/0005_Credentials_institution_length_64_200.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/authentication/migrations/0006_Credential_tbl_drop_name_column_PW-161.py b/authentication/migrations/0006_Credential_tbl_drop_name_column_PW-161.py index 82509958..9676dfad 100644 --- a/authentication/migrations/0006_Credential_tbl_drop_name_column_PW-161.py +++ b/authentication/migrations/0006_Credential_tbl_drop_name_column_PW-161.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/authentication/migrations/0007_lname_and_fname_in_credential.py b/authentication/migrations/0007_lname_and_fname_in_credential.py index 89646847..06d88dc4 100644 --- a/authentication/migrations/0007_lname_and_fname_in_credential.py +++ b/authentication/migrations/0007_lname_and_fname_in_credential.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/authentication/migrations/0008_auto_20160820_1956.py b/authentication/migrations/0008_auto_20160820_1956.py index 7bb45cc9..1adc9813 100644 --- a/authentication/migrations/0008_auto_20160820_1956.py +++ b/authentication/migrations/0008_auto_20160820_1956.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/authentication/models.py b/authentication/models.py index 848f8dbc..adcf8714 100644 --- a/authentication/models.py +++ b/authentication/models.py @@ -14,8 +14,8 @@ class Credential(models.Model): password = models.CharField(max_length=64) email = models.CharField(max_length=254, null=True) institution = models.CharField(max_length=200, null=True)#PW-254 - partyId = models.ForeignKey(Party, db_column='partyId') - partnerId = models.ForeignKey(Partner, db_column='partnerId') + partyId = models.ForeignKey(Party, db_column='partyId', on_delete=models.PROTECT) + partnerId = models.ForeignKey(Partner, db_column='partnerId', on_delete=models.PROTECT) userIdentifier = models.CharField(max_length=32, null=True) #name = models.CharField(max_length=64, null=True) vet PW-161 @@ -25,24 +25,33 @@ def validate(partyId, secretKey): pu = Party.objects.filter(partyId=partyId) if Credential.objects.filter(partyId_id__in=pu.values('partyId')).exists(): usu = Credential.objects.filter(partyId_id__in=pu.values('partyId')).first() - digested = base64.b64encode(hmac.new(str(partyId).encode('ascii'), usu.password.encode('ascii'), hashlib.sha1).digest()) + digested = Credential.generateSecretKey(partyId, usu.password) if digested == secretKey: return True #TODO: validation still fail pu = pu.first().consortiums.all() if Credential.objects.filter(partyId_id__in=pu.values('partyId')).exists(): for usu in Credential.objects.filter(partyId_id__in=pu.values('partyId')): - digested = base64.b64encode(hmac.new(str(usu.partyId).encode('ascii'), usu.password.encode('ascii'), hashlib.sha1).digest()) + digested = Credential.generateSecretKey(usu.partyId, usu.password) if digested == secretKey: return True return False + @staticmethod + def generatePasswordHash(password): + return hashlib.sha1(password.encode()).hexdigest() + + @staticmethod + def generateSecretKey(partyId, password): + encoded = base64.b64encode(hmac.new(str(partyId).encode('ascii'), password.encode('ascii'), hashlib.sha1).digest()) + return encoded.decode() + class Meta: db_table = "Credential" unique_together = ("username","partnerId") class GooglePartyAffiliation(models.Model): gmail = models.CharField(max_length=128, db_index=True) - partyId = models.ForeignKey(Party) + partyId = models.ForeignKey(Party, on_delete=models.PROTECT) class Meta: db_table = "GoogleEmail" diff --git a/authentication/testSamples.py b/authentication/testSamples.py index 87c43593..444f5ec4 100644 --- a/authentication/testSamples.py +++ b/authentication/testSamples.py @@ -5,7 +5,6 @@ from partner.models import Partner from party.models import Party from common.tests import TestGenericInterfaces -from authentication.views import generateSecretKey genericForcePost = TestGenericInterfaces.forcePost @@ -92,7 +91,7 @@ def forcePost(self,data): return genericForcePost(self.model, self.pkName, postData) def hashPassword(self, password): - return hashlib.sha1(password).hexdigest() + return Credential.generatePasswordHash(password) def getLoginUrl(self): return self.serverUrl + self.loginPath + '?partnerId=%s' % self.data['partnerId'] @@ -105,4 +104,4 @@ def getLoginData(self): def getSecretKey(self): # this has dependency on authentication.views regarding argument - return generateSecretKey(self.data['partyId'], self.hashPassword(self.data['password'])) \ No newline at end of file + return Credential.generateSecretKey(self.data['partyId'], self.hashPassword(self.data['password'])) \ No newline at end of file diff --git a/authentication/tests.py b/authentication/tests.py index fb3a5631..9fea8dab 100644 --- a/authentication/tests.py +++ b/authentication/tests.py @@ -5,15 +5,13 @@ import sys import json import copy -# Python 3: library urllib -> urllib.parse -import urllib +import urllib.request, urllib.parse, urllib.error from django.test import TestCase, Client from partner.testSamples import PartnerSample from party.testSamples import UserPartySample from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest, ManualTest, checkMatch -from testSamples import CredentialSample -# Python 3: module Cookie -> http.cookies -from Cookie import SimpleCookie +from .testSamples import CredentialSample +from http.cookies import SimpleCookie # Create your tests here. django.setup() @@ -156,7 +154,7 @@ def test_for_update_profile(self): def getUserLoginCredential(self): sample = self.sample - secretKey = urllib.quote(sample.getSecretKey()) + secretKey = urllib.parse.quote(sample.getSecretKey()) return 'credentialId=%s&secretKey=%s' % (sample.getPartyId(), secretKey) class CredentialGenericTest(TestCase): @@ -226,7 +224,7 @@ class ResetPasswordTest(ManualTest, TestCase): path = "/credentials/resetPwd/" testMethodStr = "running ./manage.py test authentication.manualTests" -print "Running unit tests on authentication/credential web services API........." +print("Running unit tests on authentication/credential web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/authentication/urls.py b/authentication/urls.py index 2070fb5f..851ef6ac 100644 --- a/authentication/urls.py +++ b/authentication/urls.py @@ -4,6 +4,7 @@ from authentication import views from rest_framework.urlpatterns import format_suffix_patterns +app_name = 'authentication' urlpatterns = [ url(r'^$', views.listcreateuser.as_view(), name='listcreateuser'), url(r'^login/$', views.login, name='login'), diff --git a/authentication/views.py b/authentication/views.py index 54d78a5a..2a466443 100644 --- a/authentication/views.py +++ b/authentication/views.py @@ -1,5 +1,4 @@ from django.shortcuts import render, redirect -from django.core.urlresolvers import reverse from django.http import HttpResponse from django.core.mail import send_mail @@ -80,7 +79,7 @@ def post(self, request, format=None): if ApiKeyPermission.has_permission(request, self): serializer_class = self.get_serializer_class() data = request.data.copy() # PW-660 - data['password'] = hashlib.sha1(data['password']).hexdigest() + data['password'] = Credential.generatePasswordHash(data['password']) if 'partyId' in data: partyId = data['partyId'] if Credential.objects.all().filter(partyId=partyId).exists(): @@ -125,7 +124,7 @@ def put(self, request, format=None): #http://stackoverflow.com/questions/18930234/django-modifying-the-request-object PW-123 data = request.data.copy() # PW-123 if 'password' in data: - data['password'] = hashlib.sha1(data['password']).hexdigest() + data['password'] = Credential.generatePasswordHash(data['password']) serializer = serializer_class(obj, data=data, partial=True) if serializer.is_valid(): serializer.save() @@ -140,8 +139,8 @@ def put(self, request, format=None): if partySerializer.is_valid(): partySerializer.save() if 'password' in data: - #data['password'] = generateSecretKey(str(obj.partyId.partyId), data['password'])#PW-254 and YM: TAIR-2493 - data['loginKey'] = generateSecretKey(str(obj.partyId.partyId), data['password']) + #data['password'] = Credential.generateSecretKey(str(obj.partyId.partyId), data['password'])#PW-254 and YM: TAIR-2493 + data['loginKey'] = Credential.generateSecretKey(str(obj.partyId.partyId), data['password']) return Response(data, status=status.HTTP_200_OK) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @@ -177,7 +176,7 @@ def login(request): # return HttpResponse(json.dumps({"message":msg}), status=401) requestPassword = request.POST.get('password') - requestHashedPassword = hashlib.sha1(request.POST.get('password')).hexdigest() + requestHashedPassword = Credential.generatePasswordHash(request.POST.get('password')) requestUser = request.POST.get('user') # iexact does not work unfortunately. Steve to find out why @@ -213,7 +212,7 @@ def login(request): response = HttpResponse(json.dumps({ "message": "Correct password", "credentialId": dbUser.partyId.partyId, - "secretKey": generateSecretKey(str(dbUser.partyId.partyId), dbUser.password), + "secretKey": Credential.generateSecretKey(str(dbUser.partyId.partyId), dbUser.password), "email": dbUser.email, "role":"librarian", "username": dbUser.username, @@ -244,7 +243,7 @@ def resetPwd(request): if user: user = user.first() password = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8)) - user.password=hashlib.sha1(password).hexdigest() + user.password = Credential.generatePasswordHash(password) user.save() subject = "Temporary password for %s (%s)" % (user.username, user.email)#PW-215 unlikely @@ -268,9 +267,6 @@ def registerUser(request): context = {'partnerId': request.GET.get('partnerId', "")} return render(request, "authentication/register.html", context) -def generateSecretKey(partyId, password): - return base64.b64encode(hmac.new(str(partyId).encode('ascii'), password.encode('ascii'), hashlib.sha1).digest()) - #/credentials/profile/ class profile(GenericCRUDView): queryset = Credential.objects.all() @@ -289,7 +285,7 @@ def put(self, request, format=None): #http://stackoverflow.com/questions/18930234/django-modifying-the-request-object PW-123 data = request.data.copy() # PW-123 if 'password' in data: - data['password'] = hashlib.sha1(data['password']).hexdigest() + data['password'] = Credential.generatePasswordHash(data['password']) serializer = serializer_class(obj, data=data, partial=True) if serializer.is_valid(): serializer.save() diff --git a/authorization/controls.py b/authorization/controls.py index c94c520b..c6d3b2ac 100644 --- a/authorization/controls.py +++ b/authorization/controls.py @@ -1,6 +1,6 @@ #import Path, AccessType -from models import Status, AccessType +from .models import Status, AccessType from subscription.models import Subscription from authentication.models import Credential diff --git a/authorization/migrations/0001_initial.py b/authorization/migrations/0001_initial.py index 6fd60bb0..2a401d1a 100644 --- a/authorization/migrations/0001_initial.py +++ b/authorization/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -34,7 +34,7 @@ class Migration(migrations.Migration): name='UriPattern', fields=[ ('patternId', models.AutoField(serialize=False, primary_key=True)), - ('pattern', models.CharField(default=b'', max_length=200)), + ('pattern', models.CharField(default='', max_length=200)), ], options={ 'db_table': 'UriPattern', @@ -43,16 +43,16 @@ class Migration(migrations.Migration): migrations.AddField( model_name='accessrule', name='accessTypeId', - field=models.ForeignKey(to='authorization.AccessType'), + field=models.ForeignKey(to='authorization.AccessType', on_delete=models.PROTECT), ), migrations.AddField( model_name='accessrule', name='partnerId', - field=models.ForeignKey(to='partner.Partner'), + field=models.ForeignKey(to='partner.Partner', on_delete=models.PROTECT), ), migrations.AddField( model_name='accessrule', name='patternId', - field=models.ForeignKey(to='authorization.UriPattern'), + field=models.ForeignKey(to='authorization.UriPattern', on_delete=models.PROTECT), ), ] diff --git a/authorization/migrations/0002_uripattern_length.py b/authorization/migrations/0002_uripattern_length.py index c13760fc..f7b6a22c 100644 --- a/authorization/migrations/0002_uripattern_length.py +++ b/authorization/migrations/0002_uripattern_length.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -14,6 +14,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='uripattern', name='pattern', - field=models.CharField(default=b'', max_length=5000), + field=models.CharField(default='', max_length=5000), ), ] diff --git a/authorization/migrations/0003_UriPattern_RedirectUri_add_column_PWL715.py b/authorization/migrations/0003_UriPattern_RedirectUri_add_column_PWL715.py index eb9dd316..304ccf48 100644 --- a/authorization/migrations/0003_UriPattern_RedirectUri_add_column_PWL715.py +++ b/authorization/migrations/0003_UriPattern_RedirectUri_add_column_PWL715.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/authorization/models.py b/authorization/models.py index 1cbb0376..75752647 100644 --- a/authorization/models.py +++ b/authorization/models.py @@ -39,9 +39,9 @@ class Meta: class AccessRule(models.Model): accessRuleId = models.AutoField(primary_key=True) - patternId = models.ForeignKey('UriPattern') - accessTypeId = models.ForeignKey('AccessType') - partnerId = models.ForeignKey('partner.Partner') + patternId = models.ForeignKey('UriPattern', on_delete=models.PROTECT) + accessTypeId = models.ForeignKey('AccessType', on_delete=models.PROTECT) + partnerId = models.ForeignKey('partner.Partner', on_delete=models.PROTECT) class Meta: db_table = "AccessRule" diff --git a/authorization/serializers.py b/authorization/serializers.py index eb1c3e1c..d15ad1f9 100644 --- a/authorization/serializers.py +++ b/authorization/serializers.py @@ -1,6 +1,6 @@ #Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. -from models import AccessType, AccessRule, UriPattern +from .models import AccessType, AccessRule, UriPattern from rest_framework import serializers class AccessTypeSerializer(serializers.ModelSerializer): diff --git a/authorization/tests.py b/authorization/tests.py index 29513283..fcd2e4f0 100644 --- a/authorization/tests.py +++ b/authorization/tests.py @@ -10,10 +10,9 @@ from partner.testSamples import PartnerSample from authentication.testSamples import CredentialSample from subscription.testSamples import SubscriptionSample -from testSamples import UriPatternSample, AccessRuleSample, AccessTypeSample +from .testSamples import UriPatternSample, AccessRuleSample, AccessTypeSample from authorization.models import Status -# Python 3: module Cookie -> http.cookies -from Cookie import SimpleCookie +from http.cookies import SimpleCookie # Create your tests here. django.setup() @@ -463,7 +462,7 @@ def runAccessTest(self, urlToCheck, expectedUrlPaidStatus, authParam = None, ipL if expectedUserIdentifier: self.assertEqual(res['userIdentifier'], str(expectedUserIdentifier)) -print "Running unit tests on authorization web services API........." +print("Running unit tests on authorization web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/authorization/views.py b/authorization/views.py index 55aa51c5..e83fdb06 100644 --- a/authorization/views.py +++ b/authorization/views.py @@ -3,10 +3,10 @@ from django.http import HttpResponse from rest_framework.views import APIView from rest_framework import generics -from controls import Authorization +from .controls import Authorization -from models import AccessType, AccessRule, UriPattern, Status -from serializers import AccessTypeSerializer, AccessRuleSerializer, UriPatternSerializer +from .models import AccessType, AccessRule, UriPattern, Status +from .serializers import AccessTypeSerializer, AccessRuleSerializer, UriPatternSerializer from partner.models import Partner from authentication.models import Credential from common.views import GenericCRUDView @@ -16,7 +16,7 @@ import json import re -import urllib +import urllib.request, urllib.parse, urllib.error import logging logger = logging.getLogger('phoenix.api.authorization') @@ -35,7 +35,7 @@ def get(self, request, format=None): partyId = request.COOKIES.get('credentialId') loginKey = request.COOKIES.get('secretKey') ipList = request.GET.get('ipList') - url = request.GET.get('url').decode('utf8') + url = request.GET.get('url') partnerId = request.GET.get('partnerId') apiKey = request.COOKIES.get('apiKey') ipList = ipList.split(',') diff --git a/common/common.py b/common/common.py index 33fb8a6a..37c70f7d 100644 --- a/common/common.py +++ b/common/common.py @@ -1,62 +1,62 @@ -# The catch-all container for any commonly used classes/functions that don't (yet) deserve dedicated containers of their own. -from django.core.exceptions import ValidationError -from django.utils.translation import ugettext_lazy as _ -from netaddr import IPAddress, IPRange, IPNetwork - -# Determine IP address of the host from which the given request has been received. -# -def getRemoteIpAddress(request): - - # If the request comes through an HTTP proxy, use the first of the IP addresses specified in the XFF header. - x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') - if x_forwarded_for: - ip = x_forwarded_for.split(',')[0] - else: - ip = request.META.get('REMOTE_ADDR') - return ip - -# validate ip range based on a series of conditions -def validateIpRange(start, end): - if isIpRangePrivate(start, end): - raise ValidationError({'IP Range': _('IP range contains private IP: %s - %s' % (start, end))}) - if not validateIpRangeSize(start, end): - raise ValidationError({'IP Range': _('IP range too large: %s - %s' % (start, end))}) - -# check if the ip range is private -def isIpRangePrivate(start, end): - if IPAddress(start).is_private() or IPAddress(end).is_private(): - return True - ipRange = IPRange(start, end) - if ipRange.__getstate__()[2] == 4: - for cidr in IPV4_PRIVATE: - - if ipRange.__contains__(cidr): - return True - if ipRange.__getstate__()[2] == 6: - for cidr in IPV6_PRIVATE: - if ipRange.__contains__(cidr): - return True - return False - -IPV4_PRIVATE = ( - IPNetwork('10.0.0.0/8'), # Class A private network local communication (RFC 1918) - IPNetwork('100.64.0.0/10'), # Carrier grade NAT (RFC 6598) - IPNetwork('172.16.0.0/12'), # Private network - local communication (RFC 1918) - IPNetwork('192.0.0.0/24'), # IANA IPv4 Special Purpose Address Registry (RFC 5736) - IPNetwork('192.168.0.0/16'), # Class B private network local communication (RFC 1918) - IPNetwork('198.18.0.0/15'), # Testing of inter-network communications between subnets (RFC 2544) - IPRange('239.0.0.0', '239.255.255.255'), # Administrative Multicast -) - -IPV6_PRIVATE = ( - IPNetwork('fc00::/7'), # Unique Local Addresses (ULA) - IPNetwork('fec0::/10'), # Site Local Addresses (deprecated - RFC 3879) -) - -# check if the ip range is over the limit -def validateIpRangeSize(start, end): - ipRange = IPRange(start, end) - if ipRange.__getstate__()[2] == 4: - return True if ipRange.size <= 65536 else False - if ipRange.__getstate__()[2] == 6: - return True if ipRange.size <= 324518553658426726783156020576256 else False +# The catch-all container for any commonly used classes/functions that don't (yet) deserve dedicated containers of their own. +from django.core.exceptions import ValidationError +from django.utils.translation import ugettext_lazy as _ +from netaddr import IPAddress, IPRange, IPNetwork + +# Determine IP address of the host from which the given request has been received. +# +def getRemoteIpAddress(request): + + # If the request comes through an HTTP proxy, use the first of the IP addresses specified in the XFF header. + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + if x_forwarded_for: + ip = x_forwarded_for.split(',')[0] + else: + ip = request.META.get('REMOTE_ADDR') + return ip + +# validate ip range based on a series of conditions +def validateIpRange(start, end): + if isIpRangePrivate(start, end): + raise ValidationError({'IP Range': _('IP range contains private IP: %s - %s' % (start, end))}) + if not validateIpRangeSize(start, end): + raise ValidationError({'IP Range': _('IP range too large: %s - %s' % (start, end))}) + +# check if the ip range is private +def isIpRangePrivate(start, end): + if IPAddress(start).is_private() or IPAddress(end).is_private(): + return True + ipRange = IPRange(start, end) + if ipRange.__getstate__()[2] == 4: + for cidr in IPV4_PRIVATE: + + if ipRange.__contains__(cidr): + return True + if ipRange.__getstate__()[2] == 6: + for cidr in IPV6_PRIVATE: + if ipRange.__contains__(cidr): + return True + return False + +IPV4_PRIVATE = ( + IPNetwork('10.0.0.0/8'), # Class A private network local communication (RFC 1918) + IPNetwork('100.64.0.0/10'), # Carrier grade NAT (RFC 6598) + IPNetwork('172.16.0.0/12'), # Private network - local communication (RFC 1918) + IPNetwork('192.0.0.0/24'), # IANA IPv4 Special Purpose Address Registry (RFC 5736) + IPNetwork('192.168.0.0/16'), # Class B private network local communication (RFC 1918) + IPNetwork('198.18.0.0/15'), # Testing of inter-network communications between subnets (RFC 2544) + IPRange('239.0.0.0', '239.255.255.255'), # Administrative Multicast +) + +IPV6_PRIVATE = ( + IPNetwork('fc00::/7'), # Unique Local Addresses (ULA) + IPNetwork('fec0::/10'), # Site Local Addresses (deprecated - RFC 3879) +) + +# check if the ip range is over the limit +def validateIpRangeSize(start, end): + ipRange = IPRange(start, end) + if ipRange.__getstate__()[2] == 4: + return True if ipRange.size <= 65536 else False + if ipRange.__getstate__()[2] == 6: + return True if ipRange.size <= 324518553658426726783156020576256 else False diff --git a/common/testSamples.py b/common/testSamples.py index 40f55f50..cd45883c 100644 --- a/common/testSamples.py +++ b/common/testSamples.py @@ -2,7 +2,6 @@ from partner.models import Partner from party.models import Party from authentication.models import Credential -from authentication.views import generateSecretKey import copy import hashlib @@ -94,8 +93,8 @@ def forcePost(self,data): return forcePost(self.model, self.pkName, postData) def hashPassword(self, password): - return hashlib.sha1(password).hexdigest() + return Credential.generatePasswordHash(password) def getSecretKey(self): # this has dependency on authentication.views regarding argument - return generateSecretKey(self.data['partyId'], self.hashPassword(self.data['password'])) + return Credential.generateSecretKey(self.data['partyId'], self.hashPassword(self.data['password'])) diff --git a/common/tests.py b/common/tests.py index 5d581fe1..4e904e5c 100644 --- a/common/tests.py +++ b/common/tests.py @@ -1,15 +1,13 @@ import json import sys import time -# Python 3: library urllib -> urllib.parse -import urllib -from testSamples import CommonApiKeySample, CommonPartnerSample, CommonUserPartySample, CommonCredentialSample +import urllib.request, urllib.parse, urllib.error +from .testSamples import CommonApiKeySample, CommonPartnerSample, CommonUserPartySample, CommonCredentialSample from partner.models import Partner from apikey.models import ApiKey from django.test import Client from django.conf import settings -# Python 3: module Cookie -> http.cookies -from Cookie import SimpleCookie +from http.cookies import SimpleCookie class TestGenericInterfaces: @staticmethod @@ -83,7 +81,7 @@ def setUp(self): self.secretKey = credentialSample.getSecretKey() def getUrl(self, url, pkName = None, pk = None): - secretKey = urllib.quote(self.secretKey) + secretKey = urllib.parse.quote(self.secretKey) fullUrl = url + '?credentialId=%s&secretKey=%s' % (self.credentialId, secretKey) if pkName and pk: fullUrl = '%s&%s=%s' % (fullUrl, pkName, str(pk)) @@ -103,12 +101,11 @@ def checkMatch(sampleData, retrievedData, pkName, pk): for key in sampleData: # makes sure that all contents from sample is the # same as content retrieved from request - if not key in item or not (item[key] == sampleData[key] or compareDateTime(sampleData[key], item[key]) - or float(item[key]) == float(sampleData[key])): + if not key in item or not (item[key] == sampleData[key] or float(item[key]) == float(sampleData[key])): hasMatch = False break if not hasMatch: - print "\nERROR: sample data %s and retrieved data %s does not match" % (sampleData, retrievedData) + print("\nERROR: sample data %s and retrieved data %s does not match" % (sampleData, retrievedData)) return hasMatch ## This function checks if sampleData is within the array of data retrieved @@ -123,10 +120,6 @@ def filterAndCheckMatch(sampleData, retrievedDataArray, pkName, pk, commonKeyNam filteredArray.append(item) return checkMatch(sampleData, filteredArray, pkName, pk) -def compareDateTime(sampleTime, retrievedTime): - retrievedTime = retrievedTime.replace('T', ' ').replace('Z', '') - return sampleTime == retrievedTime - class GenericGETOnlyTest(GenericTest): def test_for_get_all(self): @@ -213,17 +206,17 @@ class ManualTest(object): testMethodStr = "" def test_warning(self): - print "\n----------------------------------------------------------------------" - print "\nWARNING: Please manually test API end point %s if necessary.\n\ + print("\n----------------------------------------------------------------------") + print("\nWARNING: Please manually test API end point %s if necessary.\n\ If you've \n\ (1) upgraded Python version or\n\ (2) upgraded Django version or\n\ (3) updated module or setting params related to this end point\n\ - Please make sure you test this end point by %s" % (self.path, self.testMethodStr) - print "\n----------------------------------------------------------------------" + Please make sure you test this end point by %s" % (self.path, self.testMethodStr)) + print("\n----------------------------------------------------------------------") if not TestGenericInterfaces.hasHost(): - print "WARNING: No HOSTNAME detected in settings.py." + print("WARNING: No HOSTNAME detected in settings.py.") -print "Using server url %s" % TestGenericInterfaces.getHost() +print("Using server url %s" % TestGenericInterfaces.getHost()) diff --git a/common/views.py b/common/views.py index 59b59f33..b564cb69 100644 --- a/common/views.py +++ b/common/views.py @@ -7,7 +7,9 @@ def get_queryset(self): queryset = super(GenericCRUDView, self).get_queryset() params = self.request.GET for key in params: - if key in queryset.model._meta.get_all_field_names(): + # fully backward compatiable version on get_fields method can be found here: + # https://docs.djangoproject.com/en/1.10/ref/models/meta/#migrating-from-the-old-api + if key in queryset.model._meta.get_fields(): value = params[key] filters = {key:value} try: diff --git a/ipranges/tests.py b/ipranges/tests.py index 5f9af36d..7d959cf4 100644 --- a/ipranges/tests.py +++ b/ipranges/tests.py @@ -5,7 +5,7 @@ from django.test import TestCase from common.tests import TestGenericInterfaces, GenericTest -from Cookie import SimpleCookie +from http.cookies import SimpleCookie # Create your tests here. django.setup() @@ -38,20 +38,23 @@ def assert_for_valid_ip(self, ip, ipVersion): res = self.get_response(ip) self.assertEqual(res.status_code, 200) - self.assertEqual(res.content, '{"ip version": %s}' % ipVersion) + # The raw response will be bytes so need to convert to string and then compare + self.assertEqual(res.content.decode(), '{"ip version": %s}' % ipVersion) def assert_for_invalid_ip(self, ip): res = self.get_response(ip) self.assertEqual(res.status_code, 200) - self.assertEqual(res.content, '{"ip": "invalid"}') + # The raw response will be bytes so need to convert to string and then compare + self.assertEqual(res.content.decode(), '{"ip": "invalid"}') # TODO: find example that can trigger this response def assert_for_error_input(self, ip): res = self.get_response(ip) self.assertEqual(res.status_code, 200) - self.assertEqual(res.content, '{"ip": "error"}') + # The raw response will be bytes so need to convert to string and then compare + self.assertEqual(res.content.decode(), '{"ip": "error"}') def get_response(self, ip): url = '%sipranges/validateip/?ip=%s' % (serverUrl, ip) @@ -61,7 +64,7 @@ def get_response(self, ip): return res -print "Running unit tests on IP range web services API........." +print("Running unit tests on IP range web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/loggingapp/migrations/0001_initial.py b/loggingapp/migrations/0001_initial.py index 0ef91eb0..7e11c772 100644 --- a/loggingapp/migrations/0001_initial.py +++ b/loggingapp/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations import datetime @@ -19,7 +19,7 @@ class Migration(migrations.Migration): ('uri', models.CharField(max_length=250)), ('pageViewDate', models.DateTimeField(default=datetime.datetime.utcnow)), ('sessionId', models.CharField(max_length=250)), - ('partyId', models.ForeignKey(db_column=b'partyId', to='party.Party', null=True)), + ('partyId', models.ForeignKey(db_column='partyId', to='party.Party', null=True, on_delete=models.PROTECT)), ], options={ 'db_table': 'PageView', diff --git a/loggingapp/migrations/0002_pageview_ip.py b/loggingapp/migrations/0002_pageview_ip.py index 742ca3d4..09b62485 100644 --- a/loggingapp/migrations/0002_pageview_ip.py +++ b/loggingapp/migrations/0002_pageview_ip.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/loggingapp/migrations/0003_PageView_NullableSessionId.py b/loggingapp/migrations/0003_PageView_NullableSessionId.py index e9c70e25..29d7c204 100644 --- a/loggingapp/migrations/0003_PageView_NullableSessionId.py +++ b/loggingapp/migrations/0003_PageView_NullableSessionId.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/loggingapp/migrations/0004_increase_pageview_uri_length.py b/loggingapp/migrations/0004_increase_pageview_uri_length.py index ef48bc84..142ac769 100644 --- a/loggingapp/migrations/0004_increase_pageview_uri_length.py +++ b/loggingapp/migrations/0004_increase_pageview_uri_length.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/loggingapp/migrations/0005_added_3_fields.py b/loggingapp/migrations/0005_added_3_fields.py index 555cfe25..4f646228 100644 --- a/loggingapp/migrations/0005_added_3_fields.py +++ b/loggingapp/migrations/0005_added_3_fields.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -20,11 +20,11 @@ class Migration(migrations.Migration): migrations.AddField( model_name='pageview', name='isPaidContent', - field=models.NullBooleanField(), + field=models.BooleanField(null=True), ), migrations.AddField( model_name='pageview', name='partnerId', - field=models.ForeignKey(db_column=b'partnerId', to='partner.Partner', null=True), + field=models.ForeignKey(db_column='partnerId', to='partner.Partner', null=True, on_delete=models.PROTECT), ), ] diff --git a/loggingapp/migrations/0006_pageview_new_fields_PHX-497.py b/loggingapp/migrations/0006_pageview_new_fields_PHX-497.py index 54f94c5e..4d476796 100644 --- a/loggingapp/migrations/0006_pageview_new_fields_PHX-497.py +++ b/loggingapp/migrations/0006_pageview_new_fields_PHX-497.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/loggingapp/migrations/0007_choices_meterstatus_PHX-497.py b/loggingapp/migrations/0007_choices_meterstatus_PHX-497.py index 26642c42..50d120d2 100644 --- a/loggingapp/migrations/0007_choices_meterstatus_PHX-497.py +++ b/loggingapp/migrations/0007_choices_meterstatus_PHX-497.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -14,6 +14,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='pageview', name='meterStatus', - field=models.CharField(max_length=1, null=True, choices=[(b'W', b'Warning'), (b'B', b'Block'), (b'M', b'Must subscribe'), (b'N', b'Not metered')]), + field=models.CharField(max_length=1, null=True, choices=[('W', 'Warning'), ('B', 'Block'), ('M', 'Must subscribe'), ('N', 'Not metered')]), ), ] diff --git a/loggingapp/models.py b/loggingapp/models.py index e3b894f4..e5344d0d 100644 --- a/loggingapp/models.py +++ b/loggingapp/models.py @@ -9,13 +9,13 @@ class PageView(models.Model): pageViewId = models.AutoField(primary_key=True) uri = models.CharField(max_length=2000) - partyId = models.ForeignKey('party.Party', db_column='partyId', null=True) + partyId = models.ForeignKey('party.Party', db_column='partyId', null=True, on_delete=models.PROTECT) pageViewDate = models.DateTimeField(default=datetime.datetime.utcnow) sessionId = models.CharField(max_length=250, null=True) ip = models.GenericIPAddressField(max_length=200) ipList = models.CharField(max_length=250, null=True) - partnerId = models.ForeignKey(Partner, db_column='partnerId', null=True) - isPaidContent = models.NullBooleanField() + partnerId = models.ForeignKey(Partner, db_column='partnerId', null=True, on_delete=models.PROTECT) + isPaidContent = models.BooleanField(null=True) # meter choices METER_WARNING_STATUS = 'W' diff --git a/loggingapp/tests.py b/loggingapp/tests.py index 9f9f386f..52678506 100644 --- a/loggingapp/tests.py +++ b/loggingapp/tests.py @@ -9,9 +9,8 @@ from partner.testSamples import PartnerSample from party.testSamples import UserPartySample from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest -from testSamples import PageViewSample -# Python 3: module Cookie -> http.cookies -from Cookie import SimpleCookie +from .testSamples import PageViewSample +from http.cookies import SimpleCookie # Create your tests here. django.setup() @@ -92,7 +91,7 @@ def runTest(self, startDate, endDate, expectedCount): # skipped testing for /session-logs/page-views/csv/ since no external resource uses its -print "Running unit tests on session logs web services API........." +print("Running unit tests on session logs web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/metering/migrations/0001_initial.py b/metering/migrations/0001_initial.py index d5ee29ac..b0236b8b 100644 --- a/metering/migrations/0001_initial.py +++ b/metering/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -17,7 +17,7 @@ class Migration(migrations.Migration): ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('ip', models.GenericIPAddressField(db_index=True)), ('count', models.IntegerField(default=1)), - ('partnerId', models.ForeignKey(to='partner.Partner', db_column=b'partnerId')), + ('partnerId', models.ForeignKey(to='partner.Partner', db_column='partnerId', on_delete=models.PROTECT)), ], options={ 'db_table': 'IPAddressCount', @@ -28,7 +28,7 @@ class Migration(migrations.Migration): fields=[ ('limitId', models.AutoField(serialize=False, primary_key=True)), ('val', models.IntegerField()), - ('partnerId', models.ForeignKey(to='partner.Partner', db_column=b'partnerId')), + ('partnerId', models.ForeignKey(to='partner.Partner', db_column='partnerId', on_delete=models.PROTECT)), ], options={ 'db_table': 'LimitValue', diff --git a/metering/migrations/0002_LimitValue_tbl_add_pattern_column_PW-287.py b/metering/migrations/0002_LimitValue_tbl_add_pattern_column_PW-287.py index ffee22d7..4232039d 100644 --- a/metering/migrations/0002_LimitValue_tbl_add_pattern_column_PW-287.py +++ b/metering/migrations/0002_LimitValue_tbl_add_pattern_column_PW-287.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models @@ -14,6 +14,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='limitvalue', name='pattern', - field=models.CharField(default=b'', max_length=5000), + field=models.CharField(default='', max_length=5000), ), ] diff --git a/metering/migrations/0003_MeterBlacklist_newTable_PW287.py b/metering/migrations/0003_MeterBlacklist_newTable_PW287.py index eb784c8b..7ac74483 100644 --- a/metering/migrations/0003_MeterBlacklist_newTable_PW287.py +++ b/metering/migrations/0003_MeterBlacklist_newTable_PW287.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models @@ -15,8 +15,8 @@ class Migration(migrations.Migration): name='MeterBlacklist', fields=[ ('meterBlackListId', models.AutoField(serialize=False, primary_key=True)), - ('partnerId', models.CharField(default=b'', max_length=200)), - ('pattern', models.CharField(default=b'', max_length=5000)), + ('partnerId', models.CharField(default='', max_length=200)), + ('pattern', models.CharField(default='', max_length=5000)), ], options={ 'db_table': 'MeterBlacklist', diff --git a/metering/migrations/0004_LimitValue_tbl_drop_patter_columns_PW287.py b/metering/migrations/0004_LimitValue_tbl_drop_patter_columns_PW287.py index 760ca05c..1f5ea60f 100644 --- a/metering/migrations/0004_LimitValue_tbl_drop_patter_columns_PW287.py +++ b/metering/migrations/0004_LimitValue_tbl_drop_patter_columns_PW287.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/metering/models.py b/metering/models.py index 193bf551..2f358267 100644 --- a/metering/models.py +++ b/metering/models.py @@ -6,7 +6,7 @@ class IpAddressCount(models.Model): ip = models.GenericIPAddressField(max_length=200, db_index=True) count = models.IntegerField(default=1) - partnerId = models.ForeignKey(Partner, db_column="partnerId") + partnerId = models.ForeignKey(Partner, db_column="partnerId", on_delete=models.PROTECT) class Meta: db_table = "IPAddressCount" def __str__(self): @@ -15,7 +15,7 @@ def __str__(self): class LimitValue(models.Model): limitId = models.AutoField(primary_key=True) val = models.IntegerField() - partnerId = models.ForeignKey(Partner, db_column="partnerId") + partnerId = models.ForeignKey(Partner, db_column="partnerId", on_delete=models.PROTECT) class Meta: db_table = "LimitValue" def __str__(self): diff --git a/metering/tests.py b/metering/tests.py index 431c4151..8375ab8e 100644 --- a/metering/tests.py +++ b/metering/tests.py @@ -10,9 +10,8 @@ from partner.testSamples import PartnerSample from partner.models import Partner from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest -from testSamples import LimitValueSample, IpAddressCountSample, MeterBlacklistSample -# Python 3: module Cookie -> http.cookies -from Cookie import SimpleCookie +from .testSamples import LimitValueSample, IpAddressCountSample, MeterBlacklistSample +from http.cookies import SimpleCookie # Create your tests here. django.setup() @@ -164,7 +163,7 @@ def test_for_blacklisted_url(self): url = '%smeters/ip/%s/limit/?partnerId=%s&uri=%s' % (serverUrl, self.successIpAddressCountSample.getIp(), self.partnerId, uri) self.assert_check_limit(url, 'BlackListBlock') -print "Running unit tests on metering web services API........." +print("Running unit tests on metering web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/metering/views.py b/metering/views.py index 949bda4b..dd25561f 100644 --- a/metering/views.py +++ b/metering/views.py @@ -78,7 +78,7 @@ class check_limit(APIView): ''' def get(self, request, ip, format=None): partnerId = request.GET.get('partnerId') - uri = request.GET.get('uri').decode('utf8') + uri = request.GET.get('uri') """PW-287 Change the check_limit() function to get the patterns for the specified partner by partnerId and iterate through them to find any matches, diff --git a/nullservice/apps.py b/nullservice/apps.py index ef89634e..a6c0cebe 100644 --- a/nullservice/apps.py +++ b/nullservice/apps.py @@ -1,4 +1,4 @@ -from __future__ import unicode_literals + from django.apps import AppConfig diff --git a/nullservice/manualTests.py b/nullservice/manualTests.py index 6438616c..6672f807 100644 --- a/nullservice/manualTests.py +++ b/nullservice/manualTests.py @@ -5,7 +5,7 @@ from django.test import TestCase from common.tests import TestGenericInterfaces, GenericTest -from Cookie import SimpleCookie +from http.cookies import SimpleCookie # Create your tests here. django.setup() @@ -21,7 +21,7 @@ def test_for_get(self): self.assertEqual(res.status_code, 200) -print "Running unit tests on nullservice web services API........." +print("Running unit tests on nullservice web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/nullservice/models.py b/nullservice/models.py index bd4b2abe..19512613 100644 --- a/nullservice/models.py +++ b/nullservice/models.py @@ -1,4 +1,4 @@ -from __future__ import unicode_literals + from django.db import models diff --git a/partner/migrations/0001_initial.py b/partner/migrations/0001_initial.py index 5dac28d1..209755da 100644 --- a/partner/migrations/0001_initial.py +++ b/partner/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -27,7 +27,7 @@ class Migration(migrations.Migration): ('partnerPatternId', models.AutoField(serialize=False, primary_key=True)), ('sourceUri', models.CharField(max_length=200)), ('targetUri', models.CharField(max_length=200)), - ('partnerId', models.ForeignKey(to='partner.Partner', db_column=b'partnerId')), + ('partnerId', models.ForeignKey(to='partner.Partner', db_column='partnerId', on_delete=models.PROTECT)), ], options={ 'db_table': 'PartnerPattern', @@ -40,7 +40,7 @@ class Migration(migrations.Migration): ('period', models.IntegerField()), ('price', models.DecimalField(max_digits=6, decimal_places=2)), ('groupDiscountPercentage', models.DecimalField(max_digits=6, decimal_places=2)), - ('partnerId', models.ForeignKey(to='partner.Partner', db_column=b'partnerId')), + ('partnerId', models.ForeignKey(to='partner.Partner', db_column='partnerId', on_delete=models.PROTECT)), ], options={ 'db_table': 'SubscriptionTerm', diff --git a/partner/migrations/0002_subscriptiondescription_subscriptiondescriptionitem.py b/partner/migrations/0002_subscriptiondescription_subscriptiondescriptionitem.py index 065f42a2..4744479a 100644 --- a/partner/migrations/0002_subscriptiondescription_subscriptiondescriptionitem.py +++ b/partner/migrations/0002_subscriptiondescription_subscriptiondescriptionitem.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -16,8 +16,8 @@ class Migration(migrations.Migration): fields=[ ('subscriptionDescriptionId', models.AutoField(serialize=False, primary_key=True)), ('header', models.CharField(max_length=200)), - ('descriptionType', models.CharField(default=b'Default', max_length=200)), - ('partnerId', models.ForeignKey(to='partner.Partner', db_column=b'partnerId')), + ('descriptionType', models.CharField(default='Default', max_length=200)), + ('partnerId', models.ForeignKey(to='partner.Partner', db_column='partnerId', on_delete=models.PROTECT)), ], options={ 'db_table': 'SubscriptionDescription', @@ -27,7 +27,7 @@ class Migration(migrations.Migration): name='SubscriptionDescriptionItem', fields=[ ('subscriptionDescriptionItemId', models.AutoField(serialize=False, primary_key=True)), - ('subscriptionDescriptionId', models.ForeignKey(to='partner.SubscriptionDescription', db_column=b'subscriptionDescriptionId')), + ('subscriptionDescriptionId', models.ForeignKey(to='partner.SubscriptionDescription', db_column='subscriptionDescriptionId', on_delete=models.PROTECT)), ], options={ 'db_table': 'SubscriptionDescriptionItem', diff --git a/partner/migrations/0003_subscriptiondescriptionitem_text.py b/partner/migrations/0003_subscriptiondescriptionitem_text.py index 582f6c4c..76e2e4cb 100644 --- a/partner/migrations/0003_subscriptiondescriptionitem_text.py +++ b/partner/migrations/0003_subscriptiondescriptionitem_text.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/partner/migrations/0004_subscriptionterm_description.py b/partner/migrations/0004_subscriptionterm_description.py index 89d8913d..70ef8e16 100644 --- a/partner/migrations/0004_subscriptionterm_description.py +++ b/partner/migrations/0004_subscriptionterm_description.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/partner/migrations/0005_partner_termofserviceuri.py b/partner/migrations/0005_partner_termofserviceuri.py index 56e8593e..29e6330f 100644 --- a/partner/migrations/0005_partner_termofserviceuri.py +++ b/partner/migrations/0005_partner_termofserviceuri.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/partner/migrations/0006_HomePageUri.py b/partner/migrations/0006_HomePageUri.py index 0b9a9e9f..348dbfe5 100644 --- a/partner/migrations/0006_HomePageUri.py +++ b/partner/migrations/0006_HomePageUri.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/partner/migrations/0007_Partner_description_addColumn_PW271.py b/partner/migrations/0007_Partner_description_addColumn_PW271.py index cdfc4453..0bb9e9a4 100644 --- a/partner/migrations/0007_Partner_description_addColumn_PW271.py +++ b/partner/migrations/0007_Partner_description_addColumn_PW271.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/partner/migrations/0008_Partner_tbl_add_login_register_link_colums_PW-336.py b/partner/migrations/0008_Partner_tbl_add_login_register_link_colums_PW-336.py index 26c9e295..18899f8a 100644 --- a/partner/migrations/0008_Partner_tbl_add_login_register_link_colums_PW-336.py +++ b/partner/migrations/0008_Partner_tbl_add_login_register_link_colums_PW-336.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/partner/migrations/0009_Partner_tbl_rename_colums_PW-336.py b/partner/migrations/0009_Partner_tbl_rename_colums_PW-336.py index 69ab181e..b1513a7d 100644 --- a/partner/migrations/0009_Partner_tbl_rename_colums_PW-336.py +++ b/partner/migrations/0009_Partner_tbl_rename_colums_PW-336.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/partner/migrations/0010_added_subscriptionListDesc_field_to_partner_PW-332.py b/partner/migrations/0010_added_subscriptionListDesc_field_to_partner_PW-332.py index 77ac5234..6decbd4b 100644 --- a/partner/migrations/0010_added_subscriptionListDesc_field_to_partner_PW-332.py +++ b/partner/migrations/0010_added_subscriptionListDesc_field_to_partner_PW-332.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/partner/migrations/0011_Partner_registerText_column_PW321.py b/partner/migrations/0011_Partner_registerText_column_PW321.py index 411596cd..190fab9b 100644 --- a/partner/migrations/0011_Partner_registerText_column_PW321.py +++ b/partner/migrations/0011_Partner_registerText_column_PW321.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/partner/migrations/0012_Partner_ForgotUIEmail_columns_PW342.py b/partner/migrations/0012_Partner_ForgotUIEmail_columns_PW342.py index 8869b417..a919dc57 100644 --- a/partner/migrations/0012_Partner_ForgotUIEmail_columns_PW342.py +++ b/partner/migrations/0012_Partner_ForgotUIEmail_columns_PW342.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/partner/migrations/0013_Partner_ForgotUIEmail_body_columns_PW342.py b/partner/migrations/0013_Partner_ForgotUIEmail_body_columns_PW342.py index e8799fee..66f97557 100644 --- a/partner/migrations/0013_Partner_ForgotUIEmail_body_columns_PW342.py +++ b/partner/migrations/0013_Partner_ForgotUIEmail_body_columns_PW342.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/partner/migrations/0014_PartnerUIDPWDPlaceHoldersPW348.py b/partner/migrations/0014_PartnerUIDPWDPlaceHoldersPW348.py index 501ee172..7c3d92f4 100644 --- a/partner/migrations/0014_PartnerUIDPWDPlaceHoldersPW348.py +++ b/partner/migrations/0014_PartnerUIDPWDPlaceHoldersPW348.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models @@ -24,11 +24,11 @@ class Migration(migrations.Migration): migrations.AddField( model_name='partner', name='loginPasswordFieldPrompt', - field=models.CharField(default=b'Password', max_length=20), + field=models.CharField(default='Password', max_length=20), ), migrations.AddField( model_name='partner', name='loginUserNameFieldPrompt', - field=models.CharField(default=b'Username', max_length=20), + field=models.CharField(default='Username', max_length=20), ), ] diff --git a/partner/migrations/0015_partner_forgotusernametext.py b/partner/migrations/0015_partner_forgotusernametext.py index 50310f75..2333b564 100644 --- a/partner/migrations/0015_partner_forgotusernametext.py +++ b/partner/migrations/0015_partner_forgotusernametext.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/partner/migrations/0016_Partner_resetpwdemailbody_column_PW357.py b/partner/migrations/0016_Partner_resetpwdemailbody_column_PW357.py index b576eacd..5d002ebe 100644 --- a/partner/migrations/0016_Partner_resetpwdemailbody_column_PW357.py +++ b/partner/migrations/0016_Partner_resetpwdemailbody_column_PW357.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/partner/migrations/0017_Partner_loginRedirectErrorText_PW360.py b/partner/migrations/0017_Partner_loginRedirectErrorText_PW360.py index 6e2f058f..8f008732 100644 --- a/partner/migrations/0017_Partner_loginRedirectErrorText_PW360.py +++ b/partner/migrations/0017_Partner_loginRedirectErrorText_PW360.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/partner/migrations/0018_added_defaultLoginRedirect_PW-373.py b/partner/migrations/0018_added_defaultLoginRedirect_PW-373.py index abe98100..9ca42fb1 100644 --- a/partner/migrations/0018_added_defaultLoginRedirect_PW-373.py +++ b/partner/migrations/0018_added_defaultLoginRedirect_PW-373.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/partner/migrations/0019_added_uiUri_uiMeterUri_PW-376.py b/partner/migrations/0019_added_uiUri_uiMeterUri_PW-376.py index edcd8a8e..fde603ca 100644 --- a/partner/migrations/0019_added_uiUri_uiMeterUri_PW-376.py +++ b/partner/migrations/0019_added_uiUri_uiMeterUri_PW-376.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/partner/migrations/0020_Partner_GuideURI_columns_PW419.py b/partner/migrations/0020_Partner_GuideURI_columns_PW419.py index f9691a52..a0fd0a2e 100644 --- a/partner/migrations/0020_Partner_GuideURI_columns_PW419.py +++ b/partner/migrations/0020_Partner_GuideURI_columns_PW419.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import migrations, models diff --git a/partner/models.py b/partner/models.py index 43042616..9be2005b 100644 --- a/partner/models.py +++ b/partner/models.py @@ -36,7 +36,7 @@ class Meta: class PartnerPattern(models.Model): partnerPatternId = models.AutoField(primary_key=True) - partnerId = models.ForeignKey('Partner', db_column='partnerId') + partnerId = models.ForeignKey('Partner', db_column='partnerId', on_delete=models.PROTECT) sourceUri = models.CharField(max_length=200) targetUri = models.CharField(max_length=200) @@ -46,7 +46,7 @@ class Meta: class SubscriptionTerm(models.Model): subscriptionTermId = models.AutoField(primary_key=True) description = models.CharField(max_length=200) - partnerId = models.ForeignKey('partner.Partner', db_column="partnerId") + partnerId = models.ForeignKey('partner.Partner', db_column="partnerId", on_delete=models.PROTECT) period = models.IntegerField() price = models.DecimalField(decimal_places=2,max_digits=6) groupDiscountPercentage = models.DecimalField(decimal_places=2,max_digits=6) @@ -56,7 +56,7 @@ class Meta: class SubscriptionDescriptionItem(models.Model): subscriptionDescriptionItemId = models.AutoField(primary_key=True) - subscriptionDescriptionId = models.ForeignKey('SubscriptionDescription', db_column='subscriptionDescriptionId') + subscriptionDescriptionId = models.ForeignKey('SubscriptionDescription', db_column='subscriptionDescriptionId', on_delete=models.PROTECT) text = models.CharField(max_length=2048) class Meta: @@ -65,7 +65,7 @@ class Meta: class SubscriptionDescription(models.Model): subscriptionDescriptionId = models.AutoField(primary_key=True) header = models.CharField(max_length=200) - partnerId = models.ForeignKey('Partner', db_column='partnerId') + partnerId = models.ForeignKey('Partner', db_column='partnerId', on_delete=models.PROTECT) descriptionType = models.CharField(max_length=200, default='Default') # Default, Individual, Institution, Commercial class Meta: diff --git a/partner/tests.py b/partner/tests.py index eb7b2366..11ee5ba9 100644 --- a/partner/tests.py +++ b/partner/tests.py @@ -7,7 +7,7 @@ from django.test import TestCase, Client from partner.models import Partner, PartnerPattern, SubscriptionTerm, SubscriptionDescription, SubscriptionDescriptionItem from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericGETOnlyTest, checkMatch -from testSamples import PartnerSample, PartnerPatternSample, SubscriptionTermSample, SubscriptionDescriptionSample, SubscriptionDescriptionItemSample +from .testSamples import PartnerSample, PartnerPatternSample, SubscriptionTermSample, SubscriptionDescriptionSample, SubscriptionDescriptionItemSample # Create your tests here. django.setup() @@ -77,7 +77,7 @@ def setUp(self): self.descriptionId = self.descriptionSample.forcePost(self.descriptionSample.data) self.sample.data['subscriptionDescriptionId']=self.sample.updateData['subscriptionDescriptionId']=self.descriptionId -print "Running unit tests on partner web services API........." +print("Running unit tests on partner web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/partner/views.py b/partner/views.py index fddf5dcd..57c150d9 100644 --- a/partner/views.py +++ b/partner/views.py @@ -4,8 +4,8 @@ from rest_framework.views import APIView from rest_framework import generics -from models import Partner, PartnerPattern, SubscriptionTerm, SubscriptionDescription, SubscriptionDescriptionItem -from serializers import PartnerSerializer, PartnerPatternSerializer, SubscriptionTermSerializer, SubscriptionDescriptionSerializer, SubscriptionDescriptionItemSerializer +from .models import Partner, PartnerPattern, SubscriptionTerm, SubscriptionDescription, SubscriptionDescriptionItem +from .serializers import PartnerSerializer, PartnerPatternSerializer, SubscriptionTermSerializer, SubscriptionDescriptionSerializer, SubscriptionDescriptionItemSerializer import json diff --git a/party/manualTests.py b/party/manualTests.py index 7db7287e..da06180f 100644 --- a/party/manualTests.py +++ b/party/manualTests.py @@ -3,11 +3,13 @@ import sys import json from django.test import TestCase -from testSamples import UsageSample +from .testSamples import UsageSample from django.core.mail import send_mail +from django.test.utils import override_settings # test for API end point /parties/usage/ # API used for requesting usage for consortiums/institutions +@override_settings(EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend') class GetUsageRequestTest(TestCase): sample = UsageSample() @@ -16,6 +18,7 @@ def test_for_send_usage_request(self): self.send_usage_email(self.sample.consortiumData) # this code is copied from party/views.py implementation + # since the original implementation hard coded recipient email def send_usage_email(self, data): partyName = '' partyTypeName = '' @@ -38,7 +41,7 @@ def send_usage_email(self, data): recipient_list = [self.sample.RECEIPIENT_EMAIL] self.assertEqual(send_mail(subject=subject, message=message, from_email=from_email, recipient_list=recipient_list, fail_silently=False), 1) -print "Running unit tests on consortium usage email request........." +print("Running unit tests on consortium usage email request.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/party/migrations/0001_initial.py b/party/migrations/0001_initial.py index 17199e10..4ac5c205 100644 --- a/party/migrations/0001_initial.py +++ b/party/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -25,7 +25,7 @@ class Migration(migrations.Migration): name='Party', fields=[ ('partyId', models.AutoField(serialize=False, primary_key=True)), - ('partyType', models.CharField(default=b'user', max_length=200)), + ('partyType', models.CharField(default='user', max_length=200)), ], options={ 'db_table': 'Party', @@ -34,6 +34,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='iprange', name='partyId', - field=models.ForeignKey(to='party.Party', db_column=b'partyId'), + field=models.ForeignKey(to='party.Party', db_column='partyId', on_delete=models.PROTECT), ), ] diff --git a/party/migrations/0002_auto_20150817_2225.py b/party/migrations/0002_auto_20150817_2225.py index 44eacff0..026d59d2 100644 --- a/party/migrations/0002_auto_20150817_2225.py +++ b/party/migrations/0002_auto_20150817_2225.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -29,11 +29,11 @@ class Migration(migrations.Migration): migrations.AddField( model_name='party', name='name', - field=models.CharField(default=b'', max_length=200), + field=models.CharField(default='', max_length=200), ), migrations.AddField( model_name='party', name='country', - field=models.ForeignKey(db_column=b'countryId', default=334, to='party.Country', null=True), + field=models.ForeignKey(db_column='countryId', default=334, to='party.Country', null=True, on_delete=models.PROTECT), ), ] diff --git a/party/migrations/0003_iprange_label.py b/party/migrations/0003_iprange_label.py index 8d4d1163..dd180be9 100644 --- a/party/migrations/0003_iprange_label.py +++ b/party/migrations/0003_iprange_label.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/party/migrations/0004_auto_20150901_1757.py b/party/migrations/0004_auto_20150901_1757.py index a18a51bc..c418d6ea 100644 --- a/party/migrations/0004_auto_20150901_1757.py +++ b/party/migrations/0004_auto_20150901_1757.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -14,6 +14,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='party', name='country', - field=models.ForeignKey(db_column=b'countryId', default=117, to='party.Country', null=True), + field=models.ForeignKey(db_column='countryId', default=117, to='party.Country', null=True, on_delete=models.PROTECT), ), ] diff --git a/party/migrations/0004_auto_20150916_2317.py b/party/migrations/0004_auto_20150916_2317.py index 7fa91ec7..f20907b8 100644 --- a/party/migrations/0004_auto_20150916_2317.py +++ b/party/migrations/0004_auto_20150916_2317.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -14,11 +14,11 @@ class Migration(migrations.Migration): migrations.AddField( model_name='party', name='consortium', - field=models.ForeignKey(to='party.Party', null=True), + field=models.ForeignKey(to='party.Party', null=True, on_delete=models.PROTECT), ), migrations.AlterField( model_name='party', name='country', - field=models.ForeignKey(db_column=b'countryId', default=10, to='party.Country', null=True), + field=models.ForeignKey(db_column='countryId', default=10, to='party.Country', null=True, on_delete=models.PROTECT), ), ] diff --git a/party/migrations/0005_remove_party_consortium.py b/party/migrations/0005_remove_party_consortium.py index 5d3fd56b..447199d6 100644 --- a/party/migrations/0005_remove_party_consortium.py +++ b/party/migrations/0005_remove_party_consortium.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/party/migrations/0006_party_consortium.py b/party/migrations/0006_party_consortium.py index d47412d1..cb2dfe86 100644 --- a/party/migrations/0006_party_consortium.py +++ b/party/migrations/0006_party_consortium.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -14,6 +14,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='party', name='consortium', - field=models.ForeignKey(to='party.Party', null=True), + field=models.ForeignKey(to='party.Party', null=True, on_delete=models.PROTECT), ), ] diff --git a/party/migrations/0007_auto_20150917_0023.py b/party/migrations/0007_auto_20150917_0023.py index d712c2b0..aaec2fdc 100644 --- a/party/migrations/0007_auto_20150917_0023.py +++ b/party/migrations/0007_auto_20150917_0023.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -14,6 +14,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='party', name='country', - field=models.ForeignKey(db_column=b'countryId', default=219, to='party.Country', null=True), + field=models.ForeignKey(db_column='countryId', default=219, to='party.Country', null=True, on_delete=models.PROTECT), ), ] diff --git a/party/migrations/0008_merge.py b/party/migrations/0008_merge.py index 10827537..a657091e 100644 --- a/party/migrations/0008_merge.py +++ b/party/migrations/0008_merge.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/party/migrations/0009_auto_20150924_0050.py b/party/migrations/0009_auto_20150924_0050.py index c1810471..eb61efd2 100644 --- a/party/migrations/0009_auto_20150924_0050.py +++ b/party/migrations/0009_auto_20150924_0050.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -14,6 +14,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='party', name='country', - field=models.ForeignKey(db_column=b'countryId', default=219, to='party.Country', null=True), + field=models.ForeignKey(db_column='countryId', default=219, to='party.Country', null=True, on_delete=models.PROTECT), ), ] diff --git a/party/migrations/0010_change_party_model.py b/party/migrations/0010_change_party_model.py index 6e943e04..673b1493 100644 --- a/party/migrations/0010_change_party_model.py +++ b/party/migrations/0010_change_party_model.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -24,17 +24,17 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='party', name='country', - field=models.ForeignKey(db_column=b'countryId', to='party.Country', null=True), + field=models.ForeignKey(db_column='countryId', to='party.Country', null=True, on_delete=models.PROTECT), ), migrations.AddField( model_name='affiliation', name='consortiumId', - field=models.ForeignKey(related_name='consortiumId', db_column=b'consortiumId', to='party.Party'), + field=models.ForeignKey(related_name='consortiumId', db_column='consortiumId', to='party.Party', on_delete=models.PROTECT), ), migrations.AddField( model_name='affiliation', name='institutionId', - field=models.ForeignKey(related_name='institutionId', db_column=b'institutionId', to='party.Party'), + field=models.ForeignKey(related_name='institutionId', db_column='institutionId', to='party.Party', on_delete=models.PROTECT), ), migrations.AddField( model_name='party', diff --git a/party/migrations/0011_remove_affiliation.py b/party/migrations/0011_remove_affiliation.py index 771ec7c9..38cd21c0 100644 --- a/party/migrations/0011_remove_affiliation.py +++ b/party/migrations/0011_remove_affiliation.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/party/migrations/0012_create_partyaffiliation.py b/party/migrations/0012_create_partyaffiliation.py index 62aa0725..72979d04 100644 --- a/party/migrations/0012_create_partyaffiliation.py +++ b/party/migrations/0012_create_partyaffiliation.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -15,8 +15,8 @@ class Migration(migrations.Migration): name='PartyAffiliation', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('childPartyId', models.ForeignKey(related_name='childPartyId', db_column=b'childPartyId', to='party.Party')), - ('parentPartyId', models.ForeignKey(related_name='parentPartyId', db_column=b'parentPartyId', to='party.Party')), + ('childPartyId', models.ForeignKey(related_name='childPartyId', db_column='childPartyId', to='party.Party', on_delete=models.PROTECT)), + ('parentPartyId', models.ForeignKey(related_name='parentPartyId', db_column='parentPartyId', to='party.Party', on_delete=models.PROTECT)), ], options={ 'db_table': 'PartyAffiliation', diff --git a/party/migrations/0013_rename_primary_key_partyaffiliation.py b/party/migrations/0013_rename_primary_key_partyaffiliation.py index 05c84c2a..bc101ea4 100644 --- a/party/migrations/0013_rename_primary_key_partyaffiliation.py +++ b/party/migrations/0013_rename_primary_key_partyaffiliation.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations import datetime diff --git a/party/migrations/0014_add_label_field_to_party.py b/party/migrations/0014_add_label_field_to_party.py index 0185a4e4..21c63de3 100644 --- a/party/migrations/0014_add_label_field_to_party.py +++ b/party/migrations/0014_add_label_field_to_party.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/party/migrations/0015_label_allow_blank-PWL-749.py b/party/migrations/0015_label_allow_blank-PWL-749.py index 8d71f2e5..04d4d09e 100644 --- a/party/migrations/0015_label_allow_blank-PWL-749.py +++ b/party/migrations/0015_label_allow_blank-PWL-749.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/party/migrations/0016_create_image_info_table.py b/party/migrations/0016_create_image_info_table.py index 36b5fe32..f1f0e0b7 100644 --- a/party/migrations/0016_create_image_info_table.py +++ b/party/migrations/0016_create_image_info_table.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations import django.utils.timezone @@ -16,7 +16,7 @@ class Migration(migrations.Migration): name='ImageInfo', fields=[ ('imageInfoId', models.AutoField(serialize=False, primary_key=True)), - ('partyId', models.ForeignKey(to='party.Party', db_column=b'partyId')), + ('partyId', models.ForeignKey(to='party.Party', db_column='partyId', on_delete=models.PROTECT)), ('name', models.CharField(max_length=200)), ('imageUrl', models.CharField(max_length=500)), ('createdAt', models.DateTimeField(default=django.utils.timezone.now)), diff --git a/party/models.py b/party/models.py index 953172cd..92c140cc 100644 --- a/party/models.py +++ b/party/models.py @@ -5,6 +5,7 @@ from netaddr import IPAddress from django.utils import timezone from common.common import validateIpRange +import hashlib import logging logger = logging.getLogger('phoenix.api.party') @@ -19,7 +20,7 @@ class Party(models.Model): partyType = models.CharField(max_length=200, default='user') name = models.CharField(max_length=200, default='') display = models.BooleanField(default=True) - country = models.ForeignKey('Country', null=True, db_column="countryId") + country = models.ForeignKey('Country', null=True, db_column="countryId", on_delete=models.PROTECT) consortiums = models.ManyToManyField('self', through="PartyAffiliation", through_fields=('childPartyId', 'parentPartyId'), symmetrical=False, related_name="PartyAffiliation") label = models.CharField(max_length=64, null=True) @@ -42,13 +43,18 @@ def getById(partyId): partyList.extend(consortiums) return partyList + # this is the same as the method in Credential class + @staticmethod + def generatePasswordHash(password): + return hashlib.sha1(password.encode()).hexdigest() + class Meta: db_table = "Party" class PartyAffiliation(models.Model): partyAffiliationId = models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True) - childPartyId = models.ForeignKey(Party, related_name="childPartyId", db_column="childPartyId") - parentPartyId = models.ForeignKey(Party, related_name="parentPartyId", db_column="parentPartyId") + childPartyId = models.ForeignKey(Party, related_name="childPartyId", db_column="childPartyId", on_delete=models.PROTECT) + parentPartyId = models.ForeignKey(Party, related_name="parentPartyId", db_column="parentPartyId", on_delete=models.PROTECT) class Meta: db_table = "PartyAffiliation" @@ -58,7 +64,7 @@ class IpRange(models.Model): ipRangeId = models.AutoField(primary_key=True) start = models.GenericIPAddressField() end = models.GenericIPAddressField() - partyId = models.ForeignKey('Party', db_column="partyId") + partyId = models.ForeignKey('Party', db_column="partyId", on_delete=models.PROTECT) label = models.CharField(max_length=64, null=True, blank=True) class Meta: @@ -107,7 +113,7 @@ class Meta: class ImageInfo(models.Model): imageInfoId = models.AutoField(primary_key=True); - partyId = models.ForeignKey(Party, db_column="partyId") + partyId = models.ForeignKey(Party, db_column="partyId", on_delete=models.PROTECT) name = models.CharField(max_length=200) imageUrl = models.CharField(max_length=500) createdAt = models.DateTimeField(default=timezone.now) diff --git a/party/testSamples.py b/party/testSamples.py index c5dd7413..b8e2c761 100644 --- a/party/testSamples.py +++ b/party/testSamples.py @@ -232,7 +232,7 @@ class UsageSample(): PARTNER = 'phoenix' COMMENTS = 'Please send us the usage data' NUM_DAYS_DELTA = 90 - RECEIPIENT_EMAIL = 'xingguo.chen@arabidopsis.org' + RECEIPIENT_EMAIL = 'techteam@arabidopsis.org' startDateObj = datetime.today() - timedelta(days=NUM_DAYS_DELTA) startDate = startDateObj.strftime('%b %d, %Y') endDateObj = datetime.today() diff --git a/party/tests.py b/party/tests.py index 2664d2a7..c2b2b75b 100644 --- a/party/tests.py +++ b/party/tests.py @@ -5,13 +5,12 @@ import json import copy from django.test import TestCase, Client -from testSamples import CountrySample, UserPartySample, OrganizationPartySample, InstitutionPartySample, ConsortiumPartySample, IpRangeSample, PartyAffiliationSample +from .testSamples import CountrySample, UserPartySample, OrganizationPartySample, InstitutionPartySample, ConsortiumPartySample, IpRangeSample, PartyAffiliationSample from partner.testSamples import PartnerSample from subscription.testSamples import SubscriptionSample from authentication.testSamples import CredentialSample from common.tests import TestGenericInterfaces, GenericGETOnlyTest, GenericCRUDTest, LoginRequiredGETOnlyTest, LoginRequiredCRUDTest, LoginRequiredTest, ManualTest, checkMatch -# Python 3: module Cookie -> http.cookies -from Cookie import SimpleCookie +from http.cookies import SimpleCookie django.setup() serverUrl = TestGenericInterfaces.getHost() @@ -423,7 +422,8 @@ def test_for_get_by_ip(self): res = self.client.get(self.url) self.assertEqual(res.status_code, 200) - self.assertEqual(res.content, self.partySample.getName()) + # The raw response will be bytes so need to convert to string and then compare + self.assertEqual(res.content.decode(), self.partySample.getName()) # test for API end point /parties/orgstatus/ # get organization and its subscription status to partner by ip @@ -510,7 +510,7 @@ class GetUsageRequestTest(ManualTest, TestCase): # test for API end point /parties/consortiuminstitutions/{consortiumId} # this endpoint is not working -print "Running unit tests on party web services API........." +print("Running unit tests on party web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/party/views.py b/party/views.py index aca8e99b..913ad51c 100644 --- a/party/views.py +++ b/party/views.py @@ -20,8 +20,7 @@ from common.permissions import isPhoenix from common.permissions import ApiKeyPermission -import hashlib -import datetime +from django.utils import timezone from authentication.serializers import CredentialSerializer, CredentialSerializerNoPassword from genericpath import exists from django.db import connection @@ -53,8 +52,6 @@ def get_queryset(self): return super(PartyCRUD, self).get_queryset().filter(partyType=partyType) return [] - - # /org/ class PartyOrgCRUD(GenericCRUDView): requireApiKey = False @@ -137,7 +134,7 @@ def get(self, request, format=None): partyList = [] #SELECT partyId FROM phoenix_api.Subscription where partnerId = 'tair'; - now =datetime.datetime.now() + now = timezone.now() objs = Subscription.objects.all().filter(partnerId=partnerId).filter(startDate__lte=now).filter(endDate__gte=now).values('partyId') for entry in objs: partyList.append(entry['partyId']) @@ -313,7 +310,7 @@ def put(self, request, format=None): return Response({'error': 'PUT parties/consortiums/ password must not be empty'}, status=status.HTTP_400_BAD_REQUEST) else: newPwd = data['password'] - data['password'] = hashlib.sha1(newPwd).hexdigest() + data['password'] = Party.generatePasswordHash(newPwd) try: credential = Credential.objects.get(partyId=party) credentialSerializer = CredentialSerializer(credential, data=data) @@ -387,7 +384,7 @@ def post(self, request, format=None): if pwd == True: newPwd = data['password'] - data['password'] = hashlib.sha1(newPwd).hexdigest() + data['password'] = Party.generatePasswordHash(newPwd) credentialSerializer = CredentialSerializer(data=data) else: credentialSerializer = CredentialSerializerNoPassword(data=data) @@ -505,7 +502,7 @@ def put(self, request, format=None): return Response({'error': 'PUT parties/institutions/ password must not be empty'}, status=status.HTTP_400_BAD_REQUEST) else: newPwd = data['password'] - data['password'] = hashlib.sha1(newPwd).hexdigest() + data['password'] = Party.generatePasswordHash(newPwd) try: credential = Credential.objects.get(partyId=party) credentialSerializer = CredentialSerializer(credential, data=data) @@ -577,7 +574,7 @@ def post(self, request, format=None): if pwd == True: newPwd = data['password'] - data['password'] = hashlib.sha1(newPwd).hexdigest() + data['password'] = Party.generatePasswordHash(newPwd) credentialSerializer = CredentialSerializer(data=data) else: credentialSerializer = CredentialSerializerNoPassword(data=data) diff --git a/paywall2/settings.py.template.prod b/paywall2/settings.py.template.prod index 286d9447..f59b5227 100644 --- a/paywall2/settings.py.template.prod +++ b/paywall2/settings.py.template.prod @@ -34,7 +34,24 @@ HOSTNAME = 'http://localhost:9000/' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False -TEMPLATE_DEBUG = False +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'OPTIONS': { + 'debug': False, + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + 'loaders': [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader' + ], + } + } +] # Add error email setting ADMINS = [('Phoenix', 'techteam@arabidopsis.org'), ('Dev', 'dev@arabidopsis.org'), ('Xingguo', 'xingguo.chen@arabidopsis.org')] @@ -74,7 +91,14 @@ LOGGING = { 'class': 'logging.FileHandler', 'filename': '/var/log/api/security_error.log', 'formatter': 'standard' - } + }, + # override default config + # see https://djangodeconstructed.com/2018/12/18/django-and-python-logging-in-plain-english/ + # https://github.com/django/django/blob/1939dd49d142b65fa22eb5f85cee0d20864d3730/django/utils/log.py#L18 + 'console': { + 'level': 'INFO', + 'class': 'logging.StreamHandler', + }, # 'sql_log': { # 'level': 'DEBUG', # 'class': 'logging.FileHandler', @@ -101,6 +125,10 @@ LOGGING = { 'propagate': True, 'level': 'WARNING', }, + 'django': { + 'handlers': ['console'], + 'level': 'INFO' + }, # SQL statement executed 'django.db.backends': { # 'handlers': ['sql_log'], @@ -140,20 +168,20 @@ INSTALLED_APPS = ( REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny','common.permissions.ApiKeyPermission'), + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 'PAGE_SIZE': 10 } -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', -) +] # CORS Setting to allow ui sites to access the API server CORS_ORIGIN_WHITELIST = ( @@ -187,12 +215,15 @@ WSGI_APPLICATION = 'paywall2.wsgi.application' # ACTION: modify databse setting here DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.mysql', + 'ENGINE': 'mysql.connector.django', 'NAME': None, 'USER': None, 'PASSWORD': None, 'HOST': None, 'PORT': '3306', + 'OPTIONS': { + 'use_pure': True + } } } diff --git a/paywall2/settings.py.template.test b/paywall2/settings.py.template.test index ed1e0f0f..e3c2dcfb 100644 --- a/paywall2/settings.py.template.test +++ b/paywall2/settings.py.template.test @@ -34,7 +34,24 @@ HOSTNAME = 'http://localhost:9000/' # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -TEMPLATE_DEBUG = True +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'OPTIONS': { + 'debug': True, + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + 'loaders': [ + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader' + ], + } + } +] # Add error email setting ADMINS = [('Phoenix', 'techteam@arabidopsis.org'), ('Dev', 'dev@arabidopsis.org'), ('Xingguo', 'xingguo.chen@arabidopsis.org')] @@ -74,7 +91,14 @@ LOGGING = { 'class': 'logging.FileHandler', 'filename': '/var/log/api/security_error.log', 'formatter': 'standard' - } + }, + # override default config + # see https://djangodeconstructed.com/2018/12/18/django-and-python-logging-in-plain-english/ + # https://github.com/django/django/blob/1939dd49d142b65fa22eb5f85cee0d20864d3730/django/utils/log.py#L18 + 'console': { + 'level': 'INFO', + 'class': 'logging.StreamHandler', + }, # 'sql_log': { # 'level': 'DEBUG', # 'class': 'logging.FileHandler', @@ -101,6 +125,10 @@ LOGGING = { 'propagate': True, 'level': 'WARNING', }, + 'django': { + 'handlers': ['console'], + 'level': 'INFO' + }, # SQL statement executed 'django.db.backends': { # 'handlers': ['sql_log'], @@ -140,20 +168,20 @@ INSTALLED_APPS = ( REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny','common.permissions.ApiKeyPermission'), + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 'PAGE_SIZE': 10 } -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', -) +] # CORS Setting to allow ui sites to access the API server CORS_ORIGIN_WHITELIST = ( @@ -187,12 +215,15 @@ WSGI_APPLICATION = 'paywall2.wsgi.application' DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.mysql', + 'ENGINE': 'mysql.connector.django', 'NAME': 'phoenix_api', 'USER': 'phoenix', 'PASSWORD': '', 'HOST': 'phoenix-api-test.cwyjt5kql77y.us-west-2.rds.amazonaws.com', 'PORT': '3306', + 'OPTIONS': { + 'use_pure': True + } } } diff --git a/paywall2/urls.py b/paywall2/urls.py index 57391699..cff46359 100644 --- a/paywall2/urls.py +++ b/paywall2/urls.py @@ -4,14 +4,14 @@ -from django.conf.urls import patterns, include, url +from django.conf.urls import include, url from django.contrib import admin from rest_framework import routers router = routers.DefaultRouter() -urlpatterns = patterns('', - url(r'^admin/', include(admin.site.urls)), +urlpatterns = [ + url(r'^admin/', admin.site.urls), url(r'^', include(router.urls)), url(r'^meters/', include('metering.urls')), url(r'^parties/', include('party.urls')), @@ -19,9 +19,9 @@ url(r'^authorizations/', include('authorization.urls')), url(r'^partners/', include('partner.urls')), url(r'^session-logs/', include('loggingapp.urls')), - url(r'^credentials/', include('authentication.urls', namespace="authentication")), + url(r'^credentials/', include('authentication.urls')), url(r'^apikeys/', include('apikey.urls')), url(r'^cookies/', include('cookies.urls')), url(r'^ipranges/', include('ipranges.urls')), url(r'^nullservice/', include('nullservice.urls')), -) +] diff --git a/scripts/IpRangeAddChange.py b/scripts/IpRangeAddChange.py index a1724eb7..5f1fc4e0 100644 --- a/scripts/IpRangeAddChange.py +++ b/scripts/IpRangeAddChange.py @@ -16,14 +16,14 @@ # Begin main program: # Open the source CSV file and load into memory. -IpRangeFilename = raw_input('Please enter a file name(*.csv) for ip range list:\n') +IpRangeFilename = input('Please enter a file name(*.csv) for ip range list:\n') with open(IpRangeFilename, 'rb') as f: reader = csv.reader(f) IpRangeListData = list(reader) # Processing Data -print 'Processing Data' +print('Processing Data') # count variable initialization ipRangeExists = 0 @@ -52,42 +52,42 @@ if not queryset.filter(name=institutionName).exists(): #create party if not Country.objects.all().filter(name=countryName): - print '[Country Not Found] ' + countryName + print('[Country Not Found] ' + countryName) continue elif Country.objects.all().filter(name=countryName).count() >1: - print '[More than one record found with country name] ' + countryName + print('[More than one record found with country name] ' + countryName) continue else: countryId = Country.objects.get(name=countryName).countryId partySerializer = PartySerializer(data={'name':institutionName, 'partyType': 'organization', 'country':countryId}, partial=True) if partySerializer.is_valid(): partySerializer.save() - print '[New Party Created] ' + institutionName + print('[New Party Created] ' + institutionName) else: - print '[Party serializer invalid] ' + \ + print('[Party serializer invalid] ' + \ 'type: ' + actionType + \ 'institution: ' + institutionName + \ 'start: ' + startIp + \ - 'end: ' + endIp + 'end: ' + endIp) ipRangeFailed += 1 continue partyId = partySerializer.data['partyId'] childParty = Party.objects.get(partyId = partyId) parentParty = Party.objects.get(partyId = consortiumId) PartyAffiliation.objects.create(childPartyId = childParty, parentPartyId = parentParty) - print '[PartyAffiliation Created] ' + \ + print('[PartyAffiliation Created] ' + \ 'institution: ' + institutionName + \ - 'consortium: ' + parentParty.name + 'consortium: ' + parentParty.name) partyCreated += 1 # when the party exists else: if queryset.filter(name=institutionName).count() > 1: - print '[More than one party found with institution name] ' + \ + print('[More than one party found with institution name] ' + \ 'type: ' + actionType + \ 'institution: ' + institutionName + \ 'start: ' + startIp + \ - 'end: ' + endIp + 'end: ' + endIp) ipRangeFailed += 1 continue partyId = queryset.filter(name=institutionName)[0].partyId @@ -95,11 +95,11 @@ nextIter = False for ipRange in ipRangeList: if ipRange.start == startIp and ipRange.end == endIp: - print '[Ip range already exists] ' + \ + print('[Ip range already exists] ' + \ 'type: ' + actionType + \ 'institution: ' + institutionName + \ 'start: ' + startIp + \ - 'end: ' + endIp + 'end: ' + endIp) nextIter = True ipRangeExists += 1 break @@ -109,39 +109,39 @@ ipRangeSerializer = IpRangeSerializer(data={'start': startIp, 'end': endIp, 'partyId': partyId}, partial=True) if ipRangeSerializer.is_valid(): ipRangeSerializer.save() - print '[IpRange Created] ' + \ + print('[IpRange Created] ' + \ 'type: ' + actionType + \ 'institution: ' + institutionName + \ 'start: ' + startIp + \ - 'end: ' + endIp + 'end: ' + endIp) ipRangeLoaded += 1 else: - print '[Ip range serializer invalid] ' + \ + print('[Ip range serializer invalid] ' + \ 'type: ' + actionType + \ 'institution: ' + institutionName + \ 'start: ' + startIp + \ - 'end: ' + endIp + 'end: ' + endIp) ipRangeFailed += 1 elif actionType == 'update': partyId = None # when the party doesn't exist if not queryset.filter(name=institutionName).exists(): - print '[Party does not exist] ' + \ + print('[Party does not exist] ' + \ 'type: ' + actionType + \ 'institution: ' + institutionName + \ 'start: ' + startIp + \ - 'end: ' + endIp + 'end: ' + endIp) ipRangeFailed += 1 continue # when the party exists elif queryset.filter(name=institutionName).count() > 1: - print '[More than one party found with institution name] ' + \ + print('[More than one party found with institution name] ' + \ 'type: ' + actionType + \ 'institution: ' + institutionName + \ 'start: ' + startIp + \ - 'end: ' + endIp + 'end: ' + endIp) ipRangeFailed +=1 continue else: @@ -154,22 +154,22 @@ ipRangeSerializer = IpRangeSerializer(data={'start': startIp, 'end': endIp, 'partyId': partyId}, partial=True) if ipRangeSerializer.is_valid(): ipRangeSerializer.save() - print '[IpRange Created] ' + \ + print('[IpRange Created] ' + \ 'type: ' + actionType + \ 'institution: ' + institutionName + \ 'start: ' + startIp + \ - 'end: ' + endIp + 'end: ' + endIp) ipRangeLoaded += 1 else: - print '[Ip range serializer invalid] ' + \ + print('[Ip range serializer invalid] ' + \ 'type: ' + actionType + \ 'institution: ' + institutionName + \ 'start: ' + startIp + \ - 'end: ' + endIp + 'end: ' + endIp) ipRangeFailed += 1 -print 'Loading Complete: ' + \ +print('Loading Complete: ' + \ 'ipRangeLoaded: ' + str(ipRangeLoaded) + \ 'ipRangeExists: ' + str(ipRangeExists) + \ 'ipRangeFailed: ' + str(ipRangeFailed) + \ - 'partyCreated: ' + str(partyCreated) + 'partyCreated: ' + str(partyCreated)) diff --git a/scripts/LoadCountryIdScript.py b/scripts/LoadCountryIdScript.py index ca72b643..5e80f0c5 100644 --- a/scripts/LoadCountryIdScript.py +++ b/scripts/LoadCountryIdScript.py @@ -14,14 +14,14 @@ # Begin main program: # Open the source CSV file and load into memory. -orgCountriesFilename = raw_input('Please enter a file name(*.csv) for organization countires list:\n') +orgCountriesFilename = input('Please enter a file name(*.csv) for organization countires list:\n') with open(orgCountriesFilename, 'rb') as f: reader = csv.reader(f) organizationCountryData = list(reader) # Processing Data -print 'Processing Data' +print('Processing Data') for entry in organizationCountryData: organizationName = entry[0] @@ -32,16 +32,16 @@ if Country.objects.all().filter(name=countryName).exists(): countryId = Country.objects.get(name=countryName).countryId else: - print 'cannot find country name: ' + countryName + print('cannot find country name: ' + countryName) continue if Party.objects.all().filter(name=organizationName).exists(): if Party.objects.all().filter(name=organizationName).count() > 1: - print 'more than one Party returned: ' + organizationName + print('more than one Party returned: ' + organizationName) continue party = Party.objects.get(name=organizationName) else: - print 'cannot find party: ' + organizationName + print('cannot find party: ' + organizationName) continue data = {'country':countryId} @@ -50,7 +50,7 @@ if serializer.is_valid(): serializer.save() else: - print "cannot save party: " + organizationName - print data + print("cannot save party: " + organizationName) + print(data) -print 'Loading Complete' +print('Loading Complete') diff --git a/scripts/basicMigrationScript.py b/scripts/basicMigrationScript.py index 791feeb0..8139dfae 100755 --- a/scripts/basicMigrationScript.py +++ b/scripts/basicMigrationScript.py @@ -13,7 +13,7 @@ from party.serializers import PartySerializer from authentication.serializers import CredentialSerializer -from tairData import TAIR +from .tairData import TAIR APIKEY = [ {'apiKey':'test123'}, @@ -109,7 +109,7 @@ def loadPartner(partner, paidAccessTypeId, loginAccessTypeId): if serializer.is_valid(): serializer.save() else: - print "Unable to create partner %s, exiting" % partnerId + print("Unable to create partner %s, exiting" % partnerId) exit() loadItem(PartnerPatternSerializer, partner['PartnerPattern'], partnerId) diff --git a/scripts/countryMigration.py b/scripts/countryMigration.py index dab4c5c8..b0894982 100755 --- a/scripts/countryMigration.py +++ b/scripts/countryMigration.py @@ -45,7 +45,7 @@ def connect(): # Does 500 queries per transaction for performance improvement. if batchCount >= 500: - print "total commit %s" % totalCount + print("total commit %s" % totalCount) conn.commit() batchCount = 0 diff --git a/scripts/createTestAccounts0329.py b/scripts/createTestAccounts0329.py index 648418f7..1c5789b4 100644 --- a/scripts/createTestAccounts0329.py +++ b/scripts/createTestAccounts0329.py @@ -30,9 +30,9 @@ serializer = CredentialSerializer(data=data, partial=True) if serializer.is_valid(): serializer.save() - print "user record loaded: " - print json.dumps(serializer.data) + print("user record loaded: ") + print(json.dumps(serializer.data)) else: - print "user record not added: " - print serializer.errors + print("user record not added: ") + print(serializer.errors) diff --git a/scripts/ltSetup.py b/scripts/ltSetup.py index a7825cb2..e7e527d7 100755 --- a/scripts/ltSetup.py +++ b/scripts/ltSetup.py @@ -13,7 +13,7 @@ from party.serializers import PartySerializer from authentication.serializers import CredentialSerializer -from tairData import TAIR +from .tairData import TAIR def loadTestUser(testUsers): diff --git a/scripts/organizationCountryMigrationScript.py b/scripts/organizationCountryMigrationScript.py index f7429d0e..8e755383 100644 --- a/scripts/organizationCountryMigrationScript.py +++ b/scripts/organizationCountryMigrationScript.py @@ -14,7 +14,7 @@ # Begin main program: # Step1: Open the source CSV file and load into memory. -organizationFilename = raw_input("Please enter a file name(*.csv) for organization list(not organization_country):\n") +organizationFilename = input("Please enter a file name(*.csv) for organization list(not organization_country):\n") with open(organizationFilename, 'rb') as f: reader = csv.reader(f) @@ -25,7 +25,7 @@ organizationCountryData = list(reader) # Initializing organization country -print "Initializing Organization Country Array" +print("Initializing Organization Country Array") organizationCountryArray = {} for entry in organizationCountryData: organizationId = entry[0] @@ -47,11 +47,11 @@ countryId = None; organizationCountryArray[organizationId] = [countryId, display] -print "Processing Data" +print("Processing Data") count = 0 for entry in organizationData: count += 1 - print count + print(count) organizationId = entry[0] if not organizationId.isdigit(): continue @@ -84,7 +84,7 @@ if serializer.is_valid(): serializer.save() else: - print "CANNOT SAVE PARTY" - print data + print("CANNOT SAVE PARTY") + print(data) else: - print "organizationName NOT FOUND: "+organizationName + print("organizationName NOT FOUND: "+organizationName) diff --git a/scripts/personSubscriptionMigrationScript.py b/scripts/personSubscriptionMigrationScript.py index 82e0aaf8..7c3d6b40 100755 --- a/scripts/personSubscriptionMigrationScript.py +++ b/scripts/personSubscriptionMigrationScript.py @@ -50,7 +50,7 @@ def parseTime(inString): partnerId = "tair" for entry in personData: count += 1 - print count + print(count) communityId = entry[0] if not communityId.isdigit(): continue @@ -60,7 +60,7 @@ def parseTime(inString): if len(cred) > 0: partyId = cred[0].partyId.partyId else: - print "not good %s" % communityId + print("not good %s" % communityId) continue startDate = parseTime("21-DEC-12") @@ -75,8 +75,8 @@ def parseTime(inString): if serializer.is_valid(): serializer.save() else: - print "CANNOT SAVE SUBSCRIPTION" - print data + print("CANNOT SAVE SUBSCRIPTION") + print(data) subscriptionId = serializer.data['subscriptionId'] data = { diff --git a/scripts/removeTestingOrganizationScript.py b/scripts/removeTestingOrganizationScript.py index 8995f253..5bf848f6 100644 --- a/scripts/removeTestingOrganizationScript.py +++ b/scripts/removeTestingOrganizationScript.py @@ -13,7 +13,7 @@ # Begin main program: # Step1: Open the source CSV file and load into memory. -partyListFilename = raw_input("Please enter a file name(*.csv) for party list(not organization_country):\n") +partyListFilename = input("Please enter a file name(*.csv) for party list(not organization_country):\n") with open(partyListFilename, 'rb') as f: reader = csv.reader(f) @@ -23,5 +23,5 @@ if Party.objects.all().filter(name=entry[0]).exists(): Party.objects.all().filter(name=entry[0]).delete() - print 'deleted: '+ entry[0] + print('deleted: '+ entry[0]) diff --git a/scripts/runTestPartyCountry.py b/scripts/runTestPartyCountry.py index 44d3401f..9e53ccb9 100644 --- a/scripts/runTestPartyCountry.py +++ b/scripts/runTestPartyCountry.py @@ -25,7 +25,7 @@ organizationCountryData = list(reader) # Initializing organization country -print "Initializing Organization Country Array" +print("Initializing Organization Country Array") organizationCountryArray = {} for entry in organizationCountryData: organizationId = entry[0] @@ -43,7 +43,7 @@ display = False if Party.objects.all().filter(name=organizationName).exists(): countryId = int(Party.objects.all().filter(name=organizationName)[0].country.countryId) - print organizationName + ", " + str(countryId) + "\n" + print(organizationName + ", " + str(countryId) + "\n") # if Party.objects.all().filter(name=organizationName)[1].exists(): # countryId = int(Party.objects.all().filter(name=organizationName)[1].country.countryId) # print organizationName + ", " + str(countryId) + "\n" diff --git a/scripts/subscriptionMigrationScript.py b/scripts/subscriptionMigrationScript.py index c42e6319..ec7a4e09 100755 --- a/scripts/subscriptionMigrationScript.py +++ b/scripts/subscriptionMigrationScript.py @@ -65,7 +65,7 @@ def parseTime(inString): return outString # Initializing organization country -print "Initializing Organization Country Array" +print("Initializing Organization Country Array") organizationCountryArray = {} for entry in organizationCountryData: organizationId = entry[0] @@ -87,18 +87,18 @@ def parseTime(inString): countryId = None organizationCountryArray[organizationId] = [countryId, display] -print "Processing Data" +print("Processing Data") count = 0 for entry in organizationData: count += 1 - print count + print(count) organizationId = entry[0] if not organizationId.isdigit(): continue offset = 2 organizationName = entry[1] if Party.objects.all().filter(name=organizationName).exists(): - print 'organization already exists: '+'('+organizationId+')'+organizationName + print('organization already exists: '+'('+organizationId+')'+organizationName) continue while not entry[offset].isdigit(): organizationName = "%s,%s" % (organizationName, entry[offset]) @@ -142,8 +142,8 @@ def parseTime(inString): if serializer.is_valid(): serializer.save() else: - print "CANNOT SAVE SUBSCRIPTION" - print data + print("CANNOT SAVE SUBSCRIPTION") + print(data) subscriptionId = serializer.data['subscriptionId'] data = { @@ -156,12 +156,12 @@ def parseTime(inString): serializer = SubscriptionTransactionSerializer(data=data) if serializer.is_valid(): serializer.save() -print "DOING IP MIGRATION" +print("DOING IP MIGRATION") count = 0 for entry in ipData: count +=1 - print count + print(count) organizationId = entry[0] if not organizationId.isdigit(): continue @@ -170,7 +170,7 @@ def parseTime(inString): if organizationId in orgIdPartyId: partyId = orgIdPartyId[organizationId] else: - print 'organization already exists: '+ organizationId + print('organization already exists: '+ organizationId) continue data = { @@ -182,5 +182,5 @@ def parseTime(inString): if serializer.is_valid(): serializer.save() else: - print "BAD IP" - print data + print("BAD IP") + print(data) diff --git a/scripts/updateConsortiumSubscriptionFields.py b/scripts/updateConsortiumSubscriptionFields.py index 03b5c6fd..f915f037 100644 --- a/scripts/updateConsortiumSubscriptionFields.py +++ b/scripts/updateConsortiumSubscriptionFields.py @@ -63,7 +63,7 @@ continue # if the obj exists then update if not created: - for k, v in updateData.iteritems(): + for k, v in updateData.items(): if getattr(obj, k) != v: setattr(obj, k, v) obj.save() diff --git a/scripts/updatePartyPasswordsFromFile.py b/scripts/updatePartyPasswordsFromFile.py index 9b4e60b2..0a7526a3 100644 --- a/scripts/updatePartyPasswordsFromFile.py +++ b/scripts/updatePartyPasswordsFromFile.py @@ -57,9 +57,9 @@ def create_signature(password): try: cur.execute(passwordSql%(digestedPw,partyId,)) except: - print "Party {} -- exception: {}".format(partyId, sys.exc_info()[0]) + print("Party {} -- exception: {}".format(partyId, sys.exc_info()[0])) # Commit the transaction. conn.commit() -print "total passwords updated: %s" %totalCount +print("total passwords updated: %s" %totalCount) diff --git a/scripts/userMigrationScript.py b/scripts/userMigrationScript.py index 765e2fb5..8b125842 100755 --- a/scripts/userMigrationScript.py +++ b/scripts/userMigrationScript.py @@ -72,14 +72,14 @@ def create_signature(password): partyId = conn.insert_id() cur.execute(newUserSql%(username, digestedPw, email, partyId, partnerId, userIdentifier, firstName, lastName)) except: - print "{} -- exception: {}".format(username, sys.exc_info()[0]) + print("{} -- exception: {}".format(username, sys.exc_info()[0])) # Does 500 queries per transaction for performance improvement. if batchCount >= 500: - print "total commit %s" % totalCount + print("total commit %s" % totalCount) conn.commit() batchCount = 0 conn.commit() -print "total users migrated: %s" %totalCount +print("total users migrated: %s" %totalCount) diff --git a/subscription/controls.py b/subscription/controls.py index 0a100565..fbb45b2c 100644 --- a/subscription/controls.py +++ b/subscription/controls.py @@ -4,7 +4,7 @@ import stripe from partner.models import SubscriptionTerm, Partner from subscription.models import Subscription, SubscriptionTransaction, ActivationCode -from serializers import SubscriptionSerializer +from .serializers import SubscriptionSerializer from party.models import Party import datetime @@ -18,7 +18,7 @@ from django.conf import settings -import urllib +import urllib.request, urllib.parse, urllib.error class SubscriptionControl(): @@ -96,19 +96,19 @@ def tryCharge(secret_key, stripe_token, priceToCharge, partnerName, chargeDescri message['activationCodes'] = activationCodes try: pass - except stripe.error.InvalidRequestError, e: + except stripe.error.InvalidRequestError as e: status = False message['message'] = e.json_body['error']['message'] - except stripe.error.CardError, e: + except stripe.error.CardError as e: status = False message['message'] = e.json_body['error']['message'] - except stripe.error.AuthenticationError, e: + except stripe.error.AuthenticationError as e: status = False message['message'] = e.json_body['error']['message'] - except stripe.error.APIConnectionError, e: + except stripe.error.APIConnectionError as e: status = False message['message'] = e.json_body['error']['message'] - except Exception, e: + except Exception as e: status = False message['message'] = "Unexpected exception: %s" % (e) @@ -120,7 +120,7 @@ def getEmailInfo(activationCodes, partnerName, termId, quantity, payment, transa termObj = SubscriptionTerm.objects.get(subscriptionTermId=termId) partnerObj = termObj.partnerId - loginURL = domain + partnerObj.loginUri + "?redirect=" + urllib.quote(domain + "/preferences.html", safe='~') + loginURL = domain + partnerObj.loginUri + "?redirect=" + urllib.parse.quote(domain + "/preferences.html", safe='~') registerURL = partnerObj.registerUri name = firstname+" "+lastname institute = institute @@ -238,7 +238,7 @@ def postPaymentHandling(termId, quantity): codeArray = [] - for i in xrange(quantity): + for i in range(quantity): # create an activation code based on partnerId and period. activationCodeObj = ActivationCode() activationCodeObj.activationCode=str(uuid.uuid4()) @@ -259,4 +259,4 @@ def validateCharge(price, termId, quantity): if so.groupDiscountPercentage > 0 and quantity > 1: calcprice = so.price*quantity*(1-(so.groupDiscountPercentage/100)) calcprice = round(calcprice*100)/100 - return (price == calcprice) + return (price == calcprice) diff --git a/subscription/migrations/0001_initial.py b/subscription/migrations/0001_initial.py index 074fdebf..7aefa844 100644 --- a/subscription/migrations/0001_initial.py +++ b/subscription/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -18,9 +18,9 @@ class Migration(migrations.Migration): ('activationCodeId', models.AutoField(serialize=False, primary_key=True)), ('activationCode', models.CharField(unique=True, max_length=200)), ('period', models.IntegerField()), - ('purchaseDate', models.DateTimeField(default=b'2001-01-01T00:00:00Z')), - ('partnerId', models.ForeignKey(to='partner.Partner', db_column=b'partnerId')), - ('partyId', models.ForeignKey(to='party.Party', null=True)), + ('purchaseDate', models.DateTimeField(default='2001-01-01T00:00:00Z')), + ('partnerId', models.ForeignKey(to='partner.Partner', db_column='partnerId', on_delete=models.PROTECT)), + ('partyId', models.ForeignKey(to='party.Party', null=True, on_delete=models.PROTECT)), ], options={ 'db_table': 'ActivationCode', @@ -30,10 +30,10 @@ class Migration(migrations.Migration): name='Subscription', fields=[ ('subscriptionId', models.AutoField(serialize=False, primary_key=True)), - ('startDate', models.DateTimeField(default=b'2000-01-01T00:00:00Z')), - ('endDate', models.DateTimeField(default=b'2012-12-21T00:00:00Z')), - ('partnerId', models.ForeignKey(db_column=b'partnerId', to='partner.Partner', null=True)), - ('partyId', models.ForeignKey(db_column=b'partyId', to='party.Party', null=True)), + ('startDate', models.DateTimeField(default='2000-01-01T00:00:00Z')), + ('endDate', models.DateTimeField(default='2012-12-21T00:00:00Z')), + ('partnerId', models.ForeignKey(db_column='partnerId', to='partner.Partner', null=True, on_delete=models.PROTECT)), + ('partyId', models.ForeignKey(db_column='partyId', to='party.Party', null=True, on_delete=models.PROTECT)), ], options={ 'db_table': 'Subscription', @@ -43,11 +43,11 @@ class Migration(migrations.Migration): name='SubscriptionTransaction', fields=[ ('subscriptionTransactionId', models.AutoField(serialize=False, primary_key=True)), - ('transactionDate', models.DateTimeField(default=b'2000-01-01T00:00:00Z')), - ('startDate', models.DateTimeField(default=b'2001-01-01T00:00:00Z')), - ('endDate', models.DateTimeField(default=b'2020-01-01T00:00:00Z')), + ('transactionDate', models.DateTimeField(default='2000-01-01T00:00:00Z')), + ('startDate', models.DateTimeField(default='2001-01-01T00:00:00Z')), + ('endDate', models.DateTimeField(default='2020-01-01T00:00:00Z')), ('transactionType', models.CharField(max_length=200)), - ('subscriptionId', models.ForeignKey(to='subscription.Subscription', db_column=b'subscriptionId')), + ('subscriptionId', models.ForeignKey(to='subscription.Subscription', db_column='subscriptionId', on_delete=models.PROTECT)), ], options={ 'db_table': 'SubscriptionTransaction', diff --git a/subscription/migrations/0002_unique_constraint_partyId_partnerId.py b/subscription/migrations/0002_unique_constraint_partyId_partnerId.py index 824e0d4a..83d82f22 100644 --- a/subscription/migrations/0002_unique_constraint_partyId_partnerId.py +++ b/subscription/migrations/0002_unique_constraint_partyId_partnerId.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/subscription/migrations/0003_subscriptionrequestmodel.py b/subscription/migrations/0003_subscriptionrequestmodel.py index a034e974..5b13e814 100644 --- a/subscription/migrations/0003_subscriptionrequestmodel.py +++ b/subscription/migrations/0003_subscriptionrequestmodel.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations import datetime @@ -25,7 +25,7 @@ class Migration(migrations.Migration): ('librarianName', models.CharField(max_length=100)), ('librarianEmail', models.CharField(max_length=128)), ('comments', models.CharField(max_length=5000)), - ('partnerId', models.ForeignKey(db_column=b'partnerId', to='partner.Partner', max_length=200)), + ('partnerId', models.ForeignKey(db_column='partnerId', to='partner.Partner', max_length=200, on_delete=models.PROTECT)), ], options={ 'db_table': 'SubscriptionRequest', diff --git a/subscription/migrations/0004_subscriptionrequest_requesttype.py b/subscription/migrations/0004_subscriptionrequest_requesttype.py index 6254f507..c7f7480a 100644 --- a/subscription/migrations/0004_subscriptionrequest_requesttype.py +++ b/subscription/migrations/0004_subscriptionrequest_requesttype.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/subscription/migrations/0005_added_transactionType_to_activationCode_PW-438.py b/subscription/migrations/0005_added_transactionType_to_activationCode_PW-438.py index 98286cc6..0004745f 100644 --- a/subscription/migrations/0005_added_transactionType_to_activationCode_PW-438.py +++ b/subscription/migrations/0005_added_transactionType_to_activationCode_PW-438.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/subscription/migrations/0006_cons_fields_subscription_PWL-579.py b/subscription/migrations/0006_cons_fields_subscription_PWL-579.py index 64fd70d9..262e1d37 100644 --- a/subscription/migrations/0006_cons_fields_subscription_PWL-579.py +++ b/subscription/migrations/0006_cons_fields_subscription_PWL-579.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations @@ -20,7 +20,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='subscription', name='consortiumId', - field=models.ForeignKey(to='party.Party', null=True), + field=models.ForeignKey(to='party.Party', null=True, on_delete=models.PROTECT), ), migrations.AddField( model_name='subscription', @@ -35,7 +35,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='subscription', name='partyId', - field=models.ForeignKey(related_name='party_id', db_column=b'partyId', to='party.Party', null=True), + field=models.ForeignKey(related_name='party_id', db_column='partyId', to='party.Party', null=True, on_delete=models.PROTECT), ), migrations.AlterField( model_name='subscription', diff --git a/subscription/migrations/0007_added_delete_marker_POL-20.py b/subscription/migrations/0007_added_delete_marker_POL-20.py index b036e2ff..c7d23309 100644 --- a/subscription/migrations/0007_added_delete_marker_POL-20.py +++ b/subscription/migrations/0007_added_delete_marker_POL-20.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import unicode_literals + from django.db import models, migrations diff --git a/subscription/models.py b/subscription/models.py index d1744935..92a4136e 100644 --- a/subscription/models.py +++ b/subscription/models.py @@ -14,13 +14,13 @@ def db_type(self, connection): class Subscription(models.Model): subscriptionId = models.AutoField(primary_key=True) - partyId = models.ForeignKey("party.Party", null=True, db_column="partyId", related_name='party_id') - partnerId = models.ForeignKey("partner.Partner", null=True, db_column="partnerId") + partyId = models.ForeignKey("party.Party", null=True, db_column="partyId", related_name='party_id', on_delete=models.PROTECT) + partnerId = models.ForeignKey("partner.Partner", null=True, db_column="partnerId", on_delete=models.PROTECT) startDate = models.DateTimeField(null=True) endDate = models.DateTimeField(null=True) consortiumStartDate = models.DateTimeField(null=True) consortiumEndDate = models.DateTimeField(null=True) - consortiumId = models.ForeignKey("party.Party", null=True) + consortiumId = models.ForeignKey("party.Party", null=True, on_delete=models.PROTECT) @staticmethod def getByIp(ipAddress): @@ -60,8 +60,8 @@ class Meta: class ActivationCode(models.Model): activationCodeId = models.AutoField(primary_key=True) activationCode = models.CharField(max_length=200, unique=True) - partnerId = models.ForeignKey('partner.Partner', db_column="partnerId") - partyId = models.ForeignKey('party.Party', null=True) + partnerId = models.ForeignKey('partner.Partner', db_column="partnerId", on_delete=models.PROTECT) + partyId = models.ForeignKey('party.Party', null=True, on_delete=models.PROTECT) period = models.IntegerField() purchaseDate = models.DateTimeField(default='2001-01-01T00:00:00Z') transactionType = models.CharField(max_length=200, null=True) @@ -71,7 +71,7 @@ class Meta: class SubscriptionTransaction(models.Model): subscriptionTransactionId = models.AutoField(primary_key=True) - subscriptionId = models.ForeignKey('Subscription', db_column="subscriptionId") + subscriptionId = models.ForeignKey('Subscription', db_column="subscriptionId", on_delete=models.PROTECT) transactionDate = models.DateTimeField(default='2000-01-01T00:00:00Z') startDate = models.DateTimeField(default='2001-01-01T00:00:00Z') endDate = models.DateTimeField(default='2020-01-01T00:00:00Z') @@ -91,7 +91,7 @@ def createFromSubscription(subscription, transactionType, transactionStartDate=N 'endDate':transactionEndDate, 'transactionType':transactionType, } - from serializers import SubscriptionTransactionSerializer + from .serializers import SubscriptionTransactionSerializer transactionSerializer = SubscriptionTransactionSerializer(data=transactionJson) if transactionSerializer.is_valid(): return transactionSerializer.save() @@ -111,7 +111,7 @@ class SubscriptionRequest(models.Model): librarianName = models.CharField(max_length=100) librarianEmail = models.CharField(max_length=128) comments = models.CharField(max_length=5000) - partnerId = models.ForeignKey('partner.Partner', max_length=200, db_column="partnerId") + partnerId = models.ForeignKey('partner.Partner', max_length=200, db_column="partnerId", on_delete=models.PROTECT) requestType = models.CharField(max_length=32) class Meta: diff --git a/subscription/testSamples.py b/subscription/testSamples.py index bd4e850e..5430e870 100644 --- a/subscription/testSamples.py +++ b/subscription/testSamples.py @@ -2,7 +2,8 @@ from subscription.models import Subscription, SubscriptionTransaction, ActivationCode from party.models import Party from partner.models import Partner -from datetime import datetime, timedelta +from datetime import timedelta +from django.utils import timezone from common.tests import TestGenericInterfaces genericForcePost = TestGenericInterfaces.forcePost @@ -13,7 +14,7 @@ UPDATE_NUM_SUBSCRIBED_DAYS = 60 def getDateTimeString(dateTimeObj): - return dateTimeObj.strftime("%Y-%m-%d %H:%M:%S.%f") + return dateTimeObj.strftime("%Y-%m-%dT%H:%M:%S.%fZ") class ActivationCodeSample(): path = 'subscriptions/activationCodes/' @@ -39,8 +40,8 @@ class ActivationCodeSample(): def __init__(self, serverUrl): self.url = serverUrl+self.path - self.data['purchaseDate'] = getDateTimeString(datetime.today() - timedelta(days=NUM_DAYS_AFTER_PURCHASE)) - self.updateData['purchaseDate'] = getDateTimeString(datetime.today() - timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE)) + self.data['purchaseDate'] = getDateTimeString(timezone.now() - timedelta(days=NUM_DAYS_AFTER_PURCHASE)) + self.updateData['purchaseDate'] = getDateTimeString(timezone.now() - timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE)) def setPartnerId(self, partnerId): self.data['partnerId'] = partnerId @@ -87,11 +88,11 @@ def __init__(self, serverUrl): self.url = serverUrl+self.path self.data = copy.deepcopy(self.data) - startDateObj = datetime.today() - timedelta(days=NUM_DAYS_AFTER_PURCHASE) + startDateObj = timezone.now() - timedelta(days=NUM_DAYS_AFTER_PURCHASE) self.data['startDate'] = getDateTimeString(startDateObj) self.data['endDate'] = getDateTimeString(startDateObj + timedelta(days=NUM_SUBSCRIBED_DAYS)) - updateStartDateObj = datetime.today() - timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE) + updateStartDateObj = timezone.now() - timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE) self.updateData['startDate'] = getDateTimeString(updateStartDateObj) self.updateData['endDate'] = getDateTimeString(updateStartDateObj + timedelta(days=UPDATE_NUM_SUBSCRIBED_DAYS)) @@ -105,8 +106,8 @@ def getEndDate(self): return self.data['endDate'] def setAsExpired(self): - self.data['startDate'] = getDateTimeString(datetime.today() - timedelta(days=2 * NUM_SUBSCRIBED_DAYS)) - self.data['endDate'] = getDateTimeString(datetime.today() - timedelta(days=NUM_SUBSCRIBED_DAYS)) + self.data['startDate'] = getDateTimeString(timezone.now() - timedelta(days=2 * NUM_SUBSCRIBED_DAYS)) + self.data['endDate'] = getDateTimeString(timezone.now() - timedelta(days=NUM_SUBSCRIBED_DAYS)) def forcePost(self,data): postData = copy.deepcopy(data) @@ -135,12 +136,12 @@ class SubscriptionTransactionSample(): def __init__(self, serverUrl): self.url = serverUrl+self.path - transactionDateObj = datetime.today() - timedelta(days=NUM_DAYS_AFTER_PURCHASE) + transactionDateObj = timezone.now() - timedelta(days=NUM_DAYS_AFTER_PURCHASE) self.data['transactionDate'] = getDateTimeString(transactionDateObj) self.data['startDate'] = self.data['transactionDate'] self.data['endDate'] = getDateTimeString(transactionDateObj + timedelta(days=NUM_SUBSCRIBED_DAYS)) - updateTransactionDateObj = datetime.today() - timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE) + updateTransactionDateObj = timezone.now() - timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE) self.updateData['transactionDate'] = getDateTimeString(updateTransactionDateObj) self.updateData['startDate'] = self.updateData['transactionDate'] self.updateData['endDate'] = getDateTimeString(updateTransactionDateObj + timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE)) diff --git a/subscription/tests.py b/subscription/tests.py index 0583a0d4..d7ec79b7 100644 --- a/subscription/tests.py +++ b/subscription/tests.py @@ -7,15 +7,14 @@ import copy from django.test import TestCase from subscription.models import Subscription, SubscriptionTransaction, ActivationCode -from testSamples import SubscriptionSample, SubscriptionTransactionSample, ActivationCodeSample +from .testSamples import SubscriptionSample, SubscriptionTransactionSample, ActivationCodeSample from party.testSamples import UserPartySample, CountrySample, OrganizationPartySample, IpRangeSample, ConsortiumPartySample, InstitutionPartySample, PartyAffiliationSample, ImageInfoSample from partner.testSamples import PartnerSample, SubscriptionTermSample from authentication.testSamples import CredentialSample from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest, LoginRequiredTest, ManualTest, checkMatch from rest_framework import status -from controls import PaymentControl -# Python 3: module Cookie -> http.cookies -from Cookie import SimpleCookie +from .controls import PaymentControl +from http.cookies import SimpleCookie # Create your tests here. django.setup() @@ -448,8 +447,7 @@ def runTest(self, queryParam, expectedSubscriptionStatus, expectedSubscriptionTy if expectedSubscriptionType and resObj['subscriptionType']: self.assertEqual(expectedSubscriptionType, resObj['subscriptionType']) if expectedExpDate and resObj['expDate']: - expDate = resObj['expDate'].replace('T', ' ').replace('Z', '') - self.assertEqual(expectedExpDate, expDate) + self.assertEqual(expectedExpDate, resObj['expDate']) # test for API end point /subscriptions/membership/ # end point looks for the effective subscription with latest end date that covers the given IP address for a given partner @@ -510,8 +508,7 @@ def test_for_get(self): self.assertEqual(resObj['isMember'], True) self.assertEqual(resObj['name'], imageInfoSample.getName()) self.assertEqual(resObj['imageUrl'], imageInfoSample.getImageUrl()) - expDate = resObj['expDate'].replace('T', ' ').replace('Z', '') - self.assertEqual(expDate, orgSubscriptionSample.getEndDate()) + self.assertEqual(resObj['expDate'], orgSubscriptionSample.getEndDate()) # test for API end point /subscriptions/subscriptionrequest/ # this end point seems not working. Will print a warning to ask manual test @@ -835,7 +832,7 @@ def test_for_get(self): # test for API end point /subscriptions/renew/ # an end point for sending renewal request email, assume it's deprecated -print "Running unit tests on subscription web services API........." +print("Running unit tests on subscription web services API.........") if __name__ == '__main__': sys.argv[1:] = [] diff --git a/subscription/views.py b/subscription/views.py index 908f33b6..6163dd14 100644 --- a/subscription/views.py +++ b/subscription/views.py @@ -59,7 +59,7 @@ def get(self, request): return Response(serializer.data) elif 'partyId' in params: partyId = params['partyId'] - now = datetime.datetime.now() + now = timezone.now() if 'checkConsortium' in params and params['checkConsortium'] == 'true': partnerIdList = Partner.objects.all().values_list('partnerId', flat=True) idSub = [] @@ -378,7 +378,7 @@ def get(self, request): class ActiveSubscriptions(generics.GenericAPIView): requireApiKey = False def get(self, request, partyId): - now = datetime.datetime.now() + now = timezone.now() activeSubscriptions = Subscription.objects.all().filter(partyId=partyId).filter(endDate__gt=now).filter(startDate__lt=now) serializer = SubscriptionSerializer(activeSubscriptions, many=True) #return HttpResponse(json.dumps(dict(serializer.data))) @@ -407,7 +407,7 @@ def get(self, request): if not 'partyId' in params: return Response({'error':'partyId is required'}, status=status.HTTP_400_BAD_REQUEST) ret = {} - now = datetime.datetime.now() + now = timezone.now() partyId = params['partyId'] if 'active' in params and params['active'] == 'true': if Party.objects.all().get(partyId=partyId): @@ -429,7 +429,7 @@ class ConsActSubscriptions(generics.GenericAPIView): requireApiKey = False def get(self, request, partyId): ret = {} - now = datetime.datetime.now() + now = timezone.now() if Party.objects.all().get(partyId=partyId): consortiums = Party.objects.all().get(partyId=partyId).consortiums.all() for consortium in consortiums: @@ -511,16 +511,16 @@ def get(self, request): # preprocessing requestDate for request in requestJSONList: request['requestDate'] = datetime.datetime.strptime(request['requestDate'], '%Y-%m-%dT%H:%M:%S.%fZ').strftime('%m/%d/%Y') - rows = [request.values() for request in requestJSONList] + rows = [list(request.values()) for request in requestJSONList] try: - header = requestJSONList[0].keys() + header = list(requestJSONList[0].keys()) except: return Response("requestJSONList[0] index out of range") rows.insert(0, header) pseudo_buffer = Echo() writer = csv.writer(pseudo_buffer) response = StreamingHttpResponse((writer.writerow(row) for row in rows),content_type="text/csv") - now = datetime.datetime.now() + now = timezone.now() response['Content-Disposition'] = 'attachment; filename="requests_report_{:%Y-%m-%d_%H:%M}.csv"'.format(now) response['X-Sendfile'] = smart_str('/Downloads') return response @@ -584,7 +584,7 @@ def post(self,request): activationCodes = [] - for i in xrange(quantity): + for i in range(quantity): # create an activation code based on partnerId and period. activationCodeObj = ActivationCode() activationCodeObj.activationCode=str(uuid.uuid4()) @@ -612,7 +612,7 @@ def put(self, request): activationCodeId = params['activationCodeId'] deleteMarker = True if params['deleteMarker'] == 'true' else False - activationCodeIdList = map(int, activationCodeId.split(',')) + activationCodeIdList = list(map(int, activationCodeId.split(','))) activationCodes = ActivationCode.objects.all().filter(activationCodeId__in=activationCodeIdList) From 93505f3060ff322be679596b3e56f10a76089b09 Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Mon, 11 Nov 2019 12:26:44 -0800 Subject: [PATCH 03/19] PWL-742: Fix check model has attribute bug. --- common/views.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/common/views.py b/common/views.py index b564cb69..1df89e89 100644 --- a/common/views.py +++ b/common/views.py @@ -1,5 +1,6 @@ from rest_framework.response import Response from rest_framework import generics, status +from django.db import models class GenericCRUDView(generics.GenericAPIView): requireApiKey = True @@ -9,13 +10,16 @@ def get_queryset(self): for key in params: # fully backward compatiable version on get_fields method can be found here: # https://docs.djangoproject.com/en/1.10/ref/models/meta/#migrating-from-the-old-api - if key in queryset.model._meta.get_fields(): + try: + f = queryset.model._meta.get_field(key) value = params[key] filters = {key:value} try: queryset = queryset.filter(**filters) except ValueError: return [] + except models.FieldDoesNotExist: + return [] return queryset def get(self, request, format=None): From ca093f0b0dc544fcafcfdd334ff712067f5d182a Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Wed, 8 Jan 2020 17:11:37 -0800 Subject: [PATCH 04/19] PWL-742: Fix bug introduced by last commit. --- common/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/views.py b/common/views.py index 1df89e89..9cb59e41 100644 --- a/common/views.py +++ b/common/views.py @@ -19,7 +19,8 @@ def get_queryset(self): except ValueError: return [] except models.FieldDoesNotExist: - return [] + # do nothing, continue to check next key + continue return queryset def get(self, request, format=None): From 1e9691d1f38980ffdfbda6179d634417c52ba31b Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Fri, 1 Jul 2022 23:53:59 -0700 Subject: [PATCH 05/19] Add docker files to containerize the application. --- .dockerignore | 5 +++++ Dockerfile | 17 ++++++++++++++ dependencies.list | 14 ++++++++++++ docker-compose.yml | 13 +++++++++++ docker_config/vhosts.conf | 36 ++++++++++++++++++++++++++++++ docker_config/wsgi.conf | 1 + paywall2/settings.py.template.prod | 33 ++++++++++++++++++++++----- paywall2/settings.py.template.test | 29 ++++++++++++++++++++---- 8 files changed, 138 insertions(+), 10 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 dependencies.list create mode 100644 docker-compose.yml create mode 100644 docker_config/vhosts.conf create mode 100644 docker_config/wsgi.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..941226f4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +Dockerfile* +docker-compose* +.dockerignore +.git +.gitignore diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..9731b147 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +FROM amazonlinux:2017.09.0.20170930 + +RUN yum -y install vim httpd python36 python36-devel python36-pip wget gcc gcc-c++ subversion make uuid libuuid-devel httpd-devel mysql-devel +# set python 3.6 as default version +RUN alternatives --install /usr/bin/python python /usr/bin/python2.7 1 && alternatives --install /usr/bin/python python /usr/bin/python3.6 2 && alternatives --set python /usr/bin/python3.6 +RUN wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.5.15.tar.gz && tar -xvf 4.5.15.tar.gz && cd mod_wsgi-4.5.15 && ./configure --with-python=/usr/bin/python36 && make; make install && cd .. && rm -r mod_wsgi-4.5.15 4.5.15.tar.gz +# configure settings.py as part of build process +COPY docker_config/vhosts.conf /etc/httpd/conf.d/ +COPY docker_config/wsgi.conf /etc/httpd/conf.d/ +COPY dependencies.list /etc/ +RUN easy_install-3.6 pip && pip3 install --upgrade pip +RUN pip3 install -r /etc/dependencies.list && rm /etc/dependencies.list +# update this to pipe to AWS log later +RUN mkdir /var/log/api && chown apache:apache /var/log/api +RUN echo "ServerName 172.*" >> /etc/httpd/conf/httpd.conf +EXPOSE 80 +CMD ["/usr/sbin/httpd","-D","FOREGROUND"] \ No newline at end of file diff --git a/dependencies.list b/dependencies.list new file mode 100644 index 00000000..f1217801 --- /dev/null +++ b/dependencies.list @@ -0,0 +1,14 @@ +Django==2.2.5 +djangorestframework==3.10.2 +djangorestframework-jwt==1.11.0 +django-rest-swagger==2.2.0 +django-cors-headers==3.0.2 +ipaddress==1.0.22 +mysql-connector-python==8.0.17 +netaddr==0.7.19 +stripe==2.58.0 +sqlparse==0.3.1 +pandas==0.24.2 +xlsxwriter==2.0.0 +xlrd==2.0.1 +pycrypto==2.6.1 \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..89c90b16 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3' + +services: + paywall-api-python3: + build: . + image: paywall-api-python3:1.0 + platform: linux/amd64 + container_name: paywall-api-container-python3 + volumes: + - ".:/var/www/api-python" + ports: + - "9001:80" + diff --git a/docker_config/vhosts.conf b/docker_config/vhosts.conf new file mode 100644 index 00000000..8fe32702 --- /dev/null +++ b/docker_config/vhosts.conf @@ -0,0 +1,36 @@ +#top level folder of the django project +WSGIPythonPath /var/www/api-python + +NameVirtualHost *:80 + + + ServerName 172.* + WSGIScriptAlias / /var/www/api-python/paywall2/wsgi.py + DocumentRoot /var/www/api-python + + AllowOverride None + Require all granted + + + Options Indexes FollowSymLinks + AllowOverride None + + + + + Order allow,deny + Allow from all + + + + Alias /static /usr/local/lib/python3.6/site-packages/rest_framework/static + + + Order allow,deny + Allow from all + + + + ErrorLog /var/log/httpd/api.error_log + CustomLog /var/log/httpd/api.access_log combined + \ No newline at end of file diff --git a/docker_config/wsgi.conf b/docker_config/wsgi.conf new file mode 100644 index 00000000..19f35675 --- /dev/null +++ b/docker_config/wsgi.conf @@ -0,0 +1 @@ +LoadModule wsgi_module modules/mod_wsgi.so diff --git a/paywall2/settings.py.template.prod b/paywall2/settings.py.template.prod index f59b5227..93451029 100644 --- a/paywall2/settings.py.template.prod +++ b/paywall2/settings.py.template.prod @@ -176,7 +176,7 @@ MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', + #'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', @@ -185,14 +185,14 @@ MIDDLEWARE = [ # CORS Setting to allow ui sites to access the API server CORS_ORIGIN_WHITELIST = ( - 'testui.steveatgetexp.com', - 'azeem.steveatgetexp.com', ) CORS_ALLOW_CREDENTIALS = True CORS_ALLOW_METHODS = ( 'GET', + 'POST', + 'PUT', ) CORS_ALLOW_HEADERS = ( @@ -216,10 +216,10 @@ WSGI_APPLICATION = 'paywall2.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'mysql.connector.django', - 'NAME': None, - 'USER': None, + 'NAME': 'phoenix_api', + 'USER': 'phoenix', 'PASSWORD': None, - 'HOST': None, + 'HOST': 'phoenix-api.cwyjt5kql77y.us-west-2.rds.amazonaws.com', 'PORT': '3306', 'OPTIONS': { 'use_pure': True @@ -274,3 +274,24 @@ EMAIL_PORT = 25 # For AWS SES, this will be the username/password of the IAM created for SES. EMAIL_HOST_USER = None EMAIL_HOST_PASSWORD = None + +# Credentials for CIPRES password decryption +CIPHER_CLIENT_SECRET = None +CIPHER_SALT = None +CIPHER_ITERATION = 200000 # 200,000 +# Credentials for CIPRES API end point +CIPRES_API_BASE_URL = "https://cipresci.ucsd.edu/portalrest/api" +CIPRES_BASIC_AUTH_TOKEN = None +CIPRES_ACCESS_TOKEN = None +# Email addresses for sending CIPRES sync failed email +CIPRES_ADMINS = ['techteam@arabidopsis.org', 'cipresadmin@sdsc.edu'] + +# Fill in parameters for CyVerse API call +CYVERSE_DOMAIN = 'https://kc.cyverse.org/auth' +CYVERSE_REALM = 'CyVerse' +CYVERSE_CLIENT_ID = 'phoenix-bio' +CYVERSE_SECRET = None + +# Email Subject for CyVerse purchase +CYVERSE_PURCHASE_EMAIL_SUBJECT = 'New Subscription Purchase' +CYVERSE_ADMINS = ['xingguo.chen@arabidopsis.org', 'support@cyverse.org'] diff --git a/paywall2/settings.py.template.test b/paywall2/settings.py.template.test index e3c2dcfb..5b47f517 100644 --- a/paywall2/settings.py.template.test +++ b/paywall2/settings.py.template.test @@ -176,7 +176,7 @@ MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', + #'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', @@ -185,14 +185,14 @@ MIDDLEWARE = [ # CORS Setting to allow ui sites to access the API server CORS_ORIGIN_WHITELIST = ( - 'testui.steveatgetexp.com', - 'azeem.steveatgetexp.com', ) CORS_ALLOW_CREDENTIALS = True CORS_ALLOW_METHODS = ( 'GET', + 'POST', + 'PUT', ) CORS_ALLOW_HEADERS = ( @@ -219,7 +219,7 @@ DATABASES = { 'NAME': 'phoenix_api', 'USER': 'phoenix', 'PASSWORD': '', - 'HOST': 'phoenix-api-test.cwyjt5kql77y.us-west-2.rds.amazonaws.com', + 'HOST': 'phoenix-api-uat.cwyjt5kql77y.us-west-2.rds.amazonaws.com', 'PORT': '3306', 'OPTIONS': { 'use_pure': True @@ -274,3 +274,24 @@ EMAIL_PORT = 25 # For AWS SES, this will be the username/password of the IAM created for SES. EMAIL_HOST_USER = None EMAIL_HOST_PASSWORD = None + +# Credentials for CIPRES password decryption +CIPHER_CLIENT_SECRET = None +CIPHER_SALT = None +CIPHER_ITERATION = 200000 # 200,000 +# Credentials for CIPRES API end point +CIPRES_API_BASE_URL = "https://ciprescibeta.ucsd.edu/portalrest/api" +CIPRES_BASIC_AUTH_TOKEN = None +CIPRES_ACCESS_TOKEN = None +# Email addresses for sending CIPRES sync failed email +CIPRES_ADMINS = ['techteam@arabidopsis.org'] + +# Fill in parameters for CyVerse API call +CYVERSE_DOMAIN = 'https://kc.cyverse.org/auth' +CYVERSE_REALM = 'CyVerse' +CYVERSE_CLIENT_ID = 'phoenix-bio' +CYVERSE_SECRET = None + +# Email Subject for CyVerse purchase +CYVERSE_PURCHASE_EMAIL_SUBJECT = 'New Subscription Purchase' +CYVERSE_ADMINS = ['xingguo.chen@arabidopsis.org', 'support@cyverse.org'] \ No newline at end of file From d8873706a26fd4184fa610ac0a400e7cc691e0ba Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Tue, 12 Jul 2022 17:27:42 -0700 Subject: [PATCH 06/19] Update Dockerfile. --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9731b147..ae210603 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,7 +11,7 @@ COPY dependencies.list /etc/ RUN easy_install-3.6 pip && pip3 install --upgrade pip RUN pip3 install -r /etc/dependencies.list && rm /etc/dependencies.list # update this to pipe to AWS log later -RUN mkdir /var/log/api && chown apache:apache /var/log/api +RUN mkdir /var/log/api && chown -R apache:apache /var/log/api RUN echo "ServerName 172.*" >> /etc/httpd/conf/httpd.conf EXPOSE 80 CMD ["/usr/sbin/httpd","-D","FOREGROUND"] \ No newline at end of file From e14309c839817e87f9f42c14cdd30e75fae403fa Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Tue, 12 Jul 2022 18:16:21 -0700 Subject: [PATCH 07/19] Reformatted python code to remove trailing spaces. --- authentication/models.py | 2 +- authentication/tests.py | 8 ++--- authentication/views.py | 12 +++---- authorization/models.py | 2 +- authorization/tests.py | 22 ++++++------ authorization/views.py | 16 ++++----- common/common.py | 2 +- common/testSamples.py | 2 +- common/tests.py | 4 +-- metering/testSamples.py | 2 +- metering/tests.py | 4 +-- metering/views.py | 4 +-- partner/models.py | 4 +-- partner/tests.py | 2 +- party/manualTests.py | 2 +- party/models.py | 2 +- party/tests.py | 6 ++-- party/urls.py | 6 ++-- scripts/countryMigration.py | 4 +-- scripts/organizationCountryMigrationScript.py | 4 +-- scripts/personSubscriptionMigrationScript.py | 2 +- scripts/runTestPartyCountry.py | 2 +- scripts/setupDbScript.py | 2 +- scripts/subscriptionMigrationScript.py | 4 +-- scripts/updatePartyPasswordsFromFile.py | 4 +-- scripts/userMigrationScript.py | 2 +- subscription/controls.py | 18 +++++----- subscription/testSamples.py | 2 +- subscription/tests.py | 36 +++++++++---------- subscription/urls.py | 2 +- 30 files changed, 92 insertions(+), 92 deletions(-) diff --git a/authentication/models.py b/authentication/models.py index adcf8714..c7a457bc 100644 --- a/authentication/models.py +++ b/authentication/models.py @@ -18,7 +18,7 @@ class Credential(models.Model): partnerId = models.ForeignKey(Partner, db_column='partnerId', on_delete=models.PROTECT) userIdentifier = models.CharField(max_length=32, null=True) #name = models.CharField(max_length=64, null=True) vet PW-161 - + @staticmethod def validate(partyId, secretKey): if partyId and secretKey and partyId.isdigit() and Party.objects.filter(partyId=partyId).exists(): diff --git a/authentication/tests.py b/authentication/tests.py index 9fea8dab..a269ddb2 100644 --- a/authentication/tests.py +++ b/authentication/tests.py @@ -64,7 +64,7 @@ def test_for_get(self): sample = self.sample pk = sample.forcePost(sample.data) partnerId = self.partnerId - + # test get by user identifier queryByUserIdentifier = 'userIdentifier=%s&partnerId=%s' % (sample.getUserIdentifier(), partnerId) self.assertGetRequestByQueryParam(queryByUserIdentifier) @@ -124,7 +124,7 @@ def runUpdateTestByQueryParam(self, queryParam): updateData[key] = sample.updateData[key] # manipulate sample data to match the test condition self.assertEqual(checkMatch(updateData, resObj, 'partyId', sample.getPartyId()), True) - + # test for API endpoint /credentials/profile/ # this is smiliar to the UPDATE methods above except that it only accepts # pratyId as query param and returns status code 201 when succeed @@ -151,7 +151,7 @@ def test_for_update_profile(self): updateData[key] = sample.updateData[key] # manipulate sample data to match the test condition self.assertEqual(checkMatch(updateData, resObj, 'partyId', sample.getPartyId()), True) - + def getUserLoginCredential(self): sample = self.sample secretKey = urllib.parse.quote(sample.getSecretKey()) @@ -176,7 +176,7 @@ def setUp(self): # test for API endpoint /crendetials/login/ class CredentialLoginTest(CredentialGenericTest): - + def test_for_login(self): loginUrl = self.sample.getLoginUrl() loginData = self.sample.getLoginData() diff --git a/authentication/views.py b/authentication/views.py index 2a466443..9a816bad 100644 --- a/authentication/views.py +++ b/authentication/views.py @@ -107,7 +107,7 @@ def post(self, request, format=None): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - + def put(self, request, format=None): # TODO: security risk here, get username based on the partyId verified in isPhoenix -SC if not isPhoenix(self.request): @@ -170,7 +170,7 @@ def login(request): # msg = "Incorrect password" # logger.info("%s, %s: %s %s %s" % (ip, msg, request.POST['user'], request.POST['password'], request.GET['partnerId'])) # return HttpResponse(json.dumps({"message":msg}), status=401) - + # msg = "No such user" # logger.info("%s, %s: %s %s %s" % (ip, msg, request.POST['user'], request.POST['password'], request.GET['partnerId'])) # return HttpResponse(json.dumps({"message":msg}), status=401) @@ -245,7 +245,7 @@ def resetPwd(request): password = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(8)) user.password = Credential.generatePasswordHash(password) user.save() - + subject = "Temporary password for %s (%s)" % (user.username, user.email)#PW-215 unlikely ''' message = "username: %s (%s)\n\nYour temp password is %s \n\n" \ @@ -253,12 +253,12 @@ def resetPwd(request): % (user.username, user.email, password)#PW-215 ''' message = partnerObj.resetPasswordEmailBody % (user.username, user.email, password) - + from_email = "info@phoenixbioinformatics.org" - + recipient_list = [user.email] send_mail(subject=subject, message=message, from_email=from_email, recipient_list=recipient_list) - + return HttpResponse(json.dumps({'reset pwd':'success', 'username':user.username, 'useremail':user.email, 'temppwd':user.password}), content_type="application/json")#PW-215 unlikely return HttpResponse(json.dumps({"reset pwd failed":"No such user"}), status=401) #/credentials/register/ diff --git a/authorization/models.py b/authorization/models.py index 75752647..a59f3c6d 100644 --- a/authorization/models.py +++ b/authorization/models.py @@ -48,7 +48,7 @@ class Meta: class AccessType(models.Model): accessTypeId = models.AutoField(primary_key=True) name = models.CharField(max_length=200) - + @staticmethod def checkHasAccessRule(url, accessTypeName, partnerId): if not (url and accessTypeName and partnerId): diff --git a/authorization/tests.py b/authorization/tests.py index fcd2e4f0..964d1e90 100644 --- a/authorization/tests.py +++ b/authorization/tests.py @@ -31,7 +31,7 @@ class AccessTypesCRUDTest(GenericCRUDTest, TestCase): # Test for API end point /authorizations/accessRules/ class AccessRuleCRUDTest(GenericCRUDTest, TestCase): sample = AccessRuleSample(serverUrl) - + def setUp(self): super(AccessRuleCRUDTest,self).setUp() partnerSample = PartnerSample(serverUrl) @@ -51,7 +51,7 @@ def test_for_update(self): patternSample = UriPatternSample(serverUrl) updatePatternId = patternSample.forcePost(patternSample.updateData) self.sample.updateData['patternId']=updatePatternId - + # set different access type for update data accessTypeSample = AccessTypeSample(serverUrl) updateAccessTypeId = accessTypeSample.forcePost(accessTypeSample.updateData) @@ -113,7 +113,7 @@ def setUpCredentialSample(self): credentialSample.setPartnerId(self.partnerId) credentialSample.setPartyId(userPartyId) credentialSample.forcePost(credentialSample.data) - + return credentialSample def setUpSubscribedOrganization(self): @@ -178,7 +178,7 @@ class AuthenticationTest(GenericAuthorizationTest): def setUp(self): super(AuthenticationTest,self).setUp() - + self.setUpLoginAccessRule() self.loginPattern = self.patternSample.data['pattern'] self.nonLoginPattern = self.patternSample.updateData['pattern'] @@ -188,7 +188,7 @@ def setUp(self): def test_for_authentication(self): self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) - + # test login not required pattern when user is not logged in self.runAuthenticationTest(self.nonLoginPattern, True) @@ -238,7 +238,7 @@ def test_for_subscription(self): # Note if a non-exist partyId is passed in an error will be thrown authParam = 'partyId=%s' % userPartyId self.runSubscriptionTest(self.paidPattern, authParam , True) - + # IP of organization with subscription, Paid url, access should be True subscribedIP = orgIpRangeSample.getInRangeIp() authParam = 'ip=%s' % subscribedIP @@ -249,7 +249,7 @@ def test_for_subscription(self): unsubscribedIP = orgIpRangeSample.getOutRangeIp() authParam = 'ip=%s' % unsubscribedIP self.runSubscriptionTest(self.paidPattern, authParam, False) - + # No identity info, Paid url. access should be False self.runSubscriptionTest(self.paidPattern, None, False) @@ -264,7 +264,7 @@ def test_for_consortium_subscription(self): # Note if a non-exist partyId is passed in an error will be thrown authParam = 'partyId=%s' % consOrgIpRangeSample.getPartyId() self.runSubscriptionTest(self.paidPattern, authParam , True) - + # IP of institution whose parent consortium has subscription, Paid url, access should be True subscribedIP = consOrgIpRangeSample.getInRangeIp() authParam = 'ip=%s' % subscribedIP @@ -363,7 +363,7 @@ def runSubscriptionOnlyAccessTest(self, orgIpRangeSample): self.runAccessTest(urlToCheck=paidPattern, expectedUrlPaidStatus=True, authParam=authParam, ipList=None, expectedNeedLoginStatus=False, expectedAccessStatus=True, expectedUserIdentifier=credentialSample.getUserIdentifier(), cookies=cookies) - + # test valid subscription for organization, paid url, status should be OK subscribedIP = orgIpRangeSample.getInRangeIp() self.runAccessTest(urlToCheck=paidPattern, expectedUrlPaidStatus=True, @@ -410,7 +410,7 @@ def runLoginAndSubscriptionAccessTest(self, orgIpRangeSample): self.runAccessTest(urlToCheck=loginPaidPattern, expectedUrlPaidStatus=True, authParam=authParam, ipList=None, expectedNeedLoginStatus=False, expectedAccessStatus=True, expectedUserIdentifier=credentialSample.getUserIdentifier(), cookies=cookies) - + # create additional credential that is not subscribed nonSubUserPartySample = UserPartySample(serverUrl) nonSubUserPartyId = nonSubUserPartySample.forcePost(nonSubUserPartySample.updateData) @@ -420,7 +420,7 @@ def runLoginAndSubscriptionAccessTest(self, orgIpRangeSample): nonSubCredentialSample.setPartnerId(self.partnerId) nonSubCredentialSample.setPartyId(nonSubUserPartyId) nonSubCredentialSample.forcePost(nonSubCredentialSample.data) - + # test login required & paid pattern with unsubscribed user , status should be NeedSubscription partyId = nonSubCredentialSample.getPartyId() authParam = 'partyId=%s' % partyId diff --git a/authorization/views.py b/authorization/views.py index e83fdb06..50d1fcbe 100644 --- a/authorization/views.py +++ b/authorization/views.py @@ -124,12 +124,12 @@ def get(self, request, format=None): else: logger.info("Authorization URIAccess %s%s %s" % ("GET URIAccess error: requestPatternId:",requestPatternId,"not found")) return Response({'GET error: patternId' + requestPatternId + ' not found'}) - + def delete(self, request, format=None): params = request.GET if 'patternId' not in params: return Response({'DELETE error':'patternId required'},status=status.HTTP_400_BAD_REQUEST) - + requestPatternId = params['patternId'] if UriPattern.objects.filter(patternId = requestPatternId).exists(): pattern = UriPattern.objects.get(patternId = requestPatternId) @@ -137,7 +137,7 @@ def delete(self, request, format=None): return Response({'DELETE success':'delete of patternId '+requestPatternId+' completed'},status=status.HTTP_200_OK) else: return Response({'DELETE error':'delete of patternId '+requestPatternId+' failed. patternId not found'},status=status.HTTP_400_BAD_REQUEST) - + def put(self, request, format=None): params = request.GET if 'patternId' not in params: @@ -145,7 +145,7 @@ def put(self, request, format=None): data = request.data if 'pattern' not in data: return Response({'error':'PUT method:pattern is required as form-data'}, status=status.HTTP_400_BAD_REQUEST) - + patternFromRequest = data['pattern'] isREValid = isRegExpValid(patternFromRequest) if not isREValid: @@ -154,7 +154,7 @@ def put(self, request, format=None): patternIdFromRequest = request.GET.get('patternId') if not UriPattern.objects.filter(patternId = patternIdFromRequest).exists(): return Response({'error':'PUT method:patternId '+patternIdFromRequest+' not found'}, status=status.HTTP_400_BAD_REQUEST) - + pattern = UriPattern.objects.get(patternId=patternIdFromRequest) serializer = UriPatternSerializer(pattern,data=data) @@ -163,17 +163,17 @@ def put(self, request, format=None): return Response(serializer.data, status=status.HTTP_200_OK) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - + def post(self,request, format=None): data = request.data if 'pattern' not in data: return Response({'error':'POST method:pattern is required as form-data'}, status=status.HTTP_400_BAD_REQUEST) - + patternFromRequest = data['pattern'] isREValid = isRegExpValid(patternFromRequest) if not isREValid: return Response({'error':'POST method:pattern '+patternFromRequest+' is not valid regexp'}, status=status.HTTP_400_BAD_REQUEST) - + serializer = UriPatternSerializer(data=data) if serializer.is_valid(): serializer.save() diff --git a/common/common.py b/common/common.py index 37c70f7d..60b2749d 100644 --- a/common/common.py +++ b/common/common.py @@ -6,7 +6,7 @@ # Determine IP address of the host from which the given request has been received. # def getRemoteIpAddress(request): - + # If the request comes through an HTTP proxy, use the first of the IP addresses specified in the XFF header. x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: diff --git a/common/testSamples.py b/common/testSamples.py index cd45883c..a7eec1a7 100644 --- a/common/testSamples.py +++ b/common/testSamples.py @@ -84,7 +84,7 @@ def setPartnerId(self, partnerId): def setPartyId(self, partyId): self.data['partyId'] = partyId - + def forcePost(self,data): postData = copy.deepcopy(data) postData['partyId'] = Party.objects.get(partyId=self.data['partyId']) diff --git a/common/tests.py b/common/tests.py index 4e904e5c..485b98b4 100644 --- a/common/tests.py +++ b/common/tests.py @@ -188,7 +188,7 @@ def test_for_delete(self): url = self.getUrl(sample.url, sample.pkName, pk) if self.apiKey: self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) - + res = self.client.delete(url) self.assertIsNone(TestGenericInterfaces.forceGet(sample.model,sample.pkName,pk)) @@ -196,7 +196,7 @@ def test_for_delete(self): class LoginRequiredGETOnlyTest(LoginRequiredTest, GenericGETOnlyTest): # just inherit methods from two parent classes pass - + class LoginRequiredCRUDTest(LoginRequiredTest, GenericCRUDTest): # just inherit methods from two parent classes pass diff --git a/metering/testSamples.py b/metering/testSamples.py index ba458628..b0b286d6 100644 --- a/metering/testSamples.py +++ b/metering/testSamples.py @@ -84,7 +84,7 @@ def forcePost(self,data): postData = copy.deepcopy(data) postData['partnerId'] = Partner.objects.get(partnerId=data['partnerId']) return genericForcePost(self.model, self.pkName, postData) - + class MeterBlacklistSample(): path = 'meters/meterblacklist/' url = None diff --git a/metering/tests.py b/metering/tests.py index 8375ab8e..2e44f11f 100644 --- a/metering/tests.py +++ b/metering/tests.py @@ -45,7 +45,7 @@ def setUp(self): # test for API endpoint /meters/meterblacklist/ class MeterBlacklistCRUD(GenericCRUDTest, TestCase): - + sample = MeterBlacklistSample(serverUrl) partnerSample = PartnerSample(serverUrl) @@ -104,7 +104,7 @@ class CheckLimitTest(GenericTest, TestCase): limitBlockedIpAddressCountSample = IpAddressCountSample(serverUrl) meterBlacklistSample = MeterBlacklistSample(serverUrl) - + def setUp(self): super(CheckLimitTest, self).setUp() Partner.objects.filter(partnerId=self.partnerSample.data['partnerId']).delete() diff --git a/metering/views.py b/metering/views.py index dd25561f..f26f5ddf 100644 --- a/metering/views.py +++ b/metering/views.py @@ -84,7 +84,7 @@ def get(self, request, ip, format=None): and iterate through them to find any matches, returning status: Block if matched and going on to the current logic if not matched. """ - + """ Matching Versus Searching http://www.tutorialspoint.com/python/python_reg_expressions.htm Python offers two different primitive operations based on regular expressions: @@ -104,7 +104,7 @@ def get(self, request, ip, format=None): ret = {'status': "BlackListBlock"} logger.info("Metering check_limit %s%s %s%s %s%s %s" % ("ip:",ip,"partnerId:",partnerId,"uri:",uri,ret)) return HttpResponse(json.dumps(ret), content_type="application/json", status=200) - + if IpAddressCount.objects.filter(ip=ip).filter(partnerId=partnerId).exists(): currIp = IpAddressCount.objects.get(ip=ip,partnerId=partnerId) if (currIp.count >= LimitValue.objects.filter(partnerId=partnerId).aggregate(Max('val'))['val__max']): diff --git a/partner/models.py b/partner/models.py index 9be2005b..4315dd2c 100644 --- a/partner/models.py +++ b/partner/models.py @@ -30,7 +30,7 @@ class Partner(models.Model): resetPasswordEmailBody = models.CharField(max_length=2000, null=True) loginRedirectErrorText = models.CharField(max_length=100, null=True) guideUri = models.CharField(max_length=200, null=True) - + class Meta: db_table = "Partner" @@ -39,7 +39,7 @@ class PartnerPattern(models.Model): partnerId = models.ForeignKey('Partner', db_column='partnerId', on_delete=models.PROTECT) sourceUri = models.CharField(max_length=200) targetUri = models.CharField(max_length=200) - + class Meta: db_table = "PartnerPattern" diff --git a/partner/tests.py b/partner/tests.py index 11ee5ba9..01b7dcbf 100644 --- a/partner/tests.py +++ b/partner/tests.py @@ -35,7 +35,7 @@ def test_for_get(self): sample = self.sample pk = sample.forcePost(sample.data) url = sample.url + '?%s=%s' % ('sourceUri', sample.data['sourceUri']) - + # no cookie needed res = self.client.get(url) diff --git a/party/manualTests.py b/party/manualTests.py index da06180f..dc1eb784 100644 --- a/party/manualTests.py +++ b/party/manualTests.py @@ -12,7 +12,7 @@ @override_settings(EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend') class GetUsageRequestTest(TestCase): sample = UsageSample() - + def test_for_send_usage_request(self): self.send_usage_email(self.sample.institutionData) self.send_usage_email(self.sample.consortiumData) diff --git a/party/models.py b/party/models.py index 92c140cc..9f3adcae 100644 --- a/party/models.py +++ b/party/models.py @@ -99,7 +99,7 @@ def getByIp(ipAddress): except Exception: logger.error("Party IpRange %s, %s" % (obj.end, "invalid end ip")) pass - + if inputIpAddress >= start and inputIpAddress <= end: objList.append(obj) return objList diff --git a/party/tests.py b/party/tests.py index c2b2b75b..8249df67 100644 --- a/party/tests.py +++ b/party/tests.py @@ -72,7 +72,7 @@ def getUrl(self, url, pkName = None, pk = None): # need partyId for filter fullUrl = super(IpRangeCRUDTest,self).getUrl(url, pkName, pk) + '&%s=%s' % ('partyId', self.partyId) return fullUrl - + # test for API end point /parties/consortiums/ # returns consortium info and associated credential info class ConsortiumPartyCRUDTest(LoginRequiredCRUDTest, TestCase): @@ -283,7 +283,7 @@ def initForcePostInstitutionCredentialSample(self, serverUrl): institutionCredentialSample = CredentialSample(serverUrl) institutionCredentialSample.data['partnerId'] = institutionCredentialSample.updateData['partnerId'] = self.partnerId - + return institutionCredentialSample # alternative method is to post data by call create API @@ -395,7 +395,7 @@ def test_for_delete(self): url = self.getUrl(sample.url) url = '%s&parentPartyId=%s&childPartyId=%s' % (url, parentPartyId, childPartyId) - + res = self.client.delete(url) self.assertIsNone(TestGenericInterfaces.forceGet(sample.model,sample.pkName,pk)) diff --git a/party/urls.py b/party/urls.py index 2f022301..f4ef2a67 100644 --- a/party/urls.py +++ b/party/urls.py @@ -8,7 +8,7 @@ # Basic CRUD operations url(r'^countries/$', views.CountryView.as_view()), url(r'^organizations/$', views.OrganizationView.as_view()),#PW-265 - + url(r'^ipranges/$', views.IpRangeCRUD.as_view()), #https://demoapi.arabidopsis.org/parties/?partyId=31627&credentialId=33197&secretKey=kZ5yK8hdSbncXwD4%2F2DJOxqFUds%3D url(r'^$', views.PartyCRUD.as_view()), @@ -20,11 +20,11 @@ #https://demoapi.arabidopsis.org/parties/institutions/?partyId=31627&credentialId=33197&secretKey=kZ5yK8hdSbncXwD4%2F2DJOxqFUds%3D url(r'^institutions/$', views.InstitutionCRUD.as_view()),#PW-161 url(r'^affiliations/$', views.AffiliationCRUD.as_view()), - + #PW-277 - accept IP, returns organization #https://demoapi.arabidopsis.org/parties/institutions/?IP=31627&credentialId=33197&secretKey=kZ5yK8hdSbncXwD4%2F2DJOxqFUds%3D url(r'^org/$', views.PartyOrgCRUD.as_view()), url(r'^orgstatus/$', views.PartyOrgStatusView.as_view()), - + ] urlpatterns = format_suffix_patterns(urlpatterns) diff --git a/scripts/countryMigration.py b/scripts/countryMigration.py index b0894982..aaefbdaa 100755 --- a/scripts/countryMigration.py +++ b/scripts/countryMigration.py @@ -17,7 +17,7 @@ def connect(): user="phoenix" password="password" dbName="demo1" - + conn = MySQLdb.connect(host=host, user=user, passwd=password, @@ -48,5 +48,5 @@ def connect(): print("total commit %s" % totalCount) conn.commit() batchCount = 0 - + conn.commit() diff --git a/scripts/organizationCountryMigrationScript.py b/scripts/organizationCountryMigrationScript.py index 8e755383..78b1ac3d 100644 --- a/scripts/organizationCountryMigrationScript.py +++ b/scripts/organizationCountryMigrationScript.py @@ -76,10 +76,10 @@ 'display':display, 'country':countryId, } - + if Party.objects.all().filter(name=organizationName).exists(): for partyInstance in Party.objects.all().filter(name=organizationName): - + serializer = PartySerializer(partyInstance, data=data) if serializer.is_valid(): serializer.save() diff --git a/scripts/personSubscriptionMigrationScript.py b/scripts/personSubscriptionMigrationScript.py index 7c3d6b40..774f5027 100755 --- a/scripts/personSubscriptionMigrationScript.py +++ b/scripts/personSubscriptionMigrationScript.py @@ -62,7 +62,7 @@ def parseTime(inString): else: print("not good %s" % communityId) continue - + startDate = parseTime("21-DEC-12") endDate = parseTime(expirationDate) data = { diff --git a/scripts/runTestPartyCountry.py b/scripts/runTestPartyCountry.py index 9e53ccb9..3251120a 100644 --- a/scripts/runTestPartyCountry.py +++ b/scripts/runTestPartyCountry.py @@ -50,7 +50,7 @@ # if Party.objects.all().filter(name=organizationName)[2].exists(): # countryId = int(Party.objects.all().filter(name=organizationName)[2].country.countryId) # print organizationName + ", " + str(countryId) + "\n" - + else: countryId = None; #print organizationName + ", " + countryId + "\n" diff --git a/scripts/setupDbScript.py b/scripts/setupDbScript.py index dcdd56ea..2236e46e 100755 --- a/scripts/setupDbScript.py +++ b/scripts/setupDbScript.py @@ -6,7 +6,7 @@ def connect(): user="phoenix" password="password" dbName="demo1" - + conn = MySQLdb.connect(host=host, user=user, passwd=password, diff --git a/scripts/subscriptionMigrationScript.py b/scripts/subscriptionMigrationScript.py index ec7a4e09..c9ba07a1 100755 --- a/scripts/subscriptionMigrationScript.py +++ b/scripts/subscriptionMigrationScript.py @@ -60,7 +60,7 @@ def parseTime(inString): timeArr = inArr[1].split('.') timeStr = "%s:%s:%s" % (timeArr[0], timeArr[1], timeArr[2]) - + outString = "%s-%s-%sT%sZ" % (year, month, day, timeStr) return outString @@ -113,7 +113,7 @@ def parseTime(inString): organizationName = organizationName.decode('utf8') startDate = entry[offset+1] endDate = entry[offset+2] - + if not endDate or endDate == "": endDate = "01-JAN-99 01.00.00.000000000 AM AMERICA/LOS_ANGELES" startDate = parseTime(startDate) diff --git a/scripts/updatePartyPasswordsFromFile.py b/scripts/updatePartyPasswordsFromFile.py index 0a7526a3..9ebdd2e9 100644 --- a/scripts/updatePartyPasswordsFromFile.py +++ b/scripts/updatePartyPasswordsFromFile.py @@ -17,7 +17,7 @@ def connect(): user="phoenix" password="password" dbName="phoenix_api" - + conn = MySQLdb.connect(host=host, user=user, passwd=password, @@ -52,7 +52,7 @@ def create_signature(password): if digestedPw.rstrip() == '': continue totalCount += 1 - + # Execute the update. try: cur.execute(passwordSql%(digestedPw,partyId,)) diff --git a/scripts/userMigrationScript.py b/scripts/userMigrationScript.py index 8b125842..5fa864cc 100755 --- a/scripts/userMigrationScript.py +++ b/scripts/userMigrationScript.py @@ -17,7 +17,7 @@ def connect(): user="phoenix" password="password" dbName="phoenix_api" - + conn = MySQLdb.connect(host=host, user=user, passwd=password, diff --git a/subscription/controls.py b/subscription/controls.py index fbb45b2c..2cce1bc1 100644 --- a/subscription/controls.py +++ b/subscription/controls.py @@ -37,7 +37,7 @@ def createOrUpdateSubscription(partyId, partnerId, period): transactionType = None transactionStartDate = None transactionEndDate = None - + if subscription == None: # case1: new subscription partyObj = Party.objects.get(partyId=partyId) @@ -65,7 +65,7 @@ def createOrUpdateSubscription(partyId, partnerId, period): transactionType = 'renew' transactionStartDate = endDate transactionEndDate = subscription.endDate - + return (subscription, transactionType, transactionStartDate, transactionEndDate) class PaymentControl(): @@ -80,7 +80,7 @@ def tryCharge(secret_key, stripe_token, priceToCharge, partnerName, chargeDescri message['message'] = "Charge validation error" #message['status'] = False //PW-120 vet we will return 400 instead - see SubscriptionsPayment post - i.e. the caller return message - + stripe.api_key = secret_key charge = stripe.Charge.create( amount=int(priceToCharge*100), # stripe takes in cents; UI passes in dollars. multiply by 100 to convert. @@ -117,7 +117,7 @@ def tryCharge(secret_key, stripe_token, priceToCharge, partnerName, chargeDescri @staticmethod def getEmailInfo(activationCodes, partnerName, termId, quantity, payment, transactionId, email, firstname, lastname, institute, street, city, state, country, zip, hostname, redirect, vat, domain): - + termObj = SubscriptionTerm.objects.get(subscriptionTermId=termId) partnerObj = termObj.partnerId loginURL = domain + partnerObj.loginUri + "?redirect=" + urllib.parse.quote(domain + "/preferences.html", safe='~') @@ -165,7 +165,7 @@ def emailReceipt(emailInfo, termId): termObj = SubscriptionTerm.objects.get(subscriptionTermId=termId) partnerObj = termObj.partnerId - + html_message = partnerObj.activationEmailInstructionText % ( kwargs['partnerLogo'], kwargs['name'], @@ -187,8 +187,8 @@ def emailReceipt(emailInfo, termId): """+kwargs['addr2']+""",
"""+kwargs['addr3']+"""
""") - - + + subject = kwargs['subject'] from_email = kwargs['senderEmail'] recipient_list = kwargs['recipientEmails'] @@ -199,7 +199,7 @@ def emailReceipt(emailInfo, termId): # logger.info("%s" % recipient_list[0]) send_mail(subject=subject, from_email=from_email, recipient_list=recipient_list, html_message=html_message, message=None) # logger.info("------Done sending individual email------") - + @staticmethod def isValidRequest(request, message): ret = True @@ -251,7 +251,7 @@ def postPaymentHandling(termId, quantity): codeArray.append(activationCodeObj.activationCode) return codeArray - + @staticmethod def validateCharge(price, termId, quantity): so = SubscriptionTerm.objects.get(subscriptionTermId=termId) diff --git a/subscription/testSamples.py b/subscription/testSamples.py index 5430e870..16129f25 100644 --- a/subscription/testSamples.py +++ b/subscription/testSamples.py @@ -145,7 +145,7 @@ def __init__(self, serverUrl): self.updateData['transactionDate'] = getDateTimeString(updateTransactionDateObj) self.updateData['startDate'] = self.updateData['transactionDate'] self.updateData['endDate'] = getDateTimeString(updateTransactionDateObj + timedelta(days=UPDATE_NUM_DAYS_AFTER_PURCHASE)) - + def forcePost(self,data): postData = copy.deepcopy(data) diff --git a/subscription/tests.py b/subscription/tests.py index d7ec79b7..76c7b4e0 100644 --- a/subscription/tests.py +++ b/subscription/tests.py @@ -38,7 +38,7 @@ def setUp(self): partySample = UserPartySample(serverUrl) self.partyId = partySample.forcePost(partySample.data) - + self.sample.data['partyId']=self.sample.updateData['partyId']=self.partyId self.sample.data['partnerId']=self.sample.updateData['partnerId']=self.partnerId @@ -50,7 +50,7 @@ def setUp(self): def test_for_create(self): sample = self.sample url = self.getUrl(sample.url) - + res = self.client.post(url, sample.data) self.assertEqual(res.status_code, status.HTTP_201_CREATED) resObj = json.loads(res.content) @@ -96,7 +96,7 @@ def test_for_get(self): credentialSample.setPartyId(self.partyId) credentialSample.setPartnerId(self.partnerId) credentialSample.forcePost(credentialSample.data) - + url = self.getUrl(sample.url, 'userIdentifier', credentialSample.getUserIdentifier()) # need to pass ipAddress as arg even when not needed url = '%s&partnerId=%s&ipAddress=' % (url, self.partnerId) @@ -126,7 +126,7 @@ def test_for_get_by_ip_address(self): # need to pass userIdentifier as arg even when not needed url = '%s&partnerId=%s&userIdentifier=' % (url, self.partnerId) self.runGetTestByIdentifier(url, pk) - + def runGetTestByIdentifier(self, url, pk): sample = self.sample @@ -182,7 +182,7 @@ def test_for_create(self): self.assertEqual(res.status_code, 200) self.assertIsNotNone(TestGenericInterfaces.forceGet(sample.model,'activationCode',json.loads(res.content)[0])) - + # update activation code as deleted def test_for_update(self): sample = self.sample @@ -206,12 +206,12 @@ def setUp(self): partnerId = partnerSample.forcePost(partnerSample.data) self.sample.data['partnerId'] = self.sample.updateData['partnerId']=partnerId - + def test_for_get(self): sample = self.sample pk = sample.forcePost(sample.data) url = self.getUrl(sample.url, sample.pkName, pk) - + res = self.client.get(url) self.assertEqual(res.status_code, 200) @@ -235,7 +235,7 @@ def test_for_get_all(self): # Tested in above class def test_for_create(self): pass - + # Tested in above class def test_for_update(self): pass @@ -292,7 +292,7 @@ def setUp(self): partySample = UserPartySample(serverUrl) partyId = partySample.forcePost(partySample.data) - + sample = self.sample sample.data['partnerId']=sample.updateData['partnerId']=partnerId sample.data['partyId']=sample.updateData['partyId']=partyId @@ -300,7 +300,7 @@ def setUp(self): def test_for_update(self): sample = self.sample subscriptionId = sample.forcePost(sample.data) - + url = serverUrl + 'subscriptions/' + str(subscriptionId) + '/renewal/' # the default content type for put is 'application/octet-stream' res = self.client.put(url, json.dumps(sample.updateData), content_type='application/json') @@ -419,7 +419,7 @@ def test_for_have_both_subscriptions(self): userSubscriptionSample.setPartyId(self.userPartyId) userSubscriptionSample.setPartnerId(self.partnerId) userSubscriptionSample.forcePost(userSubscriptionSample.data) - + # organization (IP based) subscription will shadow individual subscription on subscription type # but end date will be the latest of both so there could be inconsistency between end date and # subscription type @@ -515,7 +515,7 @@ def test_for_get(self): class SubscriptionRequestTest(ManualTest, TestCase): path = "/subscriptions/subscriptionrequest/" testMethodStr = "clicking Subcription - Download All Requests on ui.arabidopsis.org/adminportal/" - + # test for API end point /subscriptions/active/ # endpoint returns ALL ACTIVE subscription and party info that covers the given IP address or belongs to the given # user identifier for a given partner @@ -622,7 +622,7 @@ def getOrgDataToCompare(self): class GetActiveSubscriptionByPartyIdTest(GenericTest, TestCase): partnerId = None subscriptionSample = SubscriptionSample(serverUrl) - + def setUp(self): super(GetActiveSubscriptionByPartyIdTest,self).setUp() @@ -630,13 +630,13 @@ def setUp(self): self.partnerId = partnerSample.forcePost(partnerSample.data) self.subscriptionSample.setPartnerId(self.partnerId) - + def test_for_get_individual_subscription(self): userPartySample = UserPartySample(serverUrl) partyId = userPartySample.forcePost(userPartySample.data) self.runTest(partyId) - + def test_for_get_organization_subscription(self): countrySample = CountrySample(serverUrl) countryId = countrySample.forcePost(countrySample.data) @@ -670,7 +670,7 @@ class GetSubscriptionHistoryByPartyIdTest(GenericTest, TestCase): subscriptionSample = SubscriptionSample(serverUrl) expiredSubscriptionSample = SubscriptionSample(serverUrl) expiredSubscriptionSample.setAsExpired() - + def setUp(self): super(GetSubscriptionHistoryByPartyIdTest,self).setUp() @@ -681,13 +681,13 @@ def setUp(self): self.subscriptionSample.setPartnerId(self.partnerIdWithActiveSubscription) self.expiredSubscriptionSample.setPartnerId(self.partnerIdWithExpiredSubscription) - + def test_for_get_individual_subscription(self): userPartySample = UserPartySample(serverUrl) partyId = userPartySample.forcePost(userPartySample.data) self.runTest(partyId) - + def test_for_get_organization_subscription(self): countrySample = CountrySample(serverUrl) countryId = countrySample.forcePost(countrySample.data) diff --git a/subscription/urls.py b/subscription/urls.py index 2aaad55f..da449a6d 100644 --- a/subscription/urls.py +++ b/subscription/urls.py @@ -32,7 +32,7 @@ url(r'^templates/block/$', TemplateView.as_view(template_name="subscription/block.html")), # PW-161 https://demoapi.arabidopsis.org/subscriptions/templates/login.html # url(r'^templates/login/$', TemplateView.as_view(template_name="subscription/login.html")), - + url(r'^templates/warn/$', TemplateView.as_view(template_name="subscription/warn.html")), ] urlpatterns = format_suffix_patterns(urlpatterns) From 2399ce1cb825e9cf4d1954f211d5979efd2cdd2b Mon Sep 17 00:00:00 2001 From: Kun Xiao Date: Wed, 27 Jul 2022 18:33:31 -0400 Subject: [PATCH 08/19] PWL-764 validation error handling Added four test cases to test validation error handling. Clean out the useless comments --- common/common.py | 6 ++--- party/testSamples.py | 18 ++++++++++++++ party/tests.py | 58 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/common/common.py b/common/common.py index 60b2749d..025f3121 100644 --- a/common/common.py +++ b/common/common.py @@ -1,5 +1,5 @@ # The catch-all container for any commonly used classes/functions that don't (yet) deserve dedicated containers of their own. -from django.core.exceptions import ValidationError +from rest_framework import serializers from django.utils.translation import ugettext_lazy as _ from netaddr import IPAddress, IPRange, IPNetwork @@ -18,9 +18,9 @@ def getRemoteIpAddress(request): # validate ip range based on a series of conditions def validateIpRange(start, end): if isIpRangePrivate(start, end): - raise ValidationError({'IP Range': _('IP range contains private IP: %s - %s' % (start, end))}) + raise serializers.ValidationError({'IP Range': _('IP range contains private IP: %s - %s' % (start, end))}) if not validateIpRangeSize(start, end): - raise ValidationError({'IP Range': _('IP range too large: %s - %s' % (start, end))}) + raise serializers.ValidationError({'IP Range': _('IP range too large: %s - %s' % (start, end))}) # check if the ip range is private def isIpRangePrivate(start, end): diff --git a/party/testSamples.py b/party/testSamples.py index b8e2c761..7c1f5141 100644 --- a/party/testSamples.py +++ b/party/testSamples.py @@ -151,6 +151,18 @@ class IpRangeSample(): 'partyId': None, 'label': 'test_label_II', } + invalidData_private = { + 'start':'192.168.1.0', + 'end':'192.168.255.255', + 'partyId': None, + 'label': 'test_label_III', + } + invalidData_oversize = { + 'start':'120.10.0.0', + 'end':'120.11.255.255', + 'partyId': None, + 'label': 'test_label_IV', + } pkName = 'ipRangeId' model = IpRange @@ -169,6 +181,12 @@ def getInRangeIp(self): def getOutRangeIp(self): return '133.1.8.52' + def getOutRangeIPErrorMessage(self): + return 'IP range too large: %s - %s' % (self.invalidData_oversize['start'], self.invalidData_oversize['end']) + + def getPrivateRangeIPErrorMessage(self): + return 'IP range contains private IP: %s - %s' % (self.invalidData_private['start'], self.invalidData_private['end']) + def forcePost(self,data): postData = copy.deepcopy(data) postData['partyId'] = Party.objects.get(partyId=data['partyId']) diff --git a/party/tests.py b/party/tests.py index 8249df67..c1d3d29c 100644 --- a/party/tests.py +++ b/party/tests.py @@ -64,6 +64,64 @@ def setUp(self): self.partySample.data['country']=countryId self.partyId = self.partySample.forcePost(self.partySample.data) self.sample.data['partyId']=self.sample.updateData['partyId']=self.partyId + self.sample.invalidData_oversize['partyId'] = self.partyId + self.sample.invalidData_private['partyId'] = self.partyId + + def test_for_update_private_ipRange(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = self.getUrl(sample.url, sample.pkName, pk) + if self.apiKey: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + + # the default content type for put is 'application/octet-stream' + res = self.client.put(url, json.dumps(sample.invalidData_private), content_type='application/json') + + self.assertEqual(res.status_code, 400) + is_private = json.loads(res.content)['IP Range'] = sample.getPrivateRangeIPErrorMessage() + self.assertTrue(is_private, 'Private_IpRange_Test_for_Update: Expected \ + IpRange to have a private IP address, but failed.') + + def test_for_update_oversize_ipRange(self): + sample = self.sample + pk = sample.forcePost(sample.data) + url = self.getUrl(sample.url, sample.pkName, pk) + if self.apiKey: + self.client.cookies = SimpleCookie({'apiKey':self.apiKey}) + + # the default content type for put is 'application/octet-stream' + res = self.client.put(url, json.dumps(sample.invalidData_oversize), content_type='application/json') + + self.assertEqual(res.status_code, 400) + is_oversize = json.loads(res.content)['IP Range'] = sample.getOutRangeIPErrorMessage() + self.assertTrue(is_oversize, 'Oversize_IpRange_Test_for_Update: Expected \ + IpRange to be out of range, but failed.') + + def test_for_create_private_ipRange(self): + sample = self.sample + url = self.getUrl(sample.url) + if self.apiKey: + self.client.cookies = SimpleCookie({'apikey': self.apiKey}) + + res = self.client.post(url, sample.invalidData_private) + + self.assertEqual(res.status_code, 400) + is_private = json.loads(res.content)['IP Range'] == sample.getPrivateRangeIPErrorMessage() + self.assertTrue(is_private, 'Private_IpRange_Test_for_Create: Expected \ + IpRange to have a private IP address, but failed.') + + def test_for_create_oversize_ipRange(self): + sample = self.sample + url = self.getUrl(sample.url) + if self.apiKey: + self.client.cookies = SimpleCookie({'apikey': self.apiKey}) + + res = self.client.post(url, sample.invalidData_oversize) + + self.assertEqual(res.status_code, 400) + is_oversize = json.loads(res.content)['IP Range'] == sample.getOutRangeIPErrorMessage() + self.assertTrue(is_oversize, 'Oversize_IpRange_Test_for_Create: Expected \ + IpRange to be out of range, but failed.') def test_for_get(self): pass From c509376fe4713440f02058b9e1c1a34b9da00f25 Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Fri, 29 Jul 2022 14:57:10 -0700 Subject: [PATCH 09/19] PWL-770: Add logging for activation code purchase email. --- subscription/controls.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/subscription/controls.py b/subscription/controls.py index 2cce1bc1..d03f2619 100644 --- a/subscription/controls.py +++ b/subscription/controls.py @@ -192,13 +192,13 @@ def emailReceipt(emailInfo, termId): subject = kwargs['subject'] from_email = kwargs['senderEmail'] recipient_list = kwargs['recipientEmails'] -# logging.basicConfig(filename="/home/ec2-user/logs/debug.log", -# format='%(asctime)s %(message)s' -# ) -# logger.info("------Sending individual email------") -# logger.info("%s" % recipient_list[0]) + logger.info("------Sending activation code email------") + logger.info("Receipient: %s" % recipient_list[0]) + logger.info("ActivationCodes:") + for l in kwargs['accessCodes']: + logger.info(l) send_mail(subject=subject, from_email=from_email, recipient_list=recipient_list, html_message=html_message, message=None) -# logger.info("------Done sending individual email------") + logger.info("------Done sending activation code email------") @staticmethod def isValidRequest(request, message): From 73c5281f5455865c59e6e01a9f45689b87739c93 Mon Sep 17 00:00:00 2001 From: Kun Xiao Date: Mon, 1 Aug 2022 22:45:08 -0400 Subject: [PATCH 10/19] PWL-477: Updated put method in ConsortiumCRUD and InstitutionCRUD --- party/views.py | 169 ++++++++++++++++++++++++++++--------------------- 1 file changed, 96 insertions(+), 73 deletions(-) diff --git a/party/views.py b/party/views.py index 913ad51c..73314e75 100644 --- a/party/views.py +++ b/party/views.py @@ -289,52 +289,64 @@ def put(self, request, format=None): #http://stackoverflow.com/questions/18930234/django-modifying-the-request-object data = request.data.copy() - params = request.GET - - if not params: - return Response({'error':'PUT parties/consortiums/ does not allow update without query parameters'},status=status.HTTP_400_BAD_REQUEST) + out = [] - if 'partyId' not in request.data: - return Response({'error':'PUT parties/consortiums/ partyId required'},status=status.HTTP_400_BAD_REQUEST) + if 'partyId' not in data: + return Response({'error': 'PUT parties/consortiums/ partyId required'}, status=status.HTTP_400_BAD_REQUEST) - consortiumId = request.data['partyId'] + consortiumId = data['partyId'] #get party party = Party.objects.get(partyId = consortiumId) - partySerializer = PartySerializer(party, data=data) - if 'email' in data: - for partyId in Credential.objects.all().filter(email=data['email']).filter(partnerId='phoenix').values_list('partyId', flat=True): - if Party.objects.all().filter(partyId=partyId).filter(partyType='consortium').exists(): - return Response({'error':'This email is already used by another consortium.'}, status=status.HTTP_400_BAD_REQUEST) - if 'password' in request.data: - if (not data['password'] or data['password'] == ""): - return Response({'error': 'PUT parties/consortiums/ password must not be empty'}, status=status.HTTP_400_BAD_REQUEST) + + hasPartySerializerParam = any(param in PartySerializer.Meta.fields for param in data if param != 'partyId') + hasCredentialSerializerParam = any(param in CredentialSerializer.Meta.fields for param in data if param != 'partyId') + + if hasCredentialSerializerParam: + + partner = Partner.objects.get(partnerId='phoenix') + try: + credential = Credential.objects.get(partyId=party, partnerId=partner) + except: + for param in ('username', 'password'): + if param not in data: + return Response({'error', 'username and password required.'}, status=status.HTTP_400_BAD_REQUEST) + credential = Credential(partyId=party, partnerId=partner) + + if 'email' in data: + partyIdList = Credential.objects.all().filter(email=data['email']).filter(partnerId='phoenix').values_list('partyId', flat=True) + for partyId in partyIdList: + has_partyId = Party.objects.all().filter(partyId=partyId).filter(partyType='consortium').exists() + if has_partyId: + return Response({'error':'This email is already used by another consortium.'}, status=status.HTTP_400_BAD_REQUEST) + + if 'password' in data: + if data['password'] == None or data['password'] == "": + return Response({'error': 'PUT parties/consortiums/ password must not be empty'}, status=status.HTTP_400_BAD_REQUEST) + else: + newPwd = data['password'] + data['password'] = Credential.generatePasswordHash(newPwd) + credentialSerializer = CredentialSerializer(credential, data=data, partial=True) else: - newPwd = data['password'] - data['password'] = Party.generatePasswordHash(newPwd) - try: - credential = Credential.objects.get(partyId=party) - credentialSerializer = CredentialSerializer(credential, data=data) - except Credential.DoesNotExist: - data['partnerId'] = 'phoenix' - credentialSerializer = CredentialSerializer(data=data) + credentialSerializer = CredentialSerializerNoPassword(credential, data=data, partial=True) - else: - credentialSerializer = CredentialSerializerNoPassword(credential, data=data, partial=True) #?? + partySerializer = PartySerializer(party, data=data, partial=True) - out = [] - if partySerializer.is_valid(): + if hasPartySerializerParam and not partySerializer.is_valid(): + return Response(partySerializer.errors, status=status.HTTP_400_BAD_REQUEST) + if hasCredentialSerializerParam and not credentialSerializer.is_valid(): + return Response(credentialSerializer.errors, status=status.HTTP_400_BAD_REQUEST) + + if hasPartySerializerParam: partySerializer.save() partyReturnData = partySerializer.data out.append(partyReturnData) - if credentialSerializer.is_valid(): - credentialSerializer.save() - credentialReturnData = credentialSerializer.data - out.append(credentialReturnData) - return HttpResponse(json.dumps(out), content_type="application/json") - else: - return Response(credentialSerializer.errors, status=status.HTTP_400_BAD_REQUEST) - else: - return Response(partySerializer.errors, status=status.HTTP_400_BAD_REQUEST) + + if hasCredentialSerializerParam: + credentialSerializer.save() + credentialReturnData = credentialSerializer.data + out.append(credentialReturnData) + + return HttpResponse(json.dumps(out), content_type="application/json") #PW-161 POST https://demoapi.arabidopsis.org/parties/consortiums/?credentialId=2&secretKey=7DgskfEF7jeRGn1h%2B5iDCpvIkRA%3D #NOTE ?/ in parties/consortiums/?credentialId= @@ -477,55 +489,66 @@ def get(self, request, format=None): # output data from both tables for a given partyId def put(self, request, format=None): if not isPhoenix(request): - return HttpResponse({'error':'credentialId and secretKey query parameters missing or invalid'},status=status.HTTP_400_BAD_REQUEST) + return HttpResponse({'error':'credentialId and secretKey query parameters missing or invalid'},status=status.HTTP_400_BAD_REQUEST) - params = request.GET data = request.data.copy() + out = [] - if not params: - return Response({'error':'does not allow update without query parameters'},status=status.HTTP_400_BAD_REQUEST) - - if 'partyId' not in request.data: + if 'partyId' not in data: return Response({'error':'partyId (aka institutionId) required'},status=status.HTTP_400_BAD_REQUEST) - institutionId = request.data['partyId'] - #get party + institutionId = data['partyId'] party = Party.objects.get(partyId = institutionId) - partySerializer = PartySerializer(party, data=data) - if 'email' in data: - for partyId in Credential.objects.all().filter(email=data['email']).filter(partnerId='phoenix').values_list('partyId', flat=True): - if Party.objects.all().filter(partyId=partyId).filter(partyType='organization').exists(): - return Response({'error':'This email is already used by another institution.'}, status=status.HTTP_400_BAD_REQUEST) - if 'password' in request.data: - if (not data['password'] or data['password'] == ""): - return Response({'error': 'PUT parties/institutions/ password must not be empty'}, status=status.HTTP_400_BAD_REQUEST) + hasPartySerializerParam = any(param in PartySerializer.Meta.fields for param in data if param != 'partyId') + hasCredentialSerializerParam = any(param in CredentialSerializer.Meta.fields for param in data if param != 'partyId') + + if hasCredentialSerializerParam: + + partner = Partner.objects.get(partnerId='phoenix') + try: + credential= Credential.objects.get(partyId=party, partnerId=partner) + except: + for param in ('username', 'password'): + if param not in data: + return Response({'error': 'username and password required.'}, status=status.HTTP_400_BAD_REQUEST) + credential= Credential(partyId=party, partnerId=partner) + + if 'email' in data: + partyIdList = Credential.objects.all().filter(email=data['email']).filter(partnerId='phoenix').values_list('partyId', flat=True) + for partyId in partyIdList: + has_partyId = Party.objects.all().filter(partyId=partyId).filter(partyType='organization').exists() + if has_partyId: + return Response({'error':'This email is already used by another institution.'}, status=status.HTTP_400_BAD_REQUEST) + + if 'password' in data: + if data['password'] == None or data['password'] == "": + return Response({'error': 'password must not be empty'}, status=status.HTTP_400_BAD_REQUEST) + else: + newPwd = data['password'] + data['password'] = Credential.generatePasswordHash(newPwd) + credentialSerializer = CredentialSerializer(credential, data=data, partial=True) else: - newPwd = data['password'] - data['password'] = Party.generatePasswordHash(newPwd) - try: - credential = Credential.objects.get(partyId=party) - credentialSerializer = CredentialSerializer(credential, data=data) - except Credential.DoesNotExist: - data['partnerId'] = 'phoenix' - credentialSerializer = CredentialSerializer(data=data) - else: - credentialSerializer = CredentialSerializerNoPassword(credential, data=data, partial=True) #?? + credentialSerializer = CredentialSerializerNoPassword(credential, data=data, partial=True) - out = [] - if partySerializer.is_valid(): + partySerializer = PartySerializer(party, data=data, partial=True) + + if hasPartySerializerParam and not partySerializer.is_valid(): + return Response(partySerializer.errors, status=status.HTTP_400_BAD_REQUEST) + if hasCredentialSerializerParam and not credentialSerializer.is_valid(): + return Response(credentialSerializer.errors, status=status.HTTP_400_BAD_REQUEST) + + if hasPartySerializerParam: partySerializer.save() partyReturnData = partySerializer.data out.append(partyReturnData) - if credentialSerializer.is_valid(): - credentialSerializer.save() - credentialReturnData = credentialSerializer.data - out.append(credentialReturnData) - return HttpResponse(json.dumps(out), content_type="application/json") - else: - return Response(credentialSerializer.errors, status=status.HTTP_400_BAD_REQUEST) - else: - return Response(partySerializer.errors, status=status.HTTP_400_BAD_REQUEST) + + if hasCredentialSerializerParam: + credentialSerializer.save() + credentialReturnData = credentialSerializer.data + out.append(credentialReturnData) + + return HttpResponse(json.dumps(out), content_type="application/json") #PW-161 POST https://demoapi.arabidopsis.org/parties/institutions/?credentialId=2&secretKey=7DgskfEF7jeRGn1h%2B5iDCpvIkRA%3D #NOTE ?/ in parties/institutions/?credentialId= From 3e96f437339f9caf5e8ba3ad0f6a0899209f5a6f Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Thu, 4 Aug 2022 00:33:02 -0700 Subject: [PATCH 11/19] Add test runner to skip error logging for exception assertion in the test cases. --- common/utils/__init__.py | 0 common/utils/test_runner.py | 12 ++++++++++++ paywall2/settings.py.template.prod | 2 ++ paywall2/settings.py.template.test | 2 ++ 4 files changed, 16 insertions(+) create mode 100644 common/utils/__init__.py create mode 100644 common/utils/test_runner.py diff --git a/common/utils/__init__.py b/common/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/common/utils/test_runner.py b/common/utils/test_runner.py new file mode 100644 index 00000000..98a1f020 --- /dev/null +++ b/common/utils/test_runner.py @@ -0,0 +1,12 @@ +import logging + +from django.test.runner import DiscoverRunner +from django.conf import settings + +class NoLoggingTestRunner(DiscoverRunner): + def run_tests(self, test_labels, extra_tests=None, **kwargs): + + # Don't show logging messages while testing + logging.disable(logging.CRITICAL) + + return super(NoLoggingTestRunner, self).run_tests(test_labels, extra_tests, **kwargs) diff --git a/paywall2/settings.py.template.prod b/paywall2/settings.py.template.prod index 93451029..f53b9344 100644 --- a/paywall2/settings.py.template.prod +++ b/paywall2/settings.py.template.prod @@ -57,6 +57,8 @@ TEMPLATES = [ ADMINS = [('Phoenix', 'techteam@arabidopsis.org'), ('Dev', 'dev@arabidopsis.org'), ('Xingguo', 'xingguo.chen@arabidopsis.org')] SERVER_EMAIL = 'dev@arabidopsis.org' # override the email address that error messages come from +TEST_RUNNER = 'common.utils.test_runner.NoLoggingTestRunner' + LOGGING = { 'version': 1, 'formatters': { diff --git a/paywall2/settings.py.template.test b/paywall2/settings.py.template.test index 5b47f517..871f8330 100644 --- a/paywall2/settings.py.template.test +++ b/paywall2/settings.py.template.test @@ -57,6 +57,8 @@ TEMPLATES = [ ADMINS = [('Phoenix', 'techteam@arabidopsis.org'), ('Dev', 'dev@arabidopsis.org'), ('Xingguo', 'xingguo.chen@arabidopsis.org')] SERVER_EMAIL = 'dev@arabidopsis.org' # override the email address that error messages come from +TEST_RUNNER = 'common.utils.test_runner.NoLoggingTestRunner' + LOGGING = { 'version': 1, 'formatters': { From cb42764980876fbe423b21401783a43e518de9f6 Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Thu, 4 Aug 2022 00:34:44 -0700 Subject: [PATCH 12/19] Handle validation failure for generic put request. Fix test case bug. --- common/views.py | 24 +++++++++++++++++++----- party/tests.py | 4 ++-- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/common/views.py b/common/views.py index 9cb59e41..96392950 100644 --- a/common/views.py +++ b/common/views.py @@ -37,13 +37,27 @@ def put(self, request, format=None): if not params: return Response({'error':'does not allow update without query parameters'}) obj = self.get_queryset() - ret = [] + errorRes = [] + serializerList = [] + valid = True for entry in obj: serializer = serializer_class(entry, data=request.data) - if serializer.is_valid(): - serializer.save() - ret.append(serializer.data) - return Response(ret) + if not serializer.is_valid(): + valid = False + errorRes.append(serializer.errors) + else: + serializerList.append(serializer) + + if not valid: + return Response(errorRes, status=status.HTTP_400_BAD_REQUEST) + + successRes = [] + + for serializer in serializerList: + serializer.save() + successRes.append(serializer.data) + + return Response(successRes) def post(self, request, format=None): serializer_class = self.get_serializer_class() diff --git a/party/tests.py b/party/tests.py index c1d3d29c..50c8fec9 100644 --- a/party/tests.py +++ b/party/tests.py @@ -78,7 +78,7 @@ def test_for_update_private_ipRange(self): res = self.client.put(url, json.dumps(sample.invalidData_private), content_type='application/json') self.assertEqual(res.status_code, 400) - is_private = json.loads(res.content)['IP Range'] = sample.getPrivateRangeIPErrorMessage() + is_private = json.loads(res.content)['IP Range'] == sample.getPrivateRangeIPErrorMessage() self.assertTrue(is_private, 'Private_IpRange_Test_for_Update: Expected \ IpRange to have a private IP address, but failed.') @@ -93,7 +93,7 @@ def test_for_update_oversize_ipRange(self): res = self.client.put(url, json.dumps(sample.invalidData_oversize), content_type='application/json') self.assertEqual(res.status_code, 400) - is_oversize = json.loads(res.content)['IP Range'] = sample.getOutRangeIPErrorMessage() + is_oversize = json.loads(res.content)['IP Range'] == sample.getOutRangeIPErrorMessage() self.assertTrue(is_oversize, 'Oversize_IpRange_Test_for_Update: Expected \ IpRange to be out of range, but failed.') From 28770c993153f80ccadb080bb4029ad1e9778420 Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Fri, 5 Aug 2022 01:03:41 -0700 Subject: [PATCH 13/19] And method to compare request data with database result. Fix incorrect test sample value bug. --- common/testSamples.py | 2 +- common/tests.py | 50 ++++++++++++++++++++++++++++++++++++++---- partner/testSamples.py | 8 +++---- party/tests.py | 14 ++++++++---- subscription/tests.py | 6 +++-- 5 files changed, 65 insertions(+), 15 deletions(-) diff --git a/common/testSamples.py b/common/testSamples.py index a7eec1a7..e2c59f5c 100644 --- a/common/testSamples.py +++ b/common/testSamples.py @@ -61,7 +61,7 @@ class CommonCredentialSample(): PASSWORD = 'phoenix123' EMAIL = 'info@phoenixbioinformatics.org' INSTITUTION = 'Phoenix Bioinformatics' - USER_IDENTIFIER = 123 + USER_IDENTIFIER = 1 data = { 'username': USERNAME, 'firstName': FIRSTNAME, diff --git a/common/tests.py b/common/tests.py index 485b98b4..e435d7e6 100644 --- a/common/tests.py +++ b/common/tests.py @@ -1,6 +1,7 @@ import json import sys -import time +import pytz +from datetime import datetime import urllib.request, urllib.parse, urllib.error from .testSamples import CommonApiKeySample, CommonPartnerSample, CommonUserPartySample, CommonCredentialSample from partner.models import Partner @@ -88,7 +89,7 @@ def getUrl(self, url, pkName = None, pk = None): return fullUrl # This function checks if sampleData is within the array of data retrieved -# from API call. +# from API call def checkMatch(sampleData, retrievedData, pkName, pk): hasMatch = False if not isinstance(retrievedData, list): @@ -101,13 +102,52 @@ def checkMatch(sampleData, retrievedData, pkName, pk): for key in sampleData: # makes sure that all contents from sample is the # same as content retrieved from request - if not key in item or not (item[key] == sampleData[key] or float(item[key]) == float(sampleData[key])): + if not key in item or not (checkValueMatch(sampleData[key], item[key])): hasMatch = False break if not hasMatch: print("\nERROR: sample data %s and retrieved data %s does not match" % (sampleData, retrievedData)) return hasMatch +# This function checks if sampleData is within the array of data retrieved +# from the database for the same pk +def checkMatchDB(sampleData, model, pkName, pk): + dbRecord = TestGenericInterfaces.forceGet(model, pkName, pk) + if not dbRecord: + print("\nERROR: cannot find database record %s with %s = %s" % (model, pkName, pk)) + return False + hasMatch = True + for key in sampleData: + # makes sure that all keys from sample have the same value as their + # corresponding fields in the db record if exist + if (key in dbRecord.__dict__ and not checkValueMatch(sampleData[key], dbRecord.__dict__[key])): + print("\nERROR: sample data %s:%s and database record %s:%s does not match" % (key, sampleData[key], key, dbRecord.__dict__[key])) + hasMatch = False + break + if not hasMatch: + print("\nERROR: sample data %s and database record %s does not match" % (sampleData, dbRecord.__dict__)) + return hasMatch + +def checkValueMatch(feedValue, dbValue): + if isinstance(feedValue, datetime): + if isinstance(dbValue, datetime): + return feedValue == dbValue + else: + return feedValue == getDateTime(dbValue) + else: + if isinstance(dbValue, datetime): + return getDateTime(feedValue) == dbValue + return feedValue == dbValue or float(feedValue) == float(dbValue) + +def getDateTime(str): + try: + return datetime.strptime(str, '%Y-%m-%dT%H:%M:%S.%fZ').replace(tzinfo=pytz.UTC) + except ValueError: + try: + return datetime.strptime(str, '%Y-%m-%dT%H:%M:%SZ').replace(tzinfo=pytz.UTC) + except ValueError: + return None + ## This function checks if sampleData is within the array of data retrieved # from API call, and skip common key we use for authentication, such as apiKey, # credential, party etc. @@ -165,7 +205,8 @@ def test_for_create(self): res = self.client.post(url, sample.data) self.assertEqual(res.status_code, 201) - self.assertIsNotNone(TestGenericInterfaces.forceGet(sample.model,sample.pkName,json.loads(res.content)[sample.pkName])) + pk = json.loads(res.content)[sample.pkName] + self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) def test_for_update(self): sample = self.sample @@ -181,6 +222,7 @@ def test_for_update(self): self.assertEqual(res.status_code, 200) self.assertEqual(checkMatch(sample.updateData, json.loads(res.content), sample.pkName, pk), True) + self.assertEqual(checkMatchDB(sample.updateData, sample.model, sample.pkName, pk), True) def test_for_delete(self): sample = self.sample diff --git a/partner/testSamples.py b/partner/testSamples.py index 079ce852..7cf0d538 100644 --- a/partner/testSamples.py +++ b/partner/testSamples.py @@ -12,16 +12,16 @@ class PartnerSample(): url = None path = 'partners/' data = { - 'partnerId':'test', - 'name':'testPartner', + 'partnerId':'phoenix', + 'name':'phoenixTestPartner', 'logoUri':'randomuri.com', 'termOfServiceUri':'anotherrandomuri.com', 'description':'Genome database for the reference plant Arabidopsis thaliana', 'resetPasswordEmailBody': 'Test Partner username: %s (%s). Your temp password is %s.' } updateData = { - 'partnerId':'test', - 'name':'testPartner2', + 'partnerId':'phoenix', + 'name':'phoenixTestPartner2', 'logoUri':'randomuri2.com', 'termOfServiceUri':'anotherrandomuri2.com', 'description':'Updated description: Genome database for the reference plant Arabidopsis thaliana', diff --git a/party/tests.py b/party/tests.py index 50c8fec9..29ab1903 100644 --- a/party/tests.py +++ b/party/tests.py @@ -9,7 +9,7 @@ from partner.testSamples import PartnerSample from subscription.testSamples import SubscriptionSample from authentication.testSamples import CredentialSample -from common.tests import TestGenericInterfaces, GenericGETOnlyTest, GenericCRUDTest, LoginRequiredGETOnlyTest, LoginRequiredCRUDTest, LoginRequiredTest, ManualTest, checkMatch +from common.tests import TestGenericInterfaces, GenericGETOnlyTest, GenericCRUDTest, LoginRequiredGETOnlyTest, LoginRequiredCRUDTest, LoginRequiredTest, ManualTest, checkMatch, checkMatchDB from http.cookies import SimpleCookie django.setup() @@ -243,9 +243,11 @@ def composeConsortiumPostData(self, consortiumSampleData, consortiumCredentialSa def assertConsortiumItem(self, consortiumSampleData, consortiumCredentialSampleData, consortiumCredentialSample, resObj, pkName, pk): self.assertEqual(checkMatch(consortiumSampleData, resObj[0], pkName, pk), True) + self.assertEqual(checkMatchDB(consortiumSampleData, self.sample.model, pkName, pk), True) # manipulate sample data to match the test condition consortiumCredentialSampleData['password'] = consortiumCredentialSample.hashPassword(consortiumCredentialSampleData['password']) self.assertEqual(checkMatch(consortiumCredentialSampleData, resObj[1], pkName, pk), True) + self.assertEqual(checkMatchDB(consortiumCredentialSampleData, consortiumCredentialSample.model, pkName, pk), True) # test for API end point /parties/institutions/ # returns organization info and associated credential info @@ -371,9 +373,12 @@ def composeInstitutionPostData(self, institutionSampleData, institutionCredentia def assertInstitutionItem(self, institutionSampleData, institutionCredentialSampleData, institutionCredentialSample, resObj, pkName, pk): self.assertEqual(checkMatch(institutionSampleData, resObj[0], pkName, pk), True) + self.assertEqual(checkMatchDB(institutionSampleData, self.sample.model, pkName, pk), True) + # manipulate sample data to match the test condition institutionCredentialSampleData['password'] = institutionCredentialSample.hashPassword(institutionCredentialSampleData['password']) self.assertEqual(checkMatch(institutionCredentialSampleData, resObj[1], pkName, pk), True) + self.assertEqual(checkMatchDB(institutionCredentialSampleData, institutionCredentialSample.model, pkName, pk), True) # test for end point /parties/affiliations/ # get_all and update methods unavailable, all available methods need to be override @@ -561,9 +566,10 @@ def test_for_list(self): # test for API end point /parties/usage/ # test in manualTests.py -class GetUsageRequestTest(ManualTest, TestCase): - path = "/parties/usage/" - testMethodStr = "running ./manage.py test party.manualTests (the UI invocation from librarians is not public yet)" +# deprecated and replaced by POL functions +# class GetUsageRequestTest(ManualTest, TestCase): +# path = "/parties/usage/" +# testMethodStr = "running ./manage.py test party.manualTests (the UI invocation from librarians is not public yet)" # test for API end point /parties/consortiuminstitutions/{consortiumId} # this endpoint is not working diff --git a/subscription/tests.py b/subscription/tests.py index 76c7b4e0..2053203d 100644 --- a/subscription/tests.py +++ b/subscription/tests.py @@ -11,7 +11,7 @@ from party.testSamples import UserPartySample, CountrySample, OrganizationPartySample, IpRangeSample, ConsortiumPartySample, InstitutionPartySample, PartyAffiliationSample, ImageInfoSample from partner.testSamples import PartnerSample, SubscriptionTermSample from authentication.testSamples import CredentialSample -from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest, LoginRequiredTest, ManualTest, checkMatch +from common.tests import TestGenericInterfaces, GenericCRUDTest, GenericTest, LoginRequiredTest, ManualTest, checkMatch, checkMatchDB from rest_framework import status from .controls import PaymentControl from http.cookies import SimpleCookie @@ -54,7 +54,7 @@ def test_for_create(self): res = self.client.post(url, sample.data) self.assertEqual(res.status_code, status.HTTP_201_CREATED) resObj = json.loads(res.content) - self.assertIsNotNone(TestGenericInterfaces.forceGet(sample.model,sample.pkName,resObj[sample.pkName])) + self.assertEqual(checkMatchDB(sample.data, sample.model,sample.pkName,resObj[sample.pkName]), True) transactionId = resObj['subscriptionTransactionId'] self.assertIsNotNone(TestGenericInterfaces.forceGet(SubscriptionTransaction,'subscriptionTransactionId',transactionId)) @@ -146,6 +146,7 @@ def test_for_update(self): self.assertEqual(res.status_code, 200) self.assertEqual(checkMatch(sample.updateData, json.loads(res.content), sample.pkName, pk), True) + self.assertEqual(checkMatchDB(sample.updateData, sample.model, sample.pkName, pk), True) # can only delete by party id def test_for_delete(self): @@ -307,6 +308,7 @@ def test_for_update(self): self.assertEqual(res.status_code, 200) self.assertEqual(checkMatch(sample.updateData, json.loads(res.content), sample.pkName, subscriptionId), True) + self.assertEqual(checkMatchDB(sample.updateData, sample.model, sample.pkName, subscriptionId), True) transactionId = json.loads(res.content)['subscriptionTransactionId'] self.assertIsNotNone(TestGenericInterfaces.forceGet(SubscriptionTransaction,'subscriptionTransactionId',transactionId)) From f828edc250153ba239eec12d9e81f1285b3c0766 Mon Sep 17 00:00:00 2001 From: Kun Xiao Date: Thu, 18 Aug 2022 14:24:42 -0400 Subject: [PATCH 14/19] PWL-477: Added test cases for institution PUT request in party --- authentication/testSamples.py | 27 ++++++- party/testSamples.py | 7 ++ party/tests.py | 135 ++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 3 deletions(-) diff --git a/authentication/testSamples.py b/authentication/testSamples.py index 444f5ec4..3b8c6429 100644 --- a/authentication/testSamples.py +++ b/authentication/testSamples.py @@ -26,7 +26,7 @@ class CredentialSample(): data = { 'username': USERNAME, 'firstName': FIRSTNAME, - 'lastName': LASTNAME, + 'lastName': 1234567890, 'password': PASSWORD, 'email': EMAIL, 'institution': INSTITUTION, @@ -40,7 +40,28 @@ class CredentialSample(): 'lastName': LASTNAME + '_update', 'password': PASSWORD_UPDATE, 'email': EMAIL_UPDATE, - 'institution': INSTITUTION + ' Update', + 'institution': INSTITUTION + ' Update', + 'partyId': None, + 'partnerId': None, + 'userIdentifier': USER_IDENTIFIER_UPDATE + } + updateData_no_pwd = { + 'username': USERNAME + '_update', + 'firstName': FIRSTNAME + '_update', + 'lastName': LASTNAME + '_update', + 'email': EMAIL_UPDATE, + 'institution': INSTITUTION + ' Update', + 'partyId': None, + 'partnerId': None, + 'userIdentifier': USER_IDENTIFIER_UPDATE + } + updateData_invalid = { + 'username': USERNAME + '_update', + 'firstName': True, + 'lastName': LASTNAME + '_update', + 'password': PASSWORD_UPDATE, + 'email': EMAIL_UPDATE, + 'institution': INSTITUTION + ' Update', 'partyId': None, 'partnerId': None, 'userIdentifier': USER_IDENTIFIER_UPDATE @@ -104,4 +125,4 @@ def getLoginData(self): def getSecretKey(self): # this has dependency on authentication.views regarding argument - return Credential.generateSecretKey(self.data['partyId'], self.hashPassword(self.data['password'])) \ No newline at end of file + return Credential.generateSecretKey(self.data['partyId'], self.hashPassword(self.data['password'])) diff --git a/party/testSamples.py b/party/testSamples.py index 7c1f5141..9856bfb1 100644 --- a/party/testSamples.py +++ b/party/testSamples.py @@ -113,6 +113,13 @@ class ConsortiumPartySample(): 'country': None, 'label': 'Test Consortium Label II' } + updateData_invalid = { + 'partyType':PARTY_TYPE_CONSORTIUM, + 'name': True, + 'display': False, + 'country': None, + 'label': 'Test Consortium Label III' + } pkName = 'partyId' model = Party diff --git a/party/tests.py b/party/tests.py index 29ab1903..fc3809b7 100644 --- a/party/tests.py +++ b/party/tests.py @@ -176,6 +176,141 @@ def test_for_get(self): resObj = json.loads(res.content) self.assertEqual(resObj[0]['hasIpRange'], True) + # testcase 5 : throw error & does not save when credential serializer failed + def test_for_put_case5(self): + # create new consortium party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # initialize data from credentialSample + consortiumCredentialSample = CredentialSample(serverUrl) + consortiumCredentialSample.updateData_invalid['partnerId'] = self.partnerId + consortiumCredentialSample.data['partnerId'] = self.partnerId + consortiumCredentialSample.data['partyId'] = pk + consortiumCredentialSample.updateData_invalid['partyId'] = pk + + # construct credential on Database + consortiumCredentialSample.forcePost(consortiumCredentialSample.data) + + # combine two updateData from partySample and CredentialSample into one data "putData" + putData = self.composeConsortiumPostData(sample.updateData, consortiumCredentialSample.updateData_invalid) + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test pushing successfully into the database + self.assertEqual(res.status_code, 400) + # test data from party on Database == sample.data + self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) + + # hashing the password and test data from credential on Database == consortiumCredentialSample.data + consortiumCredentialSample.data['password'] = consortiumCredentialSample.hashPassword(consortiumCredentialSample.data['password']) + self.assertEqual(checkMatchDB(consortiumCredentialSample.data, consortiumCredentialSample.model, sample.pkName, pk), True) + + # testcase 4 : throw error & does not save when party serializer failed + def test_for_put_case4(self): + # create new consortium party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # initialize data from credentialSample + consortiumCredentialSample = CredentialSample(serverUrl) + consortiumCredentialSample.updateData['partnerId'] = self.partnerId + consortiumCredentialSample.data['partnerId'] = self.partnerId + consortiumCredentialSample.data['partyId'] = pk + consortiumCredentialSample.updateData['partyId'] = pk + + # construct credential on Database + consortiumCredentialSample.forcePost(consortiumCredentialSample.data) + + # combine two updateData from partySample and CredentialSample into one data "putData" + putData = self.composeConsortiumPostData(sample.updateData_invalid, consortiumCredentialSample.updateData) + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test pushing successfully into the database + self.assertEqual(res.status_code, 400) + # test data from party on Database == sample.data + self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) + + # hashing the password and test data from credential on Database == consortiumCredentialSample.data + consortiumCredentialSample.data['password'] = consortiumCredentialSample.hashPassword(consortiumCredentialSample.data['password']) + self.assertEqual(checkMatchDB(consortiumCredentialSample.data, consortiumCredentialSample.model, sample.pkName, pk), True) + + # testcase 3: update party only + def case3(self): + # create new consortium party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # set putData to exclude update data from credential + putData = copy.deepcopy(sample.updateData) + putData['partyId'] = pk + + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test pushing successfully into the database + self.assertEqual(res.status_code, 200) + # test party data and credential data from the database = party sample's updateData and credential sample's updateData + self.assertEqual(checkMatchDB(sample.updateData, sample.model, sample.pkName, pk), True) + + # testcase 2: throw error if credential not exist & username/pwd not exist + def test_for_put_case2(self): + # create new consortium party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # initialize data from credentialSample + consortiumCredentialSample = CredentialSample(serverUrl) + consortiumCredentialSample.updateData_no_pwd['partnerId'] = self.partnerId + consortiumCredentialSample.updateData_no_pwd['partyId'] = pk + + # combine two updateData from partySample and CredentialSample into one data "putData" + putData = self.composeConsortiumPostData(sample.updateData, consortiumCredentialSample.updateData_no_pwd) + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test pushing successfully into the database + self.assertEqual(res.status_code, 400) + # test party data and credential data from the database = party sample's updateData and credential sample's updateData + self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) + # test credential does not exist + self.assertEqual(checkMatchDB(None, consortiumCredentialSample.model, sample.pkName, pk), False) + + # testcase 1: create credential when no exist + def test_for_put_case1(self): + # create new consortium party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # initialize data from credentialSample + consortiumCredentialSample = CredentialSample(serverUrl) + consortiumCredentialSample.updateData['partnerId'] = self.partnerId + consortiumCredentialSample.data['partyId'] = pk + consortiumCredentialSample.updateData['partyId'] = pk + + # combine two updateData from partySample and CredentialSample into one data "putData" + putData = self.composeConsortiumPostData(sample.updateData, consortiumCredentialSample.updateData) + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test pushing successfully into the database + self.assertEqual(res.status_code, 200) + # test if party data and credential data from the database = party sample's updateData and credential sample's updateData + self.assertEqual(checkMatchDB(sample.updateData, sample.model, sample.pkName, pk), True) + + consortiumCredentialSample.updateData['password'] = consortiumCredentialSample.hashPassword(consortiumCredentialSample.updateData['password']) + self.assertEqual(checkMatchDB(consortiumCredentialSample.updateData, consortiumCredentialSample.model, sample.pkName, pk), True) def test_for_get_all(self): pass From 0637a58947727ed04e6e48d4d040d984ed1ef9d6 Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Wed, 10 Aug 2022 19:24:05 -0700 Subject: [PATCH 15/19] Fix Python 3 dependencies error. --- dependencies.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.list b/dependencies.list index f1217801..366ef5d4 100644 --- a/dependencies.list +++ b/dependencies.list @@ -11,4 +11,4 @@ sqlparse==0.3.1 pandas==0.24.2 xlsxwriter==2.0.0 xlrd==2.0.1 -pycrypto==2.6.1 \ No newline at end of file +pycryptodome==3.15.0 From 1865fde06e839d8dc154cafe2654b0ed95c7fd2c Mon Sep 17 00:00:00 2001 From: Kun Xiao Date: Fri, 19 Aug 2022 13:31:27 -0400 Subject: [PATCH 16/19] PWL-477: add test cases for update consortium profile --- authentication/testSamples.py | 2 +- common/tests.py | 2 + party/testSamples.py | 7 ++ party/tests.py | 159 +++++++++++++++++++++++++++++++--- 4 files changed, 158 insertions(+), 12 deletions(-) diff --git a/authentication/testSamples.py b/authentication/testSamples.py index 3b8c6429..c85eeecd 100644 --- a/authentication/testSamples.py +++ b/authentication/testSamples.py @@ -26,7 +26,7 @@ class CredentialSample(): data = { 'username': USERNAME, 'firstName': FIRSTNAME, - 'lastName': 1234567890, + 'lastName': LASTNAME, 'password': PASSWORD, 'email': EMAIL, 'institution': INSTITUTION, diff --git a/common/tests.py b/common/tests.py index e435d7e6..57e3e204 100644 --- a/common/tests.py +++ b/common/tests.py @@ -114,6 +114,8 @@ def checkMatch(sampleData, retrievedData, pkName, pk): def checkMatchDB(sampleData, model, pkName, pk): dbRecord = TestGenericInterfaces.forceGet(model, pkName, pk) if not dbRecord: + if not sampleData: + return True print("\nERROR: cannot find database record %s with %s = %s" % (model, pkName, pk)) return False hasMatch = True diff --git a/party/testSamples.py b/party/testSamples.py index 9856bfb1..cf30f37c 100644 --- a/party/testSamples.py +++ b/party/testSamples.py @@ -72,6 +72,13 @@ class OrganizationPartySample(): 'country': None, 'label': 'Test Organization Label II' } + updateData_invalid = { + 'partyType':PARTY_TYPE_ORG, + 'name': True, + 'display': False, + 'country': None, + 'label': 'Test Consortium Label III' + } pkName = 'partyId' model = Party diff --git a/party/tests.py b/party/tests.py index fc3809b7..79b56adc 100644 --- a/party/tests.py +++ b/party/tests.py @@ -192,14 +192,14 @@ def test_for_put_case5(self): # construct credential on Database consortiumCredentialSample.forcePost(consortiumCredentialSample.data) - # combine two updateData from partySample and CredentialSample into one data "putData" + # combine updateData from partySample and invalid updateData from CredentialSample into one data "putData" putData = self.composeConsortiumPostData(sample.updateData, consortiumCredentialSample.updateData_invalid) url = self.getUrl(sample.url, sample.pkName, pk) # pushing putData into Database res = self.client.put(url, json.dumps(putData), content_type='application/json') - # test pushing successfully into the database + # test failing to push into the database self.assertEqual(res.status_code, 400) # test data from party on Database == sample.data self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) @@ -224,14 +224,14 @@ def test_for_put_case4(self): # construct credential on Database consortiumCredentialSample.forcePost(consortiumCredentialSample.data) - # combine two updateData from partySample and CredentialSample into one data "putData" + # combine invalid updateData from partySample and updateData from CredentialSample into one data "putData" putData = self.composeConsortiumPostData(sample.updateData_invalid, consortiumCredentialSample.updateData) url = self.getUrl(sample.url, sample.pkName, pk) # pushing putData into Database res = self.client.put(url, json.dumps(putData), content_type='application/json') - # test pushing successfully into the database + # test failing to push into the database self.assertEqual(res.status_code, 400) # test data from party on Database == sample.data self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) @@ -241,7 +241,7 @@ def test_for_put_case4(self): self.assertEqual(checkMatchDB(consortiumCredentialSample.data, consortiumCredentialSample.model, sample.pkName, pk), True) # testcase 3: update party only - def case3(self): + def test_for_put_case3(self): # create new consortium party and get partyId "pk" sample = self.sample pk = sample.forcePost(sample.data) @@ -257,7 +257,7 @@ def case3(self): # test pushing successfully into the database self.assertEqual(res.status_code, 200) - # test party data and credential data from the database = party sample's updateData and credential sample's updateData + # test party data from the database = party sample's updateData self.assertEqual(checkMatchDB(sample.updateData, sample.model, sample.pkName, pk), True) # testcase 2: throw error if credential not exist & username/pwd not exist @@ -271,19 +271,19 @@ def test_for_put_case2(self): consortiumCredentialSample.updateData_no_pwd['partnerId'] = self.partnerId consortiumCredentialSample.updateData_no_pwd['partyId'] = pk - # combine two updateData from partySample and CredentialSample into one data "putData" + # combine updateData from partySample and updateData w/o pwd from CredentialSample into one data "putData" putData = self.composeConsortiumPostData(sample.updateData, consortiumCredentialSample.updateData_no_pwd) url = self.getUrl(sample.url, sample.pkName, pk) # pushing putData into Database res = self.client.put(url, json.dumps(putData), content_type='application/json') - # test pushing successfully into the database + # test failing to push into the database self.assertEqual(res.status_code, 400) - # test party data and credential data from the database = party sample's updateData and credential sample's updateData + # test party data from the database = party sample's data self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) # test credential does not exist - self.assertEqual(checkMatchDB(None, consortiumCredentialSample.model, sample.pkName, pk), False) + self.assertEqual(checkMatchDB(None, consortiumCredentialSample.model, sample.pkName, pk), True) # testcase 1: create credential when no exist def test_for_put_case1(self): @@ -306,9 +306,10 @@ def test_for_put_case1(self): # test pushing successfully into the database self.assertEqual(res.status_code, 200) - # test if party data and credential data from the database = party sample's updateData and credential sample's updateData + # test if party data from the database = party sample's updateData self.assertEqual(checkMatchDB(sample.updateData, sample.model, sample.pkName, pk), True) + # hashing the password and test data from credential on Database == consortiumCredentialSample.updateData consortiumCredentialSample.updateData['password'] = consortiumCredentialSample.hashPassword(consortiumCredentialSample.updateData['password']) self.assertEqual(checkMatchDB(consortiumCredentialSample.updateData, consortiumCredentialSample.model, sample.pkName, pk), True) @@ -436,6 +437,142 @@ def test_for_get(self): resObj = json.loads(res.content) self.assertEqual(resObj[0]['hasIpRange'], True) + # testcase 5 : throw error & does not save when credential serializer failed + def test_for_put_case5(self): + # create new consortium party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # initialize data from credentialSample + institutionCredentialSample = CredentialSample(serverUrl) + institutionCredentialSample.updateData_invalid['partnerId'] = self.partnerId + institutionCredentialSample.data['partnerId'] = self.partnerId + institutionCredentialSample.data['partyId'] = pk + institutionCredentialSample.updateData_invalid['partyId'] = pk + + # construct credential on Database + institutionCredentialSample.forcePost(institutionCredentialSample.data) + + # combine updateData from partySample and invalid updateData from CredentialSample into one data "putData" + putData = self.composeInstitutionPostData(sample.updateData, institutionCredentialSample.updateData_invalid) + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test failing to push into the database + self.assertEqual(res.status_code, 400) + # test data from party on Database == sample.data + self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) + + # hashing the password and test data from credential on Database == institutionCredentialSample.data + institutionCredentialSample.data['password'] = institutionCredentialSample.hashPassword(institutionCredentialSample.data['password']) + self.assertEqual(checkMatchDB(institutionCredentialSample.data, institutionCredentialSample.model, sample.pkName, pk), True) + + # testcase 4 : throw error & does not save when party serializer failed + def test_for_put_case4(self): + # create new consortium party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # initialize data from credentialSample + institutionCredentialSample = CredentialSample(serverUrl) + institutionCredentialSample.updateData['partnerId'] = self.partnerId + institutionCredentialSample.data['partnerId'] = self.partnerId + institutionCredentialSample.data['partyId'] = pk + institutionCredentialSample.updateData['partyId'] = pk + + # construct credential on Database + institutionCredentialSample.forcePost(institutionCredentialSample.data) + + # combine invalid updateData from partySample and updateData from CredentialSample into one data "putData" + putData = self.composeInstitutionPostData(sample.updateData_invalid, institutionCredentialSample.updateData) + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test failing to push into the database + self.assertEqual(res.status_code, 400) + # test data from party on Database == sample.data + self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) + + # hashing the password and test data from credential on Database == institutionCredentialSample.data + institutionCredentialSample.data['password'] = institutionCredentialSample.hashPassword(institutionCredentialSample.data['password']) + self.assertEqual(checkMatchDB(institutionCredentialSample.data, institutionCredentialSample.model, sample.pkName, pk), True) + + # testcase 3: update party only + def test_for_put_case3(self): + # create new consortium party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # set putData to exclude update data from credential + putData = copy.deepcopy(sample.updateData) + putData['partyId'] = pk + + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test pushing successfully into the database + self.assertEqual(res.status_code, 200) + # test party data from the database = party sample's updateData + self.assertEqual(checkMatchDB(sample.updateData, sample.model, sample.pkName, pk), True) + + # testcase 2: throw error if credential not exist & username/pwd not exist + def test_for_put_case2(self): + # create new consortium party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # initialize data from credentialSample + institutionCredentialSample = CredentialSample(serverUrl) + institutionCredentialSample.updateData_no_pwd['partnerId'] = self.partnerId + institutionCredentialSample.updateData_no_pwd['partyId'] = pk + + # combine updateData from partySample and updateData w/o pwd from CredentialSample into one data "putData" + putData = self.composeInstitutionPostData(sample.updateData, institutionCredentialSample.updateData_no_pwd) + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test failing to push into the database + self.assertEqual(res.status_code, 400) + # test party data from the database = party sample's data + self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) + # test credential does not exist + self.assertEqual(checkMatchDB(None, institutionCredentialSample.model, sample.pkName, pk), True) + + # testcase 1: create credential when no exist + def test_for_put_case1(self): + # create new consortium party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # initialize data from credentialSample + institutionCredentialSample = CredentialSample(serverUrl) + institutionCredentialSample.updateData['partnerId'] = self.partnerId + institutionCredentialSample.data['partyId'] = pk + institutionCredentialSample.updateData['partyId'] = pk + + # combine two updateData from partySample and CredentialSample into one data "putData" + putData = self.composeInstitutionPostData(sample.updateData, institutionCredentialSample.updateData) + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test pushing successfully into the database + self.assertEqual(res.status_code, 200) + # test if party data from the database = party sample's updateData + self.assertEqual(checkMatchDB(sample.updateData, sample.model, sample.pkName, pk), True) + + # hashing the password and test data from credential on Database == institutionCredentialSample.updateData + institutionCredentialSample.updateData['password'] = institutionCredentialSample.hashPassword(institutionCredentialSample.updateData['password']) + self.assertEqual(checkMatchDB(institutionCredentialSample.updateData, institutionCredentialSample.model, sample.pkName, pk), True) def test_for_get_all(self): pass From 95772b029838cbd51287ca2335b56dadc0011b4c Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Mon, 17 Oct 2022 15:25:24 -0700 Subject: [PATCH 17/19] Remove host configuration as host is not used for the Django Test Client. --- common/tests.py | 18 ++---------------- paywall2/settings.py.template.prod | 2 -- paywall2/settings.py.template.test | 2 -- 3 files changed, 2 insertions(+), 20 deletions(-) diff --git a/common/tests.py b/common/tests.py index 57e3e204..8d3fa76c 100644 --- a/common/tests.py +++ b/common/tests.py @@ -7,20 +7,12 @@ from partner.models import Partner from apikey.models import ApiKey from django.test import Client -from django.conf import settings from http.cookies import SimpleCookie class TestGenericInterfaces: @staticmethod def getHost(): - if TestGenericInterfaces.hasHost(): - return settings.HOSTNAME - # default connection to localhost - return "http://localhost/" - - @staticmethod - def hasHost(): - return hasattr(settings, 'HOSTNAME') + return "/" @staticmethod def forceGet(model, pkName, pk): @@ -257,10 +249,4 @@ def test_warning(self): (2) upgraded Django version or\n\ (3) updated module or setting params related to this end point\n\ Please make sure you test this end point by %s" % (self.path, self.testMethodStr)) - print("\n----------------------------------------------------------------------") - -if not TestGenericInterfaces.hasHost(): - print("WARNING: No HOSTNAME detected in settings.py.") - -print("Using server url %s" % TestGenericInterfaces.getHost()) - + print("\n----------------------------------------------------------------------") \ No newline at end of file diff --git a/paywall2/settings.py.template.prod b/paywall2/settings.py.template.prod index f53b9344..253e6750 100644 --- a/paywall2/settings.py.template.prod +++ b/paywall2/settings.py.template.prod @@ -29,8 +29,6 @@ STRIPE_PUBLIC_KEY = None # ACTION: Add Stripe production public key here STRIPE_PRIVATE_KEY = None # ACTION: Add Stripe production private key here -HOSTNAME = 'http://localhost:9000/' - # SECURITY WARNING: don't run with debug turned on in production! DEBUG = False diff --git a/paywall2/settings.py.template.test b/paywall2/settings.py.template.test index 871f8330..55a1122f 100644 --- a/paywall2/settings.py.template.test +++ b/paywall2/settings.py.template.test @@ -29,8 +29,6 @@ STRIPE_PUBLIC_KEY = 'pk_test_VEu0r74glZkzeT8IXLmXxojP' STRIPE_PRIVATE_KEY = 'sk_test_dXy85QkwH66s64bIWKbikyMt' -HOSTNAME = 'http://localhost:9000/' - # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True From a5b286e11ee28e14491f7ffd7b369eec890dabda Mon Sep 17 00:00:00 2001 From: ChenXingguo Date: Thu, 20 Oct 2022 15:37:05 -0700 Subject: [PATCH 18/19] Add generic test sample template to make the test class inheritance more consistent. --- common/testSamples.py | 16 ++++++++++++++++ common/tests.py | 3 ++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/common/testSamples.py b/common/testSamples.py index e2c59f5c..6fcad5c4 100644 --- a/common/testSamples.py +++ b/common/testSamples.py @@ -20,6 +20,22 @@ class CommonApiKeySample(): def forcePost(self,data): return forcePost(self.model, self.pkName, data) +# a template sample class for all the test case sample classes +class GenericSample(): + url = None + path = 'path' + data = { + 'key':'value' + } + pkName = '' + model = Party # just a placeholder, need to be the corresponding ClassName + + def __init__(self, serverUrl): + self.url = serverUrl+self.path + + def forcePost(self,data): + return forcePost(self.model, self.pkName, data) + class CommonPartnerSample(): url = None path = 'partners/' diff --git a/common/tests.py b/common/tests.py index 8d3fa76c..9d753c86 100644 --- a/common/tests.py +++ b/common/tests.py @@ -3,7 +3,7 @@ import pytz from datetime import datetime import urllib.request, urllib.parse, urllib.error -from .testSamples import CommonApiKeySample, CommonPartnerSample, CommonUserPartySample, CommonCredentialSample +from .testSamples import CommonApiKeySample, CommonPartnerSample, CommonUserPartySample, CommonCredentialSample, GenericSample from partner.models import Partner from apikey.models import ApiKey from django.test import Client @@ -187,6 +187,7 @@ def getAllHelper(self, url, commonKeyName = None, commonKeyValue = None): self.assertEqual(checkMatch(sample.data, json.loads(res.content), sample.pkName, pk), True) class GenericCRUDTest(GenericGETOnlyTest): + sample = GenericSample(serverUrl) # GET tests defined in GenericGETOnlyTest class From e8fe66dd27db953546d2eb739549b7afa655dc01 Mon Sep 17 00:00:00 2001 From: Kartik Khosa Date: Fri, 4 Nov 2022 17:08:45 -0400 Subject: [PATCH 19/19] PWL-751: require country field for institution PYTHON-V3 --- party/models.py | 21 ++++++++++++--- party/tests.py | 69 +++++++++++++++++++++++++++++++++++++------------ 2 files changed, 70 insertions(+), 20 deletions(-) diff --git a/party/models.py b/party/models.py index 9f3adcae..3063c0f0 100644 --- a/party/models.py +++ b/party/models.py @@ -6,6 +6,8 @@ from django.utils import timezone from common.common import validateIpRange import hashlib +from rest_framework import serializers +from django.utils.translation import ugettext_lazy as _ import logging logger = logging.getLogger('phoenix.api.party') @@ -24,6 +26,17 @@ class Party(models.Model): consortiums = models.ManyToManyField('self', through="PartyAffiliation", through_fields=('childPartyId', 'parentPartyId'), symmetrical=False, related_name="PartyAffiliation") label = models.CharField(max_length=64, null=True) + class Meta: + db_table = "Party" + + def clean(self, *args, **kwargs): + self.validateInstitutionCountry() + super(Party, self).clean(*args, **kwargs) + + def save(self, *args, **kwargs): + self.clean() + super(Party, self).save(*args, **kwargs) + @staticmethod def getByIp(ipAddress): partyList = [] @@ -48,8 +61,10 @@ def getById(partyId): def generatePasswordHash(password): return hashlib.sha1(password.encode()).hexdigest() - class Meta: - db_table = "Party" + def validateInstitutionCountry(self): + if self.partyType == 'organization': + if not self.country: + raise serializers.ValidationError({'Party': _('Country field is required')}) class PartyAffiliation(models.Model): partyAffiliationId = models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True) @@ -119,4 +134,4 @@ class ImageInfo(models.Model): createdAt = models.DateTimeField(default=timezone.now) class Meta: - db_table = "ImageInfo" \ No newline at end of file + db_table = "ImageInfo" diff --git a/party/tests.py b/party/tests.py index 79b56adc..c143092f 100644 --- a/party/tests.py +++ b/party/tests.py @@ -1,4 +1,4 @@ -#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. +#Copyright 2015 Phoenix Bioinformatics Corporation. All rights reserved. import django import unittest import sys @@ -27,7 +27,7 @@ def test_for_get_all(self): url = self.getUrl(self.sample.url, 'partyType', self.sample.PARTY_TYPE_USER) self.getAllHelper(url, 'partyId', self.credentialId) -# test for API end point /parties with party type organization +# test for API end point /parties with party type organization # TODO: test for party type consortium class OrganizationPartyCRUDTest(LoginRequiredCRUDTest, TestCase): sample = OrganizationPartySample(serverUrl) @@ -142,7 +142,7 @@ def setUp(self): countrySample = CountrySample(serverUrl) countryId = countrySample.forcePost(countrySample.data) - self.sample.data['country']=self.sample.updateData['country']=countryId + self.sample.data['country']=self.sample.updateData['country']=countryId partnerSample = PartnerSample(serverUrl) self.partnerId = partnerSample.forcePost(partnerSample.data) @@ -150,12 +150,12 @@ def setUp(self): def test_for_get(self): sample = self.sample - # note this should not override the parent credential sample used for login + # note this should not override the parent credential sample used for login # so use a different name consortiumCredentialSample = self.initForcePostConsortiumCredentialSample(serverUrl) pk = self.forcePostConsortiumItem(consortiumCredentialSample) - url = self.getUrl(sample.url, sample.pkName, pk) + url = self.getUrl(sample.url, sample.pkName, pk) res = self.client.get(url) self.assertEqual(res.status_code, 200) @@ -176,6 +176,7 @@ def test_for_get(self): resObj = json.loads(res.content) self.assertEqual(resObj[0]['hasIpRange'], True) + # testcase 5 : throw error & does not save when credential serializer failed def test_for_put_case5(self): # create new consortium party and get partyId "pk" @@ -387,7 +388,7 @@ def assertConsortiumItem(self, consortiumSampleData, consortiumCredentialSampleD # test for API end point /parties/institutions/ # returns organization info and associated credential info -# difference between this API and /parties API is this API will include +# difference between this API and /parties API is this API will include # affliated consortium info and credential info class InstitutionPartyCRUDTest(LoginRequiredCRUDTest, TestCase): sample = InstitutionPartySample(serverUrl) @@ -400,8 +401,8 @@ def setUp(self): countrySample = CountrySample(serverUrl) countryId = countrySample.forcePost(countrySample.data) - self.sample.data['country']=self.sample.updateData['country']=countryId - consortiumSample.data['country']=countryId + self.sample.data['country']=self.sample.updateData['country']=countryId + consortiumSample.data['country']=countryId partnerSample = PartnerSample(serverUrl) self.partnerId = partnerSample.forcePost(partnerSample.data) @@ -410,12 +411,12 @@ def setUp(self): def test_for_get(self): sample = self.sample - # note this should not override the parent credential sample used for login + # note this should not override the parent credential sample used for login # so use a different name institutionCredentialSample = self.initForcePostInstitutionCredentialSample(serverUrl) pk = self.forcePostInstitutionItem(institutionCredentialSample) - url = self.getUrl(sample.url, sample.pkName, pk) + url = self.getUrl(sample.url, sample.pkName, pk) res = self.client.get(url) self.assertEqual(res.status_code, 200) @@ -437,6 +438,26 @@ def test_for_get(self): resObj = json.loads(res.content) self.assertEqual(resObj[0]['hasIpRange'], True) + #update country to null and expect an error + def test_for_put_case6(self): + # create new institution party and get partyId "pk" + sample = self.sample + pk = sample.forcePost(sample.data) + + # set putData to exclude update data from credential + putData = copy.deepcopy(sample.updateData) + putData['country'] = None + url = self.getUrl(sample.url, sample.pkName, pk) + + # pushing putData into Database + res = self.client.put(url, json.dumps(putData), content_type='application/json') + + # test pushing successfully into the database + # need to check this + self.assertEqual(res.status_code, 400) + # test party data from the database = party sample's data + self.assertEqual(checkMatchDB(sample.data, sample.model, sample.pkName, pk), True) + # testcase 5 : throw error & does not save when credential serializer failed def test_for_put_case5(self): # create new consortium party and get partyId "pk" @@ -577,6 +598,20 @@ def test_for_put_case1(self): def test_for_get_all(self): pass + # Post test for creating a new consortium with no country + def test_for_post(self): + sample = self.sample + institutionCredentialSample = CredentialSample(serverUrl) + institutionCredentialSample.data['partnerId'] = self.partnerId + postData = self.composeInstitutionPostData(sample.data, institutionCredentialSample.data) + print(postData) + postData.pop('country',None) + print(postData) + url = self.getUrl(sample.url) + res = self.client.post(url, postData, content_type='application/json') + + self.assertEqual(res.status_code, 400) + # API end point requires to create consortium and its user together def test_for_create(self): sample = self.sample @@ -665,10 +700,10 @@ def setUp(self): countrySample = CountrySample(serverUrl) countryId = countrySample.forcePost(countrySample.data) - self.parentPartySample.data['country']=self.childPartySample.data['country']=countryId + self.parentPartySample.data['country']=self.childPartySample.data['country']=countryId - parentPartyId = self.parentPartySample.forcePost(self.parentPartySample.data) - childPartyId = self.childPartySample.forcePost(self.childPartySample.data) + parentPartyId = self.parentPartySample.forcePost(self.parentPartySample.data) + childPartyId = self.childPartySample.forcePost(self.childPartySample.data) self.sample.setParentId(parentPartyId) self.sample.setChildId(childPartyId) @@ -684,7 +719,7 @@ def test_for_get(self): childPartyType = self.childPartySample.getPartyType() # get by consortium (parent organization) - url = self.getUrl(sample.url) + url = self.getUrl(sample.url) url = '%s&partyId=%s&partyType=%s' % (url, parentPartyId, parentPartyType) res = self.client.get(url) @@ -695,7 +730,7 @@ def test_for_get(self): self.assertEqual(resObj[0]['consortiums'][0], parentPartyId) # get by institution (child organization) - url = self.getUrl(sample.url) + url = self.getUrl(sample.url) url = '%s&partyId=%s&partyType=%s' % (url, childPartyId, childPartyType) res = self.client.get(url) @@ -708,7 +743,7 @@ def test_for_create(self): parentPartyId = sample.getParentId() childPartyId = sample.getChildId() - url = self.getUrl(sample.url) + url = self.getUrl(sample.url) url = '%s&parentPartyId=%s&childPartyId=%s' % (url, parentPartyId, childPartyId) res = self.client.post(url, sample.data) @@ -728,7 +763,7 @@ def test_for_delete(self): parentPartyId = sample.getParentId() childPartyId = sample.getChildId() - url = self.getUrl(sample.url) + url = self.getUrl(sample.url) url = '%s&parentPartyId=%s&childPartyId=%s' % (url, parentPartyId, childPartyId) res = self.client.delete(url)