Skip to content

Commit

Permalink
Merge 2b4ae2c into 6bb7863
Browse files Browse the repository at this point in the history
  • Loading branch information
RrNn committed Aug 22, 2018
2 parents 6bb7863 + 2b4ae2c commit 4d991f3
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 0 deletions.
5 changes: 5 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ django-cors-headers

# Python3 compatibility
six

#fitbit
django-fitbit==0.3.0
fitbit==0.3.0

12 changes: 12 additions & 0 deletions wger/core/templates/user/fitbit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{% extends "base.html" %}
{% load i18n staticfiles wger_extras %}
{% block title %}
<div class="text-center">
{% trans "Click the button below to sync your fitbit data" %}
</div>
{% endblock %}

{% block content %}

<a href="{{ fitbit_authentication }}" class="btn btn-primary btn-block"> Connect with Fitbit. </a>
{% endblock %}
3 changes: 3 additions & 0 deletions wger/core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,15 @@
url(r'^(?P<pk>\d+)/overview',
user.UserDetailView.as_view(),
name='overview'),
url(r'^fitbit$', user.fitbit_data,
name='fitbit'),
url(r'',
user.UserListView.as_view(),
name='list'),




# Password reset is implemented by Django, no need to cook our own soup here
# (besides the templates)
url(r'^password/change$',
Expand Down
61 changes: 61 additions & 0 deletions wger/core/views/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@
#
# You should have received a copy of the GNU Affero General Public License

import requests
import base64
import datetime
import os
from fitbit import FitbitOauth2Client


import logging

from django.shortcuts import render, get_object_or_404
Expand Down Expand Up @@ -587,3 +594,57 @@ def get_context_data(self, **kwargs):
"active": self.active,
}
return context


@login_required
def fitbit_data(request):
'''
Connect the users fitbit account to wger
'''
template_data = {}
client_id = os.environ.get('FITBIT_WEIGHT_CLIENT_ID')
client_secret = os.environ.get('FITBIT_WEIGHT_CLIENT_SECRET')
redirect_uri = 'http://127.0.0.1:8000/en/users/fitbit'
client = FitbitOauth2Client(client_id, client_secret)
"""
Fitbit redirects back with a code in the url and
the code is now used to used to get the access_token
"""

if 'code' in request.GET:
code = request.GET['code']
data = "client_id=" + client_id + "&" +\
"grant_type=" + "authorization_code" + "&" +\
"redirect_uri=" + redirect_uri + "&" +\
"code=" + code
headers = {
'Authorization': 'Basic ' +
base64.b64encode((client_id + ":" + client_secret).encode('UTF-8')).decode('ascii'),
'Content-Type': 'application/x-www-form-urlencoded'}
response = requests.post(client.request_token_url, data=data, headers=headers).json()
if 'access_token' in response:
token = response['access_token']
user_id = response['user_id']
headers = {
'Authorization': 'Bearer ' + token
}
response = requests.get('https://api.fitbit.com/1/user/' +
user_id + '/profile.json', headers=headers).json()
fitbit_weight = response['user']['weight']
# Save the weight data from fitbit into the wger database,for say, offline usecases.
# We won't have to go to fitbit to fetch it every time!, so we save it.
try:
weight = WeightEntry()
weight.weight = fitbit_weight
weight.user = request.user
weight.date = datetime.date.today()
weight.save()
messages.success(request, _('Weight data synced sucessfully!'))
except Exception:
messages.success(request, _('Already synced ' +
request.user.username + '\'s weight data from fitbit.'))
return HttpResponseRedirect(reverse('weight:overview',
kwargs={'username': request.user.username}))
template_data['fitbit_authentication'] = client.authorize_token_url(
redirect_uri=redirect_uri)[0]
return render(request, 'user/fitbit.html', template_data)
111 changes: 111 additions & 0 deletions wger/exercises/templates/exercise/fitbit.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
{% extends "base.html" %}
{% load i18n staticfiles wger_extras %}

