From 930e6712e5df2459193fd76b571d71a1831d3226 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 18:10:09 +0300 Subject: [PATCH 01/54] Add create ride test module --- ridemyway/tests/test_create_ride.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 ridemyway/tests/test_create_ride.py diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py new file mode 100644 index 0000000..ad7b021 --- /dev/null +++ b/ridemyway/tests/test_create_ride.py @@ -0,0 +1,25 @@ +import unittest +import json +from ridemyway import create_app + + +class TestCreateRideAPIEndpoints(unittest.TestCase): + """ + Tests Create Ride API endpoint + - Ride: '/api/v1/rides' # POST + """ + + def setUp(self): + self.app = create_app(config_name='testing') + self.client = self.app.test_client + self.headers = {'content-type': 'application/json'} + self.context = self.app.app_context() + self.context.push() + + def tearDown(self): + self.context.pop() + + +# Just incase a testing library is not used! +if __name__ is "__main__": + unittest.main() From 38c7f30569e6455a4735d0fa2cdf524925ed9a01 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 18:31:46 +0300 Subject: [PATCH 02/54] [Chore #158592616] A ride is created successfully with valid data --- ridemyway/tests/test_create_ride.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index ad7b021..c5275a1 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -19,6 +19,20 @@ def setUp(self): def tearDown(self): self.context.pop() + def test_creates_a_ride_successfully_with_valid_data(self): + data = { + 'data': + [{'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3}]} + + self.response = self.client().post('/api/v1/rides', data=data) + result = json.loads(self.response.data.decode()) + self.assertEqual(result['message'], "Ride created successfully") + self.assertEqual(self.response.status_code, 201) + # Just incase a testing library is not used! if __name__ is "__main__": From 694b83874c97479494f2873293df63296a988183 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 19:32:35 +0300 Subject: [PATCH 03/54] [Chore #158592616] Test does not create a ride with invalid data --- ridemyway/tests/test_create_ride.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index c5275a1..b7c3d87 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -33,6 +33,20 @@ def test_creates_a_ride_successfully_with_valid_data(self): self.assertEqual(result['message'], "Ride created successfully") self.assertEqual(self.response.status_code, 201) + def test_does_not_create_ride_with_invalid_data(self): + data = { + 'data': + [{'departure': 'Not a date', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': '%^$', 'vehicle_number_plate': + 'KBC-A21', 'capacity': 'hundred'}]} + + self.response = self.client().post('/api/v1/rides', data=data) + result = json.loads(self.response.data.decode()) + self.assertEqual(result['message'], "Invalid data given") + self.assertEqual(self.response.status_code, 400) + # Just incase a testing library is not used! if __name__ is "__main__": From bb9a1ee78d13a3255d2594f278254ec6f87df8ef Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 19:42:31 +0300 Subject: [PATCH 04/54] [Finishes #158592616] Test enpoint for creating a ride --- ridemyway/tests/test_create_ride.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index b7c3d87..d0098c1 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -3,7 +3,7 @@ from ridemyway import create_app -class TestCreateRideAPIEndpoints(unittest.TestCase): +class TestCreateRideAPIEndpoint(unittest.TestCase): """ Tests Create Ride API endpoint - Ride: '/api/v1/rides' # POST From 9c0a6aa68f29e8690e45ab8925362795641b09ff Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 20:21:53 +0300 Subject: [PATCH 05/54] [Chore #158592619] Test fetches all rides successfully --- ridemyway/tests/test_fetch_rides.py | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 ridemyway/tests/test_fetch_rides.py diff --git a/ridemyway/tests/test_fetch_rides.py b/ridemyway/tests/test_fetch_rides.py new file mode 100644 index 0000000..ae77d89 --- /dev/null +++ b/ridemyway/tests/test_fetch_rides.py @@ -0,0 +1,52 @@ +import unittest +import json +from ridemyway import create_app + + +class TestFetchRideAPIEndpoint(unittest.TestCase): + """ + Tests Fetch Ride API endpoint + - Ride: '/api/v1/rides' # GET + - Ride: '/api/v1/rides/' # GET + """ + + def setUp(self): + self.app = create_app(config_name='testing') + self.client = self.app.test_client + self.headers = {'content-type': 'application/json'} + self.context = self.app.app_context() + self.context.push() + data = { + 'data': [ + {'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, + 'vehicle_number_plate': 'KBC-A21', + 'capacity': 3 + }, + {'departure': 'Jun 28 2018 7:00AM', + 'origin': 'Garissa', + 'destination': 'Nairobi', + 'cost': 500, + 'vehicle_number_plate': 'KBC-A21', + 'capacity': 3 + } + ] + } + + self.client().post('/api/v1/rides', data=data) + + def tearDown(self): + self.context.pop() + + def test_fetches_rides_successfully(self): + self.response = self.client().get('/api/v1/rides') + result = json.loads(self.response.data.decode()) + self.assertEqual(result['message'], 'Rides retrieved successfully') + self.assertEqual(self.response.status_code, 200) + + +# Just incase a testing library is not used! +if __name__ is "__main__": + unittest.main() From 4345900b987d1adde26b60e6c8a2516aeb5f714d Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 20:24:09 +0300 Subject: [PATCH 06/54] [Chore #158592679] Test fetches a single ride successfully --- ridemyway/tests/test_fetch_rides.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ridemyway/tests/test_fetch_rides.py b/ridemyway/tests/test_fetch_rides.py index ae77d89..a37fd59 100644 --- a/ridemyway/tests/test_fetch_rides.py +++ b/ridemyway/tests/test_fetch_rides.py @@ -46,6 +46,12 @@ def test_fetches_rides_successfully(self): self.assertEqual(result['message'], 'Rides retrieved successfully') self.assertEqual(self.response.status_code, 200) + def test_fetches_a_single_ride_with_valid_id(self): + self.response = self.client().post('/api/v1/rides/1') + result = json.loads(self.response.data.decode()) + self.assertEqual(result['message'], 'Ride retrieved successfully') + self.assertEqual(self.response.status_code, 200) + # Just incase a testing library is not used! if __name__ is "__main__": From de9878c4d8e613f9d683fe143b690bb04d0519e7 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 20:29:09 +0300 Subject: [PATCH 07/54] [Chore #158592679] Test does not fetch a ride that does not exist --- ridemyway/tests/test_fetch_rides.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ridemyway/tests/test_fetch_rides.py b/ridemyway/tests/test_fetch_rides.py index a37fd59..770b26d 100644 --- a/ridemyway/tests/test_fetch_rides.py +++ b/ridemyway/tests/test_fetch_rides.py @@ -52,6 +52,12 @@ def test_fetches_a_single_ride_with_valid_id(self): self.assertEqual(result['message'], 'Ride retrieved successfully') self.assertEqual(self.response.status_code, 200) + def test_does_not_retrieve_single_ride_that_does_not_exist(self): + self.response = self.client().post('/api/v1/rides/6454') + result = json.loads(self.response.data.decode()) + self.assertEqual(result['status'], 'failed') + self.assertEqual(self.response.status_code, 404) + # Just incase a testing library is not used! if __name__ is "__main__": From 0e11aa9aec319c06c1f6d90fa907948080b4a66b Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 20:36:02 +0300 Subject: [PATCH 08/54] [Chore #158592679] Test does not fetch the wrong ride --- ridemyway/tests/test_fetch_rides.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ridemyway/tests/test_fetch_rides.py b/ridemyway/tests/test_fetch_rides.py index 770b26d..dda0743 100644 --- a/ridemyway/tests/test_fetch_rides.py +++ b/ridemyway/tests/test_fetch_rides.py @@ -58,6 +58,11 @@ def test_does_not_retrieve_single_ride_that_does_not_exist(self): self.assertEqual(result['status'], 'failed') self.assertEqual(self.response.status_code, 404) + def test_does_not_fetch_wrong_ride(self): + self.response = self.client().get('/api/v1/rides/1') + result = json.loads(self.response.data.decode()) + self.assertEqual(result['data']['rideId'], 1) + # Just incase a testing library is not used! if __name__ is "__main__": From 7286448c65f28aaf9ec89479b5fa72e11374ef13 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 20:40:22 +0300 Subject: [PATCH 09/54] [Chore #158592679] Change post methods to get --- ridemyway/tests/test_fetch_rides.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ridemyway/tests/test_fetch_rides.py b/ridemyway/tests/test_fetch_rides.py index dda0743..9448a6e 100644 --- a/ridemyway/tests/test_fetch_rides.py +++ b/ridemyway/tests/test_fetch_rides.py @@ -47,13 +47,13 @@ def test_fetches_rides_successfully(self): self.assertEqual(self.response.status_code, 200) def test_fetches_a_single_ride_with_valid_id(self): - self.response = self.client().post('/api/v1/rides/1') + self.response = self.client().get('/api/v1/rides/1') result = json.loads(self.response.data.decode()) self.assertEqual(result['message'], 'Ride retrieved successfully') self.assertEqual(self.response.status_code, 200) - def test_does_not_retrieve_single_ride_that_does_not_exist(self): - self.response = self.client().post('/api/v1/rides/6454') + def test_does_not_fetch_single_ride_that_does_not_exist(self): + self.response = self.client().get('/api/v1/rides/6454') result = json.loads(self.response.data.decode()) self.assertEqual(result['status'], 'failed') self.assertEqual(self.response.status_code, 404) From 1fe414924a23668748aaae20b0588c16a0997e55 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 20:55:32 +0300 Subject: [PATCH 10/54] [Chore #158592730] Test ride request is created successfully on existing ride --- ridemyway/tests/test_ride_request.py | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 ridemyway/tests/test_ride_request.py diff --git a/ridemyway/tests/test_ride_request.py b/ridemyway/tests/test_ride_request.py new file mode 100644 index 0000000..e10ec4b --- /dev/null +++ b/ridemyway/tests/test_ride_request.py @@ -0,0 +1,51 @@ +import unittest +import json +from ridemyway import create_app + + +class TestCreateRideRequestAPIEndpoint(unittest.TestCase): + """ + Tests Create Ride Request API endpoint + - Ride: '/api/v1/rides//requests' # POST + """ + + def setUp(self): + self.app = create_app(config_name='testing') + self.client = self.app.test_client + self.headers = {'content-type': 'application/json'} + self.context = self.app.app_context() + self.context.push() + data = { + 'data': [ + {'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, + 'vehicle_number_plate': 'KBC-A21', + 'capacity': 3 + }, + {'departure': 'Jun 28 2018 7:00AM', + 'origin': 'Garissa', + 'destination': 'Nairobi', + 'cost': 500, + 'vehicle_number_plate': 'KBC-A21', + 'capacity': 3 + } + ] + } + + self.client().post('/api/v1/rides', data=data) + + def tearDown(self): + self.context.pop() + + def test_creates_a_ride_request_successfully_with_existing_ride(self): + self.response = self.client().post('/api/v1/rides/1/requests') + result = json.loads(self.response.data.decode()) + self.assertEqual(result['message'], 'Ride request created successfully') + self.assertEqual(self.response.status_code, 201) + + +# Just incase a testing library is not used! +if __name__ is "__main__": + unittest.main() From df97123cd448d6b7311fd2cb2739dd720e0fa6a9 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 20:56:13 +0300 Subject: [PATCH 11/54] [Chore #158592730] Test ride request is not created for a nonexistent ride --- ridemyway/tests/test_ride_request.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ridemyway/tests/test_ride_request.py b/ridemyway/tests/test_ride_request.py index e10ec4b..7ef3bf2 100644 --- a/ridemyway/tests/test_ride_request.py +++ b/ridemyway/tests/test_ride_request.py @@ -45,6 +45,12 @@ def test_creates_a_ride_request_successfully_with_existing_ride(self): self.assertEqual(result['message'], 'Ride request created successfully') self.assertEqual(self.response.status_code, 201) + def test_does_not_create_a_request_to_nonexistent_ride(self): + self.response = self.client().get('/api/v1/rides/6454') + result = json.loads(self.response.data.decode()) + self.assertEqual(result['status'], 'failed') + self.assertEqual(self.response.status_code, 404) + # Just incase a testing library is not used! if __name__ is "__main__": From 1890d99309e40af8467b04d9cf44d5101a7fd5f4 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 22:07:25 +0300 Subject: [PATCH 12/54] Rename endpoint test rename test_does_not_fetch_single_ride_that_does_not_exist to test_does_not_fetch_ride_that_does_not_exist --- ridemyway/tests/test_fetch_rides.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ridemyway/tests/test_fetch_rides.py b/ridemyway/tests/test_fetch_rides.py index 9448a6e..7e20e7b 100644 --- a/ridemyway/tests/test_fetch_rides.py +++ b/ridemyway/tests/test_fetch_rides.py @@ -52,7 +52,7 @@ def test_fetches_a_single_ride_with_valid_id(self): self.assertEqual(result['message'], 'Ride retrieved successfully') self.assertEqual(self.response.status_code, 200) - def test_does_not_fetch_single_ride_that_does_not_exist(self): + def test_does_not_fetch_ride_that_does_not_exist(self): self.response = self.client().get('/api/v1/rides/6454') result = json.loads(self.response.data.decode()) self.assertEqual(result['status'], 'failed') From d9915bc856a8abb434ead6783c230a8ef61311e7 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 22:29:52 +0300 Subject: [PATCH 13/54] Split test for invalid ride data into tests for each data point --- ridemyway/tests/test_create_ride.py | 44 ++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index d0098c1..cac401e 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -33,13 +33,41 @@ def test_creates_a_ride_successfully_with_valid_data(self): self.assertEqual(result['message'], "Ride created successfully") self.assertEqual(self.response.status_code, 201) - def test_does_not_create_ride_with_invalid_data(self): + def test_does_not_create_ride_with_invalid_date(self): data = { 'data': [{'departure': 'Not a date', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3}]} + + self.response = self.client().post('/api/v1/rides', data=data) + result = json.loads(self.response.data.decode()) + self.assertEqual(result['message'], "Invalid data given") + self.assertEqual(self.response.status_code, 400) + + def test_does_not_create_ride_with_invalid_cost(self): + data = { + 'data': + [{'departure': 'Jun 25 2018 1:30PM', 'origin': 'Nairobi', 'destination': 'Garissa', 'cost': '%^$', 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3}]} + + self.response = self.client().post('/api/v1/rides', data=data) + result = json.loads(self.response.data.decode()) + self.assertEqual(result['message'], "Invalid data given") + self.assertEqual(self.response.status_code, 400) + + def test_does_not_create_ride_with_invalid_capacity(self): + data = { + 'data': + [{'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': 'KBC-A21', 'capacity': 'hundred'}]} self.response = self.client().post('/api/v1/rides', data=data) @@ -47,6 +75,20 @@ def test_does_not_create_ride_with_invalid_data(self): self.assertEqual(result['message'], "Invalid data given") self.assertEqual(self.response.status_code, 400) + def test_does_not_create_ride_with_invalid_vehicle_number_plate(self): + data = { + 'data': + [{'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 2121, 'capacity': 3}]} + + self.response = self.client().post('/api/v1/rides', data=data) + result = json.loads(self.response.data.decode()) + self.assertEqual(result['message'], "Invalid data given") + self.assertEqual(self.response.status_code, 400) + # Just incase a testing library is not used! if __name__ is "__main__": From eb89728b47e03ebdd21ede0d05661c72c625e276 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 22:35:45 +0300 Subject: [PATCH 14/54] Check responses for specific error messages --- ridemyway/tests/test_create_ride.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index cac401e..6178488 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -44,7 +44,7 @@ def test_does_not_create_ride_with_invalid_date(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) - self.assertEqual(result['message'], "Invalid data given") + self.assertEqual(result['errors']['date'], "Invalid date given") self.assertEqual(self.response.status_code, 400) def test_does_not_create_ride_with_invalid_cost(self): @@ -58,7 +58,7 @@ def test_does_not_create_ride_with_invalid_cost(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) - self.assertEqual(result['message'], "Invalid data given") + self.assertEqual(result['errors']['cost'], "Invalid cost given") self.assertEqual(self.response.status_code, 400) def test_does_not_create_ride_with_invalid_capacity(self): @@ -72,7 +72,7 @@ def test_does_not_create_ride_with_invalid_capacity(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) - self.assertEqual(result['message'], "Invalid data given") + self.assertEqual(result['errors']['capacity'], "Invalid capacity given") self.assertEqual(self.response.status_code, 400) def test_does_not_create_ride_with_invalid_vehicle_number_plate(self): @@ -86,7 +86,7 @@ def test_does_not_create_ride_with_invalid_vehicle_number_plate(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) - self.assertEqual(result['message'], "Invalid data given") + self.assertEqual(result['errors']['vehicleNumberPlate'], "Invalid vehicle number plate given") self.assertEqual(self.response.status_code, 400) From 24f7595190ae51dba2a4dbb19678f25072b506d5 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 23:06:51 +0300 Subject: [PATCH 15/54] [Finishes #158592616] Add info messages to tests --- ridemyway/tests/test_create_ride.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index 6178488..c843243 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -30,7 +30,10 @@ def test_creates_a_ride_successfully_with_valid_data(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) - self.assertEqual(result['message'], "Ride created successfully") + self.assertEqual(result['message'], + 'Ride created successfully', + msg='Given the correct details,\ + the ride should be created successfully!') self.assertEqual(self.response.status_code, 201) def test_does_not_create_ride_with_invalid_date(self): @@ -44,7 +47,9 @@ def test_does_not_create_ride_with_invalid_date(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) - self.assertEqual(result['errors']['date'], "Invalid date given") + self.assertEqual(result['errors']['date'], + 'Invalid date given', + msg='Should only accept correctly formatted dates!') self.assertEqual(self.response.status_code, 400) def test_does_not_create_ride_with_invalid_cost(self): @@ -58,7 +63,9 @@ def test_does_not_create_ride_with_invalid_cost(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) - self.assertEqual(result['errors']['cost'], "Invalid cost given") + self.assertEqual(result['errors']['cost'], + 'Invalid cost given', + msg='The cost should be a number!') self.assertEqual(self.response.status_code, 400) def test_does_not_create_ride_with_invalid_capacity(self): @@ -72,7 +79,9 @@ def test_does_not_create_ride_with_invalid_capacity(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) - self.assertEqual(result['errors']['capacity'], "Invalid capacity given") + self.assertEqual(result['errors']['capacity'], + 'Invalid capacity given', + msg='Capacity should be a number!') self.assertEqual(self.response.status_code, 400) def test_does_not_create_ride_with_invalid_vehicle_number_plate(self): @@ -86,7 +95,9 @@ def test_does_not_create_ride_with_invalid_vehicle_number_plate(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) - self.assertEqual(result['errors']['vehicleNumberPlate'], "Invalid vehicle number plate given") + self.assertEqual(result['errors']['vehicleNumberPlate'], + 'Invalid vehicle number plate given', + msg='vehicle Number Plate should be a string!') self.assertEqual(self.response.status_code, 400) From cfd16f81e7a9d4c016485ff8414167bff50075b6 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 23:12:02 +0300 Subject: [PATCH 16/54] [Finishes #158592730] Add info messages to tests --- ridemyway/tests/test_ride_request.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ridemyway/tests/test_ride_request.py b/ridemyway/tests/test_ride_request.py index 7ef3bf2..24d442d 100644 --- a/ridemyway/tests/test_ride_request.py +++ b/ridemyway/tests/test_ride_request.py @@ -42,13 +42,17 @@ def tearDown(self): def test_creates_a_ride_request_successfully_with_existing_ride(self): self.response = self.client().post('/api/v1/rides/1/requests') result = json.loads(self.response.data.decode()) - self.assertEqual(result['message'], 'Ride request created successfully') + self.assertEqual(result['message'], + 'Ride request created successfully', + msg='Should successfully create a ride request\ + given an existing ride!') self.assertEqual(self.response.status_code, 201) def test_does_not_create_a_request_to_nonexistent_ride(self): self.response = self.client().get('/api/v1/rides/6454') result = json.loads(self.response.data.decode()) - self.assertEqual(result['status'], 'failed') + self.assertEqual(result['status'], 'failed', + msg='Should only accept requests for existing rides!') self.assertEqual(self.response.status_code, 404) From ce4abb568b5818a6122fc94f323610cc7d1c2b07 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Mon, 25 Jun 2018 23:16:06 +0300 Subject: [PATCH 17/54] Add info messages to tests [Finishes #158592619] [Finishes #158592679] --- ridemyway/tests/test_fetch_rides.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/ridemyway/tests/test_fetch_rides.py b/ridemyway/tests/test_fetch_rides.py index 7e20e7b..fc2cf55 100644 --- a/ridemyway/tests/test_fetch_rides.py +++ b/ridemyway/tests/test_fetch_rides.py @@ -43,25 +43,32 @@ def tearDown(self): def test_fetches_rides_successfully(self): self.response = self.client().get('/api/v1/rides') result = json.loads(self.response.data.decode()) - self.assertEqual(result['message'], 'Rides retrieved successfully') + self.assertEqual(result['message'], + 'Rides retrieved successfully', + msg='Should fetch rides successfully!') self.assertEqual(self.response.status_code, 200) def test_fetches_a_single_ride_with_valid_id(self): self.response = self.client().get('/api/v1/rides/1') result = json.loads(self.response.data.decode()) - self.assertEqual(result['message'], 'Ride retrieved successfully') + self.assertEqual(result['message'], + 'Ride retrieved successfully', + msg='Should fetch single ride given a valid ride id!') self.assertEqual(self.response.status_code, 200) def test_does_not_fetch_ride_that_does_not_exist(self): self.response = self.client().get('/api/v1/rides/6454') result = json.loads(self.response.data.decode()) - self.assertEqual(result['status'], 'failed') + self.assertEqual(result['status'], 'failed', + msg='Should only fetch existing rides!') self.assertEqual(self.response.status_code, 404) def test_does_not_fetch_wrong_ride(self): self.response = self.client().get('/api/v1/rides/1') result = json.loads(self.response.data.decode()) - self.assertEqual(result['data']['rideId'], 1) + self.assertEqual(result['data']['rideId'], 1, + msg='Should be able to fetch the correct ride\ + with the id given in the url!') # Just incase a testing library is not used! From 4b565ad1f75587746da1c6aa3a5fc6e723b2e0a2 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 01:32:20 +0300 Subject: [PATCH 18/54] Test should not create rides for passed dates --- ridemyway/tests/test_create_ride.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index c843243..0a00b01 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -52,6 +52,22 @@ def test_does_not_create_ride_with_invalid_date(self): msg='Should only accept correctly formatted dates!') self.assertEqual(self.response.status_code, 400) + def test_cannot_create_ride_with_passed_date(self): + data = { + 'data': + [{'departure': 'Jun 25 1901 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3}]} + + self.response = self.client().post('/api/v1/rides', data=data) + result = json.loads(self.response.data.decode()) + self.assertEqual(result['errors']['date'], + 'Invalid date given', + msg='Should only accept future dates!') + self.assertEqual(self.response.status_code, 400) + def test_does_not_create_ride_with_invalid_cost(self): data = { 'data': From 3ce0e835aa9ad4ea59a06753a24e75f7f51fbcf4 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 01:35:01 +0300 Subject: [PATCH 19/54] Update project dependencies --- requirements.txt | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/requirements.txt b/requirements.txt index a045776..f64a2f1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,26 +1,13 @@ -aniso8601==2.0.1 -attrs==17.4.0 -certifi==2018.1.18 -chardet==3.0.4 +aniso8601==3.0.2 click==6.7 -coverage==4.5.1 -coveralls==1.3.0 -docopt==0.6.2 -Flask==0.12.2 -Flask-JWT-Extended==3.7.1 +Flask==1.0.2 +Flask-JWT-Extended==3.10.0 Flask-RESTful==0.3.6 -gunicorn==19.7.1 -idna==2.6 +gunicorn==19.8.1 itsdangerous==0.24 Jinja2==2.10 MarkupSafe==1.0 -nose==1.3.7 -pluggy==0.6.0 -py==1.5.2 -PyJWT==1.6.0 -pytest==3.4.2 -pytz==2018.3 -requests==2.18.4 +PyJWT==1.6.4 +pytz==2018.4 six==1.11.0 -urllib3==1.22 Werkzeug==0.14.1 From da8b2213ce322788d109961bdaa10c060321aa61 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 02:26:00 +0300 Subject: [PATCH 20/54] Add run.py --- run.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 run.py diff --git a/run.py b/run.py new file mode 100644 index 0000000..0bbf143 --- /dev/null +++ b/run.py @@ -0,0 +1,8 @@ +from ridemyway import create_app + + +app = create_app('development') + + +if __name__ == "__main__": + app.run() From 7b3a45e8314a81436edc11bfc012f3dc956a391a Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 02:26:56 +0300 Subject: [PATCH 21/54] [Finishes #158607497] Setup flask-restful --- ridemyway/__init__.py | 15 ++++++++++++++- ridemyway/api/v1/routes.py | 5 +++++ ridemyway/resources.py | 17 +++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/ridemyway/__init__.py b/ridemyway/__init__.py index 445748f..25cdd6c 100644 --- a/ridemyway/__init__.py +++ b/ridemyway/__init__.py @@ -1,6 +1,7 @@ from flask import Flask from config import config from .api.v1.routes import v1 +from flask_jwt_extended import JWTManager # An in memory database @@ -40,6 +41,18 @@ def create_app(config_name): app = Flask(__name__) app.database = database app.config.from_object(config[config_name]) - + app.config['JWT_SECRET_KEY'] = 'super-secret' + app.config['JWT_BLACKLIST_ENABLED'] = True + app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh'] + app.jwt = JWTManager(app) + app.blacklist = set() + + @app.jwt.token_in_blacklist_loader + def check_if_token_in_blacklist(decrypted_token): + jti = decrypted_token['jti'] + return jti in app.blacklist + + # Register Blueprint here app.register_blueprint(v1, url_prefix="/api/v1") + return app diff --git a/ridemyway/api/v1/routes.py b/ridemyway/api/v1/routes.py index 11311df..7987549 100644 --- a/ridemyway/api/v1/routes.py +++ b/ridemyway/api/v1/routes.py @@ -6,3 +6,8 @@ v1 = Blueprint('v1', __name__) api = Api(v1) add = api.add_resource + + +# Add routes here + +add(r.All, '/all') # GET diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 5dfef18..22fe2be 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -1,2 +1,19 @@ from flask_restful import Resource, reqparse +from flask_jwt_extended import (create_access_token, + create_refresh_token, jwt_required, + get_jwt_identity, get_raw_jwt) from flask import current_app as app + + +class All(Resource): + + def __init__(self): + pass + + def get(self): + """ + Returns: + All database items + """ + + return {'message': 'all'}, 201 From fd36e738acaa1aed7fb6a4ea13d71466dc0128f5 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 12:44:42 +0300 Subject: [PATCH 22/54] Update .travis.yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 043ba70..da091f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ python: # command to install dependencies install: - pip install -r requirements.txt + - pip install nose + - pip install coveralls # command to run tests script: nosetests --with-coverage --cover-package=ridemyway && coveralls From c18b4e9b1e9080cb3b41816f544100665d1293d3 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 13:01:49 +0300 Subject: [PATCH 23/54] Update .travis.yml --- .travis.yml | 1 + ridemyway/resources.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index da091f6..184ea44 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ install: - pip install -r requirements.txt - pip install nose - pip install coveralls + - pip install coverage # command to run tests script: nosetests --with-coverage --cover-package=ridemyway && coveralls diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 22fe2be..d05ba95 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -15,5 +15,5 @@ def get(self): Returns: All database items """ - + return {'message': 'all'}, 201 From bba96ee80361bf81dd7b02e4e85e9f05b7e6b2a2 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 14:06:03 +0300 Subject: [PATCH 24/54] [Feature #158594222] Create a ride model --- ridemyway/models/ride.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 ridemyway/models/ride.py diff --git a/ridemyway/models/ride.py b/ridemyway/models/ride.py new file mode 100644 index 0000000..5787069 --- /dev/null +++ b/ridemyway/models/ride.py @@ -0,0 +1,36 @@ +class Ride(): + """ + Creates Ride objects. + + **Kwargs: + ride_id: A unique identifier for the ride. + departure: Date and time the ride is to take place. + origin: Place where the ride starts. + destination: Where the ride should end. + vehicle_number_plate: The number plate of the vehicle. + capacity: Maximum number of passengers the ride will accept. + cost: The cost of receiving the ride. + date_offered: The time this ride offer was created. + availability: Status of the ride. + """ + + def __init__(self, **kwargs): + """ + Ride object initializer. + + Returns: + Object + """ + self.ride_id = kwargs['ride_id'] + self.departure = kwargs['departure'] + self.origin = kwargs['origin'] + self.destination = kwargs['destination'] + self.vehicle_number_plate = kwargs['vehicle_number_plate'] + self.capacity = kwargs['capacity'] + self.cost = kwargs['cost'] + self.date_offered = kwargs['date_offered'] + self.availability = kwargs['availability'] + + def __repr__(self): + return(self.ride_id + ' - from ' + + self.origin + ' to ' + self.destination) From 3876d6a39ec1553a18ae741791ba185128cebb77 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 16:51:50 +0300 Subject: [PATCH 25/54] Add create ride controller --- ridemyway/controllers/ride_controller.py | 65 ++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 ridemyway/controllers/ride_controller.py diff --git a/ridemyway/controllers/ride_controller.py b/ridemyway/controllers/ride_controller.py new file mode 100644 index 0000000..5c20c14 --- /dev/null +++ b/ridemyway/controllers/ride_controller.py @@ -0,0 +1,65 @@ +from ridemyway.models.ride import Ride +from datetime import datetime +from flask import current_app as app + + +class RideController(): + """ + Controls all CRUD operations of the Ride object. + """ + + def create_ride(self, **Kwargs): + """ + Creates and adds a ride to the app database. + + Returns: + A success status if success adding ride, + failed status otherwise. + """ + try: + ride_ids = [x for x in app.database['Rides']] + if ride_ids: + ride_id = max(ride_ids) + 1 + else: + ride_id = 1 + date_offered = datetime.now().strftime('%b %d %Y %H:%M%p') + self.new_ride = Ride( + ride_id=ride_id, + departure=Kwargs['departure'], + origin=Kwargs['origin'], + destination=Kwargs['destination'], + vehicle_number_plate= + Kwargs['vehicle_number_plate'], + capacity=Kwargs['capacity'], + cost=Kwargs['cost'], + date_offered=date_offered, + availability='available') + ride = self.new_ride.__dict__ + app.database['Rides'][self.new_ride.ride_id] = ride + status = { + 'status': 'success', + 'message': 'Ride created successfully', + 'attributes': { + 'location': + '/api/v1/rides/' + ride['ride_id'], + 'repr': + ride['ride_id'] + ' - from ' + + ride['origin'] + ' to ' + + ride['destination'] + } + } + return(status) + except Exception as e: + status = { + 'status': 'failed', + 'message': 'Exceptions', + 'meta': { + 'errors': 1 + }, + 'errors': [ + { + str(type(e)): str(e) + } + ] + } + return(status) From a30498ffd4e8aa1c2458d1fedb41912cb822e953 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 17:18:56 +0300 Subject: [PATCH 26/54] Add resource for creating a ride --- ridemyway/__init__.py | 1 + ridemyway/resources.py | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/ridemyway/__init__.py b/ridemyway/__init__.py index 25cdd6c..ed9a99d 100644 --- a/ridemyway/__init__.py +++ b/ridemyway/__init__.py @@ -41,6 +41,7 @@ def create_app(config_name): app = Flask(__name__) app.database = database app.config.from_object(config[config_name]) + app.config['BUNDLE_ERRORS'] = True app.config['JWT_SECRET_KEY'] = 'super-secret' app.config['JWT_BLACKLIST_ENABLED'] = True app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh'] diff --git a/ridemyway/resources.py b/ridemyway/resources.py index d05ba95..08c605a 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -4,6 +4,43 @@ get_jwt_identity, get_raw_jwt) from flask import current_app as app +from ridemyway.controllers.ride_controller import RideController + + +rides = RideController() + + +class Rides(Resource): + + def __init__(self): + self.parser = reqparse.RequestParser() + self.parser.add_argument('departure', + help='This field cannot be blank', + required=True) + self.parser.add_argument('origin', + help='This field cannot be blank', + required=True) + self.parser.add_argument('destination', + help='This field cannot be blank', + required=True) + self.parser.add_argument('cost', + help='This field cannot be blank', + required=True) + self.parser.add_argument('vehicle_number_plate', + help='This field cannot be blank', + required=True) + self.parser.add_argument('capacity', + help='This field cannot be blank', + required=True) + + def get(self): + """ + Gets all available rides and responds with a json formatted data + """ + data = self.parser.parse_args() + self.response = rides.create_ride(**data) + return self.response, 201 + class All(Resource): From d597ec3620ddefd62090495f693e01fcd414d0eb Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 17:23:17 +0300 Subject: [PATCH 27/54] Add create ride endpoint url --- ridemyway/api/v1/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ridemyway/api/v1/routes.py b/ridemyway/api/v1/routes.py index 7987549..8eca9e4 100644 --- a/ridemyway/api/v1/routes.py +++ b/ridemyway/api/v1/routes.py @@ -9,5 +9,5 @@ # Add routes here - add(r.All, '/all') # GET +add(r.Rides, '/rides') # POST From 570f5c157f44f17890c5c94fc9d89998c3791301 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 17:50:03 +0300 Subject: [PATCH 28/54] Change create ride method from get to post --- ridemyway/resources.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 08c605a..bfab60b 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -33,9 +33,9 @@ def __init__(self): help='This field cannot be blank', required=True) - def get(self): + def post(self): """ - Gets all available rides and responds with a json formatted data + Creates a ride """ data = self.parser.parse_args() self.response = rides.create_ride(**data) From b291d20904f2288d81e1b1b0e5d54ebea968ad68 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 17:54:52 +0300 Subject: [PATCH 29/54] Convert int to str before concatinating --- ridemyway/controllers/ride_controller.py | 4 ++-- ridemyway/models/ride.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ridemyway/controllers/ride_controller.py b/ridemyway/controllers/ride_controller.py index 5c20c14..80d1638 100644 --- a/ridemyway/controllers/ride_controller.py +++ b/ridemyway/controllers/ride_controller.py @@ -41,9 +41,9 @@ def create_ride(self, **Kwargs): 'message': 'Ride created successfully', 'attributes': { 'location': - '/api/v1/rides/' + ride['ride_id'], + '/api/v1/rides/' + str(ride['ride_id']), 'repr': - ride['ride_id'] + ' - from ' + + str(ride['ride_id']) + ' - from ' + ride['origin'] + ' to ' + ride['destination'] } diff --git a/ridemyway/models/ride.py b/ridemyway/models/ride.py index 5787069..3260a27 100644 --- a/ridemyway/models/ride.py +++ b/ridemyway/models/ride.py @@ -32,5 +32,5 @@ def __init__(self, **kwargs): self.availability = kwargs['availability'] def __repr__(self): - return(self.ride_id + ' - from ' + + return(str(self.ride_id) + ' - from ' + self.origin + ' to ' + self.destination) From bf0130d45e94457cd92df0510efc459ca2fc0a47 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 17:59:44 +0300 Subject: [PATCH 30/54] Refactor create ride tests --- ridemyway/tests/test_create_ride.py | 72 ++++++++++++++--------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index 0a00b01..85a2bcd 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -21,12 +21,12 @@ def tearDown(self): def test_creates_a_ride_successfully_with_valid_data(self): data = { - 'data': - [{'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3}]} + 'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3 + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -38,12 +38,12 @@ def test_creates_a_ride_successfully_with_valid_data(self): def test_does_not_create_ride_with_invalid_date(self): data = { - 'data': - [{'departure': 'Not a date', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3}]} + 'departure': 'Not a date', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3 + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -54,12 +54,12 @@ def test_does_not_create_ride_with_invalid_date(self): def test_cannot_create_ride_with_passed_date(self): data = { - 'data': - [{'departure': 'Jun 25 1901 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3}]} + 'departure': 'Jun 25 1901 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3 + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -70,12 +70,12 @@ def test_cannot_create_ride_with_passed_date(self): def test_does_not_create_ride_with_invalid_cost(self): data = { - 'data': - [{'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': '%^$', 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3}]} + 'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': '%^$', 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3 + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -86,12 +86,12 @@ def test_does_not_create_ride_with_invalid_cost(self): def test_does_not_create_ride_with_invalid_capacity(self): data = { - 'data': - [{'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 'hundred'}]} + 'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 'hundred' + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -102,12 +102,12 @@ def test_does_not_create_ride_with_invalid_capacity(self): def test_does_not_create_ride_with_invalid_vehicle_number_plate(self): data = { - 'data': - [{'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 2121, 'capacity': 3}]} + 'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 2121, 'capacity': 3 + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) From 2761bd13a5d0ee8c3a78b9b0caefa934445faf7b Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 19:13:30 +0300 Subject: [PATCH 31/54] Return date format error when creating a ride --- ridemyway/resources.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ridemyway/resources.py b/ridemyway/resources.py index bfab60b..0e277e6 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -3,9 +3,11 @@ create_refresh_token, jwt_required, get_jwt_identity, get_raw_jwt) from flask import current_app as app - +import json from ridemyway.controllers.ride_controller import RideController +from .utils import errors + rides = RideController() @@ -38,6 +40,9 @@ def post(self): Creates a ride """ data = self.parser.parse_args() + create_ride_errors = errors.create_ride(**data) + if create_ride_errors: + return json.loads(json.dumps(create_ride_errors)), 400 self.response = rides.create_ride(**data) return self.response, 201 From 89d1780547527f8d743284a135ce6d7a384d71f6 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 19:18:19 +0300 Subject: [PATCH 32/54] Return a dictionary of errors instead of a list --- ridemyway/tests/test_create_ride.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index 85a2bcd..9983912 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -47,6 +47,7 @@ def test_does_not_create_ride_with_invalid_date(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) + print(result) self.assertEqual(result['errors']['date'], 'Invalid date given', msg='Should only accept correctly formatted dates!') From a5afc74d96b2efbe51b710f6ce53fc2f21be9491 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 21:38:53 +0300 Subject: [PATCH 33/54] Pass tests for create ride endpoint --- ridemyway/tests/test_create_ride.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index 9983912..8b8083c 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -21,7 +21,7 @@ def tearDown(self): def test_creates_a_ride_successfully_with_valid_data(self): data = { - 'departure': 'Jun 25 2018 1:30PM', + 'departure': 'Jun 25 6454 1:30PM', 'origin': 'Nairobi', 'destination': 'Garissa', 'cost': 350, 'vehicle_number_plate': @@ -47,9 +47,8 @@ def test_does_not_create_ride_with_invalid_date(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) - print(result) self.assertEqual(result['errors']['date'], - 'Invalid date given', + 'Date of departure is in invalid format', msg='Should only accept correctly formatted dates!') self.assertEqual(self.response.status_code, 400) @@ -65,7 +64,7 @@ def test_cannot_create_ride_with_passed_date(self): self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) self.assertEqual(result['errors']['date'], - 'Invalid date given', + 'Date of departure is in the past', msg='Should only accept future dates!') self.assertEqual(self.response.status_code, 400) @@ -109,7 +108,6 @@ def test_does_not_create_ride_with_invalid_vehicle_number_plate(self): 'cost': 350, 'vehicle_number_plate': 2121, 'capacity': 3 } - self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) self.assertEqual(result['errors']['vehicleNumberPlate'], From e1de0cf47518e9b9e27e1a71e3003d5a4a91a716 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 22:06:22 +0300 Subject: [PATCH 34/54] Revert "[Finishes #158594222] Endpoint for creating a ride [WIP]" --- ridemyway/__init__.py | 1 - ridemyway/api/v1/routes.py | 2 +- ridemyway/controllers/ride_controller.py | 65 -------------------- ridemyway/models/ride.py | 36 ----------- ridemyway/resources.py | 42 ------------- ridemyway/tests/test_create_ride.py | 77 ++++++++++++------------ 6 files changed, 40 insertions(+), 183 deletions(-) delete mode 100644 ridemyway/controllers/ride_controller.py delete mode 100644 ridemyway/models/ride.py diff --git a/ridemyway/__init__.py b/ridemyway/__init__.py index ed9a99d..25cdd6c 100644 --- a/ridemyway/__init__.py +++ b/ridemyway/__init__.py @@ -41,7 +41,6 @@ def create_app(config_name): app = Flask(__name__) app.database = database app.config.from_object(config[config_name]) - app.config['BUNDLE_ERRORS'] = True app.config['JWT_SECRET_KEY'] = 'super-secret' app.config['JWT_BLACKLIST_ENABLED'] = True app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh'] diff --git a/ridemyway/api/v1/routes.py b/ridemyway/api/v1/routes.py index 8eca9e4..7987549 100644 --- a/ridemyway/api/v1/routes.py +++ b/ridemyway/api/v1/routes.py @@ -9,5 +9,5 @@ # Add routes here + add(r.All, '/all') # GET -add(r.Rides, '/rides') # POST diff --git a/ridemyway/controllers/ride_controller.py b/ridemyway/controllers/ride_controller.py deleted file mode 100644 index 80d1638..0000000 --- a/ridemyway/controllers/ride_controller.py +++ /dev/null @@ -1,65 +0,0 @@ -from ridemyway.models.ride import Ride -from datetime import datetime -from flask import current_app as app - - -class RideController(): - """ - Controls all CRUD operations of the Ride object. - """ - - def create_ride(self, **Kwargs): - """ - Creates and adds a ride to the app database. - - Returns: - A success status if success adding ride, - failed status otherwise. - """ - try: - ride_ids = [x for x in app.database['Rides']] - if ride_ids: - ride_id = max(ride_ids) + 1 - else: - ride_id = 1 - date_offered = datetime.now().strftime('%b %d %Y %H:%M%p') - self.new_ride = Ride( - ride_id=ride_id, - departure=Kwargs['departure'], - origin=Kwargs['origin'], - destination=Kwargs['destination'], - vehicle_number_plate= - Kwargs['vehicle_number_plate'], - capacity=Kwargs['capacity'], - cost=Kwargs['cost'], - date_offered=date_offered, - availability='available') - ride = self.new_ride.__dict__ - app.database['Rides'][self.new_ride.ride_id] = ride - status = { - 'status': 'success', - 'message': 'Ride created successfully', - 'attributes': { - 'location': - '/api/v1/rides/' + str(ride['ride_id']), - 'repr': - str(ride['ride_id']) + ' - from ' + - ride['origin'] + ' to ' + - ride['destination'] - } - } - return(status) - except Exception as e: - status = { - 'status': 'failed', - 'message': 'Exceptions', - 'meta': { - 'errors': 1 - }, - 'errors': [ - { - str(type(e)): str(e) - } - ] - } - return(status) diff --git a/ridemyway/models/ride.py b/ridemyway/models/ride.py deleted file mode 100644 index 3260a27..0000000 --- a/ridemyway/models/ride.py +++ /dev/null @@ -1,36 +0,0 @@ -class Ride(): - """ - Creates Ride objects. - - **Kwargs: - ride_id: A unique identifier for the ride. - departure: Date and time the ride is to take place. - origin: Place where the ride starts. - destination: Where the ride should end. - vehicle_number_plate: The number plate of the vehicle. - capacity: Maximum number of passengers the ride will accept. - cost: The cost of receiving the ride. - date_offered: The time this ride offer was created. - availability: Status of the ride. - """ - - def __init__(self, **kwargs): - """ - Ride object initializer. - - Returns: - Object - """ - self.ride_id = kwargs['ride_id'] - self.departure = kwargs['departure'] - self.origin = kwargs['origin'] - self.destination = kwargs['destination'] - self.vehicle_number_plate = kwargs['vehicle_number_plate'] - self.capacity = kwargs['capacity'] - self.cost = kwargs['cost'] - self.date_offered = kwargs['date_offered'] - self.availability = kwargs['availability'] - - def __repr__(self): - return(str(self.ride_id) + ' - from ' + - self.origin + ' to ' + self.destination) diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 0e277e6..d05ba95 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -3,48 +3,6 @@ create_refresh_token, jwt_required, get_jwt_identity, get_raw_jwt) from flask import current_app as app -import json -from ridemyway.controllers.ride_controller import RideController - -from .utils import errors - - -rides = RideController() - - -class Rides(Resource): - - def __init__(self): - self.parser = reqparse.RequestParser() - self.parser.add_argument('departure', - help='This field cannot be blank', - required=True) - self.parser.add_argument('origin', - help='This field cannot be blank', - required=True) - self.parser.add_argument('destination', - help='This field cannot be blank', - required=True) - self.parser.add_argument('cost', - help='This field cannot be blank', - required=True) - self.parser.add_argument('vehicle_number_plate', - help='This field cannot be blank', - required=True) - self.parser.add_argument('capacity', - help='This field cannot be blank', - required=True) - - def post(self): - """ - Creates a ride - """ - data = self.parser.parse_args() - create_ride_errors = errors.create_ride(**data) - if create_ride_errors: - return json.loads(json.dumps(create_ride_errors)), 400 - self.response = rides.create_ride(**data) - return self.response, 201 class All(Resource): diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index 8b8083c..0a00b01 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -21,12 +21,12 @@ def tearDown(self): def test_creates_a_ride_successfully_with_valid_data(self): data = { - 'departure': 'Jun 25 6454 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3 - } + 'data': + [{'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3}]} self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -38,44 +38,44 @@ def test_creates_a_ride_successfully_with_valid_data(self): def test_does_not_create_ride_with_invalid_date(self): data = { - 'departure': 'Not a date', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3 - } + 'data': + [{'departure': 'Not a date', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3}]} self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) self.assertEqual(result['errors']['date'], - 'Date of departure is in invalid format', + 'Invalid date given', msg='Should only accept correctly formatted dates!') self.assertEqual(self.response.status_code, 400) def test_cannot_create_ride_with_passed_date(self): data = { - 'departure': 'Jun 25 1901 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3 - } + 'data': + [{'departure': 'Jun 25 1901 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3}]} self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) self.assertEqual(result['errors']['date'], - 'Date of departure is in the past', + 'Invalid date given', msg='Should only accept future dates!') self.assertEqual(self.response.status_code, 400) def test_does_not_create_ride_with_invalid_cost(self): data = { - 'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': '%^$', 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3 - } + 'data': + [{'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': '%^$', 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3}]} self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -86,12 +86,12 @@ def test_does_not_create_ride_with_invalid_cost(self): def test_does_not_create_ride_with_invalid_capacity(self): data = { - 'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 'hundred' - } + 'data': + [{'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 'hundred'}]} self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -102,12 +102,13 @@ def test_does_not_create_ride_with_invalid_capacity(self): def test_does_not_create_ride_with_invalid_vehicle_number_plate(self): data = { - 'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 2121, 'capacity': 3 - } + 'data': + [{'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 2121, 'capacity': 3}]} + self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) self.assertEqual(result['errors']['vehicleNumberPlate'], From aa75b88279e16a57d332e6a59391fb707a714c98 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 22:10:31 +0300 Subject: [PATCH 35/54] Add error handler and validators for creating a ride --- ridemyway/utils/errors.py | 41 ++++++++++++++++++++++++++++++ ridemyway/utils/validators.py | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 ridemyway/utils/errors.py create mode 100644 ridemyway/utils/validators.py diff --git a/ridemyway/utils/errors.py b/ridemyway/utils/errors.py new file mode 100644 index 0000000..2fb3df3 --- /dev/null +++ b/ridemyway/utils/errors.py @@ -0,0 +1,41 @@ +from .validators import is_a_date, date_has_passed, is_currency, is_int + + +def create_ride(**kwargs): + """ + + """ + response = { + 'status': 'failed', + 'message': 'Could not create ride!', + 'meta': { + 'errors': 0 + }, + 'errors': {} + } + + # Check departure date is valid + if is_a_date(kwargs['departure']): + if date_has_passed(kwargs['departure']): + response['errors']['date'] = 'Date of departure is in the past' + else: + response['errors']['date'] = 'Date of departure is in invalid format' + + # Check cost is a valid currency value + if not is_currency(kwargs['cost']): + response['errors']['cost'] = 'Invalid cost given' + + # Check capacity is only a number + if is_int(kwargs['capacity']) is not True: + response['errors']['capacity'] = 'Invalid capacity given' + + # Check number plate is a string + try: + float(kwargs['vehicle_number_plate']) + response['errors']['vehicleNumberPlate'] = 'Invalid vehicle number plate given' + except Exception: + pass + response['meta']['errors'] = len(response['errors']) + if len(response['errors']) > 0: + return response + return False diff --git a/ridemyway/utils/validators.py b/ridemyway/utils/validators.py new file mode 100644 index 0000000..a0cc372 --- /dev/null +++ b/ridemyway/utils/validators.py @@ -0,0 +1,48 @@ +from datetime import datetime + + +def is_a_date(date_text): + """ + Returns true if date_text is a date + False otherwise + """ + try: + datetime.strptime(date_text, '%b %d %Y %I:%M%p') + return True + except ValueError: + return False + + +def date_has_passed(date_text): + """ + Returns true if date_text is a date that has passed + False otherwise + """ + date = datetime.strptime(date_text, '%b %d %Y %I:%M%p') + if date < datetime.now(): + return True + return False + + +def is_currency(a): + """ + Returns true if a is a valid currency value + False otherwise + """ + try: + float(a) + return True + except Exception: + return False + + +def is_int(a): + """ + Returns true if a is an integer + False otherwise + """ + try: + int(a) + return True + except Exception: + return False From 693999b27bf52cb321a03b567fe0ff8f474bf36d Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 22:31:06 +0300 Subject: [PATCH 36/54] Refactor tests for fetching rides --- ridemyway/tests/test_fetch_rides.py | 37 +++++++++++++++-------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/ridemyway/tests/test_fetch_rides.py b/ridemyway/tests/test_fetch_rides.py index fc2cf55..5a2d1c5 100644 --- a/ridemyway/tests/test_fetch_rides.py +++ b/ridemyway/tests/test_fetch_rides.py @@ -16,26 +16,27 @@ def setUp(self): self.headers = {'content-type': 'application/json'} self.context = self.app.app_context() self.context.push() + + # Create rides for testing data = { - 'data': [ - {'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, - 'vehicle_number_plate': 'KBC-A21', - 'capacity': 3 - }, - {'departure': 'Jun 28 2018 7:00AM', - 'origin': 'Garissa', - 'destination': 'Nairobi', - 'cost': 500, - 'vehicle_number_plate': 'KBC-A21', - 'capacity': 3 - } - ] + 'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, + 'vehicle_number_plate': 'KBC-A21', + 'capacity': 3 + } + data_1 = { + 'departure': 'Jun 28 2018 7:00AM', + 'origin': 'Garissa', + 'destination': 'Nairobi', + 'cost': 500, + 'vehicle_number_plate': 'KBC-A21', + 'capacity': 3 } self.client().post('/api/v1/rides', data=data) + self.client().post('/api/v1/rides', data=data_1) def tearDown(self): self.context.pop() @@ -44,7 +45,7 @@ def test_fetches_rides_successfully(self): self.response = self.client().get('/api/v1/rides') result = json.loads(self.response.data.decode()) self.assertEqual(result['message'], - 'Rides retrieved successfully', + 'Rides fetched successfully', msg='Should fetch rides successfully!') self.assertEqual(self.response.status_code, 200) @@ -52,7 +53,7 @@ def test_fetches_a_single_ride_with_valid_id(self): self.response = self.client().get('/api/v1/rides/1') result = json.loads(self.response.data.decode()) self.assertEqual(result['message'], - 'Ride retrieved successfully', + 'Ride fetched successfully', msg='Should fetch single ride given a valid ride id!') self.assertEqual(self.response.status_code, 200) From a1ebbac99ce1638ac4d79a36b5b7e8fed650eeb9 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 22:34:08 +0300 Subject: [PATCH 37/54] Revert "Revert "[Finishes #158594222] Endpoint for creating a ride [WIP]"" --- ridemyway/__init__.py | 1 + ridemyway/api/v1/routes.py | 2 +- ridemyway/controllers/ride_controller.py | 65 ++++++++++++++++++++ ridemyway/models/ride.py | 36 +++++++++++ ridemyway/resources.py | 42 +++++++++++++ ridemyway/tests/test_create_ride.py | 77 ++++++++++++------------ 6 files changed, 183 insertions(+), 40 deletions(-) create mode 100644 ridemyway/controllers/ride_controller.py create mode 100644 ridemyway/models/ride.py diff --git a/ridemyway/__init__.py b/ridemyway/__init__.py index 25cdd6c..ed9a99d 100644 --- a/ridemyway/__init__.py +++ b/ridemyway/__init__.py @@ -41,6 +41,7 @@ def create_app(config_name): app = Flask(__name__) app.database = database app.config.from_object(config[config_name]) + app.config['BUNDLE_ERRORS'] = True app.config['JWT_SECRET_KEY'] = 'super-secret' app.config['JWT_BLACKLIST_ENABLED'] = True app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh'] diff --git a/ridemyway/api/v1/routes.py b/ridemyway/api/v1/routes.py index 7987549..8eca9e4 100644 --- a/ridemyway/api/v1/routes.py +++ b/ridemyway/api/v1/routes.py @@ -9,5 +9,5 @@ # Add routes here - add(r.All, '/all') # GET +add(r.Rides, '/rides') # POST diff --git a/ridemyway/controllers/ride_controller.py b/ridemyway/controllers/ride_controller.py new file mode 100644 index 0000000..80d1638 --- /dev/null +++ b/ridemyway/controllers/ride_controller.py @@ -0,0 +1,65 @@ +from ridemyway.models.ride import Ride +from datetime import datetime +from flask import current_app as app + + +class RideController(): + """ + Controls all CRUD operations of the Ride object. + """ + + def create_ride(self, **Kwargs): + """ + Creates and adds a ride to the app database. + + Returns: + A success status if success adding ride, + failed status otherwise. + """ + try: + ride_ids = [x for x in app.database['Rides']] + if ride_ids: + ride_id = max(ride_ids) + 1 + else: + ride_id = 1 + date_offered = datetime.now().strftime('%b %d %Y %H:%M%p') + self.new_ride = Ride( + ride_id=ride_id, + departure=Kwargs['departure'], + origin=Kwargs['origin'], + destination=Kwargs['destination'], + vehicle_number_plate= + Kwargs['vehicle_number_plate'], + capacity=Kwargs['capacity'], + cost=Kwargs['cost'], + date_offered=date_offered, + availability='available') + ride = self.new_ride.__dict__ + app.database['Rides'][self.new_ride.ride_id] = ride + status = { + 'status': 'success', + 'message': 'Ride created successfully', + 'attributes': { + 'location': + '/api/v1/rides/' + str(ride['ride_id']), + 'repr': + str(ride['ride_id']) + ' - from ' + + ride['origin'] + ' to ' + + ride['destination'] + } + } + return(status) + except Exception as e: + status = { + 'status': 'failed', + 'message': 'Exceptions', + 'meta': { + 'errors': 1 + }, + 'errors': [ + { + str(type(e)): str(e) + } + ] + } + return(status) diff --git a/ridemyway/models/ride.py b/ridemyway/models/ride.py new file mode 100644 index 0000000..3260a27 --- /dev/null +++ b/ridemyway/models/ride.py @@ -0,0 +1,36 @@ +class Ride(): + """ + Creates Ride objects. + + **Kwargs: + ride_id: A unique identifier for the ride. + departure: Date and time the ride is to take place. + origin: Place where the ride starts. + destination: Where the ride should end. + vehicle_number_plate: The number plate of the vehicle. + capacity: Maximum number of passengers the ride will accept. + cost: The cost of receiving the ride. + date_offered: The time this ride offer was created. + availability: Status of the ride. + """ + + def __init__(self, **kwargs): + """ + Ride object initializer. + + Returns: + Object + """ + self.ride_id = kwargs['ride_id'] + self.departure = kwargs['departure'] + self.origin = kwargs['origin'] + self.destination = kwargs['destination'] + self.vehicle_number_plate = kwargs['vehicle_number_plate'] + self.capacity = kwargs['capacity'] + self.cost = kwargs['cost'] + self.date_offered = kwargs['date_offered'] + self.availability = kwargs['availability'] + + def __repr__(self): + return(str(self.ride_id) + ' - from ' + + self.origin + ' to ' + self.destination) diff --git a/ridemyway/resources.py b/ridemyway/resources.py index d05ba95..0e277e6 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -3,6 +3,48 @@ create_refresh_token, jwt_required, get_jwt_identity, get_raw_jwt) from flask import current_app as app +import json +from ridemyway.controllers.ride_controller import RideController + +from .utils import errors + + +rides = RideController() + + +class Rides(Resource): + + def __init__(self): + self.parser = reqparse.RequestParser() + self.parser.add_argument('departure', + help='This field cannot be blank', + required=True) + self.parser.add_argument('origin', + help='This field cannot be blank', + required=True) + self.parser.add_argument('destination', + help='This field cannot be blank', + required=True) + self.parser.add_argument('cost', + help='This field cannot be blank', + required=True) + self.parser.add_argument('vehicle_number_plate', + help='This field cannot be blank', + required=True) + self.parser.add_argument('capacity', + help='This field cannot be blank', + required=True) + + def post(self): + """ + Creates a ride + """ + data = self.parser.parse_args() + create_ride_errors = errors.create_ride(**data) + if create_ride_errors: + return json.loads(json.dumps(create_ride_errors)), 400 + self.response = rides.create_ride(**data) + return self.response, 201 class All(Resource): diff --git a/ridemyway/tests/test_create_ride.py b/ridemyway/tests/test_create_ride.py index 0a00b01..8b8083c 100644 --- a/ridemyway/tests/test_create_ride.py +++ b/ridemyway/tests/test_create_ride.py @@ -21,12 +21,12 @@ def tearDown(self): def test_creates_a_ride_successfully_with_valid_data(self): data = { - 'data': - [{'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3}]} + 'departure': 'Jun 25 6454 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3 + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -38,44 +38,44 @@ def test_creates_a_ride_successfully_with_valid_data(self): def test_does_not_create_ride_with_invalid_date(self): data = { - 'data': - [{'departure': 'Not a date', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3}]} + 'departure': 'Not a date', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3 + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) self.assertEqual(result['errors']['date'], - 'Invalid date given', + 'Date of departure is in invalid format', msg='Should only accept correctly formatted dates!') self.assertEqual(self.response.status_code, 400) def test_cannot_create_ride_with_passed_date(self): data = { - 'data': - [{'departure': 'Jun 25 1901 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3}]} + 'departure': 'Jun 25 1901 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3 + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) self.assertEqual(result['errors']['date'], - 'Invalid date given', + 'Date of departure is in the past', msg='Should only accept future dates!') self.assertEqual(self.response.status_code, 400) def test_does_not_create_ride_with_invalid_cost(self): data = { - 'data': - [{'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': '%^$', 'vehicle_number_plate': - 'KBC-A21', 'capacity': 3}]} + 'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': '%^$', 'vehicle_number_plate': + 'KBC-A21', 'capacity': 3 + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -86,12 +86,12 @@ def test_does_not_create_ride_with_invalid_cost(self): def test_does_not_create_ride_with_invalid_capacity(self): data = { - 'data': - [{'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 'KBC-A21', 'capacity': 'hundred'}]} + 'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 'KBC-A21', 'capacity': 'hundred' + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) @@ -102,13 +102,12 @@ def test_does_not_create_ride_with_invalid_capacity(self): def test_does_not_create_ride_with_invalid_vehicle_number_plate(self): data = { - 'data': - [{'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, 'vehicle_number_plate': - 2121, 'capacity': 3}]} - + 'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, 'vehicle_number_plate': + 2121, 'capacity': 3 + } self.response = self.client().post('/api/v1/rides', data=data) result = json.loads(self.response.data.decode()) self.assertEqual(result['errors']['vehicleNumberPlate'], From 43720e2fbaace5891d1bfa13d70ab5887633f53c Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Tue, 26 Jun 2018 22:49:28 +0300 Subject: [PATCH 38/54] Add resource for fetching all rides --- ridemyway/resources.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 0e277e6..6e1fa5c 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -46,6 +46,13 @@ def post(self): self.response = rides.create_ride(**data) return self.response, 201 + def get(self): + """ + Fetches all rides + """ + fetched_rides = rides.fetch_all() + return(fetched_rides), 200 + class All(Resource): From 8511b5782a38667ba976a4985d679f28605f33f2 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 00:02:36 +0300 Subject: [PATCH 39/54] [Feature 158594444] Fetch all rides endpoint --- ridemyway/controllers/ride_controller.py | 27 ++++++++++++++++++++++++ ridemyway/utils/__init__.py | 0 2 files changed, 27 insertions(+) create mode 100644 ridemyway/utils/__init__.py diff --git a/ridemyway/controllers/ride_controller.py b/ridemyway/controllers/ride_controller.py index 80d1638..5fdc620 100644 --- a/ridemyway/controllers/ride_controller.py +++ b/ridemyway/controllers/ride_controller.py @@ -1,6 +1,7 @@ from ridemyway.models.ride import Ride from datetime import datetime from flask import current_app as app +from ridemyway.utils.validators import date_has_passed class RideController(): @@ -63,3 +64,29 @@ def create_ride(self, **Kwargs): ] } return(status) + + def fetch_all(self): + rides_count = 0 + fetched_rides = { + 'status': 'success', + 'message': 'Rides fetched successfully', + 'meta': { + 'rides': 0 + }, + 'data': {} + } + for key, value in app.database['Rides'].items(): + if date_has_passed(value['departure']): + continue + rides_count += 1 + fetched_rides['data'][key] = { + 'departure': value['departure'], + 'origin': value['origin'], + 'destination': value['destination'], + 'cost': value['cost'], + 'vehicle_number_plate': value['vehicle_number_plate'], + 'capacity': value['capacity'], + 'dateoffered': value['date_offered'] + } + fetched_rides['meta']['rides'] = rides_count + return fetched_rides diff --git a/ridemyway/utils/__init__.py b/ridemyway/utils/__init__.py new file mode 100644 index 0000000..e69de29 From b1c0d0677a013b00e2b5f25a18f2943c8908e0eb Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 00:56:29 +0300 Subject: [PATCH 40/54] Add resource for fetching single ride --- ridemyway/resources.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 0e277e6..244b24a 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -47,6 +47,16 @@ def post(self): return self.response, 201 +class Ride(Resource): + + def __init__(self): + pass + + def get(self, rideId): + return rides.fetch_one(rideId) + + + class All(Resource): def __init__(self): From 1b4fcd0f8dd15ecc6c09c436a2187b788f7091d4 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 01:14:54 +0300 Subject: [PATCH 41/54] Create fetch single ride controller --- ridemyway/controllers/ride_controller.py | 36 ++++++++++++++++++++++++ ridemyway/resources.py | 1 - 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/ridemyway/controllers/ride_controller.py b/ridemyway/controllers/ride_controller.py index 80d1638..811599b 100644 --- a/ridemyway/controllers/ride_controller.py +++ b/ridemyway/controllers/ride_controller.py @@ -63,3 +63,39 @@ def create_ride(self, **Kwargs): ] } return(status) + + def fetch_one(self, ride_id): + try: + one_ride = app.database['Rides'][ride_id] + fetched_ride = { + 'status': 'success', + 'message': 'Ride fetched successfully', + 'data': { + 'rideId': [one_ride['ride_id']], + 'departure': one_ride['departure'], + 'origin': one_ride['origin'], + 'destination': one_ride['destination'], + 'cost': one_ride['cost'], + 'vehicleNumberPlate': one_ride['vehicle_number_plate'], + 'capacity': one_ride['capacity'], + 'dateoffered': one_ride['date_offered'] + } + } + return fetched_ride, 200 + except KeyError: + status = { + 'status': 'failed', + 'message': 'NOT FOUND', + 'meta': { + 'errors': 1 + }, + 'errors': [ + { + 404: 'Chapter 404: The Lost Resource. \ + A careful and diligent search \ + has been made for the desired resource, \ + but it just cannot be found.' + } + ] + } + return status, 404 diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 244b24a..4a4fb13 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -56,7 +56,6 @@ def get(self, rideId): return rides.fetch_one(rideId) - class All(Resource): def __init__(self): From 0d9a842a96ef08c161c8559dc2ff52f157a1a613 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 01:25:05 +0300 Subject: [PATCH 42/54] Add fetch single ride endpoint url --- ridemyway/api/v1/routes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ridemyway/api/v1/routes.py b/ridemyway/api/v1/routes.py index 8eca9e4..cb21653 100644 --- a/ridemyway/api/v1/routes.py +++ b/ridemyway/api/v1/routes.py @@ -10,4 +10,5 @@ # Add routes here add(r.All, '/all') # GET -add(r.Rides, '/rides') # POST +add(r.Rides, '/rides') # GET, POST +add(r.Ride, '/rides/') # GET From 0391fe1ac8f78baa4e4a4bd38bf9841de206739b Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 01:27:33 +0300 Subject: [PATCH 43/54] Return ride id as int not list --- ridemyway/controllers/ride_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ridemyway/controllers/ride_controller.py b/ridemyway/controllers/ride_controller.py index 811599b..5d815de 100644 --- a/ridemyway/controllers/ride_controller.py +++ b/ridemyway/controllers/ride_controller.py @@ -71,7 +71,7 @@ def fetch_one(self, ride_id): 'status': 'success', 'message': 'Ride fetched successfully', 'data': { - 'rideId': [one_ride['ride_id']], + 'rideId': one_ride['ride_id'], 'departure': one_ride['departure'], 'origin': one_ride['origin'], 'destination': one_ride['destination'], From 3c5a88941d3b744a7a45342040fd76598481df7b Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 01:46:17 +0300 Subject: [PATCH 44/54] Refactor fetch ride tests --- ridemyway/tests/test_fetch_rides.py | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/ridemyway/tests/test_fetch_rides.py b/ridemyway/tests/test_fetch_rides.py index fc2cf55..b067ef8 100644 --- a/ridemyway/tests/test_fetch_rides.py +++ b/ridemyway/tests/test_fetch_rides.py @@ -17,25 +17,25 @@ def setUp(self): self.context = self.app.app_context() self.context.push() data = { - 'data': [ - {'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, - 'vehicle_number_plate': 'KBC-A21', - 'capacity': 3 - }, - {'departure': 'Jun 28 2018 7:00AM', - 'origin': 'Garissa', - 'destination': 'Nairobi', - 'cost': 500, - 'vehicle_number_plate': 'KBC-A21', - 'capacity': 3 - } - ] + 'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, + 'vehicle_number_plate': 'KBC-A21', + 'capacity': 3 + } + + data_1 = { + 'departure': 'Jun 28 2018 7:00AM', + 'origin': 'Garissa', + 'destination': 'Nairobi', + 'cost': 500, + 'vehicle_number_plate': 'KBC-A21', + 'capacity': 3 } self.client().post('/api/v1/rides', data=data) + self.client().post('/api/v1/rides', data=data_1) def tearDown(self): self.context.pop() From ebfb3946341e3dbd33758060571f6a92eebe986d Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 02:07:59 +0300 Subject: [PATCH 45/54] Escape backslash effects on 404 json response --- ridemyway/controllers/ride_controller.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ridemyway/controllers/ride_controller.py b/ridemyway/controllers/ride_controller.py index 5d815de..f5ba360 100644 --- a/ridemyway/controllers/ride_controller.py +++ b/ridemyway/controllers/ride_controller.py @@ -1,6 +1,7 @@ from ridemyway.models.ride import Ride from datetime import datetime from flask import current_app as app +import re class RideController(): @@ -83,6 +84,10 @@ def fetch_one(self, ride_id): } return fetched_ride, 200 except KeyError: + error_message_404 = 'Chapter 404: The Lost Resource. \ + A careful and diligent search \ + has been made for the desired resource, \ + but it just cannot be found.' status = { 'status': 'failed', 'message': 'NOT FOUND', @@ -91,10 +96,7 @@ def fetch_one(self, ride_id): }, 'errors': [ { - 404: 'Chapter 404: The Lost Resource. \ - A careful and diligent search \ - has been made for the desired resource, \ - but it just cannot be found.' + 404: re.sub(' +', ' ', error_message_404) } ] } From 1d37f03eedadec2093a659169524f5641440f2e9 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 02:41:38 +0300 Subject: [PATCH 46/54] Create resource for create ride request endpoint --- ridemyway/resources.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 704c4e4..7970560 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -5,11 +5,13 @@ from flask import current_app as app import json from ridemyway.controllers.ride_controller import RideController +from ridemyway.controllers.ride_requests_controller import RequestController from .utils import errors rides = RideController() +ride_requests = RequestController class Rides(Resource): @@ -63,6 +65,15 @@ def get(self, rideId): return rides.fetch_one(rideId) +class Request(Resource): + + def __init__(self): + pass + + def post(self, rideId): + return(ride_requests.create_request()) + + class All(Resource): def __init__(self): From a0ebbc1edd3ad05525ac7ce05b9e33970506a244 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 02:42:41 +0300 Subject: [PATCH 47/54] Add docstring to resource --- ridemyway/resources.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 7970560..d795d41 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -71,6 +71,9 @@ def __init__(self): pass def post(self, rideId): + """ + Creates a ride request + """ return(ride_requests.create_request()) From 4daa9b8db7e06a3145d2c41f3d8dc03ec5732770 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 03:09:46 +0300 Subject: [PATCH 48/54] Add create request controller --- .../controllers/ride_request_controller.py | 60 +++++++++++++++++++ ridemyway/resources.py | 4 +- 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 ridemyway/controllers/ride_request_controller.py diff --git a/ridemyway/controllers/ride_request_controller.py b/ridemyway/controllers/ride_request_controller.py new file mode 100644 index 0000000..27ee561 --- /dev/null +++ b/ridemyway/controllers/ride_request_controller.py @@ -0,0 +1,60 @@ +from ridemyway.models.request import Request +from flask import current_app as app +import re +from ridemyway.utils.validators import date_has_passed + + +class RequestController(): + """ + Controls all CRUD operations of the Request object. + """ + + def create_request(self, **Kwargs): + """ + Creates and adds a request to the app database. + + Returns: + A success status if success adding ride, + failed status otherwise. + """ + try: + app.database['Rides'][Kwargs['ride_id']] + request_ids = [x for x in app.database['Requests']] + if request_ids: + request_id = max(request_ids) + 1 + else: + request_id = 1 + self.new_request = Request( + request_id=request_id, + ride_id=Kwargs['ride_id'], + status='available' + ) + request = self.new_request.__dict__ + app.database['Requests'][request['request_id']] = request + status = { + 'status': 'success', + 'message': 'Ride request created successfully', + 'attributes': { + 'location': + '/api/v1/rides/' + request['ride_id'] + '/requests' + } + } + return status, 201 + except KeyError: + error_message_404 = 'Chapter 404: The Lost Resource. \ + A careful and diligent search \ + has been made for the desired resource, \ + but it just cannot be found.' + status = { + 'status': 'failed', + 'message': 'NOT FOUND', + 'meta': { + 'errors': 1 + }, + 'errors': [ + { + 404: re.sub(' +', ' ', error_message_404) + } + ] + } + return status, 404 diff --git a/ridemyway/resources.py b/ridemyway/resources.py index d795d41..09fc094 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -5,13 +5,13 @@ from flask import current_app as app import json from ridemyway.controllers.ride_controller import RideController -from ridemyway.controllers.ride_requests_controller import RequestController +from ridemyway.controllers.ride_request_controller import RequestController from .utils import errors rides = RideController() -ride_requests = RequestController +ride_requests = RequestController() class Rides(Resource): From 8953ced7fdda97f973cb15367aebeadd211419be Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 03:14:50 +0300 Subject: [PATCH 49/54] Create request model --- ridemyway/models/request.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 ridemyway/models/request.py diff --git a/ridemyway/models/request.py b/ridemyway/models/request.py new file mode 100644 index 0000000..8c8435b --- /dev/null +++ b/ridemyway/models/request.py @@ -0,0 +1,21 @@ +class Request(): + """ + Creates Request objects. + + **Kwargs: + ride_id: A unique identifier of the ride the request is + being made to. + request_id: A unique identifier for the request. + status: Status of the request. + """ + + def __init__(self, **kwargs): + """ + Request object initializer. + + Returns: + Object + """ + self.request_id = kwargs['request_id'] + self.ride_id = kwargs['ride_id'] + self.status = kwargs['status'] From 7b7af440b4d1f4df4f56ef8897a717e0bdb79faa Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 03:17:44 +0300 Subject: [PATCH 50/54] Add create request endpoint url --- ridemyway/api/v1/routes.py | 1 + ridemyway/resources.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ridemyway/api/v1/routes.py b/ridemyway/api/v1/routes.py index cb21653..2283387 100644 --- a/ridemyway/api/v1/routes.py +++ b/ridemyway/api/v1/routes.py @@ -12,3 +12,4 @@ add(r.All, '/all') # GET add(r.Rides, '/rides') # GET, POST add(r.Ride, '/rides/') # GET +add(r.Request, '/rides//requests') # POST diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 09fc094..91d142a 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -74,7 +74,7 @@ def post(self, rideId): """ Creates a ride request """ - return(ride_requests.create_request()) + return(ride_requests.create_request(rideId)) class All(Resource): From 491c3c3cc8bfffbf3f2369fb75c45343283c69cc Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 03:19:02 +0300 Subject: [PATCH 51/54] Add create request endpoint url --- ridemyway/tests/test_ride_request.py | 31 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/ridemyway/tests/test_ride_request.py b/ridemyway/tests/test_ride_request.py index 24d442d..7e8c99b 100644 --- a/ridemyway/tests/test_ride_request.py +++ b/ridemyway/tests/test_ride_request.py @@ -16,25 +16,24 @@ def setUp(self): self.context = self.app.app_context() self.context.push() data = { - 'data': [ - {'departure': 'Jun 25 2018 1:30PM', - 'origin': 'Nairobi', - 'destination': 'Garissa', - 'cost': 350, - 'vehicle_number_plate': 'KBC-A21', - 'capacity': 3 - }, - {'departure': 'Jun 28 2018 7:00AM', - 'origin': 'Garissa', - 'destination': 'Nairobi', - 'cost': 500, - 'vehicle_number_plate': 'KBC-A21', - 'capacity': 3 - } - ] + 'departure': 'Jun 25 2018 1:30PM', + 'origin': 'Nairobi', + 'destination': 'Garissa', + 'cost': 350, + 'vehicle_number_plate': 'KBC-A21', + 'capacity': 3 + } + data_1 = { + 'departure': 'Jun 28 2018 7:00AM', + 'origin': 'Garissa', + 'destination': 'Nairobi', + 'cost': 500, + 'vehicle_number_plate': 'KBC-A21', + 'capacity': 3 } self.client().post('/api/v1/rides', data=data) + self.client().post('/api/v1/rides', data=data_1) def tearDown(self): self.context.pop() From e92dabcedb05127a8e039b08dcf857e8935241e4 Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 03:35:42 +0300 Subject: [PATCH 52/54] Convert rideId int to str and pass rideId as **kwargs --- ridemyway/controllers/ride_request_controller.py | 2 +- ridemyway/resources.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ridemyway/controllers/ride_request_controller.py b/ridemyway/controllers/ride_request_controller.py index 27ee561..d5fd137 100644 --- a/ridemyway/controllers/ride_request_controller.py +++ b/ridemyway/controllers/ride_request_controller.py @@ -36,7 +36,7 @@ def create_request(self, **Kwargs): 'message': 'Ride request created successfully', 'attributes': { 'location': - '/api/v1/rides/' + request['ride_id'] + '/requests' + '/api/v1/rides/' + str(request['ride_id']) + '/requests' } } return status, 201 diff --git a/ridemyway/resources.py b/ridemyway/resources.py index 91d142a..c4c4360 100644 --- a/ridemyway/resources.py +++ b/ridemyway/resources.py @@ -74,7 +74,7 @@ def post(self, rideId): """ Creates a ride request """ - return(ride_requests.create_request(rideId)) + return(ride_requests.create_request(ride_id=rideId)) class All(Resource): From cd24998f4e98cd0bb24f1c2bb721479d2c17420a Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 09:43:34 +0300 Subject: [PATCH 53/54] Update dependencies --- requirements.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/requirements.txt b/requirements.txt index f64a2f1..b657a31 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,13 +1,26 @@ aniso8601==3.0.2 +astroid==1.6.5 +atomicwrites==1.1.5 +attrs==18.1.0 click==6.7 Flask==1.0.2 Flask-JWT-Extended==3.10.0 Flask-RESTful==0.3.6 gunicorn==19.8.1 +isort==4.3.4 itsdangerous==0.24 Jinja2==2.10 +lazy-object-proxy==1.3.1 MarkupSafe==1.0 +mccabe==0.6.1 +more-itertools==4.2.0 +nose==1.3.7 +pluggy==0.6.0 +py==1.5.3 PyJWT==1.6.4 +pylint==1.9.2 +pytest==3.6.2 pytz==2018.4 six==1.11.0 Werkzeug==0.14.1 +wrapt==1.10.11 From ed90dbdedb2d66ddce3cbf0ffa0baa2cd4ab2c8f Mon Sep 17 00:00:00 2001 From: Joshua Ondieki Date: Wed, 27 Jun 2018 11:14:11 +0300 Subject: [PATCH 54/54] Make all **kwargs consistent with small k --- ridemyway/controllers/ride_controller.py | 14 +++++++------- ridemyway/controllers/ride_request_controller.py | 6 +++--- ridemyway/models/request.py | 2 +- ridemyway/models/ride.py | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ridemyway/controllers/ride_controller.py b/ridemyway/controllers/ride_controller.py index 670e1e7..d995556 100644 --- a/ridemyway/controllers/ride_controller.py +++ b/ridemyway/controllers/ride_controller.py @@ -10,7 +10,7 @@ class RideController(): Controls all CRUD operations of the Ride object. """ - def create_ride(self, **Kwargs): + def create_ride(self, **kwargs): """ Creates and adds a ride to the app database. @@ -27,13 +27,13 @@ def create_ride(self, **Kwargs): date_offered = datetime.now().strftime('%b %d %Y %H:%M%p') self.new_ride = Ride( ride_id=ride_id, - departure=Kwargs['departure'], - origin=Kwargs['origin'], - destination=Kwargs['destination'], + departure=kwargs['departure'], + origin=kwargs['origin'], + destination=kwargs['destination'], vehicle_number_plate= - Kwargs['vehicle_number_plate'], - capacity=Kwargs['capacity'], - cost=Kwargs['cost'], + kwargs['vehicle_number_plate'], + capacity=kwargs['capacity'], + cost=kwargs['cost'], date_offered=date_offered, availability='available') ride = self.new_ride.__dict__ diff --git a/ridemyway/controllers/ride_request_controller.py b/ridemyway/controllers/ride_request_controller.py index d5fd137..17db60c 100644 --- a/ridemyway/controllers/ride_request_controller.py +++ b/ridemyway/controllers/ride_request_controller.py @@ -9,7 +9,7 @@ class RequestController(): Controls all CRUD operations of the Request object. """ - def create_request(self, **Kwargs): + def create_request(self, **kwargs): """ Creates and adds a request to the app database. @@ -18,7 +18,7 @@ def create_request(self, **Kwargs): failed status otherwise. """ try: - app.database['Rides'][Kwargs['ride_id']] + app.database['Rides'][kwargs['ride_id']] request_ids = [x for x in app.database['Requests']] if request_ids: request_id = max(request_ids) + 1 @@ -26,7 +26,7 @@ def create_request(self, **Kwargs): request_id = 1 self.new_request = Request( request_id=request_id, - ride_id=Kwargs['ride_id'], + ride_id=kwargs['ride_id'], status='available' ) request = self.new_request.__dict__ diff --git a/ridemyway/models/request.py b/ridemyway/models/request.py index 8c8435b..153475e 100644 --- a/ridemyway/models/request.py +++ b/ridemyway/models/request.py @@ -2,7 +2,7 @@ class Request(): """ Creates Request objects. - **Kwargs: + **kwargs: ride_id: A unique identifier of the ride the request is being made to. request_id: A unique identifier for the request. diff --git a/ridemyway/models/ride.py b/ridemyway/models/ride.py index 3260a27..b456665 100644 --- a/ridemyway/models/ride.py +++ b/ridemyway/models/ride.py @@ -2,7 +2,7 @@ class Ride(): """ Creates Ride objects. - **Kwargs: + **kwargs: ride_id: A unique identifier for the ride. departure: Date and time the ride is to take place. origin: Place where the ride starts.