API & Client - add pagination and filter on users lists
This commit is contained in:
@ -31,6 +31,8 @@ from .utils_gpx import (
|
||||
|
||||
activities_blueprint = Blueprint('activities', __name__)
|
||||
|
||||
ACTIVITIES_PER_PAGE = 5
|
||||
|
||||
|
||||
@activities_blueprint.route('/activities', methods=['GET'])
|
||||
@authenticate
|
||||
@ -152,7 +154,8 @@ def get_activities(auth_user_id):
|
||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
||||
|
||||
:query integer page: page if using pagination (default: 1)
|
||||
:query integer per_page: number of activities per page (default: 5)
|
||||
:query integer per_page: number of activities per page
|
||||
(default: 5, max: 50)
|
||||
:query integer sport_id: sport id
|
||||
:query string from: start date (format: ``%Y-%m-%d``)
|
||||
:query string to: end date (format: ``%Y-%m-%d``)
|
||||
@ -200,7 +203,13 @@ def get_activities(auth_user_id):
|
||||
max_speed_to = params.get('max_speed_to')
|
||||
order = params.get('order')
|
||||
sport_id = params.get('sport_id')
|
||||
per_page = int(params.get('per_page')) if params.get('per_page') else 5
|
||||
per_page = (
|
||||
int(params.get('per_page'))
|
||||
if params.get('per_page')
|
||||
else ACTIVITIES_PER_PAGE
|
||||
)
|
||||
if per_page > 50:
|
||||
per_page = 50
|
||||
activities = (
|
||||
Activity.query.filter(
|
||||
Activity.user_id == auth_user_id,
|
||||
|
@ -158,7 +158,7 @@ def get_activities_by_time(auth_user_id, user_name):
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/stats/admin/by_time?from=2018-01-01&to=2018-06-30&time=week HTTP/1.1 # noqa
|
||||
GET /api/stats/admin/by_time?from=2018-01-01&to=2018-06-30&time=week HTTP/1.1
|
||||
|
||||
**Example responses**:
|
||||
|
||||
@ -346,7 +346,8 @@ def get_application_stats(auth_user_id):
|
||||
"data": {
|
||||
"activities": 3,
|
||||
"sports": 3,
|
||||
"users": 2
|
||||
"users": 2,
|
||||
"uploads_dir_size": 1000
|
||||
},
|
||||
"status": "success"
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ def update_application_config(auth_user_id):
|
||||
|
||||
|
||||
@config_blueprint.route('/ping', methods=['GET'])
|
||||
def ping_pong():
|
||||
def health_check():
|
||||
""" health check endpoint
|
||||
|
||||
**Example request**:
|
||||
|
@ -200,3 +200,13 @@ def test_update_config_no_config(app_no_config, user_1_admin):
|
||||
assert response.status_code == 500
|
||||
assert 'error' in data['status']
|
||||
assert 'Error on updating configuration.' in data['message']
|
||||
|
||||
|
||||
def test_ping(app):
|
||||
""" => Ensure the /ping route behaves correctly."""
|
||||
client = app.test_client()
|
||||
response = client.get('/api/ping')
|
||||
data = json.loads(response.data.decode())
|
||||
assert response.status_code == 200
|
||||
assert 'pong' in data['message']
|
||||
assert 'success' in data['status']
|
||||
|
@ -1,19 +1,11 @@
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
from io import BytesIO
|
||||
from unittest.mock import patch
|
||||
|
||||
from fittrackee_api.users.models import User
|
||||
|
||||
|
||||
def test_ping(app):
|
||||
""" => Ensure the /ping route behaves correctly."""
|
||||
client = app.test_client()
|
||||
response = client.get('/api/ping')
|
||||
data = json.loads(response.data.decode())
|
||||
assert response.status_code == 200
|
||||
assert 'pong' in data['message']
|
||||
assert 'success' in data['status']
|
||||
|
||||
|
||||
def test_single_user(app, user_1, user_2):
|
||||
"""=> Get single user details"""
|
||||
client = app.test_client()
|
||||
@ -183,6 +175,13 @@ def test_users_list(app, user_1, user_2, user_3):
|
||||
assert data['data']['users'][2]['sports_list'] == []
|
||||
assert data['data']['users'][2]['total_distance'] == 0
|
||||
assert data['data']['users'][2]['total_duration'] == '0:00:00'
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_users_list_with_activities(
|
||||
@ -246,6 +245,666 @@ def test_users_list_with_activities(
|
||||
assert data['data']['users'][2]['sports_list'] == []
|
||||
assert data['data']['users'][2]['total_distance'] == 0
|
||||
assert data['data']['users'][2]['total_duration'] == '0:00:00'
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
@patch('fittrackee_api.users.users.USER_PER_PAGE', 2)
|
||||
def test_it_gets_first_page_on_users_list(
|
||||
app, user_1, user_2, user_3,
|
||||
):
|
||||
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/users?page=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']['users']) == 2
|
||||
assert data['pagination'] == {
|
||||
'has_next': True,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 2,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
@patch('fittrackee_api.users.users.USER_PER_PAGE', 2)
|
||||
def test_it_gets_next_page_on_users_list(
|
||||
app, user_1, user_2, user_3,
|
||||
):
|
||||
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/users?page=2',
|
||||
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']['users']) == 1
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': True,
|
||||
'page': 2,
|
||||
'pages': 2,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_empty_next_page_on_users_list(
|
||||
app, user_1, user_2, user_3,
|
||||
):
|
||||
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/users?page=2',
|
||||
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']['users']) == 0
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': True,
|
||||
'page': 2,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_user_list_with_2_per_page(
|
||||
app, user_1, user_2, user_3,
|
||||
):
|
||||
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/users?per_page=2',
|
||||
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']['users']) == 2
|
||||
assert data['pagination'] == {
|
||||
'has_next': True,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 2,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_next_page_on_user_list_with_2_per_page(
|
||||
app, user_1, user_2, user_3,
|
||||
):
|
||||
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/users?page=2&per_page=2',
|
||||
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']['users']) == 1
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': True,
|
||||
'page': 2,
|
||||
'pages': 2,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_username(app, user_1, user_2, user_3):
|
||||
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/users?order_by=username',
|
||||
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']['users']) == 3
|
||||
assert 'sam' in data['data']['users'][0]['username']
|
||||
assert 'test' in data['data']['users'][1]['username']
|
||||
assert 'toto' in data['data']['users'][2]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_username_ascending(
|
||||
app, user_1, user_2, user_3
|
||||
):
|
||||
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/users?order_by=username&order=asc',
|
||||
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']['users']) == 3
|
||||
assert 'sam' in data['data']['users'][0]['username']
|
||||
assert 'test' in data['data']['users'][1]['username']
|
||||
assert 'toto' in data['data']['users'][2]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_username_descending(
|
||||
app, user_1, user_2, user_3
|
||||
):
|
||||
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/users?order_by=username&order=desc',
|
||||
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']['users']) == 3
|
||||
assert 'toto' in data['data']['users'][0]['username']
|
||||
assert 'test' in data['data']['users'][1]['username']
|
||||
assert 'sam' in data['data']['users'][2]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_creation_date(
|
||||
app, user_2, user_3, user_1_admin
|
||||
):
|
||||
user_2.created_at = datetime.utcnow() - timedelta(days=1)
|
||||
user_3.created_at = datetime.utcnow() - timedelta(hours=1)
|
||||
user_1_admin.created_at = datetime.utcnow()
|
||||
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/users?order_by=created_at',
|
||||
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']['users']) == 3
|
||||
assert 'toto' in data['data']['users'][0]['username']
|
||||
assert 'sam' in data['data']['users'][1]['username']
|
||||
assert 'admin' in data['data']['users'][2]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_creation_date_ascending(
|
||||
app, user_2, user_3, user_1_admin
|
||||
):
|
||||
user_2.created_at = datetime.utcnow() - timedelta(days=1)
|
||||
user_3.created_at = datetime.utcnow() - timedelta(hours=1)
|
||||
user_1_admin.created_at = datetime.utcnow()
|
||||
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/users?order_by=created_at&order=asc',
|
||||
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']['users']) == 3
|
||||
assert 'toto' in data['data']['users'][0]['username']
|
||||
assert 'sam' in data['data']['users'][1]['username']
|
||||
assert 'admin' in data['data']['users'][2]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_creation_date_descending(
|
||||
app, user_2, user_3, user_1_admin
|
||||
):
|
||||
user_2.created_at = datetime.utcnow() - timedelta(days=1)
|
||||
user_3.created_at = datetime.utcnow() - timedelta(hours=1)
|
||||
user_1_admin.created_at = datetime.utcnow()
|
||||
|
||||
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/users?order_by=created_at&order=desc',
|
||||
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']['users']) == 3
|
||||
assert 'admin' in data['data']['users'][0]['username']
|
||||
assert 'sam' in data['data']['users'][1]['username']
|
||||
assert 'toto' in data['data']['users'][2]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_admin_rights(
|
||||
app, user_2, user_1_admin, user_3
|
||||
):
|
||||
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/users?order_by=admin',
|
||||
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']['users']) == 3
|
||||
assert 'toto' in data['data']['users'][0]['username']
|
||||
assert 'sam' in data['data']['users'][1]['username']
|
||||
assert 'admin' in data['data']['users'][2]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_admin_rights_ascending(
|
||||
app, user_2, user_1_admin, user_3
|
||||
):
|
||||
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/users?order_by=admin&order=asc',
|
||||
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']['users']) == 3
|
||||
assert 'toto' in data['data']['users'][0]['username']
|
||||
assert 'sam' in data['data']['users'][1]['username']
|
||||
assert 'admin' in data['data']['users'][2]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_admin_rights_descending(
|
||||
app, user_2, user_3, user_1_admin
|
||||
):
|
||||
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/users?order_by=admin&order=desc',
|
||||
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']['users']) == 3
|
||||
assert 'admin' in data['data']['users'][0]['username']
|
||||
assert 'toto' in data['data']['users'][1]['username']
|
||||
assert 'sam' in data['data']['users'][2]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_activities_count(
|
||||
app, user_1, user_2, user_3, sport_1_cycling, activity_cycling_user_2,
|
||||
):
|
||||
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/users?order_by=activities_count',
|
||||
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']['users']) == 3
|
||||
assert 'test' in data['data']['users'][0]['username']
|
||||
assert 0 == data['data']['users'][0]['nb_activities']
|
||||
assert 'sam' in data['data']['users'][1]['username']
|
||||
assert 0 == data['data']['users'][1]['nb_activities']
|
||||
assert 'toto' in data['data']['users'][2]['username']
|
||||
assert 1 == data['data']['users'][2]['nb_activities']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_activities_count_ascending(
|
||||
app, user_1, user_2, user_3, sport_1_cycling, activity_cycling_user_2,
|
||||
):
|
||||
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/users?order_by=activities_count&order=asc',
|
||||
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']['users']) == 3
|
||||
assert 'test' in data['data']['users'][0]['username']
|
||||
assert 0 == data['data']['users'][0]['nb_activities']
|
||||
assert 'sam' in data['data']['users'][1]['username']
|
||||
assert 0 == data['data']['users'][1]['nb_activities']
|
||||
assert 'toto' in data['data']['users'][2]['username']
|
||||
assert 1 == data['data']['users'][2]['nb_activities']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_ordered_by_activities_count_descending(
|
||||
app, user_1, user_2, user_3, sport_1_cycling, activity_cycling_user_2,
|
||||
):
|
||||
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/users?order_by=activities_count&order=desc',
|
||||
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']['users']) == 3
|
||||
assert 'toto' in data['data']['users'][0]['username']
|
||||
assert 1 == data['data']['users'][0]['nb_activities']
|
||||
assert 'test' in data['data']['users'][1]['username']
|
||||
assert 0 == data['data']['users'][1]['nb_activities']
|
||||
assert 'sam' in data['data']['users'][2]['username']
|
||||
assert 0 == data['data']['users'][2]['nb_activities']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_it_gets_users_list_filtering_on_username(app, user_1, user_2, user_3):
|
||||
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/users?q=toto',
|
||||
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']['users']) == 1
|
||||
assert 'toto' in data['data']['users'][0]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 1,
|
||||
'total': 1,
|
||||
}
|
||||
|
||||
|
||||
def test_it_returns_empty_users_list_filtering_on_username(
|
||||
app, user_1, user_2, user_3
|
||||
):
|
||||
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/users?q=not_existing',
|
||||
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']['users']) == 0
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': False,
|
||||
'page': 1,
|
||||
'pages': 0,
|
||||
'total': 0,
|
||||
}
|
||||
|
||||
|
||||
def test_it_users_list_with_complex_query(app, user_1, user_2, user_3):
|
||||
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/users?order_by=username&order=desc&page=2&per_page=2',
|
||||
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']['users']) == 1
|
||||
assert 'sam' in data['data']['users'][0]['username']
|
||||
assert data['pagination'] == {
|
||||
'has_next': False,
|
||||
'has_prev': True,
|
||||
'page': 2,
|
||||
'pages': 2,
|
||||
'total': 3,
|
||||
}
|
||||
|
||||
|
||||
def test_encode_auth_token(app, user_1):
|
||||
|
@ -4,6 +4,8 @@ import jwt
|
||||
from fittrackee_api import bcrypt, db
|
||||
from flask import current_app
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.sql.expression import select
|
||||
|
||||
from ..activities.models import Activity
|
||||
|
||||
@ -88,13 +90,22 @@ class User(db.Model):
|
||||
except jwt.InvalidTokenError:
|
||||
return 'Invalid token. Please log in again.'
|
||||
|
||||
@hybrid_property
|
||||
def activities_count(self):
|
||||
return Activity.query.filter(Activity.user_id == self.id).count()
|
||||
|
||||
@activities_count.expression
|
||||
def activities_count(self):
|
||||
return (
|
||||
select([func.count(Activity.id)])
|
||||
.where(Activity.user_id == self.id)
|
||||
.label("activities_count")
|
||||
)
|
||||
|
||||
def serialize(self):
|
||||
nb_activity = Activity.query.filter(
|
||||
Activity.user_id == self.id
|
||||
).count()
|
||||
sports = []
|
||||
total = (None, None)
|
||||
if nb_activity > 0:
|
||||
if self.activities_count > 0:
|
||||
sports = (
|
||||
db.session.query(Activity.sport_id)
|
||||
.filter(Activity.user_id == self.id)
|
||||
@ -123,7 +134,7 @@ class User(db.Model):
|
||||
'timezone': self.timezone,
|
||||
'weekm': self.weekm,
|
||||
'language': self.language,
|
||||
'nb_activities': nb_activity,
|
||||
'nb_activities': self.activities_count,
|
||||
'nb_sports': len(sports),
|
||||
'sports_list': [
|
||||
sport for sportslist in sports for sport in sportslist
|
||||
|
@ -11,6 +11,8 @@ from .utils import authenticate, authenticate_as_admin
|
||||
|
||||
users_blueprint = Blueprint('users', __name__)
|
||||
|
||||
USER_PER_PAGE = 10
|
||||
|
||||
|
||||
@users_blueprint.route('/users', methods=['GET'])
|
||||
@authenticate
|
||||
@ -20,9 +22,18 @@ def get_users(auth_user_id):
|
||||
|
||||
**Example request**:
|
||||
|
||||
- without parameters
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/users HTTP/1.1
|
||||
GET /api/users/ HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
- with some query parameters
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/users?order_by=activities_count&par_page=5 HTTP/1.1
|
||||
Content-Type: application/json
|
||||
|
||||
**Example response**:
|
||||
@ -84,6 +95,13 @@ def get_users(auth_user_id):
|
||||
|
||||
:param integer auth_user_id: authenticate user id (from JSON Web Token)
|
||||
|
||||
:query integer page: page if using pagination (default: 1)
|
||||
:query integer per_page: number of users per page (default: 10, max: 50)
|
||||
:query string q: query on user name
|
||||
:query string order_by: sorting criteria (``username``, ``created_at``,
|
||||
``activities_count``, ``admin``)
|
||||
:query string order: sorting order (default: ``asc``)
|
||||
|
||||
:reqheader Authorization: OAuth 2.0 Bearer Token
|
||||
|
||||
:statuscode 200: success
|
||||
@ -93,10 +111,61 @@ def get_users(auth_user_id):
|
||||
- Invalid token. Please log in again.
|
||||
|
||||
"""
|
||||
users = User.query.all()
|
||||
params = request.args.copy()
|
||||
page = 1 if 'page' not in params.keys() else int(params.get('page'))
|
||||
per_page = (
|
||||
int(params.get('per_page'))
|
||||
if params.get('per_page')
|
||||
else USER_PER_PAGE
|
||||
)
|
||||
if per_page > 50:
|
||||
per_page = 50
|
||||
order_by = params.get('order_by')
|
||||
order = params.get('order', 'asc')
|
||||
query = params.get('q')
|
||||
users_pagination = (
|
||||
User.query.filter(
|
||||
User.username.like('%' + query + '%') if query else True,
|
||||
)
|
||||
.order_by(
|
||||
User.activities_count.asc()
|
||||
if order_by == 'activities_count' and order == 'asc'
|
||||
else True,
|
||||
User.activities_count.desc()
|
||||
if order_by == 'activities_count' and order == 'desc'
|
||||
else True,
|
||||
User.username.asc()
|
||||
if order_by == 'username' and order == 'asc'
|
||||
else True,
|
||||
User.username.desc()
|
||||
if order_by == 'username' and order == 'desc'
|
||||
else True,
|
||||
User.created_at.asc()
|
||||
if order_by == 'created_at' and order == 'asc'
|
||||
else True,
|
||||
User.created_at.desc()
|
||||
if order_by == 'created_at' and order == 'desc'
|
||||
else True,
|
||||
User.admin.asc()
|
||||
if order_by == 'admin' and order == 'asc'
|
||||
else True,
|
||||
User.admin.desc()
|
||||
if order_by == 'admin' and order == 'desc'
|
||||
else True,
|
||||
)
|
||||
.paginate(page, per_page, False)
|
||||
)
|
||||
users = users_pagination.items
|
||||
response_object = {
|
||||
'status': 'success',
|
||||
'data': {'users': [user.serialize() for user in users]},
|
||||
'pagination': {
|
||||
'has_next': users_pagination.has_next,
|
||||
'has_prev': users_pagination.has_prev,
|
||||
'page': users_pagination.page,
|
||||
'pages': users_pagination.pages,
|
||||
'total': users_pagination.total,
|
||||
},
|
||||
}
|
||||
return jsonify(response_object), 200
|
||||
|
||||
@ -227,6 +296,7 @@ def get_picture(user_name):
|
||||
def update_user(auth_user_id, user_name):
|
||||
"""
|
||||
Update user to add admin rights
|
||||
|
||||
Only user with admin rights can modify another user
|
||||
|
||||
**Example request**:
|
||||
@ -321,12 +391,14 @@ def update_user(auth_user_id, user_name):
|
||||
|
||||
@users_blueprint.route('/users/<user_name>', methods=['DELETE'])
|
||||
@authenticate
|
||||
def delete_activity(auth_user_id, user_name):
|
||||
def delete_user(auth_user_id, user_name):
|
||||
"""
|
||||
Delete a user account
|
||||
- a user can only delete his own account
|
||||
- an admin can delete all accounts except his account if he's the only
|
||||
one admin
|
||||
|
||||
A user can only delete his own account
|
||||
|
||||
An admin can delete all accounts except his account if he's the only
|
||||
one admin
|
||||
|
||||
**Example request**:
|
||||
|
||||
|
Reference in New Issue
Block a user