class FallbackSchema(colander.MappingSchema): """ A schema validating the fields present in fallback options. """ lacf = DefaultNode(colander.Boolean(), missing=True) ipf = DefaultNode(colander.Boolean(), missing=True)
class ValidWifiReportSchema(colander.MappingSchema, ValidatorNode): """A schema which validates the wifi specific fields in a report.""" mac = MacNode(colander.String()) age = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_AGE, constants.MAX_AGE), ) channel = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_WIFI_CHANNEL, constants.MAX_WIFI_CHANNEL), ) frequency = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_WIFI_FREQUENCY, constants.MAX_WIFI_FREQUENCY), ) signal = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_WIFI_SIGNAL, constants.MAX_WIFI_SIGNAL), ) snr = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_WIFI_SNR, constants.MAX_WIFI_SNR), ) def deserialize(self, data): data = super(ValidWifiReportSchema, self).deserialize(data) if data and data is not colander.drop and data is not colander.null: channel = data.get("channel") frequency = data.get("frequency") if (frequency is None and channel is not None) or (frequency is not None and channel is None): # shallow copy data = dict(data) data["channel"], data["frequency"] = channel_frequency( channel, frequency) return data
class ValidWifiSignalSchema(colander.MappingSchema, ValidatorNode): """ A schema which validates the fields related to wifi signal strength and quality. """ age = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_AGE, constants.MAX_AGE)) channel = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_WIFI_CHANNEL, constants.MAX_WIFI_CHANNEL)) signal = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_WIFI_SIGNAL, constants.MAX_WIFI_SIGNAL)) snr = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(0, 100)) def deserialize(self, data): if data: channel = data.get('channel') channel = channel is not None and int(channel) or None if (channel is None or not (constants.MIN_WIFI_CHANNEL < channel < constants.MAX_WIFI_CHANNEL)): # shallow copy data = dict(data) # if no explicit channel was given, calculate freq = data.get('frequency', None) if freq is None: freq = 0 if 2411 < freq < 2473: # 2.4 GHz band data['channel'] = (freq - 2407) // 5 elif freq == 2484: data['channel'] = 14 elif 5169 < freq < 5826: # 5 GHz band data['channel'] = (freq - 5000) // 5 else: data['channel'] = None return super(ValidWifiSignalSchema, self).deserialize(data)
class ValidCellKeySchema(ValidCellAreaKeySchema): cid = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_CID, constants.MAX_CID), ) psc = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_PSC, constants.MAX_PSC), ) def __init__(self, *args, **kw): super(ValidCellKeySchema, self).__init__(*args, **kw) self.radio_node = self.get("radio") def deserialize(self, data): if data: # shallow copy data = dict(data) # deserialize and validate radio field early data["radio"] = self.radio_node.deserialize( data.get("radio", colander.null) ) # If the cell id > 65535 then it must be a WCDMA tower if ( data["radio"] is Radio["gsm"] and data.get("cid") is not None and data.get("cid", 0) > constants.MAX_CID_GSM ): data["radio"] = Radio["wcdma"] if ( data["radio"] is Radio["lte"] and data.get("psc") is not None and data.get("psc", 0) > constants.MAX_PSC_LTE ): data["psc"] = None return super(ValidCellKeySchema, self).deserialize(data) def validator(self, node, cstruct): super(ValidCellKeySchema, self).validator(node, cstruct) if (cstruct.get("lac") is None or cstruct.get("cid") is None) and cstruct.get( "psc" ) is None: raise colander.Invalid(node, ("Must have (LAC and CID) or PSC."))
class ValidBlueReportSchema(colander.MappingSchema, ValidatorNode): """A schema which validates the Bluetooth specific fields in a report.""" mac = MacNode(colander.String()) age = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_AGE, constants.MAX_AGE)) signal = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_BLUE_SIGNAL, constants.MAX_BLUE_SIGNAL))
class ValidBlueSignalSchema(colander.MappingSchema, ValidatorNode): """ A schema which validates the fields related to Bluetooth signal strength and quality. """ age = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_AGE, constants.MAX_AGE)) signal = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_BLUE_SIGNAL, constants.MAX_BLUE_SIGNAL))
class ValidBlueLookupSchema(colander.MappingSchema, ValidatorNode): """A schema which validates the fields in a Bluetooth lookup.""" macAddress = MacNode(colander.String()) name = DefaultNode(colander.String(), missing=None) age = DefaultNode( colander.Integer(), missing=None, validator=colander.Range( constants.MIN_AGE, constants.MAX_AGE)) signalStrength = DefaultNode( colander.Integer(), missing=None, validator=colander.Range( constants.MIN_BLUE_SIGNAL, constants.MAX_BLUE_SIGNAL))
class ValidCellKeySchema(ValidCellAreaKeySchema): cid = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_CID, constants.MAX_CID)) psc = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_PSC, constants.MAX_PSC)) def __init__(self, *args, **kw): super(ValidCellKeySchema, self).__init__(*args, **kw) self.radio_node = self.get('radio') def deserialize(self, data): if data: # shallow copy data = dict(data) # deserialize and validate radio field early data['radio'] = self.radio_node.deserialize( data.get('radio', colander.null)) # If the cell id > 65535 then it must be a WCDMA tower if (data['radio'] is Radio['gsm'] and data.get('cid') is not None and data.get('cid', 0) > constants.MAX_CID_GSM): data['radio'] = Radio['wcdma'] # Treat cid=65535 without a valid lac as an unspecified value if (data.get('lac') is None and data.get('cid') == constants.MAX_CID_GSM): data['cid'] = None return super(ValidCellKeySchema, self).deserialize(data) def validator(self, node, cstruct): super(ValidCellKeySchema, self).validator(node, cstruct) if ((cstruct.get('lac') is None or cstruct.get('cid') is None) and cstruct.get('psc') is None): raise colander.Invalid(node, ('Must have (LAC and CID) or PSC.')) if (cstruct['radio'] is Radio['lte'] and cstruct.get('psc') is not None and cstruct.get('psc', 0) > constants.MAX_PSC_LTE): raise colander.Invalid(node, ('PSC is out of range for LTE.'))
class ValidCellLookupSchema(ValidCellAreaKeySchema, ValidCellSignalSchema): """A schema which validates the fields in a cell lookup.""" cellId = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_CID, constants.MAX_CID), ) primaryScramblingCode = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_PSC, constants.MAX_PSC), ) def __init__(self, *args, **kw): super(ValidCellLookupSchema, self).__init__(*args, **kw) self.radio_node = self.get("radioType") def deserialize(self, data): if data: # shallow copy data = dict(data) # deserialize and validate radio field early data["radioType"] = self.radio_node.deserialize( data.get("radioType", colander.null)) # If the cell id > 65535 then it must be a WCDMA tower if (data["radioType"] is Radio["gsm"] and data.get("cellId") is not None and data.get("cellId", 0) > constants.MAX_CID_GSM): data["radioType"] = Radio["wcdma"] if (data["radioType"] is Radio["lte"] and data.get("primaryScramblingCode") is not None and data.get("primaryScramblingCode", 0) > constants.MAX_PSC_LTE): data["primaryScramblingCode"] = None return super(ValidCellLookupSchema, self).deserialize(data) def validator(self, node, cstruct): super(ValidCellLookupSchema, self).validator(node, cstruct) if cstruct["locationAreaCode"] is None or cstruct["cellId"] is None: raise colander.Invalid(node, ("LAC/CID are required in lookups."))
class ValidWifiLookupSchema(ValidWifiKeySchema): """A schema which validates the fields in a wifi lookup.""" channel = colander.SchemaNode( colander.Integer(), missing=0, validator=colander.Range( constants.MIN_WIFI_CHANNEL, constants.MAX_WIFI_CHANNEL)) signal = DefaultNode( colander.Integer(), missing=0, validator=colander.Range( constants.MIN_WIFI_SIGNAL, constants.MAX_WIFI_SIGNAL)) snr = DefaultNode( colander.Integer(), missing=0, validator=colander.Range(0, 100)) def deserialize(self, data): if data: channel = int(data.get('channel', 0)) if not (constants.MIN_WIFI_CHANNEL < channel < constants.MAX_WIFI_CHANNEL): # if no explicit channel was given, calculate freq = data.get('frequency', 0) if 2411 < freq < 2473: # 2.4 GHz band data['channel'] = (freq - 2407) // 5 elif 5169 < freq < 5826: # 5 GHz band data['channel'] = (freq - 5000) // 5 else: data['channel'] = self.fields['channel'].missing # map external name to internal if data.get('snr', None) is None: data['snr'] = data.get('signalToNoiseRatio', 0) return super(ValidWifiLookupSchema, self).deserialize(data)
class ValidCellAreaKeySchema(colander.MappingSchema, ValidatorNode): radio = DefaultNode(RadioType()) mcc = colander.SchemaNode(colander.Integer()) mnc = colander.SchemaNode(colander.Integer()) lac = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_LAC, constants.MAX_LAC)) def validator(self, node, cstruct): super(ValidCellAreaKeySchema, self).validator(node, cstruct) if cstruct['mcc'] not in constants.ALL_VALID_MCCS: raise colander.Invalid( node, ('Check against the list of all known valid mccs')) if not (constants.MIN_MNC <= cstruct['mnc'] <= constants.MAX_MNC): raise colander.Invalid(node, ('MNC out of valid range.'))
class ValidCellLookupSchema(ValidCellKeySchema): """A schema which validates the fields in a cell lookup.""" asu = DefaultNode(colander.Integer(), missing=-1, validator=colander.Range(0, 97)) signal = DefaultNode(colander.Integer(), missing=0, validator=colander.Range(-150, -1)) ta = DefaultNode(colander.Integer(), missing=0, validator=colander.Range(0, 63)) def deserialize(self, data): if data: # Sometimes the asu and signal fields are swapped if data.get('asu', 0) < -1 and data.get('signal', None) == 0: data['signal'] = data['asu'] data['asu'] = self.fields['asu'].missing return super(ValidCellLookupSchema, self).deserialize(data)
class ValidCellAreaKeySchema(colander.MappingSchema, ValidatorNode): radioType = DefaultNode(RadioType()) mobileCountryCode = colander.SchemaNode(colander.Integer()) mobileNetworkCode = colander.SchemaNode(colander.Integer()) locationAreaCode = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_LAC, constants.MAX_LAC), ) def validator(self, node, cstruct): super(ValidCellAreaKeySchema, self).validator(node, cstruct) if cstruct["mobileCountryCode"] not in constants.ALL_VALID_MCCS: raise colander.Invalid( node, ("Check against the list of all known valid mccs")) if not (constants.MIN_MNC <= cstruct["mobileNetworkCode"] <= constants.MAX_MNC): raise colander.Invalid(node, ("MNC out of valid range."))
class ValidCellAreaKeySchema(FieldSchema, CopyingSchema): """A schema which validates the fields present in a cell area key.""" radio = RadioNode(RadioType()) mcc = colander.SchemaNode(colander.Integer(), validator=colander.Range(1, 999)) mnc = colander.SchemaNode(colander.Integer(), validator=colander.Range(0, 32767)) lac = DefaultNode(colander.Integer(), missing=0, validator=colander.Range(constants.MIN_LAC, constants.MAX_LAC_ALL))
class ValidReportSchema(ValidPositionSchema): """A schema which validates the fields present in a report.""" accuracy = DefaultNode( colander.Float(), missing=0, validator=colander.Range( 0, constants.MAX_ACCURACY)) altitude = DefaultNode( colander.Float(), missing=0, validator=colander.Range( constants.MIN_ALTITUDE, constants.MAX_ALTITUDE)) altitude_accuracy = DefaultNode( colander.Float(), missing=0, validator=colander.Range( 0, constants.MAX_ALTITUDE_ACCURACY)) heading = DefaultNode( colander.Float(), missing=-1, validator=colander.Range( 0, constants.MAX_HEADING)) speed = DefaultNode( colander.Float(), missing=-1, validator=colander.Range( 0, constants.MAX_SPEED)) report_id = ReportIDNode(UUIDType()) created = colander.SchemaNode(DateTimeFromString(), missing=None) time = RoundToMonthDateNode(DateTimeFromString(), missing=None)
class ValidReportSchema(colander.MappingSchema, ValidatorNode): """A schema which validates the fields present in a report.""" lat = colander.SchemaNode(colander.Float(), missing=None, validator=colander.Range(constants.MIN_LAT, constants.MAX_LAT)) lon = colander.SchemaNode(colander.Float(), missing=None, validator=colander.Range(constants.MIN_LON, constants.MAX_LON)) accuracy = DefaultNode(colander.Float(), missing=None, validator=colander.Range(0.0, constants.MAX_ACCURACY)) altitude = DefaultNode(colander.Float(), missing=None, validator=colander.Range(constants.MIN_ALTITUDE, constants.MAX_ALTITUDE)) altitude_accuracy = DefaultNode(colander.Float(), missing=None, validator=colander.Range( 0.0, constants.MAX_ALTITUDE_ACCURACY)) heading = DefaultNode(colander.Float(), missing=None, validator=colander.Range(0.0, constants.MAX_HEADING)) speed = DefaultNode(colander.Float(), missing=None, validator=colander.Range(0.0, constants.MAX_SPEED)) def validator(self, node, cstruct): super(ValidReportSchema, self).validator(node, cstruct) for field in ('lat', 'lon'): if (cstruct[field] is None or cstruct[field] is colander.null): # pragma: no cover raise colander.Invalid(node, 'Report %s is required.' % field) if not GEOCODER.any_region(cstruct['lat'], cstruct['lon']): raise colander.Invalid(node, ('Lat/lon must be inside a region.'))
class ValidCellSignalSchema(colander.MappingSchema, ValidatorNode): asu = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(0, 97)) signal = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(-150, -1)) ta = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(0, 63)) def deserialize(self, data): if data: # Sometimes the asu and signal fields are swapped if (data.get('asu') is not None and data.get('asu', 0) < -1 and data.get('signal', None) == 0): # shallow copy data = dict(data) data['signal'] = data['asu'] data['asu'] = None return super(ValidCellSignalSchema, self).deserialize(data)
class ValidWifiLookupSchema(colander.MappingSchema, ValidatorNode): """A schema which validates the fields in a WiFi lookup.""" macAddress = MacNode(colander.String()) ssid = DefaultNode(colander.String(), missing=None) age = DefaultNode( colander.Integer(), missing=None, validator=colander.Range( constants.MIN_AGE, constants.MAX_AGE)) channel = DefaultNode( colander.Integer(), missing=None, validator=colander.Range( constants.MIN_WIFI_CHANNEL, constants.MAX_WIFI_CHANNEL)) frequency = DefaultNode( colander.Integer(), missing=None, validator=colander.Range( constants.MIN_WIFI_FREQUENCY, constants.MAX_WIFI_FREQUENCY)) signalStrength = DefaultNode( colander.Integer(), missing=None, validator=colander.Range( constants.MIN_WIFI_SIGNAL, constants.MAX_WIFI_SIGNAL)) signalToNoiseRatio = DefaultNode( colander.Integer(), missing=None, validator=colander.Range( constants.MIN_WIFI_SNR, constants.MAX_WIFI_SNR)) def deserialize(self, data): data = super(ValidWifiLookupSchema, self).deserialize(data) if (data and data is not colander.drop and data is not colander.null): channel = data.get('channel') frequency = data.get('frequency') if ((frequency is None and channel is not None) or (frequency is not None and channel is None)): # shallow copy data = dict(data) data['channel'], data['frequency'] = channel_frequency( channel, frequency) return data
class ValidCellReportSchema(ValidCellKeySchema): """A schema which validates the cell specific fields in a report.""" age = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_AGE, constants.MAX_AGE)) asu = DefaultNode(colander.Integer(), missing=None, validator=colander.Range( min(constants.MIN_CELL_ASU.values()), max(constants.MAX_CELL_ASU.values()))) signal = DefaultNode(colander.Integer(), missing=None, validator=colander.Range( min(constants.MIN_CELL_SIGNAL.values()), max(constants.MAX_CELL_SIGNAL.values()))) ta = DefaultNode(colander.Integer(), missing=None, validator=colander.Range(constants.MIN_CELL_TA, constants.MAX_CELL_TA)) def _signal_from_asu(self, radio, value): if radio is Radio.gsm: return (value * 2) - 113 if radio is Radio.wcdma: return value - 116 if radio is Radio.lte: return value - 140 def deserialize(self, data): if data: # Sometimes the asu and signal fields are swapped if (data.get('asu') is not None and data.get('asu', 0) < -5 and (data.get('signal') is None or data.get('signal', 0) >= 0)): # shallow copy data = dict(data) data['signal'] = data['asu'] data['asu'] = None data = super(ValidCellReportSchema, self).deserialize(data) if isinstance(data.get('radio'), Radio): radio = data['radio'] # Radio type specific checks for ASU field if data.get('asu') is not None: if not (constants.MIN_CELL_ASU[radio] <= data['asu'] <= constants.MAX_CELL_ASU[radio]): data = dict(data) data['asu'] = None # Radio type specific checks for signal field if data.get('signal') is not None: if not (constants.MIN_CELL_SIGNAL[radio] <= data['signal'] <= constants.MAX_CELL_SIGNAL[radio]): data = dict(data) data['signal'] = None # Radio type specific checks for TA field if data.get('ta') is not None and radio is Radio.wcdma: data = dict(data) data['ta'] = None # Calculate signal from ASU field if data.get('asu') is not None and data.get('signal') is None: if (constants.MIN_CELL_ASU[radio] <= data['asu'] <= constants.MAX_CELL_ASU[radio]): data = dict(data) data['signal'] = self._signal_from_asu(radio, data['asu']) return data def validator(self, node, cstruct): super(ValidCellReportSchema, self).validator(node, cstruct) for field in ('radio', 'mcc', 'mnc', 'lac', 'cid'): if (cstruct[field] is None or cstruct[field] is colander.null): raise colander.Invalid(node, 'Cell %s is required.' % field)
class ValidBlueLookupSchema(ValidBlueSignalSchema): """A schema which validates the fields in a Bluetooth lookup.""" mac = MacNode(colander.String()) name = DefaultNode(colander.String(), missing=None)
class ValidCellKeySchema(ValidCellAreaKeySchema): """A schema which validates the fields present in a cell key.""" cid = DefaultNode(colander.Integer(), missing=0, validator=colander.Range(constants.MIN_CID, constants.MAX_CID_ALL)) psc = DefaultNode(colander.Integer(), missing=-1, validator=colander.Range(0, 512)) def deserialize(self, data): if data: # deserialize and validate radio field early radio_node = self.fields['radio'] radio = radio_node.deserialize(data['radio']) if radio_node.validator(radio_node, radio): data['radio'] = radio # If the cell id >= 65536 then it must be a umts tower if (data.get('cid', 0) >= 65536 and data['radio'] == Radio.gsm): data['radio'] = Radio.umts # Treat cid=65535 without a valid lac as an unspecified value if (self.is_missing(data, 'lac') and data.get('cid', None) == 65535): data['cid'] = self.fields['cid'].missing return super(ValidCellKeySchema, self).deserialize(data) def validator(self, schema, data): lac_missing = self.is_missing(data, 'lac') cid_missing = self.is_missing(data, 'cid') if data['mcc'] not in constants.ALL_VALID_MCCS: raise colander.Invalid( schema, ('Check against the list of all known valid mccs')) if (data['radio'] == Radio.cdma and (lac_missing or cid_missing)): raise colander.Invalid( schema, ('Skip CDMA towers missing lac or cid ' '(no psc on CDMA exists to backfill using inference)')) if data['radio'] in Radio._gsm_family() and data['mnc'] > 999: raise colander.Invalid( schema, ('Skip GSM/LTE/UMTS towers with an invalid MNC')) if ((lac_missing or cid_missing) and self.is_missing(data, 'psc')): raise colander.Invalid(schema, ('Must have (lac and cid) or ' 'psc (psc-only to use in backfill)')) if (data['radio'] == Radio.cdma and data['cid'] > constants.MAX_CID_CDMA): raise colander.Invalid(schema, ('CID is out of range for CDMA.')) if (data['radio'] == Radio.lte and data['cid'] > constants.MAX_CID_LTE): raise colander.Invalid(schema, ('CID is out of range for LTE.')) if (data['radio'] in Radio._gsm_family() and data['lac'] > constants.MAX_LAC_GSM_UMTS_LTE): raise colander.Invalid(schema, ('LAC is out of range for GSM/UMTS/LTE.'))
class ValidReportSchema(colander.MappingSchema, ValidatorNode): """A schema which validates the fields present in a report.""" lat = colander.SchemaNode( colander.Float(), missing=None, validator=colander.Range(constants.MIN_LAT, constants.MAX_LAT), ) lon = colander.SchemaNode( colander.Float(), missing=None, validator=colander.Range(constants.MIN_LON, constants.MAX_LON), ) accuracy = DefaultNode( colander.Float(), missing=None, validator=colander.Range(constants.MIN_ACCURACY, constants.MAX_ACCURACY), ) altitude = DefaultNode( colander.Float(), missing=None, validator=colander.Range(constants.MIN_ALTITUDE, constants.MAX_ALTITUDE), ) altitude_accuracy = DefaultNode( colander.Float(), missing=None, validator=colander.Range(constants.MIN_ALTITUDE_ACCURACY, constants.MAX_ALTITUDE_ACCURACY), ) heading = DefaultNode( colander.Float(), missing=None, validator=colander.Range(constants.MIN_HEADING, constants.MAX_HEADING), ) pressure = DefaultNode( colander.Float(), missing=None, validator=colander.Range(constants.MIN_PRESSURE, constants.MAX_PRESSURE), ) source = ReportSourceNode(ReportSourceType(), missing=None) speed = DefaultNode( colander.Float(), missing=None, validator=colander.Range(constants.MIN_SPEED, constants.MAX_SPEED), ) timestamp = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_TIMESTAMP, constants.MAX_TIMESTAMP), ) def validator(self, node, cstruct): super(ValidReportSchema, self).validator(node, cstruct) for field in ("lat", "lon"): if cstruct[field] is None or cstruct[field] is colander.null: raise colander.Invalid(node, "Report %s is required." % field) if not GEOCODER.any_region(cstruct["lat"], cstruct["lon"]): raise colander.Invalid(node, "Lat/lon must be inside a region.")
class ValidCellSignalSchema(colander.MappingSchema, ValidatorNode): age = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_AGE, constants.MAX_AGE), ) asu = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(min(constants.MIN_CELL_ASU.values()), max(constants.MAX_CELL_ASU.values())), ) signalStrength = DefaultNode( colander.Integer(), missing=None, validator=colander.Range( min(constants.MIN_CELL_SIGNAL.values()), max(constants.MAX_CELL_SIGNAL.values()), ), ) timingAdvance = DefaultNode( colander.Integer(), missing=None, validator=colander.Range(constants.MIN_CELL_TA, constants.MAX_CELL_TA), ) def _signal_from_asu(self, radio, value): if radio is Radio.gsm: return (value * 2) - 113 if radio is Radio.wcdma: return value - 116 if radio is Radio.lte: return value - 140 def deserialize(self, data): if data: # Sometimes the asu and signal fields are swapped if (data.get("asu") is not None and data.get("asu", 0) < -5 and (data.get("signalStrength") is None or data.get("signalStrength", 0) >= 0)): # shallow copy data = dict(data) data["signalStrength"] = data["asu"] data["asu"] = None data = super(ValidCellSignalSchema, self).deserialize(data) if isinstance(data.get("radioType"), Radio): radio = data["radioType"] # Radio type specific checks for ASU field if data.get("asu") is not None: if not (constants.MIN_CELL_ASU[radio] <= data["asu"] <= constants.MAX_CELL_ASU[radio]): data = dict(data) data["asu"] = None # Radio type specific checks for signal field if data.get("signalStrength") is not None: if not (constants.MIN_CELL_SIGNAL[radio] <= data["signalStrength"] <= constants.MAX_CELL_SIGNAL[radio]): data = dict(data) data["signalStrength"] = None # Radio type specific checks for TA field if data.get("timingAdvance") is not None and radio is Radio.wcdma: data = dict(data) data["timingAdvance"] = None # Calculate signal from ASU field if data.get( "asu") is not None and data.get("signalStrength") is None: if (constants.MIN_CELL_ASU[radio] <= data["asu"] <= constants.MAX_CELL_ASU[radio]): data = dict(data) data["signalStrength"] = self._signal_from_asu( radio, data["asu"]) return data
class ValidWifiLookupSchema(ValidWifiSignalSchema): """A schema which validates the fields in a WiFi lookup.""" mac = MacNode(colander.String()) ssid = DefaultNode(colander.String(), missing=None)