halkyon_base: a Serverpod module for sign-in, accounts and instance basics
What every Halkyon server has, taken from Halkyon Learn's: anonymous, GitHub and email-code sign-in with their endpoints, an account's ways in and its deletion, the pruning of abandoned anonymous people, of sign-up attempts and of expired codes, and the instance's basics (the sign-in ways offered, the source link, the minimum app build, where people's data and its backups are). Endpoints sit under the nickname `base`. A host configures it in one place before its pod starts: its name for the mails, its source link, its minimum build, and hooks that delete its own data with a person. The tables keep Learn's names, columns and indexes, so a host moving onto the module migrates nothing but version rows. Server package under the SSPL, client under the AGPL, as Learn's are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
80fa7b9628
commit
af1de799f4
1 changed files with 17704 additions and 3 deletions
|
|
@ -0,0 +1,78 @@
|
|||
import 'package:halkyon_base_server/base.dart';
|
||||
import 'package:serverpod/serverpod.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '../support/fixtures.dart';
|
||||
import '../test_tools/serverpod_test_tools.dart';
|
||||
|
||||
/// Keeps nothing; there to say the instance can mail codes.
|
||||
final class _NoMail implements CodeMailer {
|
||||
@override
|
||||
Future<void> send(
|
||||
Session session, {
|
||||
required String to,
|
||||
required String code,
|
||||
required String language,
|
||||
}) async {}
|
||||
}
|
||||
|
||||
void main() {
|
||||
withServerpod('What every instance tells its apps', (
|
||||
sessionBuilder,
|
||||
endpoints,
|
||||
) {
|
||||
late InstanceBasics basics;
|
||||
|
||||
setUp(() async {
|
||||
useBase(sessionBuilder);
|
||||
basics = await endpoints.instance.basics(
|
||||
sessionBuilder.copyWith(
|
||||
authentication: AuthenticationOverride.unauthenticated(),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test("names where the host's project publishes its source when the "
|
||||
'operator set nothing', () {
|
||||
// The tests run without SOURCE_URL.
|
||||
expect(basics.sourceCodeUrl, testUpstreamSourceCodeUrl);
|
||||
});
|
||||
|
||||
test('names the oldest app build the host works with, to anyone, so an '
|
||||
'older app can say it needs an update', () {
|
||||
expect(basics.minimumAppBuild, testMinimumAppBuild);
|
||||
});
|
||||
|
||||
test('says nothing of where its data and backups are where the '
|
||||
'operator said nothing', () {
|
||||
// The tests run without DATA_LOCATION and BACKUP_LOCATION.
|
||||
expect(basics.dataLocation, isNull);
|
||||
expect(basics.backupLocation, isNull);
|
||||
});
|
||||
|
||||
test('offers no GitHub sign-in without an OAuth app of its own', () {
|
||||
// The tests' passwords hold no githubClientId.
|
||||
expect(basics.gitHubClientId, isNull);
|
||||
});
|
||||
|
||||
test('offers email sign-in only where it can mail codes', () async {
|
||||
final codes = EmailCodes.of(sessionBuilder.build().serverpod);
|
||||
final unauthenticated = sessionBuilder.copyWith(
|
||||
authentication: AuthenticationOverride.unauthenticated(),
|
||||
);
|
||||
addTearDown(() => codes.mailer = null);
|
||||
|
||||
codes.mailer = null;
|
||||
expect(
|
||||
(await endpoints.instance.basics(unauthenticated)).emailSignIn,
|
||||
isFalse,
|
||||
);
|
||||
|
||||
codes.mailer = _NoMail();
|
||||
expect(
|
||||
(await endpoints.instance.basics(unauthenticated)).emailSignIn,
|
||||
isTrue,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue