implemented a post request to add a device and did some refactoring

pull/79/head
Chris Veilleux 2019-03-20 17:17:40 -05:00
parent 8f4e10aa4d
commit 3bd458476a
2 changed files with 116 additions and 7 deletions

View File

@ -64,7 +64,7 @@ device_endpoint = DeviceEndpoint.as_view('device_endpoint')
acct.add_url_rule(
'/api/devices',
view_func=device_endpoint,
methods=['GET']
methods=['GET', 'POST']
)
preferences_endpoint = AccountPreferencesEndpoint.as_view(

View File

@ -1,25 +1,68 @@
from dataclasses import asdict
from http import HTTPStatus
from logging import getLogger
from flask import json
from schematics import Model
from schematics.types import StringType
from schematics.exceptions import ValidationError
from selene.api import SeleneEndpoint
from selene.data.device import DeviceRepository
from selene.util.cache import SeleneCache
from selene.util.db import get_db_connection
ONE_DAY = 86400
_log = getLogger()
def validate_pairing_code(pairing_code):
cache_key = 'pairing.code:' + pairing_code
cache = SeleneCache()
pairing_cache = cache.get(cache_key)
if pairing_cache is None:
raise ValidationError('pairing code not found')
class NewDeviceRequest(Model):
city = StringType(required=True)
country = StringType(required=True)
name = StringType(required=True)
pairing_code = StringType(required=True, validators=[validate_pairing_code])
placement = StringType()
region = StringType(required=True)
timezone = StringType(required=True)
wake_word = StringType(required=True)
voice = StringType(required=True)
class DeviceEndpoint(SeleneEndpoint):
def __init__(self):
super(DeviceEndpoint, self).__init__()
self.devices = None
self.cache = SeleneCache()
def get(self):
self._authenticate()
self._get_devices()
response_data = self._build_response()
return response_data, HTTPStatus.OK
def _get_devices(self):
with get_db_connection(self.config['DB_CONNECTION_POOL']) as db:
device_repository = DeviceRepository(db)
devices = device_repository.get_devices_by_account_id(
self.devices = device_repository.get_devices_by_account_id(
self.account.id
)
def _build_response(self):
response_data = []
for device in devices:
for device in self.devices:
wake_word = dict(
id=device.wake_word.id,
name=device.wake_word.wake_word
name=device.wake_word.display_name
)
voice = dict(
id=device.text_to_speech.id,
@ -28,7 +71,7 @@ class DeviceEndpoint(SeleneEndpoint):
geography = dict(
id=device.geography.id,
country=device.geography.country,
region=device.geography.state,
region=device.geography.region,
city=device.geography.city,
timezone=device.geography.time_zone,
latitude=device.geography.latitude,
@ -52,4 +95,70 @@ class DeviceEndpoint(SeleneEndpoint):
)
)
return response_data, HTTPStatus.OK
return response_data
def post(self):
self._authenticate()
device = self._validate_request()
device_id = self._pair_device(device)
return device_id, HTTPStatus.OK
def _validate_request(self) -> NewDeviceRequest:
request_data = json.loads(self.request.data)
device = NewDeviceRequest()
device.city = request_data['city']
device.country = request_data['country']
device.name = request_data['name']
device.pairing_code = request_data['pairingCode']
device.placement = request_data['placement']
device.region = request_data['region']
device.timezone = request_data['timezone']
device.wake_word = request_data['wakeWord']
device.voice = request_data['voice']
device.validate()
return device
def _pair_device(self, device):
with get_db_connection(self.config['DB_CONNECTION_POOL']) as db:
db.autocommit = False
try:
pairing_data = self._get_pairing_data(device.pairing_code)
device_id = self._add_device(device)
pairing_data['uuid'] = device_id
self.cache.delete('pairing.code:{}'.format(device.pairing_code))
self._build_pairing_token(pairing_data)
except Exception:
db.rollback()
raise
else:
db.commit()
return device_id
def _get_pairing_data(self, pairing_code: str) -> dict:
"""Checking if there's one pairing session for the pairing code."""
cache_key = 'pairing.code:' + pairing_code
pairing_cache = self.cache.get(cache_key)
pairing_data = json.loads(pairing_cache)
return pairing_data
def _add_device(self, device: NewDeviceRequest):
"""Creates a device and associate it to a pairing session"""
with get_db_connection(self.config['DB_CONNECTION_POOL']) as db:
device_repository = DeviceRepository(db)
device_id = device_repository.add_device(
self.account.id,
device.to_native()
)
return device_id
def _build_pairing_token(self, pairing_data):
self.cache.set_with_expiration(
key='pairing.token:' + pairing_data['token'],
value=json.dumps(pairing_data),
expiration=ONE_DAY
)