def create_device_group():
    uid, err = get_oemid(request=request)
    if err is not None:
        return jsonify(UNAUTH_RESULT)

    ctx.current_user = DccaUser.get_by_id(uid)

    check_json(request)
    name = get_json(request).get('name')
    desc = get_json(request).get('description')
    customer = get_json(request).get('customer')

    if desc is None:
        desc = ''

    empty_check(name, error_message='Name cannot be empty')

    DccaDeviceGroup.is_name_taken(name, ctx.current_user)

    group = DccaDeviceGroup(name, description=desc, customer=customer)
    try:
        session.add(group)
        session.commit()
    except Exception:
        raise DCCAException('Fail to create device group')

    results = OrderedDict()
    results['status'] = 'success'
    results['message'] = 'Success to create a group'
    results['group'] = group.as_dict(schema=DeviceGroupSchema)

    return jsonify(results)
def query_device_groups():
    uid, err = get_oemid(request=request)
    if err is not None:
        return jsonify(UNAUTH_RESULT)

    ctx.current_user = DccaUser.get_by_id(uid)

    limit = request.args.get('limit') or DEFAULT_GROUP_LIMTI
    offset = request.args.get('offset') or DEFAULT_GROUP_OFFSET

    filter_name = request.args.get('filter_name')
    order_by = request.args.get('order_by')

    groups, size = DccaDeviceGroup.query_all(DeviceGroupSchema,
                                             order_column=order_by,
                                             uid=uid,
                                             filter_name=filter_name,
                                             limit=limit,
                                             offset=offset)

    results = OrderedDict()
    results['limit'] = limit
    results['offset'] = offset
    results['total'] = size
    results['groups'] = []

    for group in groups:
        results['groups'].append(group.as_dict(schema=DeviceGroupSchema))

    return jsonify(results)
def query_one_group(group_id):
    uid, err = get_oemid(request=request)
    if err is not None:
        return jsonify(UNAUTH_RESULT)

    ctx.current_user = DccaUser.get_by_id(uid)

    limit = request.args.get('limit') if request.args.get(
        'limit') else DEFAULT_GROUP_LIMTI
    offset = request.args.get('offset') if request.args.get(
        'offset') else DEFAULT_GROUP_OFFSET

    empty_check(group_id, error_message='The "group_id" cannot be empty.')
    results = OrderedDict()

    # workaround it is not a uuid, group id
    if group_id and len(str(group_id)) < 32:
        devices_group_list = DccaAssHostModel.get_model_deviceid(int(group_id))

        r = DccaModel.get_by_id(int(group_id))
        if not r:
            raise Exception("%s: group or model not found" % (str(group_id)))

        results['id'] = r.id
        name = "%s-%s-%s-%s" % (r.model, r.type, r.platform, r.vendor)
        results['name'] = name
        results["description"] = "%s: model group" % name

    else:
        group = DccaDeviceGroup.get_by_id(group_id, uid)
        empty_check(group, error_message='The "group" is not accessable.')
        devices_group_list = group.query_bind_devices(limit=limit,
                                                      offset=offset)

        results['id'] = group_id
        results["name"] = group.name
        results["description"] = group.desc

    results["device"] = OrderedDict()
    results["device"]['limit'] = limit
    results["device"]['offset'] = offset
    results['devices'] = []
    total = 0

    for device_group in devices_group_list:
        device_id = device_group[0]
        device = Host.get_id(device_id)
        if device:
            model_id = Host.get_model_id(device_id)
            devices = device.as_dict(schema=DeviceSchema)
            devices['status'] = query_one_device_status(devices['name'])
            total += 1
            results['devices'].append(devices)
            if model_id[0]:
                model = DccaModel.get_by_id(model_id)
                devices['model'] = model.as_dict(schema=ModelSchema)
    results['device']['total'] = total

    return jsonify(results)
