Applying requested changes

pull/47/head
Matheus Lima 2019-02-20 19:13:04 -03:00
parent f978ca5239
commit af83a190db
3 changed files with 68 additions and 40 deletions

View File

@ -1,10 +1,19 @@
import json import json
from http import HTTPStatus
from schematics import Model
from schematics.types import StringType, UUIDType
from selene.api import SeleneEndpoint from selene.api import SeleneEndpoint
from selene.data.device import DeviceRepository from selene.data.device import DeviceRepository
from selene.util.db import get_db_connection from selene.util.db import get_db_connection
from selene.util.cache import SeleneCache from selene.util.cache import SeleneCache
from flask_restful import http_status_message
class AddDevice(Model):
name = StringType(required=True)
wake_word_id = UUIDType(required=True)
text_to_speech_id = UUIDType(required=True)
class AccountDeviceEndpoint(SeleneEndpoint): class AccountDeviceEndpoint(SeleneEndpoint):
@ -16,27 +25,32 @@ class AccountDeviceEndpoint(SeleneEndpoint):
self.device_pairing_time = 86400 self.device_pairing_time = 86400
def post(self, account_id): def post(self, account_id):
device = json.loads(self.request.data) payload = json.loads(self.request.data)
if device: device = AddDevice(payload)
name = device['name'] device.validate()
wake_word_id = device['wake_word_id'] code = self.request.args['code']
text_to_speech_id = device['text_to_speech_id'] # Checking if there's one pairing session for the pairing code
code = self.request.args['code'] pairing_json = self.cache.get('pairing.code:{}'.format(code))
# Checking if there's one pairing session for the pairing code if pairing_json:
pairing_json = self.cache.get('pairing.code:{}'.format(code)) device_id = self._finish_pairing(account_id, code, device, pairing_json)
if pairing_json: response = device_id, HTTPStatus.OK
pairing = json.loads(pairing_json) else:
# Removing the pairing code from the cache response = '', HTTPStatus.NO_CONTENT
self.cache.delete('pairing.code:{}'.format(code)) return response
# Finishing the pairing process
device_id = self._pair(account_id, name, wake_word_id, text_to_speech_id, pairing)
return device_id, http_status_message(200)
return http_status_message(204)
return http_status_message(204)
@staticmethod def _finish_pairing(self, account_id, code, device, pairing_json):
def _code_key(code): pairing = json.loads(pairing_json)
return 'pairing.code:{}'.format(code) # Removing the pairing code from the cache
self.cache.delete('pairing.code:{}'.format(code))
# Finishing the pairing process
device_id = self._pair(
account_id,
str(device.name),
str(device.wake_word_id),
str(device.text_to_speech_id),
pairing
)
return device_id
def _pair(self, account_id: str, name: str, wake_word_id: str, text_to_speech_id: str, pairing: dict): def _pair(self, account_id: str, name: str, wake_word_id: str, text_to_speech_id: str, pairing: dict):
"""Creates a device and associate it to a pairing session""" """Creates a device and associate it to a pairing session"""

View File

@ -1,14 +1,25 @@
import hashlib import hashlib
import json import json
import uuid import uuid
from http import HTTPStatus
from schematics import Model
from schematics.types import StringType
from flask_restful import http_status_message
from selene.api import SeleneEndpoint from selene.api import SeleneEndpoint
from selene.data.device import DeviceRepository from selene.data.device import DeviceRepository
from selene.util.cache import SeleneCache from selene.util.cache import SeleneCache
from selene.util.db import get_db_connection from selene.util.db import get_db_connection
class DeviceActivate(Model):
token = StringType(required=True)
state = StringType(required=True)
platform = StringType(default='unknown')
core_version = StringType(default='unknown')
enclosure_version = StringType(default='unknown')
class DeviceActivateEndpoint(SeleneEndpoint): class DeviceActivateEndpoint(SeleneEndpoint):
"""Endpoint to activate a device and finish the pairing process""" """Endpoint to activate a device and finish the pairing process"""
@ -20,30 +31,33 @@ class DeviceActivateEndpoint(SeleneEndpoint):
self.sha512 = hashlib.sha512() self.sha512 = hashlib.sha512()
def post(self): def post(self):
device_activate = json.loads(self.request.data) payload = json.loads(self.request.data)
device_activate = DeviceActivate(payload)
if device_activate: if device_activate:
pairing = self._get_pairing_session(device_activate) pairing = self._get_pairing_session(device_activate)
if pairing: if pairing:
device_activate['uuid'] = pairing['uuid'] device_id = pairing['uuid']
self._activate( self._activate(
pairing['uuid'], device_id,
device_activate.get('platform', 'unknown'), str(device_activate.platform),
device_activate.get('enclosure_version', 'unknown'), str(device_activate.enclosure_version),
device_activate.get('core_version', 'unknown') str(device_activate.core_version)
) )
return self._generate_login(device_activate['uuid']) response = self._generate_login(device_id), HTTPStatus.OK
return http_status_message(204) else:
return http_status_message(204) response = '', HTTPStatus.NO_CONTENT
else:
response = '', HTTPStatus.NO_CONTENT
return response
def _get_pairing_session(self, device_activate: dict): def _get_pairing_session(self, device_activate: DeviceActivate):
"""Get the pairing session from the cache if device_activate has the same state that """Get the pairing session from the cache if device_activate has the same state that
the state stored in the pairing session""" the state stored in the pairing session"""
assert ('token' in device_activate and 'state' in device_activate) token = str(device_activate.token)
token = device_activate['token']
pairing = self.cache.get(self._token_key(token)) pairing = self.cache.get(self._token_key(token))
if pairing: if pairing:
pairing = json.loads(pairing) pairing = json.loads(pairing)
if device_activate['state'] == pairing['state']: if str(device_activate.state) == pairing['state']:
self.cache.delete(self._token_key(token)) self.cache.delete(self._token_key(token))
return pairing return pairing

View File

@ -44,8 +44,8 @@ def activate_device(context):
def validate_response(context): def validate_response(context):
assert_that(context.pairing['state'], equal_to(context.state)) assert_that(context.pairing['state'], equal_to(context.state))
login = json.loads(context.activate_device_response.data) login = json.loads(context.activate_device_response.data)
assert_that(has_key(equal_to('uuid'))) assert_that(login, has_key(equal_to('uuid')))
assert_that(has_key(equal_to('accessToken'))) assert_that(login, has_key(equal_to('accessToken')))
assert_that(has_key(equal_to('refreshToken'))) assert_that(login, has_key(equal_to('refreshToken')))
assert_that(has_key(equal_to('expiration'))) assert_that(login, has_key(equal_to('expiration')))
assert_that(context.device_id, equal_to(login['uuid'])) assert_that(login, context.device_id, equal_to(login['uuid']))