예제 #1
0
async def model_delete_all(request, model_id):
    try:
        await cfg.models[model_id]["model"].delete.where(True).gino.status()
        message = f"All objects in {model_id} was deleted"
        flash_message = (message, "success")
        log_history_event(request, message, f"all, model_id: {model_id}")
    except asyncpg.exceptions.ForeignKeyViolationError as e:
        flash_message = (e.args, "error")
    return await model_view_table(request, model_id, flash_message)
예제 #2
0
async def upload_from_csv_data(upload_file: File, file_name: Text,
                               request: Request, model_id: Text):
    with TextIOWrapper(BytesIO(upload_file.body)) as read_obj:
        request, is_success = await insert_data_from_csv_rows(
            read_obj, model_id, request)
        if is_success:
            log_history_event(
                request,
                f"Upload data from CSV from file {file_name} to model {model_id}",
                "system: upload_csv",
            )
        return request, is_success
예제 #3
0
async def init_db_run(request: Request):

    data = literal_eval(request.form["data"][0])
    count = 0
    for _, value in data.items():
        if isinstance(value, int):
            count += value
    await drop_and_recreate_all_tables()
    message = f"{count} object was deleted. DB was Init from Scratch"
    request.ctx.flash(message, "success")
    log_history_event(request, message, "system: init_db")
    return jinja.render("init_db.html",
                        request,
                        data=await count_elements_in_db())
예제 #4
0
async def model_edit_post(request, model_id):
    model_data = cfg.models[model_id]
    model = model_data["model"]
    columns_data = model_data["columns_data"]
    previous_id: Dict = utils.extract_obj_id_from_query(
        dict(request.query_args)["_id"])
    previous_id: Dict = utils.correct_types(previous_id,
                                            columns_data,
                                            no_default=True)

    request_params = {
        key: request.form[key][0] if request.form[key][0] != "None" else None
        for key in request.form
    }
    request_params = utils.prepare_request_params(request_params, model_id,
                                                  model_data)
    try:
        if not model_data["identity"]:
            old_obj = previous_id
            await update_all_by_params(request_params, previous_id, model)
            obj = request_params
        else:
            obj = await get_by_params(previous_id, model)
            old_obj = obj.to_dict()
            await obj.update(**request_params).apply()
            obj = obj.to_dict()
        changes = utils.get_changes(old_obj, obj)
        new_obj_id = utils.get_obj_id_from_row(model_data, request_params,
                                               previous_id)
        message = f"Object with id {previous_id} was updated."
        if changes:
            message += f'Changes: from {changes["from"]} to {changes["to"]}'
        request.ctx.flash(message, "success")
        log_history_event(request, message, previous_id)
    except asyncpg.exceptions.ForeignKeyViolationError as e:
        request.ctx.flash(
            f"ForeignKey error. "
            f"Impossible to edit field for row {previous_id}, "
            f"because exists objects that depend on it. {e}",
            "error",
        )
    except asyncpg.exceptions.UniqueViolationError:
        request.ctx.flash(
            f"{model_id.capitalize()} with such id already exists", "error")
    except asyncpg.exceptions.NotNullViolationError as e:
        column = e.args[0].split("column")[1].split("violates")[0]
        request.ctx.flash(f"Field {column} cannot be null", "error")
    return await render_add_or_edit_form(request, model_id, new_obj_id)
예제 #5
0
async def presets(request: Request):
    # json content/type expected
    preset_path = request.json.get("preset")
    preset_id = request.json.get("preset_id")
    if preset_id:
        preset = get_preset_by_id(preset_id)
        if not preset:
            answer = {
                "error":
                f"Could not find preset with id {preset_id} in presets folder {cfg.presets_folder}. "
            }
            return response.json(answer, status=422)
        presets_folder = cfg.presets_folder
    else:
        if not preset_path:
            answer = {
                "error":
                'You must provide "preset" field with path to preset yml file or preset_id. '
            }
            return response.json(answer, status=422)
        preset = read_yaml(preset_path)
        presets_folder = os.path.dirname(preset_path)
    with_drop = "drop" in request.json
    if with_drop:
        await drop_and_recreate_all_tables()
    try:
        for model_id, file_path in preset["files"].items():
            request.ctx.flash_messages = []
            # TODO(ehborisov): handle is_success and errors properly?
            request, is_success = await insert_data_from_csv_file(
                os.path.join(presets_folder, file_path), model_id.lower(),
                request)
        logger.debug(str(request.ctx.flash_messages))
        if "drop" in request.json:
            message = "DB was dropped & Preset was success loaded"
        else:
            message = "Preset was loaded"
        result = response.json({"status": f"{message}"}, status=200)
        log_history_event(
            request,
            f"Loaded preset {preset['id']}{' with DB drop' if with_drop else ''}",
            "system: load_preset",
        )
    except FileNotFoundError:
        answer = {"error": f"Wrong file path in Preset {preset['name']}."}
        result = response.json(answer, status=422)
    return result
예제 #6
0
async def model_delete(request, model_id):
    """ route for delete item per row """
    model_data = cfg.models[model_id]
    model = model_data["model"]
    request_params = {key: request.form[key][0] for key in request.form}
    obj_id = utils.get_obj_id_from_row(model_data, request_params)
    try:
        if not model_data["identity"]:
            await delete_all_by_params(obj_id, model)
        else:
            obj = await get_by_params(obj_id, model)
            await obj.delete()
        message = f"Object with {obj_id} was deleted"
        flash_message = (message, "success")
        log_history_event(request, message, obj_id)
    except asyncpg.exceptions.ForeignKeyViolationError as e:
        flash_message = (str(e.args), "error")

    return await model_view_table(request, model_id, flash_message)
