API & Client - display only active sports when adding an activity

This commit is contained in:
Sam
2019-09-23 14:09:26 +02:00
parent a9cbe220ac
commit 8a4b114af8
13 changed files with 413 additions and 101 deletions

View File

@ -74,16 +74,16 @@ class Sport(db.Model):
def __init__(self, label):
self.label = label
def serialize(self):
return {
def serialize(self, is_admin=False):
serialized_sport = {
'id': self.id,
'label': self.label,
'img': self.img,
'is_active': self.is_active,
'_can_be_disabled': not (
len(self.activities) > 0 and self.is_active
),
}
if is_admin:
serialized_sport['has_activities'] = len(self.activities) > 0
return serialized_sport
class Activity(db.Model):

View File

@ -2,6 +2,7 @@ from fittrackee_api import appLog, db
from flask import Blueprint, jsonify, request
from sqlalchemy import exc
from ..users.models import User
from ..users.utils import authenticate, authenticate_as_admin
from .models import Sport
@ -23,6 +24,8 @@ def get_sports(auth_user_id):
**Example response**:
- for non admin user :
.. sourcecode:: http
HTTP/1.1 200 OK
@ -32,42 +35,93 @@ def get_sports(auth_user_id):
"data": {
"sports": [
{
"_can_be_disabled": false,
"id": 1,
"img": "/img/sports/cycling-sport.png",
"is_active": true,
"label": "Cycling (Sport)"
},
{
"_can_be_disabled": false,
"id": 2,
"img": "/img/sports/cycling-transport.png",
"is_active": true,
"label": "Cycling (Transport)"
},
{
"_can_be_disabled": false,
"id": 3,
"img": "/img/sports/hiking.png",
"is_active": true,
"label": "Hiking"
},
{
"_can_be_disabled": false,
"id": 4,
"img": "/img/sports/mountain-biking.png",
"is_active": true,
"label": "Mountain Biking"
},
{
"_can_be_disabled": false,
"id": 5,
"img": "/img/sports/running.png",
"is_active": true,
"label": "Running"
},
{
"_can_be_disabled": false,
"id": 6,
"img": "/img/sports/walking.png",
"is_active": true,
"label": "Walking"
}
]
},
"status": "success"
}
- for admin user :
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"sports": [
{
"has_activities": true,
"id": 1,
"img": "/img/sports/cycling-sport.png",
"is_active": true,
"label": "Cycling (Sport)"
},
{
"has_activities": false,
"id": 2,
"img": "/img/sports/cycling-transport.png",
"is_active": true,
"label": "Cycling (Transport)"
},
{
"has_activities": false,
"id": 3,
"img": "/img/sports/hiking.png",
"is_active": true,
"label": "Hiking"
},
{
"has_activities": false,
"id": 4,
"img": "/img/sports/mountain-biking.png",
"is_active": true,
"label": "Mountain Biking"
},
{
"has_activities": false,
"id": 5,
"img": "/img/sports/running.png",
"is_active": true,
"label": "Running"
},
{
"has_activities": false,
"id": 6,
"img": "/img/sports/walking.png",
"is_active": true,
@ -90,10 +144,11 @@ def get_sports(auth_user_id):
"""
user = User.query.filter_by(id=int(auth_user_id)).first()
sports = Sport.query.order_by(Sport.id).all()
response_object = {
'status': 'success',
'data': {'sports': [sport.serialize() for sport in sports]},
'data': {'sports': [sport.serialize(user.admin) for sport in sports]},
}
return jsonify(response_object), 200
@ -101,7 +156,8 @@ def get_sports(auth_user_id):
@sports_blueprint.route('/sports/<int:sport_id>', methods=['GET'])
@authenticate
def get_sport(auth_user_id, sport_id):
"""Get a sport
"""
Get a sport
**Example request**:
@ -112,7 +168,7 @@ def get_sport(auth_user_id, sport_id):
**Example response**:
- success
- success for non admin user :
.. sourcecode:: http
@ -123,7 +179,28 @@ def get_sport(auth_user_id, sport_id):
"data": {
"sports": [
{
"_can_be_disabled": false,
"id": 1,
"img": "/img/sports/cycling-sport.png",
"is_active": true,
"label": "Cycling (Sport)"
}
]
},
"status": "success"
}
- success for admin user :
.. sourcecode:: http
HTTP/1.1 200 OK
Content-Type: application/json
{
"data": {
"sports": [
{
"has_activities": false,
"id": 1,
"img": "/img/sports/cycling-sport.png",
"is_active": true,
@ -162,11 +239,12 @@ def get_sport(auth_user_id, sport_id):
"""
user = User.query.filter_by(id=int(auth_user_id)).first()
sport = Sport.query.filter_by(id=sport_id).first()
if sport:
response_object = {
'status': 'success',
'data': {'sports': [sport.serialize()]},
'data': {'sports': [sport.serialize(user.admin)]},
}
code = 200
else:
@ -178,7 +256,9 @@ def get_sport(auth_user_id, sport_id):
@sports_blueprint.route('/sports/<int:sport_id>', methods=['PATCH'])
@authenticate_as_admin
def update_sport(auth_user_id, sport_id):
"""Update a sport
"""
Update a sport
Authenticated user must be an admin
**Example request**:
@ -200,7 +280,7 @@ def update_sport(auth_user_id, sport_id):
"data": {
"sports": [
{
"_can_be_disabled": false,
"has_activities": false,
"id": 1,
"img": "/img/sports/cycling-sport.png",
"is_active": false,
@ -238,6 +318,7 @@ def update_sport(auth_user_id, sport_id):
- Provide a valid auth token.
- Signature expired. Please log in again.
- Invalid token. Please log in again.
:statuscode 403: You do not have permissions.
:statuscode 404: sport not found
:statuscode 500:
@ -250,24 +331,13 @@ def update_sport(auth_user_id, sport_id):
try:
sport = Sport.query.filter_by(id=sport_id).first()
if sport:
if not (
not sport_data.get('is_active')
and sport.is_active
and len(sport.activities) > 0
):
sport.is_active = sport_data.get('is_active')
db.session.commit()
response_object = {
'status': 'success',
'data': {'sports': [sport.serialize()]},
}
code = 200
else:
response_object = {
'status': 'fail',
'message': 'Sport can not be disabled, activities exist.',
}
code = 400
sport.is_active = sport_data.get('is_active')
db.session.commit()
response_object = {
'status': 'success',
'data': {'sports': [sport.serialize(True)]},
}
code = 200
else:
response_object = {'status': 'not found', 'data': {'sports': []}}
code = 404

View File

@ -107,6 +107,15 @@ def sport_1_cycling():
return sport
@pytest.fixture()
def sport_1_cycling_inactive():
sport = Sport(label='Cycling')
sport.is_active = False
db.session.add(sport)
db.session.commit()
return sport
@pytest.fixture()
def sport_2_running():
sport = Sport(label='Running')

View File

@ -5,16 +5,29 @@ expected_sport_1_cycling_result = {
'label': 'Cycling',
'img': None,
'is_active': True,
'_can_be_disabled': True,
}
expected_sport_1_cycling_admin_result = expected_sport_1_cycling_result.copy()
expected_sport_1_cycling_admin_result['has_activities'] = False
expected_sport_2_running_result = {
'id': 2,
'label': 'Running',
'img': None,
'is_active': True,
'_can_be_disabled': True,
}
expected_sport_2_running_admin_result = expected_sport_2_running_result.copy()
expected_sport_2_running_admin_result['has_activities'] = False
expected_sport_1_cycling_inactive_result = {
'id': 1,
'label': 'Cycling',
'img': None,
'is_active': False,
}
expected_sport_1_cycling_inactive_admin_result = (
expected_sport_1_cycling_inactive_result.copy()
)
expected_sport_1_cycling_inactive_admin_result['has_activities'] = False
def test_get_all_sports(app, user_1, sport_1_cycling, sport_2_running):
@ -41,6 +54,63 @@ def test_get_all_sports(app, user_1, sport_1_cycling, sport_2_running):
assert data['data']['sports'][1] == expected_sport_2_running_result
def test_get_all_sports_with_inactive_one(
app, user_1, sport_1_cycling_inactive, sport_2_running
):
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
response = client.get(
'/api/sports',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['sports']) == 2
assert (
data['data']['sports'][0] == expected_sport_1_cycling_inactive_result
)
assert data['data']['sports'][1] == expected_sport_2_running_result
def test_get_all_sports_admin(
app, user_1_admin, sport_1_cycling_inactive, sport_2_running
):
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='admin@example.com', password='12345678')),
content_type='application/json',
)
response = client.get(
'/api/sports',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['sports']) == 2
assert (
data['data']['sports'][0]
== expected_sport_1_cycling_inactive_admin_result
)
assert data['data']['sports'][1] == expected_sport_2_running_admin_result
def test_get_a_sport(app, user_1, sport_1_cycling):
client = app.test_client()
resp_login = client.post(
@ -85,6 +155,59 @@ def test_get_a_sport_invalid(app, user_1):
assert len(data['data']['sports']) == 0
def test_get_a_inactive_sport(app, user_1, sport_1_cycling_inactive):
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='test@test.com', password='12345678')),
content_type='application/json',
)
response = client.get(
'/api/sports/1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['sports']) == 1
assert (
data['data']['sports'][0] == expected_sport_1_cycling_inactive_result
)
def test_get_a_inactive_sport_as_admin(
app, user_1_admin, sport_1_cycling_inactive
):
client = app.test_client()
resp_login = client.post(
'/api/auth/login',
data=json.dumps(dict(email='admin@example.com', password='12345678')),
content_type='application/json',
)
response = client.get(
'/api/sports/1',
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['sports']) == 1
assert (
data['data']['sports'][0]
== expected_sport_1_cycling_inactive_admin_result
)
def test_update_a_sport(app, user_1_admin, sport_1_cycling):
client = app.test_client()
resp_login = client.post(
@ -108,6 +231,7 @@ def test_update_a_sport(app, user_1_admin, sport_1_cycling):
assert len(data['data']['sports']) == 1
assert data['data']['sports'][0]['is_active'] is False
assert data['data']['sports'][0]['has_activities'] is False
response = client.patch(
'/api/sports/1',
@ -125,9 +249,10 @@ def test_update_a_sport(app, user_1_admin, sport_1_cycling):
assert len(data['data']['sports']) == 1
assert data['data']['sports'][0]['is_active'] is True
assert data['data']['sports'][0]['has_activities'] is False
def test_disable_a_sport_with_activities(
def test_update_a_sport_with_activities(
app, user_1_admin, sport_1_cycling, activity_cycling_user_1
):
client = app.test_client()
@ -147,9 +272,30 @@ def test_disable_a_sport_with_activities(
)
data = json.loads(response.data.decode())
assert response.status_code == 400
assert 'fail' in data['status']
assert 'Sport can not be disabled, activities exist.' in data['message']
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['sports']) == 1
assert data['data']['sports'][0]['is_active'] is False
assert data['data']['sports'][0]['has_activities'] is True
response = client.patch(
'/api/sports/1',
content_type='application/json',
data=json.dumps(dict(is_active=True)),
headers=dict(
Authorization='Bearer '
+ json.loads(resp_login.data.decode())['auth_token']
),
)
data = json.loads(response.data.decode())
assert response.status_code == 200
assert 'success' in data['status']
assert len(data['data']['sports']) == 1
assert data['data']['sports'][0]['is_active'] is True
assert data['data']['sports'][0]['has_activities'] is True
def test_update_a_sport_not_admin(app, user_1, sport_1_cycling):

View File

@ -1,24 +1,29 @@
def test_sport_model(app, sport_1_cycling):
assert 1 == sport_1_cycling.id
assert 'Cycling' == sport_1_cycling.label
assert '<Sport \'Cycling\'>' == str(sport_1_cycling)
def assert_sport_model(sport, is_admin=False):
assert 1 == sport.id
assert 'Cycling' == sport.label
assert '<Sport \'Cycling\'>' == str(sport)
serialized_sport = sport_1_cycling.serialize()
serialized_sport = sport.serialize(is_admin)
assert 1 == serialized_sport['id']
assert 'Cycling' == serialized_sport['label']
assert serialized_sport['is_active'] is True
assert serialized_sport['_can_be_disabled'] is True
return serialized_sport
def test_sport_model(app, sport_1_cycling):
serialized_sport = assert_sport_model(sport_1_cycling)
assert 'has_activities' not in serialized_sport
def test_sport_model_with_activity(
app, sport_1_cycling, user_1, activity_cycling_user_1
):
assert 1 == sport_1_cycling.id
assert 'Cycling' == sport_1_cycling.label
assert '<Sport \'Cycling\'>' == str(sport_1_cycling)
serialized_sport = assert_sport_model(sport_1_cycling)
assert 'has_activities' not in serialized_sport
serialized_sport = sport_1_cycling.serialize()
assert 1 == serialized_sport['id']
assert 'Cycling' == serialized_sport['label']
assert serialized_sport['is_active'] is True
assert serialized_sport['_can_be_disabled'] is False
def test_sport_model_with_activity_admin(
app, sport_1_cycling, user_1, activity_cycling_user_1
):
serialized_sport = assert_sport_model(sport_1_cycling, True)
assert serialized_sport['has_activities'] is True