API & Client: filter activities - fix #3

This commit is contained in:
Sam 2018-06-07 21:01:46 +02:00
parent f45db7b969
commit 76b2d5aad2
8 changed files with 92 additions and 32 deletions

View File

@ -10,9 +10,10 @@ from sqlalchemy import exc
from ..users.utils import authenticate, verify_extension from ..users.utils import authenticate, verify_extension
from .models import Activity from .models import Activity
from .utils import ( from .utils import (
ActivityException, convert_in_duration, create_activity, edit_activity, ActivityException, create_activity, edit_activity, get_chart_data,
get_chart_data, process_files process_files
) )
from .utils_format import convert_in_duration
activities_blueprint = Blueprint('activities', __name__) activities_blueprint = Blueprint('activities', __name__)
@ -62,7 +63,8 @@ def get_activities(auth_user_id):
response_object = { response_object = {
'status': 'success', 'status': 'success',
'data': { 'data': {
'activities': [activity.serialize() for activity in activities] 'activities': [activity.serialize(params)
for activity in activities]
} }
} }
code = 200 code = 200

View File

@ -8,6 +8,8 @@ from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm.session import object_session from sqlalchemy.orm.session import object_session
from sqlalchemy.types import Enum from sqlalchemy.types import Enum
from .utils_format import convert_in_duration, convert_value_to_integer
record_types = [ record_types = [
'AS', # 'Best Average Speed' 'AS', # 'Best Average Speed'
'FD', # 'Farthest Distance' 'FD', # 'Farthest Distance'
@ -16,23 +18,6 @@ record_types = [
] ]
def convert_timedelta_to_integer(value):
hours, minutes, seconds = str(value).split(':')
return int(hours) * 3600 + int(minutes) * 60 + int(seconds)
def convert_value_to_integer(record_type, val):
if val is None:
return None
if record_type == 'LD':
return convert_timedelta_to_integer(val)
elif record_type in ['AS', 'MS']:
return int(val * 100)
else: # 'FD'
return int(val * 1000)
def update_records(user_id, sport_id, connection, session): def update_records(user_id, sport_id, connection, session):
record_table = Record.__table__ record_table = Record.__table__
new_records = Activity.get_user_activity_records( new_records = Activity.get_user_activity_records(
@ -161,18 +146,61 @@ class Activity(db.Model):
self.distance = distance self.distance = distance
self.duration = duration self.duration = duration
def serialize(self): def serialize(self, params=None):
date_from = params.get('from') if params else None
date_to = params.get('to') if params else None
distance_from = params.get('distance_from') if params else None
distance_to = params.get('distance_to') if params else None
duration_from = params.get('duration_from') if params else None
duration_to = params.get('duration_to') if params else None
ave_speed_from = params.get('ave_speed_from') if params else None
ave_speed_to = params.get('ave_speed_to') if params else None
sport_id = params.get('sport_id') if params else None
previous_activity = Activity.query.filter( previous_activity = Activity.query.filter(
Activity.id != self.id, Activity.id != self.id,
Activity.user_id == self.user_id, Activity.user_id == self.user_id,
Activity.activity_date <= self.activity_date Activity.sport_id == sport_id if sport_id else True,
Activity.activity_date <= self.activity_date,
Activity.activity_date >= datetime.datetime.strptime(
date_from, '%Y-%m-%d'
) if date_from else True,
Activity.activity_date <= datetime.datetime.strptime(
date_to, '%Y-%m-%d'
) if date_to else True,
Activity.distance >= int(distance_from) if distance_from else True,
Activity.distance <= int(distance_to) if distance_to else True,
Activity.duration >= convert_in_duration(duration_from)
if duration_from else True,
Activity.duration <= convert_in_duration(duration_to)
if duration_to else True,
Activity.ave_speed >= float(ave_speed_from)
if ave_speed_from else True,
Activity.ave_speed <= float(ave_speed_to)
if ave_speed_to else True,
).order_by( ).order_by(
Activity.activity_date.desc() Activity.activity_date.desc()
).first() ).first()
next_activity = Activity.query.filter( next_activity = Activity.query.filter(
Activity.id != self.id, Activity.id != self.id,
Activity.user_id == self.user_id, Activity.user_id == self.user_id,
Activity.activity_date >= self.activity_date Activity.sport_id == sport_id if sport_id else True,
Activity.activity_date >= self.activity_date,
Activity.activity_date >= datetime.datetime.strptime(
date_from, '%Y-%m-%d'
) if date_from else True,
Activity.activity_date <= datetime.datetime.strptime(
date_to, '%Y-%m-%d'
) if date_to else True,
Activity.distance >= int(distance_from) if distance_from else True,
Activity.distance <= int(distance_to) if distance_to else True,
Activity.duration >= convert_in_duration(duration_from)
if duration_from else True,
Activity.duration <= convert_in_duration(duration_to)
if duration_to else True,
Activity.ave_speed >= float(ave_speed_from)
if ave_speed_from else True,
Activity.ave_speed <= float(ave_speed_to)
if ave_speed_to else True,
).order_by( ).order_by(
Activity.activity_date.asc() Activity.activity_date.asc()
).first() ).first()

View File

@ -5,7 +5,8 @@ from flask import Blueprint, jsonify, request
from ..users.models import User from ..users.models import User
from ..users.utils import authenticate from ..users.utils import authenticate
from .models import Activity, Sport, convert_timedelta_to_integer from .models import Activity, Sport
from .utils_format import convert_timedelta_to_integer
stats_blueprint = Blueprint('stats', __name__) stats_blueprint = Blueprint('stats', __name__)

View File

@ -360,9 +360,3 @@ def process_files(auth_user_id, activity_data, activity_file, folders):
return [process_one_gpx_file(common_params, filename)] return [process_one_gpx_file(common_params, filename)]
else: else:
return process_zip_archive(common_params, folders['extract_dir']) return process_zip_archive(common_params, folders['extract_dir'])
def convert_in_duration(value):
hours = int(value.split(':')[0])
minutes = int(value.split(':')[1])
return timedelta(seconds=(hours*3600 + minutes*60))

View File

@ -0,0 +1,24 @@
from datetime import timedelta
def convert_in_duration(value):
hours = int(value.split(':')[0])
minutes = int(value.split(':')[1])
return timedelta(seconds=(hours*3600 + minutes*60))
def convert_timedelta_to_integer(value):
hours, minutes, seconds = str(value).split(':')
return int(hours) * 3600 + int(minutes) * 60 + int(seconds)
def convert_value_to_integer(record_type, val):
if val is None:
return None
if record_type == 'LD':
return convert_timedelta_to_integer(val)
elif record_type in ['AS', 'MS']:
return int(val * 100)
else: # 'FD'
return int(val * 1000)

View File

@ -6,7 +6,7 @@ export default function ActivitiesList (props) {
const { activities, sports } = props const { activities, sports } = props
return ( return (
<div className="card"> <div className="card">
<div className="card-bord"> <div className="card-body">
<table className="table"> <table className="table">
<thead> <thead>
<tr> <tr>

View File

@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import { Helmet } from 'react-helmet' import { Helmet } from 'react-helmet'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import ActivitiesFilter from './ActivitiesFilter' import ActivitiesFilter from './ActivitiesFilter'
import ActivitiesList from './ActivitiesList' import ActivitiesList from './ActivitiesList'
@ -75,6 +76,16 @@ class Activities extends React.Component {
}} }}
/> />
} }
{activities.length === 0 && (
<div className="card text-center">
<div className="card-body">
No workouts. {' '}
<Link to={{ pathname: '/activities/add' }}>
Upload one !
</Link>
</div>
</div>
)}
</div> </div>
</div> </div>
</div> </div>

View File

@ -54,7 +54,7 @@ function NavBar(props) {
pathname: '/activities/add', pathname: '/activities/add',
}} }}
> >
Add workout <strong>Add workout</strong>
</Link> </Link>
</li> </li>
)} )}