2023-07-29 19:43:41 +01:00
|
|
|
from datetime import datetime, timedelta
|
2023-07-27 15:37:18 +01:00
|
|
|
|
2023-07-29 19:43:41 +01:00
|
|
|
from django.db import models, IntegrityError
|
2023-07-27 15:37:18 +01:00
|
|
|
from django.contrib.auth.models import User
|
2023-07-29 02:41:45 +01:00
|
|
|
from django.conf import settings
|
|
|
|
from django.utils import timezone
|
|
|
|
import requests
|
2023-07-27 15:37:18 +01:00
|
|
|
|
2023-07-29 19:43:41 +01:00
|
|
|
from . import api
|
|
|
|
|
2023-07-27 15:37:18 +01:00
|
|
|
|
|
|
|
class AccessToken(models.Model):
|
2023-07-29 02:41:45 +01:00
|
|
|
account = models.OneToOneField("ApiAccount", on_delete=models.CASCADE, primary_key=True)
|
2023-07-27 15:37:18 +01:00
|
|
|
value = models.CharField(max_length=256, verbose_name="Withings API Access Token")
|
|
|
|
expires = models.DateTimeField(verbose_name="Time of expiration")
|
|
|
|
|
|
|
|
|
|
|
|
class RefreshToken(models.Model):
|
2023-07-29 02:41:45 +01:00
|
|
|
account = models.OneToOneField("ApiAccount", on_delete=models.CASCADE, primary_key=True)
|
2023-07-27 15:37:18 +01:00
|
|
|
value = models.CharField(max_length=256, verbose_name="Withings API Refresh Token")
|
|
|
|
expires = models.DateTimeField(verbose_name="Time of expiration")
|
2023-07-29 02:41:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
class ApiAccount(models.Model):
|
|
|
|
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
|
|
|
|
userid = models.PositiveIntegerField(verbose_name="Withings API User ID")
|
2023-07-29 19:43:41 +01:00
|
|
|
last_update = models.DateTimeField(null=True, default=None, verbose_name="Time of last synchronization with Withings API")
|
2023-07-29 02:41:45 +01:00
|
|
|
|
|
|
|
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()
|
2023-07-29 19:43:41 +01:00
|
|
|
|
|
|
|
|
|
|
|
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()
|