ba-thesis/app/withings/models.py

91 lines
3.2 KiB
Python

from datetime import datetime, timedelta
from django.db import models, IntegrityError
from django.contrib.auth.models import User
from django.conf import settings
from django.utils import timezone
import requests
from . import api
class AccessToken(models.Model):
account = models.OneToOneField("ApiAccount", on_delete=models.CASCADE, primary_key=True)
value = models.CharField(max_length=256, verbose_name="Withings API Access Token")
expires = models.DateTimeField(verbose_name="Time of expiration")
class RefreshToken(models.Model):
account = models.OneToOneField("ApiAccount", on_delete=models.CASCADE, primary_key=True)
value = models.CharField(max_length=256, verbose_name="Withings API Refresh Token")
expires = models.DateTimeField(verbose_name="Time of expiration")
class ApiAccount(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
userid = models.PositiveIntegerField(verbose_name="Withings API User ID")
last_update = models.DateTimeField(null=True, default=None, verbose_name="Time of last synchronization with Withings API")
def refresh_tokens(self):
data = {
'action': 'requesttoken',
'client_id': settings.WITHINGS_CONFIG['CLIENT_ID'],
'client_secret': settings.WITHINGS_CONFIG['CLIENT_SECRET'],
'grant_type': 'refresh_token',
'refresh_token': self.refreshtoken.value
}
response = requests.post(
url=settings.WITHINGS_CONFIG['ENDPOINT_URL_OAUTH2'],
json=data
)
if response is not None:
response.raise_for_status()
response_data = response.json()
now = timezone.now()
self.accesstoken.value = response_data['body']['access_token']
self.accesstoken.expires = now + timedelta(seconds=response_data['body']['expires_in'])
self.refreshtoken.value = response_data['body']['refresh_token']
self.refreshtoken.expires = now + timedelta(days=365)
self.accesstoken.save()
self.refreshtoken.save()
def get_measurements(self, since: datetime | None = None) -> list:
if self.accesstoken.expires < timezone.now():
self.refresh_tokens()
params={
'action': 'getmeas',
'meastypes': '9,10,11,54,71'
}
if since:
params['lastupdate'] = str(int(since.timestamp()))
response = requests.get(
url="https://wbsapi.withings.net/measure",
params=params,
headers={
'Authorization': f"Bearer {self.accesstoken.value}"
}
)
if response is not None:
response.raise_for_status()
data = response.json()
if data['status'] != 0:
raise RuntimeError(f"Received status {data['status']} while retrieving measurements: {data['error']}")
return api.parse_getmeas_response(data, self.user)
def update_records(self):
records = self.get_measurements(self.last_update)
for record in records:
try:
record.save()
except IntegrityError:
pass
self.last_update = timezone.now()
self.save()