{# #}
{# Title #}
{# #}
{% block title %}{% trans "Fitbit Exercise data" %}
{% endblock %}

{# #}
{# Header #}
{# #}
{% block header %}

{% endblock %}



{# #}
{# Content #}
{# #}
{% block content %}

<div id="current-username" data-current-username="{{ owner_user.username }}"></div>


{% if not data %}
<p>
{% trans "There is no chart here because fibit hasnt synced." %}
<a href="{{ fitbit_authentication }}"> Connect to view your fitbit exercises . </a>

</p>
{% endif %}

{% if data %}
<table class="table">
<legend class="text-center">Your Fitbit exercise data</legend>
<tr>
<th>{% trans 'Activity Name' %}</th>
<th>{% trans 'Calories' %}</th>
<th>{% trans 'Duration (milisecs)' %}</th>
<th>{% trans 'Discription' %}</th>
<th>{% trans 'Distance' %}</th>
</tr>
{% for datum in data %}
<tr>
<td>
{{ datum.name }}
</td>
<td>
{% if datum.calories %}
{{ datum.calories }}
{% else %}
{% trans 'N/A' %}
{% endif %}
</td>

<td>
{% if datum.description %}
{{ datum.duration }}
{% else %}
{% trans 'N/A'%}
{% endif %}
</td>
<td>
{% if datum.description %}
{{ datum.description }}
{% else %}
{% trans 'N/A' %}
{% endif %}
</td>
<td>
{% if datum.distance%}
{{datum.distance}}
{% else %}
{% trans 'N/A' %}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
{% endif %}
<!-- Since we are not persisting fitbit data,
reloading will lead to losing it so we prompt the user -->
{% if data %}
<script>
window.onbeforeunload = function (evt) {
var message = 'Are you sure you want to leave?';
if (typeof evt == 'undefined') {
evt = window.event;
}
if (evt) {
evt.returnValue = message;
}
return message;
}
</script>
{% endif %}
{% endblock %}

{# #}
{# Side bar #}
{# #}
{% block sidebar %}
{% endblock %}

{# #}
{# Options #}
{# #}
{% block options %}
{% endblock %}
3 changes: 3 additions & 0 deletions wger/exercises/templates/exercise/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ <h4>{% trans "Search" %}</h4>
<a href="{% url 'exercise:exercise:add' %}" class="btn btn-success btn-sm">
{% trans "Add new exercise" %}
</a>
<a href="{% url 'exercise:exercise:fitbit' %}" class="btn btn-info btn-sm">
{% trans "Sync fitbit" %}
</a>
{% else %}
<a href="#" class="btn btn-success btn-sm disabled">
{% trans "Add new exercise" %}<br>
Expand Down
1 change: 1 addition & 0 deletions wger/exercises/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
url(r'^(?P<pk>\d+)/decline/$',
exercises.decline,
name='decline'),
url(r'fitbit', exercises.fitbit_data, name='fitbit'),
]


Expand Down
51 changes: 51 additions & 0 deletions wger/exercises/views/exercises.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
import requests
import base64
import datetime
import os
from fitbit import FitbitOauth2Client

import six
import logging
import uuid
Expand Down Expand Up @@ -368,3 +374,48 @@ def decline(request, pk):
exercise.save()
messages.success(request, _('Exercise was successfully marked as rejected'))
return HttpResponseRedirect(exercise.get_absolute_url())


# @login_required
def fitbit_data(request):
'''
Connect the users fitbit account to wger
'''
template_data = {}
client_id = os.environ.get('FITBIT_EXERCISE_CLIENT_ID')
client_secret = os.environ.get('FITBIT_EXERCISE_CLIENT_SECRET')
redirect_uri = os.environ.get('FITBIT_EXERCISE_REDIRECT')

client = FitbitOauth2Client(client_id, client_secret)
"""
Fitbit redirects back with a code in the url and
the code is now used to used to get the access_token
"""

if 'code' in request.GET:
code = request.GET['code']
data = "client_id=" + client_id + "&" +\
"grant_type=" + "authorization_code" + "&" +\
"redirect_uri=" + redirect_uri + "&" +\
"code=" + code
headers = {
'Authorization': 'Basic ' +
base64.b64encode((client_id + ":" + client_secret).encode('UTF-8')).decode('ascii'),
'Content-Type': 'application/x-www-form-urlencoded'}
response = requests.post(client.request_token_url, data=data, headers=headers).json()
if 'access_token' in response:
token = response['access_token']
user_id = response['user_id']
headers = {
'Authorization': 'Bearer ' + token
}

response = requests.get('https://api.fitbit.com/1/user/' +
user_id + '/activities/recent.json', headers=headers).json()
# print(response[0])
template_data['data'] = response

return render(request, 'exercise/fitbit.html', template_data)
template_data['fitbit_authentication'] = client.authorize_token_url(
redirect_uri=redirect_uri)[0]
return render(request, 'exercise/fitbit.html', template_data)
2 changes: 2 additions & 0 deletions wger/weight/templates/overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,7 @@
<a href="{% url 'weight:add' %}" class="btn btn-success btn-sm wger-modal-dialog">
{% trans "Add" %}
</a>
<a class="btn btn-info btn-sm" href="{% url 'core:user:fitbit' %}" role="button">Sync fitbit</a>
</a>
{% endif %}
{% endblock %}

0 comments on commit 4d991f3

Please sign in to comment.