def batch_delete_device_group():
    uid, err = get_oemid(request=request)
    if err is not None:
        return jsonify(UNAUTH_RESULT)

    ctx.current_user = DccaUser.get_by_id(uid)

    check_json(request)
    group_ids = get_json(request).get('group_ids')

    empty_check(group_ids, error_message='The "group_ids" cannot be empty.')

    remove_fail_list = []
    remove_list = []
    results = OrderedDict()
    results['groups'] = OrderedDict()
    results['groups']['success'] = []
    results['groups']['fail'] = []

    for group_id in group_ids:
        group = DccaDeviceGroup.get_by_id(group_id, uid)
        if group:
            try:
                remove_list.append(group)
                group.remove()
                session.commit()
            except Exception as e:
                remove_fail_dict = {'id': group_id, 'message': e}
                remove_fail_list.append(remove_fail_dict)
                raise DCCAException('Fail to remove device group')
        else:
            message = 'Fail to remove device group'
            remove_fail_dict = {'id': group_id, 'message': message}
            remove_fail_list.append(remove_fail_dict)

    if len(remove_list) == 0:
        results['status'] = "fail"
        results['message'] = "Fail to remove device group"
        for group_fail in remove_fail_list:
            results['groups']['fail'].append(group_fail)
        results['groups']['fail_total'] = len(remove_fail_list)
    else:
        for group in remove_list:
            results['status'] = "success"
            results['message'] = "Success to remove group"
            results['groups']['success'].append(
                group.as_dict(schema=DeviceGroupBindSchema))
        results['groups']['success_total'] = len(remove_list)
        for group_fail in remove_fail_list:
            results['groups']['fail'].append(group_fail)
        results['groups']['fail_total'] = len(remove_fail_list)

    return jsonify(results)
def modify_one_group(group_id):
    uid, err = get_oemid(request=request)
    if err is not None:
        return jsonify(UNAUTH_RESULT)

    ctx.current_user = DccaUser.get_by_id(uid)

    empty_check(group_id, error_message='The "group_id" cannot be empty.')

    check_json(request)
    name = get_json(request).get('name')
    input_valid_check(name, error_message='Invalid characters in name.')

    group = DccaDeviceGroup.get_by_id(group_id, uid)

    empty_check(group, error_message='The "group" is not accessable.')

    desc = get_json(request).get('description')

    if not name and not desc:
        return jsonify({
            'status': 'fail',
            'message': 'Empty parameters, not modified'
        })

    if name:
        group.name = name

    if desc:
        group.desc = desc
    elif desc == '':
        group.desc = ''

    group.updated_at = datetime.utcnow()

    try:
        session.add(group)
        session.commit()
    except Exception:
        raise DCCAException('Fail to update group')

    results = OrderedDict()
    results['status'] = 'success'
    results['message'] = 'Success to update group'
    results['group'] = group.as_dict(schema=DeviceGroupSchema)

    return jsonify(results)
def bind_device_to_group(group_id, device_id):
    uid, err = get_oemid(request=request)
    if err is not None:
        return jsonify(UNAUTH_RESULT)

    ctx.current_user = DccaUser.get_by_id(uid)

    empty_check(group_id, error_message='The "group_id" cannot be empty.')
    empty_check(device_id, error_message='The "device_id" cannot be empty')

    group = DccaDeviceGroup.get_by_id(group_id, uid)

    if group is None:
        return jsonify({
            'status': 'fail',
            'message': "The group_id does not exist"
        })

    device = Host.get_by_id(device_id)
    if device is None:
        return jsonify({
            'status': 'fail',
            'message': "The device_id does not exist"
        })

    results = OrderedDict()

    if not device.has_group(group):
        try:
            device.groups.append(group)
            session.add(device)
            session.commit()
        except Exception:
            raise DCCAException('Fail to bind device to group')

        results['status'] = 'success'
        results['message'] = 'Success to add device to group'
        results['group'] = group.as_dict(schema=DeviceGroupBindSchema)
        results['device'] = device.as_dict(schema=DeviceIDSchema)
    else:
        results['status'] = 'fail'
        results[
            'message'] = 'This device already exists in the {} group, please do not add it repeatedly'.format(
                group.name)

    return jsonify(results)
