Revert "feat: rename product to Screened, add PRODUCT_NAME constant to domain"
This reverts commit f2e3a876dc.
This commit is contained in:
@@ -53,7 +53,7 @@ EVENT_BUS_BACKEND=db
|
||||
# EVENT_BUS_BACKEND=nats
|
||||
# NATS_URL=nats://localhost:4222
|
||||
# NATS_MODE=jetstream # "jetstream" (default, at-least-once) or "core" (fire-and-forget)
|
||||
# NATS_SUBJECT_PREFIX=screened.events
|
||||
# NATS_SUBJECT_PREFIX=movies-diary.events
|
||||
# NATS_STREAM_NAME=MOVIES_DIARY_EVENTS
|
||||
# NATS_CONSUMER_NAME=worker
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Screened
|
||||
# Movies Diary
|
||||
|
||||
A self-hosted, server-side rendered movie logging system with a full REST API. Built in Rust — no JavaScript in the HTML interface, just HTML forms and an RSS feed. Designed to run as a lightweight widget embedded on a personal site or as a backend for third-party clients.
|
||||
|
||||
@@ -10,7 +10,7 @@ A self-hosted, server-side rendered movie logging system with a full REST API. B
|
||||
- Movie enrichment via TMDb — full cast, crew, genres, keywords, runtime, budget/revenue, ratings; fetched automatically on movie discovery and refreshed every 30 days; exposed via `GET /api/v1/movies/{id}/profile`
|
||||
- RSS/Atom feed for public subscription (global and per-user)
|
||||
- JWT authentication via cookie (HTML) or Bearer token (REST API)
|
||||
- ActivityPub federation — follow/unfollow remote users, accept/reject/remove followers, federated reviews broadcast as `Note` objects with `#Screened` + `#MovieTitle` hashtags, paginated outbox, boost/Announce tracking, NodeInfo discovery endpoint, shared inbox delivery, actor profile sync (bio, avatar, discoverable)
|
||||
- ActivityPub federation — follow/unfollow remote users, accept/reject/remove followers, federated reviews broadcast as `Note` objects with `#MoviesDiary` + `#MovieTitle` hashtags, paginated outbox, boost/Announce tracking, NodeInfo discovery endpoint, shared inbox delivery, actor profile sync (bio, avatar, discoverable)
|
||||
- Federation moderation — instance-level domain blocking (admin-managed), per-user actor blocking with `Block` activity, delivery filter excludes blocked actors and blocked-domain inboxes
|
||||
- CSV and JSON diary export
|
||||
- File importer: upload CSV, TSV, JSON, or XLSX from any source (Letterboxd, IMDb, etc.), map columns to domain fields via a step-by-step wizard or REST API, save mapping profiles for repeat imports
|
||||
|
||||
@@ -6,8 +6,6 @@ pub mod review_handler;
|
||||
pub(crate) mod urls;
|
||||
pub mod user_adapter;
|
||||
|
||||
use domain::PRODUCT_NAME;
|
||||
|
||||
// Re-export the generic base types that callers need
|
||||
pub use activitypub_base::{
|
||||
ActivityPubService, ApFederationConfig, ApObjectHandler, ApUser, ApUserRepository,
|
||||
@@ -48,7 +46,7 @@ pub async fn wire(
|
||||
}),
|
||||
base_url.clone(),
|
||||
allow_registration,
|
||||
PRODUCT_NAME.to_lowercase(),
|
||||
"movies-diary".to_string(),
|
||||
cfg!(debug_assertions),
|
||||
)
|
||||
.await?,
|
||||
|
||||
@@ -69,9 +69,9 @@ pub fn review_to_ap_object(
|
||||
let tag = vec![
|
||||
ApHashtag {
|
||||
kind: "Hashtag".to_string(),
|
||||
href: Url::parse(&format!("{}/tags/screened", base_url))
|
||||
href: Url::parse(&format!("{}/tags/moviesdiary", base_url))
|
||||
.expect("valid base_url"),
|
||||
name: "#Screened".to_string(),
|
||||
name: "#MoviesDiary".to_string(),
|
||||
},
|
||||
ApHashtag {
|
||||
kind: "Hashtag".to_string(),
|
||||
@@ -137,7 +137,7 @@ mod tests {
|
||||
);
|
||||
assert_eq!(obj.tag.len(), 2);
|
||||
let names: Vec<&str> = obj.tag.iter().map(|t| t.name.as_str()).collect();
|
||||
assert!(names.contains(&"#Screened"));
|
||||
assert!(names.contains(&"#MoviesDiary"));
|
||||
assert!(names.contains(&"#Dune"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +28,9 @@ impl NatsConfig {
|
||||
};
|
||||
|
||||
let subject_prefix = std::env::var("NATS_SUBJECT_PREFIX")
|
||||
.unwrap_or_else(|_| "screened.events".to_string());
|
||||
.unwrap_or_else(|_| "movies-diary.events".to_string());
|
||||
let stream_name = std::env::var("NATS_STREAM_NAME")
|
||||
.unwrap_or_else(|_| "SCREENED_EVENTS".to_string());
|
||||
.unwrap_or_else(|_| "MOVIES_DIARY_EVENTS".to_string());
|
||||
let consumer_name = std::env::var("NATS_CONSUMER_NAME")
|
||||
.unwrap_or_else(|_| "worker".to_string());
|
||||
|
||||
@@ -61,8 +61,8 @@ mod tests {
|
||||
let cfg = NatsConfig::from_env().unwrap();
|
||||
assert_eq!(cfg.url, "nats://localhost:4222");
|
||||
assert_eq!(cfg.mode, NatsMode::JetStream);
|
||||
assert_eq!(cfg.subject_prefix, "screened.events");
|
||||
assert_eq!(cfg.stream_name, "SCREENED_EVENTS");
|
||||
assert_eq!(cfg.subject_prefix, "movies-diary.events");
|
||||
assert_eq!(cfg.stream_name, "MOVIES_DIARY_EVENTS");
|
||||
assert_eq!(cfg.consumer_name, "worker");
|
||||
|
||||
unsafe { std::env::remove_var("NATS_URL"); }
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
content="A personal movie diary — track what you watch, rate and review films."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="Screened" />
|
||||
<meta property="og:site_name" content="Movies Diary" />
|
||||
<meta property="og:title" content="{{ ctx.page_title }}" />
|
||||
<meta property="og:url" content="{{ ctx.canonical_url }}" />
|
||||
<meta name="twitter:card" content="summary" />
|
||||
@@ -26,7 +26,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<a href="/" class="site-title">Screened</a>
|
||||
<a href="/" class="site-title">Movies Diary</a>
|
||||
<nav>
|
||||
<a href="/">Feed</a>
|
||||
<a href="/users">Users</a>
|
||||
|
||||
@@ -4,5 +4,3 @@ pub mod models;
|
||||
pub mod ports;
|
||||
pub mod services;
|
||||
pub mod value_objects;
|
||||
|
||||
pub const PRODUCT_NAME: &str = "Screened";
|
||||
|
||||
@@ -64,7 +64,7 @@ pub(crate) async fn build_page_context(
|
||||
is_admin,
|
||||
register_enabled: state.app_ctx.config.allow_registration,
|
||||
rss_url: "/feed.rss".to_string(),
|
||||
page_title: domain::PRODUCT_NAME.to_string(),
|
||||
page_title: "Movies Diary".to_string(),
|
||||
canonical_url: state.app_ctx.config.base_url.clone(),
|
||||
csrf_token,
|
||||
page_rss_url: None,
|
||||
@@ -108,7 +108,7 @@ pub async fn get_login_page(
|
||||
is_admin: false,
|
||||
register_enabled: state.app_ctx.config.allow_registration,
|
||||
rss_url: "/feed.rss".to_string(),
|
||||
page_title: format!("Login — {}", domain::PRODUCT_NAME),
|
||||
page_title: "Login — Movies Diary".to_string(),
|
||||
canonical_url: format!("{}/login", state.app_ctx.config.base_url),
|
||||
csrf_token: csrf.0,
|
||||
page_rss_url: None,
|
||||
@@ -175,7 +175,7 @@ pub async fn get_register_page(
|
||||
is_admin: false,
|
||||
register_enabled: true,
|
||||
rss_url: "/feed.rss".to_string(),
|
||||
page_title: format!("Register — {}", domain::PRODUCT_NAME),
|
||||
page_title: "Register — Movies Diary".to_string(),
|
||||
canonical_url: format!("{}/register", state.app_ctx.config.base_url),
|
||||
csrf_token: csrf.0,
|
||||
page_rss_url: None,
|
||||
@@ -236,7 +236,7 @@ pub async fn get_new_review_page(
|
||||
Extension(csrf): Extension<CsrfToken>,
|
||||
) -> impl IntoResponse {
|
||||
let mut ctx = build_page_context(&state, Some(user_id), csrf.0).await;
|
||||
ctx.page_title = format!("Log a Review — {}", domain::PRODUCT_NAME);
|
||||
ctx.page_title = "Log a Review — Movies Diary".to_string();
|
||||
ctx.canonical_url = format!("{}/reviews/new", state.app_ctx.config.base_url);
|
||||
let html = state
|
||||
.html_renderer
|
||||
@@ -450,7 +450,7 @@ pub async fn get_users_list(
|
||||
Extension(csrf): Extension<CsrfToken>,
|
||||
) -> impl IntoResponse {
|
||||
let mut ctx = build_page_context(&state, user_id, csrf.0).await;
|
||||
ctx.page_title = format!("Members — {}", domain::PRODUCT_NAME);
|
||||
ctx.page_title = "Members — Movies Diary".to_string();
|
||||
ctx.canonical_url = format!("{}/users", state.app_ctx.config.base_url);
|
||||
|
||||
#[cfg(feature = "federation")]
|
||||
@@ -575,7 +575,7 @@ pub async fn get_user_profile(
|
||||
};
|
||||
|
||||
let display_name = profile_user.username().value();
|
||||
ctx.page_title = format!("{}'s Diary — {}", display_name, domain::PRODUCT_NAME);
|
||||
ctx.page_title = format!("{}'s Diary — Movies Diary", display_name);
|
||||
ctx.canonical_url = format!(
|
||||
"{}/users/{}",
|
||||
state.app_ctx.config.base_url, profile_user_uuid
|
||||
@@ -822,7 +822,7 @@ pub async fn get_following_page(
|
||||
return StatusCode::FORBIDDEN.into_response();
|
||||
}
|
||||
let mut ctx = build_page_context(&state, Some(user_id.clone()), csrf.0).await;
|
||||
ctx.page_title = format!("Following — {}", domain::PRODUCT_NAME);
|
||||
ctx.page_title = "Following — Movies Diary".to_string();
|
||||
ctx.canonical_url = format!(
|
||||
"{}/users/{}/following-list",
|
||||
state.app_ctx.config.base_url, profile_user_uuid
|
||||
@@ -872,7 +872,7 @@ pub async fn get_followers_page(
|
||||
return StatusCode::FORBIDDEN.into_response();
|
||||
}
|
||||
let mut ctx = build_page_context(&state, Some(user_id.clone()), csrf.0).await;
|
||||
ctx.page_title = format!("Followers — {}", domain::PRODUCT_NAME);
|
||||
ctx.page_title = "Followers — Movies Diary".to_string();
|
||||
ctx.canonical_url = format!(
|
||||
"{}/users/{}/followers-list",
|
||||
state.app_ctx.config.base_url, profile_user_uuid
|
||||
@@ -1006,7 +1006,7 @@ pub async fn get_profile_settings(
|
||||
Extension(csrf): Extension<CsrfToken>,
|
||||
) -> impl IntoResponse {
|
||||
let mut ctx = build_page_context(&state, Some(user_id.clone()), csrf.0).await;
|
||||
ctx.page_title = format!("Profile Settings — {}", domain::PRODUCT_NAME);
|
||||
ctx.page_title = "Profile Settings — Movies Diary".to_string();
|
||||
ctx.canonical_url = format!("{}/settings/profile", state.app_ctx.config.base_url);
|
||||
|
||||
let user = match state
|
||||
@@ -1061,7 +1061,7 @@ pub async fn get_blocked_domains_page(
|
||||
Extension(csrf): Extension<CsrfToken>,
|
||||
) -> impl IntoResponse {
|
||||
let mut ctx = build_page_context(&state, Some(user_id), csrf.0).await;
|
||||
ctx.page_title = format!("Blocked Domains — {}", domain::PRODUCT_NAME);
|
||||
ctx.page_title = "Blocked Domains — Movies Diary".to_string();
|
||||
ctx.canonical_url = format!("{}/admin/blocked-domains", state.app_ctx.config.base_url);
|
||||
match state.ap_service.get_blocked_domains().await {
|
||||
Ok(domains) => {
|
||||
@@ -1134,7 +1134,7 @@ pub async fn get_blocked_actors_page(
|
||||
Extension(csrf): Extension<CsrfToken>,
|
||||
) -> impl IntoResponse {
|
||||
let mut ctx = build_page_context(&state, Some(user_id.clone()), csrf.0).await;
|
||||
ctx.page_title = format!("Blocked Users — {}", domain::PRODUCT_NAME);
|
||||
ctx.page_title = "Blocked Users — Movies Diary".to_string();
|
||||
ctx.canonical_url = format!("{}/social/blocked", state.app_ctx.config.base_url);
|
||||
match state.ap_service.get_blocked_actors(user_id.value()).await {
|
||||
Ok(actors) => {
|
||||
|
||||
@@ -6,7 +6,6 @@ mod social;
|
||||
mod users;
|
||||
|
||||
use axum::Router;
|
||||
use domain::PRODUCT_NAME;
|
||||
use utoipa::{
|
||||
Modify, OpenApi,
|
||||
openapi::security::{Http, HttpAuthScheme, SecurityScheme},
|
||||
@@ -29,9 +28,9 @@ impl Modify for SecurityAddon {
|
||||
fn build() -> utoipa::openapi::OpenApi {
|
||||
let mut api = auth::AuthDoc::openapi();
|
||||
api.info = utoipa::openapi::InfoBuilder::new()
|
||||
.title(format!("{} API", PRODUCT_NAME))
|
||||
.title("Movies Diary API")
|
||||
.version("1.0.0")
|
||||
.description(Some(format!("REST API for {}. Authenticate with `POST /api/v1/auth/login` to get a Bearer token.", PRODUCT_NAME)))
|
||||
.description(Some("REST API for Movies Diary. Authenticate with `POST /api/v1/auth/login` to get a Bearer token."))
|
||||
.build();
|
||||
api.merge(diary::DiaryDoc::openapi());
|
||||
api.merge(movies::MoviesDoc::openapi());
|
||||
|
||||
Reference in New Issue
Block a user