Пример #1
0
def query(dbname):
    "Perform a query of the database; return rows."
    try:
        db = dbshare.db.get_check_read(dbname)
    except ValueError:
        flask.abort(http.client.UNAUTHORIZED)
    except KeyError:
        flask.abort(http.client.NOT_FOUND)
    timer = utils.Timer()
    try:
        query = flask.request.get_json()
        sql = dbshare.query.get_sql_statement(query)
        dbcnx = dbshare.db.get_cnx(dbname)
        cursor = utils.execute_timeout(dbcnx, sql)
    except (jsonschema.ValidationError, sqlite3.Error) as error:
        utils.abort_json(http.client.BAD_REQUEST, error)
    except SystemError:
        flask.abort(http.client.REQUEST_TIMEOUT)
    columns = [d[0] for d in cursor.description]
    rows = cursor.fetchall()
    result = {
        "query": query,
        "sql": sql,
        "nrows": len(rows),
        "columns": columns,
        "cpu_time": timer(),
        "data": [dict(zip(columns, row)) for row in rows],
    }
    return utils.jsonify(utils.get_json(**result), "/query/output")
Пример #2
0
def public():
    "Return the list of public databases."
    result = {
        "title": "Public databases",
        "databases": get_json(dbshare.dbs.get_dbs(public=True)),
    }
    return utils.jsonify(utils.get_json(**result), "/dbs")
Пример #3
0
def all():
    "Return the list of all databases."
    dbs = dbshare.dbs.get_dbs()
    result = {
        "title": "All databases",
        "total_size": sum([db["size"] for db in dbs]),
        "databases": get_json(dbs),
    }
    return utils.jsonify(utils.get_json(**result), "/dbs")
Пример #4
0
def owner(username):
    "Return the list of databases owned by the given user."
    if not dbshare.dbs.has_access(username):
        return flask.abort(http.client.UNAUTHORIZED)
    dbs = dbshare.dbs.get_dbs(owner=username)
    result = {
        "title": f"Databases owned by {username}",
        "user": dbshare.api.user.get_json(username),
        "total_size": sum([db["size"] for db in dbs]),
        "databases": get_json(dbs),
    }
    return utils.jsonify(utils.get_json(**result), "/dbs")
Пример #5
0
def table(dbname, tablename):
    """GET: Return the schema for the table.
    PUT: Create the table.
    DELETE: Delete the table.
    """
    if utils.http_GET():
        try:
            db = dbshare.db.get_check_read(dbname)
        except ValueError:
            flask.abort(http.client.UNAUTHORIZED)
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        try:
            schema = db["tables"][tablename]
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        result = get_json(db, schema, complete=True)
        result.update(schema)
        return utils.jsonify(utils.get_json(**result), "/table")

    elif utils.http_PUT():
        try:
            db = dbshare.db.get_check_write(dbname)
        except ValueError:
            flask.abort(http.client.UNAUTHORIZED)
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        try:
            with dbshare.db.DbSaver(db) as saver:
                schema = flask.request.get_json()
                saver.add_table(schema)
                for index in schema.get("indexes", []):
                    saver.add_index(tablename, index)
        except (jsonschema.ValidationError, ValueError) as error:
            utils.abort_json(http.client.BAD_REQUEST, error)
        return flask.redirect(
            flask.url_for("api_table.table",
                          dbname=dbname,
                          tablename=tablename))

    elif utils.http_DELETE():
        try:
            db = dbshare.db.get_check_write(dbname)
        except ValueError:
            flask.abort(http.client.UNAUTHORIZED)
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        try:
            with dbshare.db.DbSaver(db) as saver:
                saver.delete_table(tablename)
        except ValueError as error:
            utils.abort_json(http.client.BAD_REQUEST, error)
        return ("", http.client.NO_CONTENT)
Пример #6
0
def all():
    "Return the list of all user accounts."
    sql = "SELECT username, email, role, status, created, modified" " FROM users"
    users = [{
        "username": row[0],
        "email": row[1],
        "role": row[2],
        "status": row[3],
        "created": row[4],
        "modified": row[5],
        "href": utils.url_for("api_user.user", username=row[0]),
    } for row in flask.g.syscnx.execute(sql)]
    result = {"title": "All user accounts.", "users": users}
    return utils.jsonify(utils.get_json(**result), "/users")