def delete_device_group(group_id):
    uid, err = get_oemid(request=request)
    if err is not None:
        return jsonify(UNAUTH_RESULT)

    ctx.current_user = DccaUser.get_by_id(uid)

    empty_check(group_id, error_message='The "group_id" cannot be empty.')

    group = DccaDeviceGroup.get_by_id(group_id, uid)
    empty_check(group, error_message='The "group" is not accessable.')

    try:
        group.remove()
        session.commit()
    except Exception:
        raise DCCAException('Fail to remove device group')

    results = OrderedDict()
    results['status'] = 'success'
    results['message'] = 'Success to remove group'
    results['group'] = group.as_dict(schema=DeviceGroupSchema)

    return jsonify(results)
def remove_device_from_group(group_id):
    uid, err = get_oemid(request=request)
    if err is not None:
        return jsonify(UNAUTH_RESULT)

    ctx.current_user = DccaUser.get_by_id(uid)

    empty_check(group_id, error_message='The "group_id" cannot be empty.')

    check_json(request)
    device_ids = get_json(request).get('devices')
    empty_check(device_ids, error_message='The "device_ids" cannot be empty')

    group = DccaDeviceGroup.get_by_id(group_id, uid)

    if group is None:
        return jsonify({
            'status': 'fail',
            'message': "The group_id does not exist"
        })

    remove_fail_list = []
    remove_list = []
    for device_id in device_ids:
        device = Host.get_by_id(device_id)
        if device is None:
            bind_fail_dict = {
                'id': device_id,
                'message': 'The device_id does not exist'
            }
            remove_fail_list.append(bind_fail_dict)
        else:
            if device.has_group(group):
                try:
                    group.devices.remove(device)
                    session.commit()
                    remove_list.append(device)
                except Exception as e:
                    bind_fail_dict = {'id': device_id, 'message': e}
                    remove_fail_list.append(bind_fail_dict)
                    raise DCCAException('Fail to bind device to group')
            else:
                message = 'This device already exists in the {} group, please do not add it repeatedly'.format(
                    group.name)
                bind_fail_dict = {'id': device_id, 'message': message}
                remove_fail_list.append(bind_fail_dict)

    results = OrderedDict()
    if len(remove_list) == 0:
        results['status'] = "fail"
        results['message'] = "Fail to unbind device from group"
        results['group'] = group.as_dict(schema=DeviceGroupBindSchema)
        results['devices'] = {}
    else:
        results['status'] = "success"
        results['message'] = "Success to remove device from group"
        results['group'] = group.as_dict(schema=DeviceGroupBindSchema)
        results['devices'] = {}
        results['devices']['success'] = []
        results['devices']['success_total'] = len(remove_list)
        for device in remove_list:
            results['devices']['success'].append(
                device.as_dict(schema=DeviceIDSchema))
    results['devices']['fail'] = []
    results['devices']['fail_total'] = len(remove_fail_list)
    for device_fail in remove_fail_list:
        results['devices']['fail'].append(device_fail)

    return jsonify(results)
