API: follower lists, blocking, reports, admin; drop Spotify sign-in
- Followers/following lists (paginated), 'follows you', remove a follower - Blocking severs follows both ways and hides each user from the other (profile 404s, search, follows); the blocker sees activity hidden - Reports for moderation (App Store guideline 1.2) - First account on a server becomes admin; admins see the report queue, resolve reports, and suspend accounts (signs out, blocks login, hides the profile, stops sharing). set-role script to promote/demote - users.onboardedAt drives first-run onboarding; existing accounts are backfilled as already onboarded. Empty PATCH /me no longer 500s - Remove Spotify account sign-in and polling: Spotify caps new apps at 5 accounts, so Spotify arrives via its Last.fm/ListenBrainz link or the Android reader. App-level catalog search stays for exact links - Shared: QR code generation and profile-link parsing (verified with jsQR) - Integration test timeout raised; password hashing is slow by design Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
This commit is contained in:
@@ -23,6 +23,9 @@ export interface MeDTO extends UserSummaryDTO {
|
||||
email: string;
|
||||
bio: string | null;
|
||||
preferredService: StreamingService | null;
|
||||
role: 'user' | 'admin';
|
||||
/** When onboarding was finished; null means show it. */
|
||||
onboardedAt: string | null;
|
||||
/** ISO time sharing resumes, or null when sharing. Far future means "until turned back on". */
|
||||
sharingPausedUntil: string | null;
|
||||
plan: Plan;
|
||||
@@ -77,6 +80,10 @@ export interface ProfileDTO {
|
||||
isFollowing: boolean;
|
||||
isPinned: boolean;
|
||||
isSelf: boolean;
|
||||
/** They follow the viewer. */
|
||||
followsYou: boolean;
|
||||
/** The viewer has blocked them (activity is hidden; they can be unblocked). */
|
||||
isBlocked: boolean;
|
||||
featured: FeaturedSongDTO | null;
|
||||
nowPlaying: NowPlayingDTO | null;
|
||||
/** Most recent first, not including the track playing right now. */
|
||||
@@ -85,6 +92,35 @@ export interface ProfileDTO {
|
||||
attribution: Partial<Record<'lastfm' | 'listenbrainz', string>>;
|
||||
}
|
||||
|
||||
export interface AdminReportDTO {
|
||||
id: string;
|
||||
reason: string;
|
||||
note: string | null;
|
||||
status: 'open' | 'resolved';
|
||||
createdAt: string;
|
||||
reporter: UserSummaryDTO | null;
|
||||
reported: UserSummaryDTO & { suspended: boolean };
|
||||
}
|
||||
|
||||
export interface AdminStatsDTO {
|
||||
users: number;
|
||||
listeningNow: number;
|
||||
openReports: number;
|
||||
suspended: number;
|
||||
}
|
||||
|
||||
/** A row in a followers/following list. */
|
||||
export interface FollowListItemDTO extends UserSummaryDTO {
|
||||
/** Whether the viewer follows this person (for Follow/Following buttons). */
|
||||
isFollowing: boolean;
|
||||
}
|
||||
|
||||
export interface FollowListDTO {
|
||||
users: FollowListItemDTO[];
|
||||
/** Pass back as ?cursor= for the next page; null when there are no more. */
|
||||
nextCursor: string | null;
|
||||
}
|
||||
|
||||
export interface ConnectionDTO {
|
||||
provider: NowPlayingProvider;
|
||||
externalUserId: string;
|
||||
|
||||
Reference in New Issue
Block a user