Пример #7
0
def view(dbname, viewname):
    """GET: Return the schema for the view.
    PUT: Create the view.
    DELETE: Delete the view.
    """
    if utils.http_GET():
        try:
            db = dbshare.db.get_check_read(dbname, nrows=[viewname])
        except ValueError:
            flask.abort(http.client.UNAUTHORIZED)
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        try:
            schema = db["views"][viewname]
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        result = get_json(db, schema, complete=True)
        result.update(schema)
        result.pop("type", None)
        return utils.jsonify(utils.get_json(**result), "/view")

    elif utils.http_PUT():
        try:
            db = dbshare.db.get_check_write(dbname)
        except ValueError:
            flask.abort(http.client.UNAUTHORIZED)
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        try:
            with dbshare.db.DbSaver(db) as saver:
                saver.add_view(flask.request.get_json(), create=True)
        except (jsonschema.ValidationError, ValueError) as error:
            utils.abort_json(http.client.BAD_REQUEST, error)
        return flask.redirect(
            flask.url_for("api_view.view", dbname=dbname, viewname=viewname)
        )

    elif utils.http_DELETE():
        try:
            db = dbshare.db.get_check_write(dbname)
        except ValueError:
            flask.abort(http.client.UNAUTHORIZED)
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        try:
            with dbshare.db.DbSaver(db) as saver:
                saver.delete_view(viewname)
        except ValueError as error:
            utils.abort_json(http.client.BAD_REQUEST, error)
        return ("", http.client.NO_CONTENT)
Пример #8
0
def user(username):
    "Return the API JSON user display."
    user = dbshare.user.get_user(username=username)
    if user is None:
        flask.abort(http.client.NOT_FOUND)
    if not dbshare.user.is_admin_or_self(user):
        flask.abort(http.client.UNAUTHORIZED)
    # Remove sensitive information.
    user.pop("password")
    user.pop("apikey", None)
    user["total_size"] = dbshare.db.get_usage(username)[1]
    user["databases"] = {
        "href": utils.url_for("api_dbs.owner", username=user["username"])
    }
    return utils.jsonify(utils.get_json(**user), "/user")
Пример #9
0
def statistics(dbname, tablename):
    "GET: Return the schema for the table with statistics for the columns."
    try:
        db = dbshare.db.get_check_read(dbname)
    except ValueError:
        flask.abort(http.client.UNAUTHORIZED)
    except KeyError:
        flask.abort(http.client.NOT_FOUND)
    try:
        schema = db["tables"][tablename]
    except KeyError:
        flask.abort(http.client.NOT_FOUND)
    result = get_json(db, schema, complete=False)
    dbshare.table.compute_statistics(db, schema)
    result.update(schema)
    return utils.jsonify(utils.get_json(**result), "/table/statistics")
Пример #10
0
def rows_json(dbname, tablename):
    "Return the rows in JSON format."
    try:
        db = dbshare.db.get_check_read(dbname)
    except ValueError:
        flask.abort(http.client.UNAUTHORIZED)
    except KeyError:
        flask.abort(http.client.NOT_FOUND)
    try:
        schema = db["tables"][tablename]
    except KeyError:
        flask.abort(http.client.NOT_FOUND)
    try:
        dbcnx = dbshare.db.get_cnx(dbname)
        columns = [c["name"] for c in schema["columns"]]
        colnames = ",".join([f'"{c}"' for c in columns])
        sql = f'SELECT {colnames} FROM "{tablename}"'
        try:
            cursor = utils.execute_timeout(dbcnx, sql)
        except SystemError:
            flask.abort(http.client.REQUEST_TIMEOUT)
    except sqlite3.Error:
        flask.abort(http.client.INTERNAL_SERVER_ERROR)
    result = {
        "name": tablename,
        "title": schema.get("title") or "Table {}".format(tablename),
        "source": {
            "type":
            "table",
            "href":
            utils.url_for("api_table.table",
                          dbname=db["name"],
                          tablename=tablename),
        },
        "nrows": schema["nrows"],
        "data": [dict(zip(columns, row)) for row in cursor],
    }
    return utils.jsonify(utils.get_json(**result), "/rows")