def group_create_tasks():
    uid, err = get_oemid(request=request)
    if err is not None:
        return jsonify(UNAUTH_RESULT)

    ctx.current_user = DccaUser.get_by_id(uid)

    check_json(request)
    group_id = get_json(request).get('group_id')
    task_type = get_json(request).get('type')
    payloads = get_json(request).get('payload')
    # workaround it is not a uuid, group id
    if group_id and len(str(group_id)) < 32:
        device_list = DccaAssHostModel.get_model_deviceid(int(group_id))
    else:
        group = DccaDeviceGroup.get_by_id(group_id, uid)
        empty_check(group, error_message='The "group" is not accessable.')
        device_list = DccaDeviceGroup.query_bind_model_devices(group_id, uid)
    if not device_list or len(device_list) < 1:
        return jsonify({
            'status': 'fail',
            'message': 'There are no devices in this device group'
        })
    device_list = set(device_list)
    device_ids = [device_id[0] for device_id in device_list]

    devices = Host.query_in(device_ids)
    if len(devices) != len(device_ids):
        return jsonify({
            'status':
            'fail',
            'message':
            'Not authorized devices exist. Device not exist or cannot access',
            'not_authorized_devices':
            list(set(device_ids) - set([d.id for d in devices]))
        })

    if task_type not in list(TASK_TYPE_NAMES.values()):
        return jsonify({'status': 'fail', 'message': 'No such kind of task'})

    try:
        inst_list = []
        if task_type == TASK_TYPE_NAMES[TASK_TYPE_APP]:
            unauthoried = EsTask.check_da_payload(payloads)
            if unauthoried:
                return jsonify({
                    'status': 'fail',
                    'message':
                    'Unauthorized application exists, not exist or cannot access.',
                    'unauthorized': unauthoried
                })

            task = EsTask.create_da_task(payloads)
            session.add(task)
            session.flush()
            for pl in payloads:
                softapp = DccaSoftapp.get(pl['softapp_id'])
                del pl['softapp_id']
                for device in devices:
                    inst = task.da_inst(device, softapp, pl)
                    session.add(inst)
                    inst_list.append(inst)
            session.commit()
        elif task_type == TASK_TYPE_NAMES[TASK_TYPE_SOLUTION]:
            authed, solution = EsTask.check_ota_payload(payloads)
            if not authed:
                return jsonify({
                    'status':
                    'fail',
                    'message':
                    'Solution not exist or cannot access.'
                })

            task = EsTask.create_ota_task(payloads)
            session.add(task)
            session.flush()
            for device in devices:
                inst = task.ota_inst(device, solution)
                session.add(inst)
                inst_list.append(inst)
            session.commit()
        else:
            return jsonify({
                'status': 'fail',
                'message': 'No such kind of task'
            })

        try:
            for inst in inst_list:
                if inst.task.type == TASK_TYPE_APP:
                    print(('Start da task: ', inst))
                    inst.start(APPSERVER_HOST, APPSERVER_PORT)
                elif inst.task.type == TASK_TYPE_SOLUTION:
                    print('Start ota task')
                    inst.start(MQTT_HOST)
        except Exception:
            import traceback
            traceback.print_exc()
            session.rollback()
        else:
            session.commit()

        results = OrderedDict()
        results['status'] = 'success'
        results['message'] = 'Success to create the task'
        results['task'] = task.as_dict(schema=TaskSchema)
        return jsonify(results)
    except Exception as e:
        raise DCCAException(str(e))