예제 #7
0
async def model_copy(request, model_id):
    """ route for copy item per row """
    request_params = {elem: request.form[elem][0] for elem in request.form}
    base_obj_id = utils.extract_obj_id_from_query(request_params["_id"])
    try:
        new_obj_key = await create_object_copy(model_id, base_obj_id,
                                               cfg.models[model_id])
        message = f"Object with {base_obj_id} key was copied as {new_obj_key}"
        flash_message = (message, "success")
        log_history_event(request, message, new_obj_key)
    except asyncpg.exceptions.UniqueViolationError as e:
        flash_message = (
            f"Duplicate in Unique column Error during copy: {e.args}. \n"
            f"Try to rename existed id or add manual.",
            "error",
        )
    except asyncpg.exceptions.ForeignKeyViolationError as e:
        flash_message = (e.args, "error")
    return await model_view_table(request, model_id, flash_message)
예제 #8
0
async def sql_query_run(request):
    result = []
    if not request.form.get("sql_query"):
        request.ctx.flash("SQL query cannot be empty", "error")
    else:
        sql_query = request.form["sql_query"][0]
        try:
            result = await cfg.app.db.status(cfg.app.db.text(sql_query))
            log_history_event(request, f"Query run '{sql_query}'",
                              "system: sql_run")
        except asyncpg.exceptions.PostgresSyntaxError as e:
            request.ctx.flash(f"{e.args}", "error")
        except asyncpg.exceptions.UndefinedTableError as e:
            request.ctx.flash(f"{e.args}", "error")
    if result:
        return jinja.render("sql_runner.html",
                            request,
                            columns=result[1],
                            result=result[1])
    else:
        return jinja.render("sql_runner.html", request)
예제 #9
0
async def presets_use(request: Request):
    preset = utils.get_preset_by_id(request.form["preset"][0])
    with_drop = "with_db" in request.form
    if with_drop:
        await drop_and_recreate_all_tables()
        request.ctx.flash("DB was successful Dropped", "success")
    try:
        for model_id, file_path in preset["files"].items():
            request, is_success = await insert_data_from_csv_file(
                os.path.join(cfg.presets_folder, file_path), model_id.lower(),
                request)
        for message in request.ctx.flash_messages:
            request.ctx.flash(*message)
        history_message = (
            f"Loaded preset {preset['id']} {' with DB drop' if with_drop else ''}"
        )
        log_history_event(request, history_message, "system: load_preset")
    except FileNotFoundError:
        request.ctx.flash(f"Wrong file path in Preset {preset['name']}.",
                          "error")
    return jinja.render("presets.html",
                        request,
                        presets=utils.get_presets()["presets"])
예제 #10
0
async def model_add(request, model_id):
    model_data = cfg.models[model_id]
    request_params = {key: request.form[key][0] for key in request.form}
    request_params = utils.prepare_request_params(request_params, model_id,
                                                  model_data)
    not_filled = [
        x for x in model_data["required_columns"] if x not in request_params
    ]
    if not_filled:
        request.ctx.flash(f"Fields {not_filled} required. Please fill it",
                          "error")
    else:
        try:
            obj = await model_data["model"].create(**request_params)
            obj_id = utils.get_obj_id_from_row(model_data, obj.to_dict())
            message = f"Object with {obj_id} was added."
            request.ctx.flash(message, "success")
            log_history_event(request, message, obj_id)
        except (
                asyncpg.exceptions.StringDataRightTruncationError,
                ValueError,
                asyncpg.exceptions.ForeignKeyViolationError,
        ) as e:
            request.ctx.flash(e.args, "error")
        except asyncpg.exceptions.UniqueViolationError:
            request.ctx.flash(
                f"{model_id.capitalize()} with such id already exists",
                "error")
        except asyncpg.exceptions.NotNullViolationError as e:
            column = e.args[0].split("column")[1].split("violates")[0]
            request.ctx.flash(f"Field {column} cannot be null", "error")
        except asyncpg.exceptions.UndefinedTableError:
            request.ctx.flash(
                f"Somebody stole the table. Table {model_id} does not exist",
                "error")

    return await render_add_or_edit_form(request, model_id)
예제 #11
0
async def model_deepcopy(request, model_id):
    """
    Recursively creates copies for the whole chain of entities, referencing the given model and instance id through
    the foreign keys.
    :param request:
    :param model_id:
    :return:
    """
    request_params = {key: request.form[key][0] for key in request.form}

    columns_data = cfg.models[model_id]["columns_data"]
    base_obj_id = utils.extract_obj_id_from_query(request_params["_id"])
    try:
        # todo: fix deepcopy
        new_id = utils.extract_obj_id_from_query(request_params["new_id"])
        new_id = utils.correct_types(new_id, columns_data)
    except ValueError as e:
        request.ctx.flash(e, "error")
        return await render_model_view(request, model_id)
    try:
        async with cfg.app.db.acquire() as conn:
            async with conn.transaction() as _:
                new_base_obj_id = await deepcopy_recursive(
                    cfg.models[model_id]["model"],
                    base_obj_id,
                    new_id=new_id,
                    model_data=cfg.models[model_id],
                )
                if isinstance(new_base_obj_id, tuple):
                    request.ctx.flash(new_base_obj_id, "error")
                else:
                    message = f"Object with {request_params['_id']} was deepcopied with new id {new_base_obj_id}"
                    request.ctx.flash(message, "success")
                    log_history_event(request, message, new_base_obj_id)
    except asyncpg.exceptions.PostgresError as e:
        request.ctx.flash(e.args, "error")
    return await render_model_view(request, model_id)