Пример #11
0
def root():
    "API root resource; links to other API resources."
    schema_base_url = flask.current_app.config["SCHEMA_BASE_URL"]
    result = {
        "title": "DbShare API",
        "version": dbshare.__version__,
        "databases": {"public": {"href": utils.url_for("api_dbs.public")}},
    }
    if flask.g.current_user:
        result["databases"]["owner"] = {
            "href": utils.url_for(
                "api_dbs.owner", username=flask.g.current_user["username"]
            )
        }
    result["schema"] = {"href": schema_base_url}
    if flask.g.is_admin:
        result["databases"]["all"] = {"href": utils.url_for("api_dbs.all")}
        result["users"] = {"all": {"href": utils.url_for("api_users.all")}}
    if flask.g.current_user:
        result["user"] = dbshare.api.user.get_json(flask.g.current_user["username"])
    result["operations"] = {
        "database": {
            "query": {
                "title": "Perform a database query.",
                "href": utils.url_for_unq("api_db.query", dbname="{dbname}"),
                "variables": {"dbname": {"title": "Name of the database."}},
                "method": "POST",
                "input": {
                    "content-type": constants.JSON_MIMETYPE,
                    "schema": {"href": schema_base_url + "/query/input"},
                },
                "output": {
                    "content-type": constants.JSON_MIMETYPE,
                    "schema": {"href": schema_base_url + "/query/output"},
                },
            }
        }
    }
    if flask.g.current_user:
        result["operations"]["database"].update(
            {
                "create": {
                    "title": "Create a new database.",
                    "href": utils.url_for_unq("api_db.database", dbname="{dbname}"),
                    "variables": {"dbname": {"title": "Name of the database."}},
                    "method": "PUT",
                },
                "edit": {
                    "title": "Edit the database metadata.",
                    "href": utils.url_for_unq("api_db.database", dbname="{dbname}"),
                    "variables": {"dbname": {"title": "Name of the database."}},
                    "method": "POST",
                    "input": {
                        "content-type": constants.JSON_MIMETYPE,
                        "schema": {"href": schema_base_url + "/db/edit"},
                    },
                },
                "delete": {
                    "title": "Delete the database.",
                    "href": utils.url_for_unq("api_db.database", dbname="{dbname}"),
                    "variables": {"dbname": {"title": "Name of the database."}},
                    "method": "DELETE",
                },
                "readonly": {
                    "title": "Set the database to read-only.",
                    "href": utils.url_for_unq("api_db.database", dbname="{dbname}"),
                    "variables": {"dbname": {"title": "Name of the database."}},
                    "method": "POST",
                },
                "readwrite": {
                    "title": "Set the database to read-write.",
                    "href": utils.url_for_unq("api_db.database", dbname="{dbname}"),
                    "variables": {"dbname": {"title": "Name of the database."}},
                    "method": "POST",
                },
            }
        )
        result["operations"]["table"] = {
            "create": {
                "title": "Create a new table in the database.",
                "href": utils.url_for_unq(
                    "api_table.table", dbname="{dbname}", tablename="{tablename}"
                ),
                "variables": {
                    "dbname": {"title": "Name of the database."},
                    "tablename": {"title": "Name of the table."},
                },
                "method": "PUT",
                "input": {
                    "content-type": constants.JSON_MIMETYPE,
                    "schema": {"href": schema_base_url + "/table/create"},
                },
            },
            "delete": {
                "title": "Delete the table from the database.",
                "href": utils.url_for_unq(
                    "api_table.table", dbname="{dbname}", tablename="{tablename}"
                ),
                "variables": {
                    "dbname": {"title": "Name of the database."},
                    "tablename": {"title": "Name of the table."},
                },
                "method": "DELETE",
            },
            "insert": {
                "title": "Insert rows from JSON or CSV data into the table.",
                "href": utils.url_for_unq(
                    "api_table.insert", dbname="{dbname}", tablename="{tablename}"
                ),
                "variables": {
                    "dbname": {"title": "Name of the database."},
                    "tablename": {"title": "Name of the table."},
                },
                "method": "POST",
                "input": [
                    {
                        "content-type": constants.JSON_MIMETYPE,
                        "schema": {"href": schema_base_url + "/table/input"},
                    },
                    {"content-type": constants.CSV_MIMETYPE},
                ],
            },
            "update": {
                "title": "Update rows in the table from CSV data.",
                "href": utils.url_for_unq(
                    "api_table.update", dbname="{dbname}", tablename="{tablename}"
                ),
                "variables": {
                    "dbname": {"title": "Name of the database."},
                    "tablename": {"title": "Name of the table."},
                },
                "method": "POST",
                "input": {"content-type": constants.CSV_MIMETYPE},
            },
            "empty": {
                "title": "Empty the table; remove all rows.",
                "href": utils.url_for_unq(
                    "api_table.empty", dbname="{dbname}", tablename="{tablename}"
                ),
                "variables": {
                    "dbname": {"title": "Name of the database."},
                    "tablename": {"title": "Name of the table."},
                },
                "method": "POST",
            },
        }
        result["operations"]["view"] = {
            "create": {
                "title": "Create a new view in the database.",
                "href": utils.url_for_unq(
                    "api_view.view", dbname="{dbname}", viewname="{viewname}"
                ),
                "variables": {
                    "dbname": {"title": "Name of the database."},
                    "viewname": {"title": "Name of the view."},
                },
                "method": "PUT",
                "input": {
                    "content-type": constants.JSON_MIMETYPE,
                    "schema": {"href": schema_base_url + "/view/create"},
                },
            },
            "delete": {
                "title": "Delete the view from the database.",
                "href": utils.url_for_unq(
                    "api_view.view", dbname="{dbname}", viewname="{viewname}"
                ),
                "variables": {
                    "dbname": {"title": "Name of the database."},
                    "viewname": {"title": "Name of the view."},
                },
                "method": "DELETE",
            },
        }
    return utils.jsonify(utils.get_json(**result), "/root")
