quokka-admin 0.1.0

An admin panel for quokka
Documentation
use quokka::{
    helper::database::{
        execute, query_all, query_one, query_optional, BaseRepository, PaginationOrder,
    },
    state::{Database, FromState},
};

#[derive(Clone, sqlx::FromRow, serde::Deserialize, serde::Serialize)]
pub struct Permission {
    pub id: i32,
    pub verb: String,
    pub resource: String,
    pub created_at: time::OffsetDateTime,
    pub updated_at: time::OffsetDateTime,
}

#[derive(Clone, sqlx::FromRow, serde::Deserialize, serde::Serialize)]
pub struct UserPermission {
    pub user_id: i32,
    pub permission_id: i32,
    pub created_at: time::OffsetDateTime,
    pub updated_at: time::OffsetDateTime,
}

#[derive(Clone, sqlx::FromRow, serde::Deserialize, serde::Serialize)]
pub struct GroupPermission {
    pub group_id: i32,
    pub permission_id: i32,
    pub created_at: time::OffsetDateTime,
    pub updated_at: time::OffsetDateTime,
}

#[derive(Clone, FromState)]
pub struct PermissionRepository {
    database: Database,
}

#[derive(Clone, FromState)]
pub struct UserPermissionRepository {
    database: Database,
}

#[derive(Clone, FromState)]
pub struct GroupPermissionRepository {
    database: Database,
}

impl BaseRepository for PermissionRepository {
    type Entity = Permission;

    type PkType = i32;

    #[query_all(
        query = "SELECT * FROM \"permission\" ORDER BY {#order_by} {#direction.to_string()} LIMIT {#page_size} OFFSET {#page_size * page}"
    )]
    async fn get_entities(
        &self,
        page: i32,
        page_size: i32,
        order_by: &'static str,
        direction: PaginationOrder,
    ) -> quokka::Result<Vec<Self::Entity>>;

    #[query_one(query = "SELECT * FROM \"permission\" WHERE id = {pk}")]
    fn get_entity(&self, pk: Self::PkType) -> quokka::Result<Self::Entity>;

    #[execute(
        query = "UPDATE \"permission\" SET verb = {entity.verb}, resource = {entity.resource}, updated_at = NOW() WHERE id = {entity.id}",
        write
    )]
    fn update_entity(&self, entity: Self::Entity) -> quokka::Result<u64>;

    #[query_one(
        query = "INSERT INTO \"permission\" (id, verb, resource) VALUES ({entity.id}, {entity.verb}, {entity.resource}) RETURNING *",
        write
    )]
    fn create_entity(&self, entity: Self::Entity) -> quokka::Result<Self::Entity>;

    #[execute(query = "DELETE FROM \"permission\" WHERE id = {pk}", write)]
    fn delete_entity(&self, pk: Self::PkType) -> quokka::Result<u64>;
}

impl PermissionRepository {
    #[query_optional(query = r#"SELECT "permission".*
        FROM "permission"
        INNER JOIN "user_permission" up
            ON up.permission_id = "permission".id
        INNER JOIN "user"
            ON "user".id = up.user_id
        WHERE "user".username = {username} AND "permission".verb = {verb} AND {resource} LIKE "permission".resource"#)]
    pub async fn get_of_user(
        &self,
        username: &str,
        verb: &str,
        resource: &str,
    ) -> quokka::Result<Option<Permission>>;

    #[query_optional(query = r#"SELECT "permission".*
        FROM "permission"
        INNER JOIN "group_permission" gp
            ON gp.permission_id = "permission".id
            INNER JOIN "group"
            ON "group".id = gp.group_id
            WHERE "group".name = {name} AND "permission".verb = {verb} AND {resource} LIKE "permission".resource"#)]
    pub async fn get_of_group(
        &self,
        name: &str,
        verb: &str,
        resource: &str,
    ) -> quokka::Result<Option<Permission>>;
}

impl BaseRepository for UserPermissionRepository {
    type Entity = UserPermission;

    type PkType = (i32, i32);

    #[query_all(
        query = "SELECT * FROM \"user_permission\" ORDER BY {#order_by} {#direction.to_string()} LIMIT {#page_size} OFFSET {#page_size * page}"
    )]
    async fn get_entities(
        &self,
        page: i32,
        page_size: i32,
        order_by: &'static str,
        direction: PaginationOrder,
    ) -> quokka::Result<Vec<Self::Entity>>;

    #[query_one(
        query = "SELECT * FROM \"user_permission\" WHERE user_id = {pk.0} AND permission_id = {pk.1}"
    )]
    fn get_entity(&self, pk: Self::PkType) -> quokka::Result<Self::Entity>;

    /// There is nothing to be updated here
    #[execute(
        query = "UPDATE \"user_permission\" SET updated_at = NOW() WHERE user_id = {entity.user_id} AND permission_id = {entity.permission_id}",
        write
    )]
    fn update_entity(&self, entity: Self::Entity) -> quokka::Result<u64>;

    #[query_one(
        query = "INSERT INTO \"user_permission\" (user_id, permission_id) VALUES ({entity.user_id}, {entity.permission_id}) RETURNING *",
        write
    )]
    fn create_entity(&self, entity: Self::Entity) -> quokka::Result<Self::Entity>;

    #[execute(
        query = "DELETE FROM \"user_permission\" WHERE user_id = {pk.0} AND permission_id = {pk.1}",
        write
    )]
    fn delete_entity(&self, pk: Self::PkType) -> quokka::Result<u64>;
}

impl BaseRepository for GroupPermissionRepository {
    type Entity = GroupPermission;

    type PkType = (i32, i32);

    #[query_all(
        query = "SELECT * FROM \"group_permission\" ORDER BY {#order_by} {#direction.to_string()} LIMIT {#page_size} OFFSET {#page_size * page}"
    )]
    async fn get_entities(
        &self,
        page: i32,
        page_size: i32,
        order_by: &'static str,
        direction: PaginationOrder,
    ) -> quokka::Result<Vec<Self::Entity>>;

    #[query_one(
        query = "SELECT * FROM \"group_permission\" WHERE group_id = {pk.0} AND permission_id = {pk.1}"
    )]
    fn get_entity(&self, pk: Self::PkType) -> quokka::Result<Self::Entity>;

    /// There is nothing to be updated here
    #[execute(
        query = "UPDATE \"group_permission\" SET updated_at = NOW() WHERE group_id = {entity.group_id} AND permission_id = {entity.permission_id}",
        write
    )]
    fn update_entity(&self, entity: Self::Entity) -> quokka::Result<u64>;

    #[query_one(
        query = "INSERT INTO \"group_permission\" (group_id, permission_id) VALUES ({entity.group_id}, {entity.permission_id}) RETURNING *",
        write
    )]
    fn create_entity(&self, entity: Self::Entity) -> quokka::Result<Self::Entity>;

    #[execute(
        query = "DELETE FROM \"group_permission\" WHERE group_id = {pk.0} AND permission_id = {pk.1}",
        write
    )]
    fn delete_entity(&self, pk: Self::PkType) -> quokka::Result<u64>;
}