def device_save_to_group():
    uid, err = get_oemid(request=request)
    if err is not None:
        return jsonify(UNAUTH_RESULT)

    ctx.current_user = DccaUser.get_by_id(uid)

    limit = request.args.get('limit') if request.args.get(
        'limit') else DEFAULT_GROUP_LIMTI
    offset = request.args.get('offset') if request.args.get(
        'offset') else DEFAULT_GROUP_OFFSET

    check_json(request)
    group_name = get_json(request).get("name")
    group_desc = get_json(request).get('description')
    customer_id = get_json(request).get('customer')
    bind_fail_list = []
    bind_list = []

    if group_desc is None:
        group_desc = ''

    customer = DccaCustomer.get_by_id(customer_id)
    if customer is None:
        customer_id = None
        session.commit()

    empty_check(group_name, error_message='Name cannot be empty')

    DccaDeviceGroup.is_name_taken(group_name, ctx.current_user)

    group = DccaDeviceGroup(group_name,
                            description=group_desc,
                            customer=customer_id)
    try:
        session.add(group)
    except Exception:
        raise DCCAException("Fail to create device group")
    devices = get_json(request).get('devices')

    if devices:
        for device in devices:
            device = Host.get_by_id(device)
            if device is None:
                bind_fail_dict = {
                    'id': device,
                    'message': 'The device_id does not exist'
                }
                bind_fail_list.append(bind_fail_dict)
            else:
                if not device.has_group(group):
                    try:
                        device.groups.append(group)
                        session.add(device)
                        session.commit()
                        bind_list.append(device)
                    except Exception as e:
                        bind_fail_dict = {'id': device.id, 'message': e}
                        bind_fail_list.append(bind_fail_dict)
                        raise DCCAException('Fail to bind device to group')
                else:
                    message = 'This device already exists in the {} group, please do not add it repeatedly'.format(
                        group.name)
                    bind_fail_dict = {'id': device.id, 'message': message}
                    bind_fail_list.append(bind_fail_dict)
    else:
        intersection = get_json(request).get('intersection', False)

        results = []
        condition_items = get_json(request).get('by_condition')
        if 'by_condition' in get_json(request) and condition_items:
            if not any([x['value'] for x in condition_items]):
                devices_by_attr = set()
            else:
                devices_by_attr = device_attr_filter(request.cursor, uid,
                                                     limit, offset,
                                                     condition_items)
                results.append(devices_by_attr)
        else:
            devices_by_attr = set()

        if 'by_solution' in get_json(request) and get_json(request).get(
                'by_solution'):
            solution_id = get_json(request).get('by_solution')

            devices_by_sol = device_solution_filter(request.cursor, uid, limit,
                                                    offset, solution_id)
            results.append(devices_by_sol)

        else:
            devices_by_sol = set()

        if intersection:
            if results:
                devices = list(reduce(lambda x, y: x & y, results))
            else:
                devices = []
        else:
            devices = list(devices_by_attr | devices_by_sol)

        if len(devices) == 0:
            return jsonify({
                "status":
                "fail",
                "message":
                "The device that matches the search criteria is empty. Please re-enter."
            })

        for device in devices:
            device = Host.get_by_id(device['id'])
            if device is None:
                bind_fail_dict = {
                    'id': device.id,
                    'message': 'The device_id does not exist'
                }
                bind_fail_list.append(bind_fail_dict)
            else:
                if not device.has_group(group):
                    try:
                        device.groups.append(group)
                        session.add(device)
                        session.commit()
                        bind_list.append(device)
                    except Exception as e:
                        bind_fail_dict = {'id': device.id, 'message': e}
                        bind_fail_list.append(bind_fail_dict)
                        raise DCCAException('Fail to bind device to group')
                else:
                    message = 'This device already exists in the {} group, please do not add it repeatedly'.format(
                        group.name)
                    bind_fail_dict = {'id': device.id, 'message': message}
                    bind_fail_list.append(bind_fail_dict)

    results = OrderedDict()
    if len(bind_list) == 0:
        results['status'] = "fail"
        results['message'] = "Fail to bind device to group"
        results['group'] = group.as_dict(schema=DeviceGroupBindSchema)
        results['devices'] = {}
    else:
        results['status'] = "success"
        results['message'] = "Success to add device to group"
        results['group'] = group.as_dict(schema=DeviceGroupBindSchema)
        results['devices'] = {}
        results['devices']['success'] = []
        results['devices']['success_total'] = len(bind_list)
        for device in bind_list:
            results['devices']['success'].append(
                device.as_dict(schema=DeviceIDSchema))
    results['devices']['fail'] = []
    results['devices']['fail_total'] = len(bind_fail_list)
    for device_fail in bind_fail_list:
        results['devices']['fail'].append(device_fail)

    return jsonify(results)