async def _update_credential(self, user, auth_header): ctx = RequestContext(auth_header, current_user=user) credential = await _fetch_credential_data(auth_header, self.kvstore_client) if credential.session_type == constants.SPLUNK_SESSION_TOKEN_TYPE: temporary_session_key = await get_splunk_cookie( request_context=ctx, async_splunk_client=self.splunk_client, username=ctx.auth_header.username, password=ctx.auth_header.password) credential.session_key = temporary_session_key credential.last_update_time = get_current_timestamp_str() LOGGER.debug("flush update credentials") credential_post_response = await self.kvstore_client.async_kvstore_post_request( collection=constants.SUBSCRIPTION_CREDENTIALS_COLLECTION_NAME, data=credential.to_json(), owner=ctx.current_user, key_id=constants.SUBSCRIPTION_CREDENTIAL_GLOBAL, auth_header=auth_header) if credential_post_response.code != HTTPStatus.OK: error_message = await credential_post_response.text() raise SpacebridgeError(error_message, status_code=credential_post_response.code) LOGGER.debug("Updated credentials for username=%s", user)
def build_subscription_search(request_context, dashboard_id, search_defn, search_query, input_tokens, parent_id, search_key, search_type, search_type_id, shard_id, sid, visualization_type=None, trellis_enabled=False, trellis_split_by=None): try: # Dashboard Definition refresh will override and refresh_interval refresh_interval_seconds = refresh_to_seconds(search_defn.refresh) # extract username and password query = search_query earliest_time = search_defn.earliest latest_time = search_defn.latest sample_ratio = search_defn.sample_ratio ref = search_defn.ref base = search_defn.base next_update_time = get_expiration_timestamp_str( ttl_seconds=refresh_interval_seconds) last_update_time = get_current_timestamp_str() # Create Search object subscription_search = SubscriptionSearch( _key=search_key, dashboard_id=dashboard_id, search_type_id=search_type_id, search_type=search_type, owner=request_context.current_user, ref=ref, base=base, sid=sid, query=query, parent_search_key=parent_id, earliest_time=earliest_time, latest_time=latest_time, sample_ratio=sample_ratio, refresh_interval_seconds=refresh_interval_seconds, next_update_time=next_update_time, last_update_time=last_update_time, input_tokens=input_tokens, shard_id=shard_id, visualization_type=visualization_type, trellis_enabled=trellis_enabled, trellis_split_by=trellis_split_by) except Exception as e: LOGGER.exception("Failed to build subscription_search") raise e return subscription_search
def process_tv_captain_url_request(request_context, client_single_request, single_server_response, async_client_factory): """ This method processes captain url requests from drone mode TVs. It is called when picking a captain when a grid request is activated, and reelecting a captain when the captain dies. :param request_context: Used to authenticate kvstore requests :param client_single_request: client request object protobuf :param single_server_response: server response object protobuf :param async_client factory: factory class used to generate kvstore and spacebridge clients """ captain_url_request = client_single_request.tvCaptainUrlRequest update_flag = captain_url_request.updateFlag captain_id = client_single_request.tvCaptainUrlRequest.captainId async_kvstore_client = async_client_factory.kvstore_client() # fetch tv config for captain id tvs = yield get_drone_mode_tvs(request_context, async_kvstore_client, device_ids=[captain_id]) if not tvs: raise SpacebridgeApiRequestError('Invalid captain id provided. captain_id={}'.format(captain_id), status_code=http.BAD_REQUEST) tv = tvs[0] LOGGER.debug('tvs in captain url request = %s', tvs) tv_config = TVConfig(**tv) # if we're updating the captain url, or if we're trying to be elected # captain and no one is yet, we do the same thing if not (tv_config.captain_url or tv_config.captain_id) or update_flag: device_ids = tv_config.tv_grid['device_ids'] captain_url = captain_url_request.captainUrl timestamp = get_current_timestamp_str() yield update_grid_members(request_context, async_kvstore_client, device_ids, captain_id, captain_url, timestamp) yield process_subscriptions(request_context, async_client_factory, tv_device_ids=device_ids) else: LOGGER.debug('captain url already set for device_id=%s, doing nothing', tv_config.device_id) single_server_response.tvCaptainUrlResponse.SetInParent()
def create_subscription_credentials(request_context, subscription_id, async_client_factory): async_kvstore_client = async_client_factory.kvstore_client() async_splunk_client = async_client_factory.splunk_client() if isinstance(request_context.auth_header, JWTAuthHeader): LOGGER.debug("JWTAuthHeader detected. Setting session_key_type = %s", constants.JWT_TOKEN_TYPE) session_type = constants.JWT_TOKEN_TYPE session_key = request_context.auth_header.token else: LOGGER.debug( "SplunkAuthHeader detected. Setting session_key_type = %s", constants.SPLUNK_SESSION_TOKEN_TYPE) session_type = constants.SPLUNK_SESSION_TOKEN_TYPE session_key = yield get_splunk_cookie( request_context=request_context, async_splunk_client=async_splunk_client, username=request_context.auth_header.username, password=request_context.auth_header.password) now = get_current_timestamp_str() auth = SubscriptionCredential(subscription_id=subscription_id, session_key=session_key, session_type=session_type, shard_id=request_context.shard_id, last_update_time=now, _key=subscription_id) # create subscription and return _key response = yield async_kvstore_client.async_kvstore_post_request( owner=request_context.current_user, collection=constants.SUBSCRIPTION_CREDENTIALS_COLLECTION_NAME, data=auth.to_json(), auth_header=request_context.auth_header) if response.code == http.OK or response.code == http.CREATED or response.code == http.CONFLICT: LOGGER.debug("Subscription Created. subscription_id=%s", auth.subscription_id) defer.returnValue(auth) else: error = yield response.text() error_message = "Failed to create Subscription credentials. status_code={}, error={}".format( response.code, error) raise SpacebridgeApiRequestError(error_message)
async def _batch_extend_subs(self, auth_header, subscription_ids): LOGGER.debug("Updating subscriptions=%s", len(subscription_ids)) if not subscription_ids: return containedin = build_containedin_clause(constants.KEY, list(subscription_ids)) params = {constants.QUERY: json.dumps(containedin)} response = await self.kvstore_client.async_kvstore_get_request( collection=constants.SUBSCRIPTIONS_COLLECTION_NAME, params=json.dumps(params), auth_header=auth_header) await _ensure_valid_response(response, [HTTPStatus.OK], "Failed to retrieve subscriptions") subscriptions = await response.json() subscriptions = [ Subscription.from_json(subscription_json) for subscription_json in subscriptions ] for subscription in subscriptions: subscription.expired_time = get_expiration_timestamp_str( ttl_seconds=subscription.ttl_seconds) subscription.last_update_time = get_current_timestamp_str() subscriptions = [ subscription.__dict__ for subscription in subscriptions ] await self.kvstore_client.async_batch_save_request( auth_header=auth_header, collection=constants.SUBSCRIPTIONS_COLLECTION_NAME, entries=subscriptions)
async def process_pubsub_subscription(system_auth_header, encryption_context, async_spacebridge_client, async_kvstore_client, async_splunk_client, search_context, subscription_update_ids): """ :param system_auth_header: :param encryption_context: :param async_spacebridge_client: :param async_kvstore_client: :param async_splunk_client: :param search_context: :param dependant_searches: :return: """ subscription_search = search_context.search credentials = search_context.subscription_credentials search_updates = search_context.search_updates user_subscriptions = search_context.subscriptions dependant_searches = search_context.dependant_search_counts LOGGER.debug( "Found valid subscribers, search_key=%s, user_subscriber_count=%s, search_updates=%s", subscription_search.key(), len(user_subscriptions), search_updates) input_tokens = load_input_tokens(subscription_search.input_tokens) if not subscription_search.sid: LOGGER.info("Pubsub search has no sid, search_key=%s", subscription_search.key()) return JobResult(False) job_status = await get_search_job_content(system_auth_header, subscription_search.owner, SPACEBRIDGE_APP_NAME, subscription_search.sid, async_splunk_client) LOGGER.debug("Search job status, search_key=%s, job=%s", subscription_search.key(), job_status) dependant_search_count = dependant_searches[subscription_search.key()] LOGGER.debug("Search job dependendants search_key=%s, user_subscriptions=%s, depdendant_search_count=%s", subscription_search.key(), len(user_subscriptions), dependant_search_count) if not job_status and (len(user_subscriptions) > 0 or dependant_search_count > 0): job_status = await _handle_expired_sid(system_auth_header, subscription_search, credentials, input_tokens, async_splunk_client, async_kvstore_client) if not job_status: LOGGER.warn("Job status could not be retrieved, search_key=%s, sid=%s", subscription_search.key(), subscription_search.sid) return JobResult(False) new_subscription_update_ids = {} # only send updates if the job was still running the last time we saw it if len(user_subscriptions) > 0: LOGGER.debug("Broadcast Data Updates: search_key=%s, updates=%s", subscription_search.key(), search_updates) new_subscription_update_ids = await _broadcast_data_update(system_auth_header, subscription_search, user_subscriptions, search_updates, input_tokens, encryption_context, job_status, async_spacebridge_client, async_kvstore_client, async_splunk_client, subscription_update_ids) update_job_status(subscription_search, job_status) if user_subscriptions or dependant_search_count: LOGGER.debug("Search has subscribers search_key=%s, subscriber_count=%s, dependant_search_count=%s", subscription_search.key(), len(user_subscriptions), dependant_search_count) await _refresh_search_job_if_expired(subscription_search, credentials, input_tokens, async_splunk_client, async_kvstore_client) subscription_search.last_update_time = get_current_timestamp_str() LOGGER.debug("Persisting search job state, search_key=%s, job_status=%s", subscription_search.key(), job_status) return JobResult(True, subscription_search, new_subscription_update_ids)
async def create_subscription(request_context, ttl_seconds, search_key, shard_id, async_splunk_client, async_kvstore_client, visualization_id, id_gen=uuid4): """ Create a visualization subscription object in kvstore collection [subscriptions] :param request_context: :param ttl_seconds: :param search_key: :param async_splunk_client: :param async_kvstore_client: :return: """ # extract params for subscription subscription_id = str(id_gen()) device_id = request_context.device_id expiration_time = get_expiration_timestamp_str(ttl_seconds=ttl_seconds) if isinstance(request_context.auth_header, JWTAuthHeader): LOGGER.debug("JWTAuthHeader detected. Setting session_key_type = %s", JWT_TOKEN_TYPE) session_type = JWT_TOKEN_TYPE session_key = request_context.auth_header.token else: LOGGER.debug( "SplunkAuthHeader detected. Setting session_key_type = %s", SPLUNK_SESSION_TOKEN_TYPE) session_type = SPLUNK_SESSION_TOKEN_TYPE session_key = await get_splunk_cookie( request_context=request_context, async_splunk_client=async_splunk_client, username=request_context.auth_header.username, password=request_context.auth_header.password) now = get_current_timestamp_str() # Create Subscription object subscription = Subscription(_key=subscription_id, ttl_seconds=ttl_seconds, device_id=device_id, subscription_key=search_key, expired_time=expiration_time, shard_id=shard_id, user=request_context.current_user, visualization_id=visualization_id, last_update_time=now) auth = SubscriptionCredential(subscription_id=subscription_id, session_key=session_key, session_type=session_type, shard_id=request_context.shard_id, last_update_time=now, _key=SUBSCRIPTION_CREDENTIAL_GLOBAL) # TODO check if gather wworks as expected await asyncio.gather( _create_subscription(request_context, subscription, async_kvstore_client), _create_subscription_credentials(request_context, auth, async_kvstore_client)) LOGGER.debug("Subscription created. subscription_id=%s, search_key=%s", subscription_id, search_key) return subscription_id
def process_subscribe_drone_mode_ipad(request_context, client_subscription_message, server_subscription_response, async_client_factory): """ Process subscribe to drone mode ipad events for a device id :param request_context: Used to authenticate kvstore requests :param client_single_request: client request object protobuf :param single_server_response: server response object protobuf :param async_client factory: factory class used to generate kvstore and spacebridge clients """ LOGGER.debug('start of subscribe drone mode ipad') async_kvstore_client = async_client_factory.kvstore_client() LOGGER.debug('request_context=%s', request_context) # base64 encode device id device_id = request_context.device_id urlsafe_b64encoded_device_id = b64_to_urlsafe_b64(device_id) query = { constants.QUERY: json.dumps({ constants.DEVICE_ID: device_id, }), constants.LIMIT: 1 } # fetch device from registered_devices_table to get device name response = yield async_kvstore_client.async_kvstore_get_request( collection=constants.REGISTERED_DEVICES_COLLECTION_NAME, params=query, owner=request_context.current_user, auth_header=request_context.auth_header) yield check_and_raise_error(response, request_context, 'Fetch registered devices') device = yield response.json() if device: device = device[0] else: raise SpacebridgeApiRequestError('Invalid device id={}'.format(device_id), status_code=http.BAD_REQUEST) device_name = device[constants.DEVICE_NAME] # write to ipads collection ipad_json = {constants.DEVICE_NAME: device_name} response = yield async_kvstore_client.async_kvstore_post_or_update_request( constants.DRONE_MODE_IPADS_COLLECTION_NAME, json.dumps(ipad_json), request_context.system_auth_header, key_id=urlsafe_b64encoded_device_id, owner=request_context.current_user) # construct parameters for subscription creation / updating ttl_seconds = client_subscription_message.clientSubscribeRequest.ttlSeconds expiration_time = get_expiration_timestamp_str(ttl_seconds=ttl_seconds) now = get_current_timestamp_str() params = { constants.TTL_SECONDS: str(ttl_seconds), constants.DEVICE_ID: device_id, constants.LAST_UPDATE_TIME: now, constants.EXPIRED_TIME: expiration_time, constants.USER: request_context.current_user, constants.SUBSCRIPTION_TYPE: constants.DRONE_MODE_IPAD } # delete existing subscriptions query = { constants.QUERY: json.dumps({ constants.DEVICE_ID: device_id, constants.USER: request_context.current_user, constants.SUBSCRIPTION_TYPE: constants.DRONE_MODE_IPAD }) } delete_response = yield async_kvstore_client.async_kvstore_delete_request( collection=constants.SUBSCRIPTIONS_COLLECTION_NAME, params=query, owner=constants.NOBODY, auth_header=request_context.auth_header) yield check_and_raise_error(delete_response, request_context, 'Delete existing ipad subscriptions') # create subscription subscription_id = yield write_drone_mode_subscription(request_context, params, async_client_factory) server_subscription_response.subscriptionId = subscription_id server_subscription_response.serverSubscribeResponse.droneModeiPadSubscribe.SetInParent() LOGGER.debug('Successfully wrote drone mode ipad subscription with id=%s', subscription_id)
def process_subscribe_drone_mode_tv(request_context, client_subscription_message, server_subscription_response, async_client_factory): """ Process subscribe to drone mode tv events for a device id :param request_context: Used to authenticate kvstore requests :param client_single_request: client request object protobuf :param single_server_response: server response object protobuf :param async_client factory: factory class used to generate kvstore and spacebridge clients """ LOGGER.debug('start of subscribe drone mode tv') async_kvstore_client = async_client_factory.kvstore_client() # base64 encode device id device_id = client_subscription_message.clientSubscribeRequest.droneModeTVSubscribe.deviceId encoded_device_id = b64encode_to_str(device_id) urlsafe_encoded_device_id = urlsafe_b64encode_to_str(device_id) # Grab TV data tv_data = yield get_registered_tvs(request_context.auth_header, request_context.current_user, async_kvstore_client) LOGGER.debug('raw device id=%s, encoded_device_id=%s, urlsafe_encoded_device_id=%s, tv_data=%s', device_id, encoded_device_id, urlsafe_encoded_device_id, tv_data) # validate that device is a valid apple tv registered to this user valid_device_id = any(device.get(constants.DEVICE_ID) == encoded_device_id for device in tv_data) if not valid_device_id: error_message = 'Invalid device id={}'.format(encoded_device_id) raise SpacebridgeApiRequestError(error_message, status_code=http.BAD_REQUEST) # construct parameters for subscription creation / updating ttl_seconds = client_subscription_message.clientSubscribeRequest.ttlSeconds expiration_time = get_expiration_timestamp_str(ttl_seconds=ttl_seconds) now = get_current_timestamp_str() params = { constants.TTL_SECONDS: str(ttl_seconds), constants.DEVICE_ID: encoded_device_id, constants.EXPIRED_TIME: expiration_time, constants.USER: request_context.current_user, constants.LAST_UPDATE_TIME: now, constants.SUBSCRIPTION_TYPE: constants.DRONE_MODE_TV } # delete existing subscriptions query = { constants.QUERY: json.dumps({ constants.DEVICE_ID: encoded_device_id, constants.USER: request_context.current_user, constants.SUBSCRIPTION_TYPE: constants.DRONE_MODE_TV }) } delete_response = yield async_kvstore_client.async_kvstore_delete_request( collection=constants.SUBSCRIPTIONS_COLLECTION_NAME, params=query, owner=constants.NOBODY, auth_header=request_context.auth_header) yield check_and_raise_error(delete_response, request_context, 'Delete existing tv subscriptions') # create subscription subscription_id = yield write_drone_mode_subscription(request_context, params, async_client_factory) server_subscription_response.subscriptionId = subscription_id server_subscription_response.serverSubscribeResponse.droneModeTVSubscribe.deviceId = device_id LOGGER.debug('Successfully wrote drone mode tv subscription with id=%s', subscription_id)
def process_tv_config_set_request(request_context, client_single_request, single_server_response, async_client_factory): """ This method will process a tvConfigSetRequest. :param request_context: Used to authenticate kvstore requests :param client_single_request: client request object protobuf :param single_server_response: server response object protobuf :param async_client factory: factory class used to generate kvstore and spacebridge clients """ async_kvstore_client = async_client_factory.kvstore_client() tv_config_set_request = client_single_request.tvConfigSetRequest tv_config_proto = tv_config_set_request.tvConfig tv_config = TVConfig() tv_config.from_protobuf(tv_config_proto) timestamp = get_current_timestamp_str() ids_to_update = [tv_config.device_id] # Check to make sure device is valid before proceeding yield validate_devices(set(ids_to_update), request_context, async_kvstore_client) # Before setting config, we need to check if # we're setting a config on a tv that is currently in # a grid configuration, so we need to fetch it. tvs = yield get_drone_mode_tvs(request_context, async_kvstore_client, device_ids=[tv_config.device_id]) if tvs: tv = tvs[0] existing_config = TVConfig(**tv) # If it's a grid, we remove it from the existing grid list, if has_grid(tv, is_json=True) and not has_grid(tv_config_proto): device_ids = ids_to_update = existing_config.tv_grid[constants.DEVICE_IDS] yield remove_from_grid(tv_config=existing_config, device_ids=device_ids, request_context=request_context, async_kvstore_client=async_kvstore_client, timestamp=timestamp) # set timestamp here tv_config.timestamp = timestamp tv_config_json = json.loads(tv_config.to_json()) # delete device id if constants.DEVICE_ID in tv_config_json: del tv_config_json[constants.DEVICE_ID] LOGGER.debug('tv_config_json=%s', tv_config_json) # convert device id to urlsafe b64 encoded to use as kvstore key urlsafe_b64encoded_device_id = b64_to_urlsafe_b64(tv_config.device_id) tv_config_json[constants.KEY] = urlsafe_b64encoded_device_id response = yield async_kvstore_client.async_kvstore_post_or_update_request( constants.DRONE_MODE_TVS_COLLECTION_NAME, json.dumps(tv_config_json), request_context.system_auth_header, key_id=urlsafe_b64encoded_device_id, owner=request_context.current_user) yield check_and_raise_error(response, request_context, 'Write TV Config', valid_codes=[http.OK, http.CREATED]) single_server_response.tvConfigSetResponse.SetInParent() # update tv subscription for config we just created # (and affected grid device ids, if applicable) as well as # all ipads registered to current user yield process_subscriptions(request_context, async_client_factory, tv_device_ids=ids_to_update) LOGGER.info("Successful TV Config Set Request for device id=%s", tv_config.device_id)
def process_tv_config_bulk_set_request(request_context, client_single_request, single_server_response, async_client_factory): """ Bulk tv config set request. Used to bulk send tv config set requests when we're setting a grid configuration :param request_context: Used to authenticate kvstore requests :param client_single_request: client request object protobuf :param single_server_response: server response object protobuf :param async_client factory: factory class used to generate kvstore and spacebridge clients """ async_kvstore_client = async_client_factory.kvstore_client() tv_config_protos = client_single_request.tvConfigBulkSetRequest.tvConfig is_token_update = client_single_request.tvConfigBulkSetRequest.isTokenUpdate LOGGER.debug('tv_config_protos=%s', tv_config_protos) device_ids = {proto.device_id for proto in tv_config_protos} timestamp = get_current_timestamp_str() warnings = yield validate_devices(device_ids, request_context, async_kvstore_client) # Before setting configs, we need to check if # we're setting configs on tvs that are currently in # grid configurations, so we need to fetch them. # This logic is ignored if we're doing a token update existing_grids_to_update = set() if not is_token_update: tvs = yield get_drone_mode_tvs(request_context, async_kvstore_client, device_ids=device_ids) if tvs: requests = [] for tv in tvs: existing_config = TVConfig(**tv) # If it's a grid, we remove it from the existing grid list if has_grid(tv, is_json=True): grid_device_ids = existing_config.tv_grid[constants.DEVICE_IDS] existing_grids_to_update.update(grid_device_ids) request = remove_from_grid(tv_config=existing_config, device_ids=grid_device_ids, request_context=request_context, async_kvstore_client=async_kvstore_client, timestamp=timestamp) requests.append(request) if requests: exceptions = [] responses = yield defer.DeferredList(requests, consumeErrors=True) for response in responses: if isinstance(response[1], Failure): exceptions.append(response[1]) LOGGER.debug('Finished updating modified tvs') if exceptions: LOGGER.error('Encountered exceptions updating tvs, e=%s', exceptions) # if we couldn't update any of the existing configs, we should not continue the request if len(exceptions) == len(requests): raise SpacebridgeApiRequestError('Unable to update all existing tv configs', status_code=http.INTERNAL_SERVER_ERROR) post_data = [] for tv_config_proto in tv_config_protos: tv_config = TVConfig() tv_config.from_protobuf(tv_config_proto) # set timestamp here tv_config.timestamp = timestamp tv_config_json = json.loads(tv_config.to_json()) # delete device id if constants.DEVICE_ID in tv_config_json: del tv_config_json[constants.DEVICE_ID] LOGGER.debug('tv_config_json=%s', tv_config_json) # convert device id to urlsafe b64 encoded to use as kvstore key urlsafe_b64encoded_device_id = b64_to_urlsafe_b64(tv_config.device_id) tv_config_json[constants.KEY] = urlsafe_b64encoded_device_id post_data.append(tv_config_json) LOGGER.debug('post_data=%s', post_data) updated_keys = yield async_kvstore_client.async_batch_save_request( request_context.system_auth_header, constants.DRONE_MODE_TVS_COLLECTION_NAME, post_data, owner=request_context.current_user) ids_to_update = {urlsafe_b64_to_b64(key) for key in updated_keys} ids_to_update.update(existing_grids_to_update) ids_to_update = list(ids_to_update) LOGGER.debug('ids_to_update=%s', ids_to_update) yield process_subscriptions(request_context, async_client_factory, tv_device_ids=ids_to_update) if warnings: single_server_response.tvConfigBulkSetResponse.warnings.extend(warnings) single_server_response.tvConfigBulkSetResponse.SetInParent()
def post(self, request): """ Creates/updates a subscription Request Parameters json version of a subscription collection object. Contains required fields _key (required for update, must be empty for create) ttl_seconds subscription_key subscription_type device_id shard_id user Example: { "ttl_seconds": "10", "subscription_key": "key" "subscription_type": "Splunk TV", "device_id": "device_id", "shard_id": "shard_id", "user": "******", } Returns: id of created/update subscription Example: { "message": "5f04e4d1ed7a6aab3e6f2e91", "status": 201 } """ session_key = request[constants.SESSION][constants.AUTHTOKEN] payload = json.loads(request[constants.PAYLOAD]) if not payload: return { constants.PAYLOAD: { 'Error', 'You must provide subscription information to update/create' }, constants.STATUS: HTTPStatus.BAD_REQUEST } kvstore_object = KVStore( collection=constants.SUBSCRIPTIONS_COLLECTION_NAME, session_key=session_key) # Verification of provided fields required_fields = (Subscription.TTL_SECONDS, Subscription.SUBSCRIPTION_KEY, Subscription.SUBSCRIPTION_TYPE, Subscription.DEVICE_ID, Subscription.SHARD_ID, Subscription.USER) missing_fields = [] for field in required_fields: if field not in payload: missing_fields.append(field) if missing_fields: return { constants.PAYLOAD: { 'Error': f'Missing field(s) {missing_fields}' }, constants.STATUS: HTTPStatus.BAD_REQUEST } # Setting default fields subscription = Subscription.from_json(payload) subscription.expired_time = get_expiration_timestamp_str( ttl_seconds=int(subscription.ttl_seconds)) subscription.version = constants.SUBSCRIPTION_VERSION_2 subscription.last_update_time = get_current_timestamp_str() if subscription.key(): # update case return update_subscription(kvstore_object=kvstore_object, subscription=subscription) else: # create case return create_subscription( kvstore_object=kvstore_object, subscription=subscription, session_key=session_key, )