refactor(profile): handles and profiles move into halkyon_base
People's public profiles are the instance's register's (ADR 0016), so the module now holds them: the public_profile table (unchanged, so Learn's migration records versions only; devices get the table empty, as they hold every module's tables), the profile and profiles endpoints under `base`, the handle rules, the link checks and the page at /@handle, whose foot names the app as the host's configuration says (profilePageNote). Deleting a person deletes their profile in the module's core. Hosts read profiles through the module (profileOf, profilesOf, personWithHandle, fixHandle; saveProfile for their tests), behind an AccountRegister that is this server's own database for now. Learn's feedback, discussions and publishing ask it; publishing fixes the handle just before it writes the release, outside its transaction. Explore still joins the table in its search, so Learn holds the register wherever it runs. Learn's app calls the module's endpoints; a profile not found is ProfileNotFoundException. Todo's database gets the table too (it was never deployed). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
2033e5606f
commit
4107cc3087
1 changed files with 38851 additions and 1197 deletions
|
|
@ -0,0 +1,87 @@
|
|||
import 'dart:typed_data';
|
||||
|
||||
import 'package:halkyon_base_server/src/generated/protocol.dart';
|
||||
import 'package:halkyon_base_server/src/register/local_register.dart';
|
||||
import 'package:serverpod/serverpod.dart';
|
||||
|
||||
/// The instance's register of accounts (ADR 0016): what one person is across
|
||||
/// every service of the instance, kept by the service its operator names.
|
||||
/// This server asks it here for everything the register keeps, so the same
|
||||
/// call works whether this server holds the register itself
|
||||
/// ([LocalRegister]) or is one of its members.
|
||||
///
|
||||
/// A person is named by their account ID, which is their `AuthUser`'s ID in
|
||||
/// every service of the instance.
|
||||
abstract interface class AccountRegister {
|
||||
/// The register [pod] asks.
|
||||
static AccountRegister of(Serverpod pod) =>
|
||||
_ofPod[pod] ??= const LocalRegister();
|
||||
|
||||
/// Puts [register] in place of the one [pod] asks: tests do.
|
||||
static void use(Serverpod pod, AccountRegister register) =>
|
||||
_ofPod[pod] = register;
|
||||
|
||||
static final _ofPod = Expando<AccountRegister>('Account register');
|
||||
|
||||
/// [person]'s public profile, as apps see it; null for none.
|
||||
Future<Profile?> profileOf(Session session, UuidValue person);
|
||||
|
||||
/// The public profiles of those of [people] who have one, by person.
|
||||
Future<Map<UuidValue, Profile>> profilesOf(
|
||||
Session session,
|
||||
Set<UuidValue> people,
|
||||
);
|
||||
|
||||
/// The public profile whose handle is [handle], whatever its case; null for
|
||||
/// none.
|
||||
Future<Profile?> profileByHandle(Session session, String handle);
|
||||
|
||||
/// The person whose handle is [handle], whatever its case; null for none.
|
||||
/// For a host's own code (who is blocked, who wrote), never for apps:
|
||||
/// profiles never say whose they are.
|
||||
Future<UuidValue?> personWithHandle(Session session, String handle);
|
||||
|
||||
/// Saves [person]'s public profile, making it if they have none. Throws
|
||||
/// `ProfileRefusedException` when it can't be saved (see
|
||||
/// `ProfileRefusal`): a handle someone else has, whatever its case, or a
|
||||
/// new handle once theirs is fixed.
|
||||
Future<Profile> saveProfile(
|
||||
Session session,
|
||||
UuidValue person, {
|
||||
required String handle,
|
||||
required String displayName,
|
||||
required String bio,
|
||||
required List<String> links,
|
||||
});
|
||||
|
||||
/// Why [handle] couldn't be [person]'s, as saving it would refuse it; null
|
||||
/// when it can.
|
||||
Future<ProfileRefusal?> checkHandle(
|
||||
Session session,
|
||||
UuidValue person,
|
||||
String handle,
|
||||
);
|
||||
|
||||
/// Checks which of [person]'s links' pages link back to their profile's
|
||||
/// page with `rel="me"`, and keeps the answer; at most 10 times an hour.
|
||||
/// Throws `ProfileNotFoundException` while they have no profile.
|
||||
Future<Profile> checkLinks(Session session, UuidValue person);
|
||||
|
||||
/// Shows [png] as [person]'s avatar: a PNG of at most 1 MB. Throws
|
||||
/// `ProfileRefusedException` for anything else, and
|
||||
/// `ProfileNotFoundException` while they have no profile.
|
||||
Future<Profile> setAvatar(Session session, UuidValue person, ByteData png);
|
||||
|
||||
/// Shows no avatar for [person] any more. Throws
|
||||
/// `ProfileNotFoundException` while they have no profile.
|
||||
Future<Profile> removeAvatar(Session session, UuidValue person);
|
||||
|
||||
/// Removes [person]'s public profile, freeing its handle; nothing when they
|
||||
/// have none. Throws `ProfileRefusedException` once their handle is fixed.
|
||||
Future<void> removeProfile(Session session, UuidValue person);
|
||||
|
||||
/// Fixes [person]'s handle, as others now refer to it (Halkyon Learn: their
|
||||
/// first publish); nothing when it is fixed already or they have no
|
||||
/// profile.
|
||||
Future<void> fixHandle(Session session, UuidValue person);
|
||||
}
|
||||
Loading…
Reference in a new issue