diff --git a/pirant/app.py b/pirant/app.py index 5e13f88..f9fe349 100644 --- a/pirant/app.py +++ b/pirant/app.py @@ -21,4 +21,12 @@ def get_weekly_rants(self, sort, skip): def search_rants_by_keyword(self, keyword): response = self.RequestHandler.search_rants_by_keyword(keyword) - return self.ResponseHandler.search_rants_by_keyword_build_response(response) \ No newline at end of file + return self.ResponseHandler.search_rants_by_keyword_build_response(response) + + def get_collabs(self, skip, limit): + response = self.RequestHandler.get_collabs(skip, limit) + return self.ResponseHandler.get_collabs_build_response(response) + + def get_collab_by_id(self, collab_id): + response = self.RequestHandler.get_rant_by_id(collab_id) + return self.ResponseHandler.get_rant_by_id_build_response(response) \ No newline at end of file diff --git a/pirant/handlers.py b/pirant/handlers.py index e1377e5..464e3aa 100644 --- a/pirant/handlers.py +++ b/pirant/handlers.py @@ -26,13 +26,18 @@ def search_rants_by_keyword_build_response(self, response): deserialized = self.SearchResponse.deserialize(json_string) return deserialized + def get_collabs_build_response(self, response): + json_string = json.loads(response.content) + deserialized = self.RantsResponse.deserialize(json_string) + return deserialized + class RequestHandler: def __init__(self): self.UrlBuilder = URLBuilder() def get_rants(self, sort, limit, skip): - url = self.UrlBuilder.get_rant_url(sort, limit, skip) + url = self.UrlBuilder.get_rants_url(sort, limit, skip) response = requests.get(url) return response @@ -49,4 +54,9 @@ def get_weekly_rants(self, sort, skip): def search_rants_by_keyword(self, keyword): url = self.UrlBuilder.search_rants_by_keywords(keyword) response = requests.get(url) + return response + + def get_collabs(self, skip, sort): + url = self.UrlBuilder.get_collabs_url(skip, sort) + response = requests.get(url) return response \ No newline at end of file diff --git a/pirant/models.py b/pirant/models.py index 6f07a96..7a30aec 100644 --- a/pirant/models.py +++ b/pirant/models.py @@ -40,13 +40,24 @@ class Rant(colander.MappingSchema): num_comments = colander.SchemaNode(colander.Int()) user_username = colander.SchemaNode(colander.String()) user_userscore = colander.SchemaNode(colander.Int(), missing=colander.drop) + edited = colander.SchemaNode(colander.Boolean(), missing=colander.drop) + + # The below attributes only exist for collabs + link = colander.SchemaNode(colander.String(), missing=colander.drop) + c_type = colander.SchemaNode(colander.Int(), missing=colander.drop) + c_type_long = colander.SchemaNode(colander.String(), missing=colander.drop) + c_description = colander.SchemaNode(colander.String(), missing=colander.drop) + c_tect_stack = colander.SchemaNode(colander.String(), missing=colander.drop) + c_team_size = colander.SchemaNode(colander.Int(), missing=colander.drop) + c_url = colander.SchemaNode(colander.String(), missing=colander.drop) + class Rants(colander.SequenceSchema): rant = Rant() class RantsResponse(colander.MappingSchema): rants = Rants() - news = News() + news = News(missing=colander.drop) success = colander.SchemaNode(colander.Boolean(), missing=colander.drop) error = colander.SchemaNode(colander.Boolean(), missing=colander.drop) settings = colander.SchemaNode(colander.String(), missing=colander.drop) diff --git a/pirant/urlbuilder.py b/pirant/urlbuilder.py index 68b5d37..956d0cb 100644 --- a/pirant/urlbuilder.py +++ b/pirant/urlbuilder.py @@ -1,24 +1,25 @@ class URLBuilder: def __init__(self): self.APP_VERSION = 3 - self.BASE_URL = "https://www.devrant.io/api" - self.RANTS_URL = "%s/devrant/rants?sort=%s&limit=%d&skip=%d&app=%d" - self.WEEKLY_RANTS_URL = "%s/devrant/weekly-rants?sort=%s&skip=%d&app=%d" - self.RANT_PATH = "%s/devrant/rants/%d?app=%d" - self.SEARCH_PATH = "%s/devrant/search?term=%s&app=%d" + self.BASE_URL = "https://www.devrant.io/api/devrant" + self.RANTS_URL = "%s/rants?sort=%s&limit=%d&skip=%d&app=%d" + self.WEEKLY_RANTS_URL = "%s/weekly-rants?sort=%s&skip=%d&app=%d" + self.RANT_URL = "%s/rants/%d?app=%d" + self.SEARCH_URL = "%s/search?term=%s&app=%d" + self.COLLABS_URL = "%s/collabs?app=%d&skip=%d&limit=%d" self.SORT_TOP = "top" self.SORT_ALGO = "algo" self.SORT_RECENT = "recent" self.VALID_SORTS = [self.SORT_ALGO, self.SORT_RECENT, self.SORT_TOP] - def get_rant_url(self, sort, limit, skip): + def get_rants_url(self, sort, limit, skip): sort = self.validate_sort_input(self, sort) limit = self.validate_int_input(limit) skip = self.validate_int_input(skip) return str(self.RANTS_URL % (self.BASE_URL, sort, limit, skip, self.APP_VERSION)) def get_rant_by_id_url(self, rant_id): - return str(self.RANT_PATH % (self.BASE_URL, rant_id, self.APP_VERSION)) + return str(self.RANT_URL % (self.BASE_URL, rant_id, self.APP_VERSION)) def get_weekly_rant_url(self, sort, skip): sort = self.validate_sort_input(self, sort) @@ -26,7 +27,12 @@ def get_weekly_rant_url(self, sort, skip): return str(self.WEEKLY_RANTS_URL % (self.BASE_URL, sort, skip, self.APP_VERSION)) def search_rants_by_keywords(self, keyword): - return str(self.SEARCH_PATH % (self.BASE_URL, keyword, self.APP_VERSION)) + return str(self.SEARCH_URL % (self.BASE_URL, keyword, self.APP_VERSION)) + + def get_collabs_url(self, skip, limit): + limit = self.validate_int_input(limit) + skip = self.validate_int_input(skip) + return str(self.COLLABS_URL % (self.BASE_URL, self.APP_VERSION, skip, limit)) @staticmethod def validate_sort_input(self, sort_type): diff --git a/samples/Demo.py b/samples/Demo.py index 1831883..d070aa8 100644 --- a/samples/Demo.py +++ b/samples/Demo.py @@ -26,4 +26,13 @@ searchResult = devrant.search_rants_by_keyword("devrant") print searchResult['results'][1]['text'] print searchResult['results'][1]['attached_image']['url'] -print searchResult['results'][1]['user_avatar']['i'] \ No newline at end of file +print searchResult['results'][1]['user_avatar']['i'] + +# Get Top 5 collabs +collabsResult = devrant.get_collabs(0, 5) +print collabsResult['rants'][0]['c_type_long'] + +# Get Collab and all its comments given Collab Id +collab= devrant.get_collab_by_id(913738) +print collab['rant']['c_description'] +print collab['comments'][0]['body'] \ No newline at end of file diff --git a/tests/test_app.py b/tests/test_app.py index d579326..87ba462 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -9,7 +9,7 @@ def setUp(self): self.devrant = DevRant() @patch('pirant.handlers.RequestHandler.get_rants') - def test_happyCaseGetRants(self, mock_get_rants_response): + def test_happy_case_get_rants(self, mock_get_rants_response): test_content = { 'rants': [{ 'id': 1234, @@ -41,7 +41,7 @@ def test_happyCaseGetRants(self, mock_get_rants_response): self.assertEqual(rants['rants'][0]['text'], 'Txt') @patch('pirant.handlers.RequestHandler.get_rant_by_id') - def test_happyCaseGetRantById(self, mock_get_rant_by_id_response): + def test_happy_case_get_rant_by_id(self, mock_get_rant_by_id_response): test_content = { 'rant': { 'id': 1234, @@ -175,11 +175,82 @@ def test_happy_case_search_rants_by_keyword(self, mock_search_rants_by_keyword_r test_content = json.dumps(test_content) test_status_code = 200 test_keyword = "test" - mock_reponse = MockHttpResponse(test_content, test_status_code) - mock_search_rants_by_keyword_response.return_value = mock_reponse + mock_response = MockHttpResponse(test_content, test_status_code) + mock_search_rants_by_keyword_response.return_value = mock_response searchResults = self.devrant.search_rants_by_keyword(test_keyword) self.assertTrue(mock_search_rants_by_keyword_response.called) assert searchResults['success'] == True + @patch('pirant.handlers.RequestHandler.get_collabs') + def test_happy_case_get_collabs(self, mock_get_collabs_response): + test_content = { + "success": True, + "rants": [{ + "id": 1, + "text": "Test text", + "score": 5, + "created_time": 1507872, + "attached_image": "", + "num_comments": 3, + "tags": [], + "vote_state": 0, + "edited": False, + "link": "collabs\/1\/test", + "rt": 2, + "rc": 2, + "c_type": 3, + "c_type_long": "Project idea", + "user_id": 3321, + "user_username": "test", + "user_score": 14, + "user_avatar": { + "b": "2awsd", + "i": "v-17_c-3_b-4_g-m_9-1_1-9-9_6-3_10-1_2-10_15-11_4-1.jpg" + } + }] + } + test_content = json.dumps(test_content) + test_status_code = 200 + mock_response = MockHttpResponse(test_content, test_status_code) + mock_get_collabs_response.return_value = mock_response + collabs = self.devrant.get_collabs(0,1) + self.assertTrue(mock_get_collabs_response.called) + assert collabs['rants'][0]['id'] == 1 + + @patch('pirant.handlers.RequestHandler.get_rant_by_id') + def test_happy_case_get_collab_by_id(self, mock_get_rant_by_id_response): + test_content = { + 'rant': { + 'id': 1234, + 'text': 'Txt', + 'score': 111, + 'created_time': 234432, + 'user_id': 43289, + 'num_comments': 121, + 'user_username': 'user' + }, + 'comments': [{ + 'id': 1234, + 'rant_id': 2345, + 'body': 'test body', + 'upvotes': 2, + 'downvotes': 1, + 'score': 10, + 'created_time': 20102313123, + 'user_id': 111, + 'user_username': 'testUser', + 'user_userscore': 56 + }], + 'success': True + } + test_content = json.dumps(test_content) + test_status_code = 200 + mock_response = MockHttpResponse(test_content, test_status_code) + mock_get_rant_by_id_response.return_value = mock_response + rant = self.devrant.get_collab_by_id(2) + self.assertTrue(mock_get_rant_by_id_response.called) + assert rant['rant']['id'] == 1234 + assert rant['comments'][0]['upvotes'] == 2 + if __name__ == '__main__': unittest.main() diff --git a/tests/test_handlers.py b/tests/test_handlers.py index a405e40..13050ae 100644 --- a/tests/test_handlers.py +++ b/tests/test_handlers.py @@ -13,7 +13,7 @@ def setUp(self): self.requestHandler = RequestHandler() @patch('pirant.handlers.requests.get') - def test_successfulGetRantsResponse(self, mock_success_get_rants_request): + def test_successful_get_rants_response(self, mock_success_get_rants_request): sortType = "top" limit = 1 skip = 0 @@ -25,7 +25,7 @@ def test_successfulGetRantsResponse(self, mock_success_get_rants_request): self.assertEqual(testJSONResponse, response.json()) @patch('pirant.handlers.requests.get') - def test_successfulGetRantByIdResponse(self, mock_success_get_rant_by_id_request): + def test_successful_get_rant_by_id_response(self, mock_success_get_rant_by_id_request): rantId = 1 testJSONResponse = "{\"rant\": {\"id\": 1234,\"text\": \"Txt\",\"score\": 111,\"created_time\": 234432,\"user_id\": 43289,\"num_comments\": 121,\"user_username\": \"user\"},\"comments\": [{\"id\": 1234,\"rant_id\": 2345,\"body\": \"test body\",\"upvotes\": 2,\"downvotes\": 1,\"score\": 10,\"created_time\": 20102313123,\"user_id\": 111,\"user_username\": \"testUser\",\"user_userscore\": 56}],\"success\": True}" mock_success_get_rant_by_id_request.return_value = Mock(ok=True) @@ -55,6 +55,17 @@ def test_successful_search_rants_by_keyword(self, mock_success_search_rants_by_k self.assertTrue(mock_success_search_rants_by_keyword.called) self.assertEqual(test_json_response, response.json()) + @patch('pirant.handlers.requests.get') + def test_successful_get_collabs(self, mock_success_get_collabs): + test_skip = 0 + test_limit = 1 + test_json_response = "{\"success\":true,\"rants\":[{\"id\":435,\"text\":\"Test Text\",\"score\":5,\"created_time\":15072,\"attached_image\":\"\",\"num_comments\":3,\"tags\":[],\"vote_state\":0,\"edited\":false,\"link\":\"collabs\/913738\/sample-link\",\"rt\":2,\"rc\":2,\"c_type\":3,\"c_type_long\":\"Project idea\",\"user_id\":9856,\"user_username\":\"testuser\",\"user_score\":14,\"user_avatar\":{\"b\":\"b9d\",\"i\":\"v-10-1_2-10_15-11_4-1.jpg\"}}]}" + mock_success_get_collabs.return_value = Mock(ok=True) + mock_success_get_collabs.return_value.json.return_value = test_json_response + response = self.requestHandler.get_collabs(test_skip, test_limit) + self.assertTrue(mock_success_get_collabs.called) + self.assertEqual(test_json_response, response.json()) + class TestResponseHandler(unittest.TestCase): """ Unit tests for ResponseHandler class diff --git a/tests/test_urlbuilder.py b/tests/test_urlbuilder.py index 9c3c6d0..d64fd5c 100644 --- a/tests/test_urlbuilder.py +++ b/tests/test_urlbuilder.py @@ -11,25 +11,25 @@ def setUp(self): self.test_limit = 10 self.test_skip = 1 - def test_happy_case_get_rant_url(self): + def test_happy_case_get_rants_url(self): expected_url = "https://www.devrant.io/api/devrant/rants?sort=top&limit=10&skip=1&app=3" - obtained_url = self.url_builder.get_rant_url(self.test_sort, self.test_limit, self.test_skip) + obtained_url = self.url_builder.get_rants_url(self.test_sort, self.test_limit, self.test_skip) self.assertEqual(expected_url, obtained_url) - def test_empty_sort_type_get_rant_url(self): + def test_empty_sort_type_get_rants_url(self): test_devrant_url = "https://www.devrant.io/api/devrant/rants?sort=top&limit=10&skip=1&app=3" - devrant_url = self.url_builder.get_rant_url("", self.test_limit, self.test_skip) + devrant_url = self.url_builder.get_rants_url("", self.test_limit, self.test_skip) self.assertEqual(test_devrant_url, devrant_url) - def test_invalid_sort_type_get_rant_url(self): + def test_invalid_sort_type_get_rants_url(self): test_sort = "dummy_sort" with self.assertRaises(ValueError): - self.url_builder.get_rant_url(test_sort, self.test_limit, self.test_skip) + self.url_builder.get_rants_url(test_sort, self.test_limit, self.test_skip) - def test_invalid_limit_value_get_rant_url(self): + def test_invalid_limit_value_get_rants_url(self): test_limit = -1 with self.assertRaises(ValueError): - self.url_builder.get_rant_url(self.test_sort, test_limit, self.test_skip) + self.url_builder.get_rants_url(self.test_sort, test_limit, self.test_skip) def test_happy_case_get_rant_by_id_url(self): test_devrant_url = "https://www.devrant.io/api/devrant/rants/2?app=3" @@ -42,11 +42,25 @@ def test_id_must_be_int_get_rant_by_id_url(self): with self.assertRaises(TypeError): self.url_builder.get_rant_by_id_url(test_rant_id) - def test_idMustBeIntGetRantByIdUrl(self): + def test_id_must_b_int_get_rant_by_id_url(self): test_rant_id = '2' with self.assertRaises(TypeError): self.url_builder.get_rant_by_id_url(test_rant_id) + def test_happy_case_get_collabs_url(self): + expected_url = "https://www.devrant.io/api/devrant/collabs?app=3&skip=1&limit=10" + actual_url = self.url_builder.get_collabs_url(self.test_skip, self.test_limit) + self.assertEqual(expected_url, actual_url) + + def test_invalid_limit_value_get_collabs_url(self): + test_limit = -1 + with self.assertRaises(ValueError): + self.url_builder.get_collabs_url(self.test_skip, test_limit) + + def test_invalid_skip_value_get_collabs_url(self): + test_skip = -1 + with self.assertRaises(ValueError): + self.url_builder.get_collabs_url(test_skip, self.test_limit) if __name__ == '__main__': unittest.main()