Пример #12
0
def database(dbname):
    """GET: List the database tables, views and metadata.
    PUT: Create the database, load the data if any input.
    POST: Edit the database metadata.
    DELETE: Delete the database.
    """
    if utils.http_GET():
        try:
            db = dbshare.db.get_check_read(dbname, nrows=True)
        except ValueError:
            flask.abort(http.client.UNAUTHORIZED)
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        return utils.jsonify(utils.get_json(**get_json(db, complete=True)),
                             "/db")

    elif utils.http_PUT():
        db = dbshare.db.get_db(dbname)
        if db is not None:
            utils.abort_json(http.client.FORBIDDEN, "database exists")
        if not flask.request.content_length:
            add_func = None
        elif flask.request.content_type is None:
            add_func = None
        elif flask.request.content_type == constants.SQLITE3_MIMETYPE:
            add_func = dbshare.db.add_sqlite3_database
        elif flask.request.content_type == constants.XLSX_MIMETYPE:
            add_func = dbshare.db.add_xlsx_database
        else:
            flask.abort(http.client.UNSUPPORTED_MEDIA_TYPE)
        try:
            if add_func:
                db = add_func(
                    dbname,
                    io.BytesIO(flask.request.get_data()),
                    flask.request.content_length,
                )
            else:
                with dbshare.db.DbSaver() as saver:
                    dbname = saver.set_name(dbname)
                    saver.initialize()
                db = saver.db
        except ValueError as error:
            utils.abort_json(http.client.BAD_REQUEST, error)
        return flask.redirect(flask.url_for(".database", dbname=dbname))

    elif utils.http_POST(csrf=False):
        try:
            db = dbshare.db.get_check_write(dbname)
        except ValueError:
            flask.abort(http.client.UNAUTHORIZED)
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        try:
            data = flask.request.get_json()
            utils.json_validate(data, dbshare.schema.db.edit)
            with dbshare.db.DbSaver(db) as saver:
                try:
                    dbname = saver.set_name(data["name"])
                except KeyError:
                    pass
                try:
                    saver.set_title(data["title"])
                except KeyError:
                    pass
                try:
                    saver.set_description(data["description"])
                except KeyError:
                    pass
                try:
                    saver.set_public(data["public"])
                except KeyError:
                    pass
        except (jsonschema.ValidationError, ValueError) as error:
            utils.abort_json(http.client.BAD_REQUEST, error)
        return flask.redirect(flask.url_for(".database", dbname=dbname))

    elif utils.http_DELETE(csrf=False):
        try:
            dbshare.db.get_check_write(dbname)
        except ValueError:
            flask.abort(http.client.UNAUTHORIZED)
        except KeyError:
            flask.abort(http.client.NOT_FOUND)
        dbshare.db.delete_database(dbname)
        return ("", http.client.NO_CONTENT)