rok-cli 0.3.6

Developer CLI for rok-based Axum applications
use super::{write_file, Scaffold, ScaffoldArgs, ScaffoldResult};
use anyhow::Result;

pub struct NotificationScaffold;

impl Scaffold for NotificationScaffold {
    fn name(&self) -> &'static str {
        "notification"
    }
    fn description(&self) -> &'static str {
        "Notifications: in-app list/mark-read, push registration, email preferences"
    }

    fn generate(&self, args: &ScaffoldArgs) -> Result<ScaffoldResult> {
        let mut r = ScaffoldResult::default();
        let d = args.dry_run;
        write_file(
            &mut r,
            "src/app/controllers/notification_controller.rs",
            CONTROLLER,
            d,
        )?;
        write_file(
            &mut r,
            "migrations/create_notifications_table.sql",
            MIGRATION,
            d,
        )?;
        r.warnings.push("Register GET /notifications routes".into());
        Ok(r)
    }
}

const CONTROLLER: &str = r#"use axum::{extract::{Path, State}, response::IntoResponse};
use rok_auth::axum::{Ctx, Response};

pub async fn index(ctx: Ctx, State(pool): State<sqlx::PgPool>) -> impl IntoResponse {
    // TODO: fetch notifications for ctx.user_id, paginated
    Response::json(serde_json::json!({ "data": [], "unread_count": 0 }))
}

pub async fn unread_count(ctx: Ctx, State(pool): State<sqlx::PgPool>) -> impl IntoResponse {
    // TODO: COUNT WHERE read_at IS NULL AND user_id = ctx.user_id
    Response::json(serde_json::json!({ "count": 0 }))
}

pub async fn mark_read(ctx: Ctx, Path(id): Path<i64>, State(pool): State<sqlx::PgPool>) -> impl IntoResponse {
    // TODO: set read_at = now() WHERE id = id AND user_id = ctx.user_id
    Response::json(serde_json::json!({ "message": "marked as read" }))
}

pub async fn mark_all_read(ctx: Ctx, State(pool): State<sqlx::PgPool>) -> impl IntoResponse {
    // TODO: set read_at = now() WHERE user_id = ctx.user_id AND read_at IS NULL
    Response::json(serde_json::json!({ "message": "all marked as read" }))
}
"#;

const MIGRATION: &str = r#"CREATE TABLE notifications (
    id         BIGSERIAL PRIMARY KEY,
    user_id    BIGINT NOT NULL,
    type       TEXT NOT NULL,
    title      TEXT NOT NULL,
    body       TEXT,
    data       JSONB,
    read_at    TIMESTAMPTZ,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX ON notifications (user_id, read_at);
"#;