def _lwm2m_protocol(data): """ handle lwm2m protocol publish """ try: load_payload = json.loads(data['payload']) except Exception: raise FormInvalid(field='payload') # build emqx lwm2m protocol require payload handled_payload = _validate_lwm2m_topic(data['topic']) if data['topic'] == '/19/1/0': handled_payload['msgType'] = 'write' handled_payload['value'] = load_payload else: msg_type = load_payload.get('msgType') if msg_type == 'read': # {'msgType': 'read', 'path': xx} handled_payload['msgType'] = 'read' elif msg_type == 'write' and load_payload.get('value'): # {'msgType': 'write', 'path': xx, 'value': xx, 'type': xx} handled_payload['msgType'] = 'write' handled_payload['value'] = load_payload['value'] elif msg_type == 'execute': # {'msgType': 'execute', 'path': xx, 'args'} handled_payload['msgType'] = 'execute' if load_payload.get('args'): handled_payload['args'] = load_payload['args'] else: raise FormInvalid(field='payload') data['payload'] = json.dumps(handled_payload) return data
def device_name_is_exist(self, value): device_type = self.get_origin_obj('deviceType') if device_type and device_type != value: # deviceType not support update raise FormInvalid(field='deviceType') product_type = self.get_request_data('productType') if device_type != product_type: raise FormInvalid(field='deviceType')
def email_is_exist(self, value): try: split_email = value.split('@')[0] if split_email in current_app.config.get('RESERVED'): raise FormInvalid(field='email') except Exception: raise FormInvalid(field='email') if db.session.query(User.email).filter_by(email=value).first(): raise DataExisted(field='email')
def validate_webhook(self, data): url = data.get('url') token = data.get('token') if not all([url, token]): return timestamp = int(time.time()) nonce = generate_uuid(size=10) hash_str = f"{token}{timestamp}{nonce}".encode('utf-8') signature = hashlib.sha1(hash_str).hexdigest() validate_status = True params = dict(signature=signature, timestamp=timestamp, nonce=nonce) with SyncHttp() as sync_http: response = sync_http.get(url=url, params=params) if response.responseCode != 200: validate_status = False try: response_dict = json.loads(response.responseContent) if response_dict.get('nonce') != params.get('nonce'): validate_status = False except Exception as e: logger.error(f"Webhook {e}", exc_info=True) validate_status = False if not validate_status: raise FormInvalid(field='Webhook url')
def signup_normal_user(normal_user=None): tenant_dict = TenantSchema.validate_request() tenant_type = tenant_dict.get('tenantType') tenant_uid = random_tenant_uid(tenant_type) tenant_dict['contactEmail'] = normal_user['email'] tenant_dict['tenantID'] = tenant_uid phone = normal_user.get('phone') or tenant_dict.get('contactPhone') tenant_dict['contactPhone'] = phone normal_user['phone'] = phone new_tenant = Tenant() for key, value in tenant_dict.items(): if hasattr(new_tenant, key): setattr(new_tenant, key, value) db.session.add(new_tenant) db.session.flush() # Role if tenant_type == 1: normal_user['roleIntID'] = 3 elif tenant_type == 2: normal_user['roleIntID'] = 2 else: raise FormInvalid(field='tenantType') normal_user['tenantID'] = tenant_uid return normal_user
def validate_uplink_system(self, data): uplink_system = data.get('upLinkSystem') if uplink_system == 1: data['parentDevice'], data['gateway'] = None, None elif uplink_system == 2 and isinstance(data.get('parentDevice'), int): parent_device = data['parentDevice'] end_device_id = EndDevice.query \ .filter_tenant(tenant_uid=g.tenant_uid) \ .filter(EndDevice.id == parent_device) \ .with_entities(EndDevice.id).first() if not end_device_id: raise DataNotFound(field='parentDevice') data['parentDevice'], data['gateway'] = end_device_id, None elif uplink_system == 3 and isinstance(data.get('gateway'), int): gateway = data['gateway'] gateway_id = Gateway.query \ .filter_tenant(tenant_uid=g.tenant_uid) \ .filter(Gateway.id == gateway) \ .with_entities(Gateway.id).first() if not gateway_id: raise DataNotFound(field='gateway') data['parentDevice'], data['gateway'] = None, gateway_id else: raise FormInvalid(field='upLinkSystem') return data
def _validate_lwm2m_topic(topic: str) -> dict: handled_payload = {'path': topic} if topic == '/19/1/0': handled_payload['type'] = 'Opaque' else: product_item_info = [i for i in topic.split('/') if i.isdigit()] if len(product_item_info) != 3: raise FormInvalid(field='topic') # item_id/xx/object_id/ or item_id/xx/object_id/xxx object_id, item_id = product_item_info[0], product_item_info[2] lwm2m_item = Lwm2mItem.query \ .filter(Lwm2mItem.objectID == object_id, Lwm2mItem.itemID == item_id) \ .with_entities(Lwm2mItem.objectItem, Lwm2mItem.itemType).first() if not lwm2m_item: raise FormInvalid(field='topic') handled_payload['type'] = lwm2m_item.itemType return handled_payload
def product_load(self, data): product_type = data.get('productType') if not product_type: data['productType'] = 1 gateway_protocol = data.get('gatewayProtocol') if data['productType'] == 2 and not gateway_protocol: raise FormInvalid(field='gatewayProtocol') if data['productType'] == 1 and gateway_protocol: data['gatewayProtocol'] = None return data
def stream_id_is_exist(self, value): if self._validate_obj('streamID', value): return if not re.match(r"^[a-zA-Z]\w{3,}$", value): raise FormInvalid(field='streamID') product_uid = self.get_request_data('productID') stream_name = db.session.query(DataStream.streamID) \ .filter(DataStream.productID == product_uid, DataStream.streamID == value).first() if stream_name: raise DataExisted(field='streamID')
def validate_timer_format(data): timer_type = data.get('timerType') interval_time = data.get('intervalTime') crontab_time = data.get('crontabTime') if timer_type == 1 and crontab_time and not interval_time: date_now = arrow.now(tz=current_app.config['TIMEZONE']).shift( minutes=+2) try: crontab_time = arrow.get(crontab_time) except ParserError: raise FormInvalid(field='crontabTime') if crontab_time < date_now: FormInvalid(field='crontabTime') elif timer_type == 2 and interval_time and not crontab_time: check_status = check_interval_time(interval_time) if not check_status: raise FormInvalid(field='intervalTime') else: raise FormInvalid(field='timerType') return data
def validate_point_uid(self, value): if not value or self._validate_obj('dataPointID', value): return if not re.match(r"^[0-9A-Za-z_\-]*$", value): raise FormInvalid(field='dataPointID') product_uid = self.get_request_data('productID') data_point_uid = db.session.query(DataPoint.dataPointID) \ .filter(DataPoint.productID == product_uid, DataPoint.dataPointID == value).first() if data_point_uid: raise DataExisted(field='dataPointID')
def signup_invite_user(token): jwt = JWT(current_app.config['SECRET_KEY']) try: data = jwt.loads(token) except Exception: raise FormInvalid(field='token') if not data.get('invitation_id'): raise FormInvalid(field='invitation') invitation = Invitation.query \ .join(Tenant, Tenant.tenantID == Invitation.tenantID) \ .filter(Invitation.id == data.get('invitation_id'), Invitation.inviteStatus == 0, Tenant.enable == 1) \ .first() if not invitation: raise DataNotFound(field='invitation') invitation.inviteStatus = 1 invite_user = { 'roleIntID': invitation.roleIntID, 'tenantID': invitation.tenantID } return invite_user
def handle_load_data(self, data): product_uid: str = data.get('productID') if not isinstance(product_uid, str): raise FormInvalid(field='productID') product = Product.query. \ filter_tenant(tenant_uid=g.tenant_uid) \ .filter(Product.productID == product_uid).first() if not product: raise DataNotFound(field='productID') data['productID'] = product.productID data['cloudProtocol'] = product.cloudProtocol data = handle_extend_type_attr(data) return data
def device_query_object() -> Tuple[BaseQueryT, BaseModelT]: device_type = request.args.get('deviceType', type=int) if request.method in ('PUT', 'POST'): request_dict = request.get_json() or {} device_type = request_dict.get('deviceType') if device_type not in [1, 2]: raise FormInvalid(field='deviceType') if device_type == 1: query, model = EndDevice.query, EndDevice elif device_type == 2: query, model = Gateway.query, Gateway else: query, model = Device.query, Device return query, model
def handle_origin_data(self, data): product_uid = data.get('productID') if not isinstance(product_uid, str): raise FormInvalid(field='productID') product = Product.query \ .filter_tenant(tenant_uid=g.tenant_uid) \ .filter(Product.productID == product_uid).first() if not product: raise DataNotFound(field='productID') data['productType'] = product.productType data['productID'] = product.productID data['cloudProtocol'] = product.cloudProtocol data['gatewayProtocol'] = product.gatewayProtocol return data
def device_publish(): request_dict = PublishSchema.validate_request() # # create publish logs request_dict['taskID'] = generate_uuid() request_dict['publishStatus'] = 1 request_dict['payload'] = json.loads(request_dict['payload']) client_publish_log = PublishLog() created_publish_log = client_publish_log.create(request_dict) # get publish json of protocol publish_json_func = PROTOCOL_PUBLISH_JSON_FUNC.get(request_dict['protocol']) if not publish_json_func: raise FormInvalid(field='cloudProtocol') publish_json = publish_json_func(request_dict) record = _emqx_client_publish(publish_json, created_publish_log) return jsonify(record)
def update_tenant(tenant_id): if g.role_id != 1: raise DataNotFound(field='url') tenant = Tenant.filter(Tenant.id == tenant_id).first_or_404() request_dict = request.get_json() if not request_dict: raise APIException() enable = request_dict.get('enable') if enable not in [0, 1]: raise FormInvalid(field='enable') update_dict = {'enable': enable} updated_tenant = tenant.update(update_dict) record = updated_tenant.to_dict() return jsonify(record)
def handle_user_auth_type(self, data): if 'user_id' not in g: data['userAuthType'] = 1 groups_uid = self.get_request_data(key='groups') auth_type = data.get('userAuthType') if auth_type not in (1, 2): raise FormInvalid(field='userAuthType') if auth_type == 2 and groups_uid: groups = Group.query \ .filter_tenant(tenant_uid=g.tenant_uid) \ .filter(Group.groupID.in_(set(groups_uid))).all() if len(groups_uid) != len(groups): raise DataNotFound(field='groups') data['groups'] = groups else: data.pop('groups', None) return data
def handle_data(self, data): device_uid = data.get('deviceID') if not isinstance(device_uid, str): raise FormInvalid(field='deviceID') client_info = db.session \ .query(Device.id.label('deviceIntID'), Device.productID, Device.tenantID, DictCode.codeValue.label('cloudProtocol'), func.lower(DictCode.enLabel).label('protocol')) \ .join(Product, Product.productID == Device.productID) \ .join(DictCode, DictCode.codeValue == Product.cloudProtocol) \ .filter(Device.deviceID == device_uid, Device.tenantID == g.tenant_uid, DictCode.code == 'cloudProtocol').to_dict() data.update(client_info) data['prefixTopic'] = ( f"/{data['protocol']}/{data['tenantID']}" f"/{data['productID']}/{data['deviceID']}/" ) return data
def handle_validated_data(self, data): data = self.handle_put_request(data) groups_uid: List[str] = data.get('groups') if groups_uid: groups = Group.query \ .filter_tenant(tenant_uid=g.tenant_uid) \ .filter(Group.groupID.in_(set(groups_uid))) \ .many(expect_result=len(groups_uid)) data['groups'] = groups if data['authType'] == 2: certs_id: List[int] = data.get('certs') if not certs_id: raise FormInvalid(field='certs') certs = Cert.query \ .filter_tenant(tenant_uid=g.tenant_uid) \ .filter(Cert.id.in_(set(certs_id))) \ .many(expect_result=len(certs_id)) data['certs'] = certs return data
def create_rule(): request_dict = RuleSchema.validate_request() rule = Rule() new_rule = rule.create(request_dict, commit=False) action_ids = request.get_json().get('actions') if not isinstance(action_ids, list): raise FormInvalid(field='actions') actions = Action.query \ .filter(Action.id.in_(action_ids)) \ .many() for action in actions: new_rule.actions.append(action) rule_json = get_rule_json(new_rule) url = f"{current_app.config.get('STREAM_RULE_URL')}/" stream_rule_http('post', url=url, json=rule_json) db.session.commit() record = new_rule.to_dict() return jsonify(record), 201
def validate_cloud_protocol(self, data): cloud_protocol = data.get('cloudProtocol') if cloud_protocol in [1, 2, 5, 6, 7]: # mqtt, coap, http, websocket, modbus data['loraData'], data['lwm2mData'] = None, None elif cloud_protocol == 3 and data.get('lwm2mData'): # lwm2m data data['loraData'] = None data['lwm2mData'] = Lwm2mDeviceSchema().load( data['lwm2mData']).data data['deviceID'] = data['lwm2mData']['IMEI'] elif cloud_protocol == 4 and data.get('loraData'): # lora data data['lwm2mData'] = None data['loraData'] = LoRaDeviceSchema().load(data['loraData']).data else: error_fields = {3: 'lwm2mData', 4: 'loraData'} raise FormInvalid( field=error_fields.get(cloud_protocol, 'cloudProtocol')) return data
def get_rule_json(rule): rule_actions = [] for action in rule.actions: if action.actionType == 1: alert_dict = AlertActionSchema().dump(action.config).data action_config = { 'webhook': { **alert_dict, 'url': current_app.config.get('CURRENT_ALERT_URL'), 'ruleIntID': rule.id } } elif action.actionType == 2: email_dict = EmailActionSchema().dump(action.config).data action_config = {'mail': email_dict} elif action.actionType == 3: webhook_dict = WebhookActionSchema().dump(action.config).data action_config = {'webhook': webhook_dict} elif action.actionType == 4: publish_dict = PublishActionSchema().dump(action.config).data publish_dict['taskID'] = generate_uuid() publish_json_func = PROTOCOL_PUBLISH_JSON_FUNC.get( publish_dict['protocol']) if not publish_json_func: raise FormInvalid(field='cloudProtocol') publish_json = publish_json_func(publish_dict) action_config = {'publish': {'json': json.dumps(publish_json)}} elif action.actionType == 5: mqtt_dict = MqttActionSchema().dump(action.config).data action_config = {'mqtt': mqtt_dict} else: continue rule_actions.append(action_config) rule_json = { 'id': rule.id, 'sql': rule.sql, 'enabled': rule.enable == 1, 'actions': rule_actions } return rule_json
def device_uid_is_exist(self, data): device_uid = data.get('deviceID') username = data.get('deviceUsername') if self.get_origin_obj('deviceID'): return data if not device_uid or not username: device_uuid = generate_uuid(size=36) data['deviceID'] = device_uuid data['deviceUsername'] = device_uuid return data # unique within the tenant device_uid = db.session.query(Device.deviceID) \ .filter(Device.deviceID == device_uid, Device.tenantID == g.tenant_uid).first() if device_uid: raise DataExisted(field='deviceID') # unique within the platform device = db.session.query(Device.id) \ .filter(Device.deviceID == device_uid, Device.deviceUsername == username).first() if device: raise FormInvalid(field='deviceID') return data
def company_is_exist(self, value): if value == '': raise FormInvalid(field='company') if Tenant.query.filter_by(company=value).first(): raise DataExisted(field='company')
def validate_username(self, value): if value in current_app.config.get('RESERVED'): raise FormInvalid(field='username')
def is_empty_list(self, value): if not value: raise FormInvalid('permissions')
def validate_topic(self, value): if not value or self._validate_obj('topic', value): return if not re.match(r"^[0-9A-Za-z_\-/]*$", value): raise FormInvalid(field='topic')
def handle_error(self, exception, data): """ Log and raise our custom exception when (de)serialization fails. """ raise FormInvalid(errors=exception.messages)