1
This commit is contained in:
@@ -38,10 +38,10 @@ use spacetime_client::{
|
||||
CustomWorldAgentSessionRecord, CustomWorldDraftCardDetailRecord,
|
||||
CustomWorldDraftCardDetailSectionRecord, CustomWorldDraftCardRecord,
|
||||
CustomWorldGalleryEntryRecord, CustomWorldLibraryEntryRecord,
|
||||
CustomWorldProfilePlayReportRecordInput, CustomWorldProfileRemixRecordInput,
|
||||
CustomWorldProfileUpsertRecordInput, CustomWorldPublishGateRecord,
|
||||
CustomWorldResultPreviewBlockerRecord, CustomWorldSupportedActionRecord,
|
||||
CustomWorldWorkSummaryRecord, SpacetimeClientError,
|
||||
CustomWorldProfileLikeReportRecordInput, CustomWorldProfilePlayReportRecordInput,
|
||||
CustomWorldProfileRemixRecordInput, CustomWorldProfileUpsertRecordInput,
|
||||
CustomWorldPublishGateRecord, CustomWorldResultPreviewBlockerRecord,
|
||||
CustomWorldSupportedActionRecord, CustomWorldWorkSummaryRecord, SpacetimeClientError,
|
||||
};
|
||||
use std::{collections::BTreeSet, convert::Infallible, sync::Arc, time::Instant};
|
||||
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
|
||||
@@ -73,6 +73,7 @@ use crate::{
|
||||
},
|
||||
request_context::RequestContext,
|
||||
state::AppState,
|
||||
work_author::resolve_work_author_by_user_id,
|
||||
};
|
||||
|
||||
const DRAFT_ASSET_GENERATION_MAX_ATTEMPTS: u32 = 3;
|
||||
@@ -414,7 +415,6 @@ pub async fn get_custom_world_library(
|
||||
Extension(authenticated): Extension<AuthenticatedAccessToken>,
|
||||
) -> Result<Json<Value>, Response> {
|
||||
let owner_user_id = authenticated.claims().user_id().to_string();
|
||||
let author_display_name = resolve_author_display_name(&state, &authenticated);
|
||||
let entries = state
|
||||
.spacetime_client()
|
||||
.list_custom_world_works(owner_user_id.clone())
|
||||
@@ -430,9 +430,9 @@ pub async fn get_custom_world_library(
|
||||
.into_iter()
|
||||
.filter_map(|item| {
|
||||
map_custom_world_library_entry_response_from_work_summary(
|
||||
&state,
|
||||
item,
|
||||
&owner_user_id,
|
||||
&author_display_name,
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
@@ -467,7 +467,7 @@ pub async fn get_custom_world_library_detail(
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
CustomWorldGalleryDetailResponse {
|
||||
entry: map_custom_world_library_entry_response(detail.entry),
|
||||
entry: map_custom_world_library_entry_response(&state, detail.entry),
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -548,8 +548,11 @@ pub async fn put_custom_world_library_profile(
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
CustomWorldLibraryMutationResponse {
|
||||
entry: map_custom_world_library_entry_response(mutation.entry.clone()),
|
||||
entries: vec![map_custom_world_library_entry_response(mutation.entry)],
|
||||
entry: map_custom_world_library_entry_response(&state, mutation.entry.clone()),
|
||||
entries: vec![map_custom_world_library_entry_response(
|
||||
&state,
|
||||
mutation.entry,
|
||||
)],
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -584,7 +587,7 @@ pub async fn delete_custom_world_library_profile(
|
||||
CustomWorldLibraryResponse {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(map_custom_world_library_entry_response)
|
||||
.map(|entry| map_custom_world_library_entry_response(&state, entry))
|
||||
.collect(),
|
||||
},
|
||||
))
|
||||
@@ -636,8 +639,11 @@ pub async fn publish_custom_world_library_profile(
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
CustomWorldLibraryMutationResponse {
|
||||
entry: map_custom_world_library_entry_response(mutation.entry.clone()),
|
||||
entries: vec![map_custom_world_library_entry_response(mutation.entry)],
|
||||
entry: map_custom_world_library_entry_response(&state, mutation.entry.clone()),
|
||||
entries: vec![map_custom_world_library_entry_response(
|
||||
&state,
|
||||
mutation.entry,
|
||||
)],
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -675,8 +681,11 @@ pub async fn unpublish_custom_world_library_profile(
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
CustomWorldLibraryMutationResponse {
|
||||
entry: map_custom_world_library_entry_response(mutation.entry.clone()),
|
||||
entries: vec![map_custom_world_library_entry_response(mutation.entry)],
|
||||
entry: map_custom_world_library_entry_response(&state, mutation.entry.clone()),
|
||||
entries: vec![map_custom_world_library_entry_response(
|
||||
&state,
|
||||
mutation.entry,
|
||||
)],
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -698,7 +707,7 @@ pub async fn list_custom_world_gallery(
|
||||
CustomWorldGalleryResponse {
|
||||
entries: entries
|
||||
.into_iter()
|
||||
.map(map_custom_world_gallery_card_response)
|
||||
.map(|entry| map_custom_world_gallery_card_response(&state, entry))
|
||||
.collect(),
|
||||
},
|
||||
))
|
||||
@@ -730,7 +739,7 @@ pub async fn get_custom_world_gallery_detail(
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
CustomWorldGalleryDetailResponse {
|
||||
entry: map_custom_world_library_entry_response(detail.entry),
|
||||
entry: map_custom_world_library_entry_response(&state, detail.entry),
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -761,7 +770,7 @@ pub async fn get_custom_world_gallery_detail_by_code(
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
CustomWorldGalleryDetailResponse {
|
||||
entry: map_custom_world_library_entry_response(detail.entry),
|
||||
entry: map_custom_world_library_entry_response(&state, detail.entry),
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -800,8 +809,11 @@ pub async fn remix_custom_world_gallery_profile(
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
CustomWorldLibraryMutationResponse {
|
||||
entry: map_custom_world_library_entry_response(mutation.entry.clone()),
|
||||
entries: vec![map_custom_world_library_entry_response(mutation.entry)],
|
||||
entry: map_custom_world_library_entry_response(&state, mutation.entry.clone()),
|
||||
entries: vec![map_custom_world_library_entry_response(
|
||||
&state,
|
||||
mutation.entry,
|
||||
)],
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -837,7 +849,44 @@ pub async fn record_custom_world_gallery_play(
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
CustomWorldGalleryDetailResponse {
|
||||
entry: map_custom_world_library_entry_response(mutation.entry),
|
||||
entry: map_custom_world_library_entry_response(&state, mutation.entry),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub async fn record_custom_world_gallery_like(
|
||||
State(state): State<AppState>,
|
||||
Path((owner_user_id, profile_id)): Path<(String, String)>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
Extension(authenticated): Extension<AuthenticatedAccessToken>,
|
||||
) -> Result<Json<Value>, Response> {
|
||||
if owner_user_id.trim().is_empty() || profile_id.trim().is_empty() {
|
||||
return Err(custom_world_error_response(
|
||||
&request_context,
|
||||
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
|
||||
"provider": "custom-world-gallery",
|
||||
"message": "ownerUserId and profileId are required",
|
||||
})),
|
||||
));
|
||||
}
|
||||
|
||||
let mutation = state
|
||||
.spacetime_client()
|
||||
.record_custom_world_profile_like(CustomWorldProfileLikeReportRecordInput {
|
||||
owner_user_id,
|
||||
profile_id,
|
||||
user_id: authenticated.claims().user_id().to_string(),
|
||||
liked_at_micros: current_utc_micros(),
|
||||
})
|
||||
.await
|
||||
.map_err(|error| {
|
||||
custom_world_error_response(&request_context, map_custom_world_client_error(error))
|
||||
})?;
|
||||
|
||||
Ok(json_success_body(
|
||||
Some(&request_context),
|
||||
CustomWorldGalleryDetailResponse {
|
||||
entry: map_custom_world_library_entry_response(&state, mutation.entry),
|
||||
},
|
||||
))
|
||||
}
|
||||
@@ -2697,18 +2746,25 @@ async fn upsert_custom_world_draft_foundation_progress(
|
||||
}
|
||||
|
||||
fn map_custom_world_library_entry_response(
|
||||
state: &AppState,
|
||||
entry: CustomWorldLibraryEntryRecord,
|
||||
) -> CustomWorldLibraryEntryResponse {
|
||||
let author = resolve_work_author_by_user_id(
|
||||
state,
|
||||
&entry.owner_user_id,
|
||||
Some(&entry.author_display_name),
|
||||
entry.author_public_user_code.as_deref(),
|
||||
);
|
||||
CustomWorldLibraryEntryResponse {
|
||||
owner_user_id: entry.owner_user_id,
|
||||
profile_id: entry.profile_id,
|
||||
public_work_code: entry.public_work_code,
|
||||
author_public_user_code: entry.author_public_user_code,
|
||||
author_public_user_code: author.public_user_code.or(entry.author_public_user_code),
|
||||
profile: entry.profile,
|
||||
visibility: entry.visibility,
|
||||
published_at: entry.published_at,
|
||||
updated_at: entry.updated_at,
|
||||
author_display_name: entry.author_display_name,
|
||||
author_display_name: author.display_name,
|
||||
world_name: entry.world_name,
|
||||
subtitle: entry.subtitle,
|
||||
summary_text: entry.summary_text,
|
||||
@@ -2724,23 +2780,24 @@ fn map_custom_world_library_entry_response(
|
||||
}
|
||||
|
||||
fn map_custom_world_library_entry_response_from_work_summary(
|
||||
state: &AppState,
|
||||
item: CustomWorldWorkSummaryRecord,
|
||||
owner_user_id: &str,
|
||||
author_display_name: &str,
|
||||
) -> Option<CustomWorldLibraryEntryResponse> {
|
||||
let profile_id = item.profile_id.as_ref()?.clone();
|
||||
let profile = build_custom_world_library_list_profile_payload(&item, &profile_id);
|
||||
let author = resolve_work_author_by_user_id(state, owner_user_id, None, None);
|
||||
Some(CustomWorldLibraryEntryResponse {
|
||||
owner_user_id: owner_user_id.to_string(),
|
||||
public_work_code: (item.status == "published")
|
||||
.then(|| build_public_work_code_from_profile_id(&profile_id)),
|
||||
profile_id,
|
||||
author_public_user_code: None,
|
||||
author_public_user_code: author.public_user_code,
|
||||
profile,
|
||||
visibility: item.status,
|
||||
published_at: item.published_at,
|
||||
updated_at: item.updated_at,
|
||||
author_display_name: author_display_name.to_string(),
|
||||
author_display_name: author.display_name,
|
||||
world_name: item.title,
|
||||
subtitle: item.subtitle,
|
||||
summary_text: item.summary,
|
||||
@@ -2803,17 +2860,26 @@ fn build_custom_world_library_list_profile_payload(
|
||||
}
|
||||
|
||||
fn map_custom_world_gallery_card_response(
|
||||
state: &AppState,
|
||||
entry: CustomWorldGalleryEntryRecord,
|
||||
) -> CustomWorldGalleryCardResponse {
|
||||
let author = resolve_work_author_by_user_id(
|
||||
state,
|
||||
&entry.owner_user_id,
|
||||
Some(&entry.author_display_name),
|
||||
Some(&entry.author_public_user_code),
|
||||
);
|
||||
CustomWorldGalleryCardResponse {
|
||||
owner_user_id: entry.owner_user_id,
|
||||
profile_id: entry.profile_id,
|
||||
public_work_code: entry.public_work_code,
|
||||
author_public_user_code: entry.author_public_user_code,
|
||||
author_public_user_code: author
|
||||
.public_user_code
|
||||
.unwrap_or(entry.author_public_user_code),
|
||||
visibility: entry.visibility,
|
||||
published_at: entry.published_at,
|
||||
updated_at: entry.updated_at,
|
||||
author_display_name: entry.author_display_name,
|
||||
author_display_name: author.display_name,
|
||||
world_name: entry.world_name,
|
||||
subtitle: entry.subtitle,
|
||||
summary_text: entry.summary_text,
|
||||
|
||||
Reference in New Issue
Block a user