Flexibele kluissoorten: soorten in de database, beheer op de website
- Tabellen vault_categories en vault_category_fields (db/21), startrijen handmatig (db/handmatig/21b) - VaultCategoryService met regels voor zichtbaarheid, gebruik en eigen velden - Beheer > Kluissoorten (/beheer/soorten) met gebruikstellers; soort in gebruik niet te verwijderen - Kluis en Nalatenschap (web en app) tonen soorten en eigen velden uit de database - Socketprotocol: vault.categories; GRANTs voor mijnbesluit_app in db/02 - db/20 herhaalbaar gemaakt - App versie 1.1 (versiecode 3) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014MGLqt1uKfNARQHut9ifcx
This commit is contained in:
@@ -0,0 +1,446 @@
|
||||
using MijnBesluit.Application.Models;
|
||||
using MijnBesluit.Application.Services;
|
||||
using MijnBesluit.Domain.Entities;
|
||||
using MijnBesluit.Domain.Enums;
|
||||
|
||||
namespace MijnBesluit.SelfCheck;
|
||||
|
||||
/// <summary>
|
||||
/// De soorten kluisitems uit de database: wat de beheerder kan instellen en welke regels daarbij
|
||||
/// vastliggen.
|
||||
///
|
||||
/// Het hart is één afspraak: wat in gebruik is, verdwijnt nooit. Een soort waar een item mee is
|
||||
/// gemaakt kan niet worden verwijderd, en niet-actief zetten haalt hem alleen weg bij wie hem nog
|
||||
/// nooit gebruikte. De rest hier is daar de omlijsting van: wie het mag instellen, hoe de velden
|
||||
/// van een eigen soort worden gecontroleerd, en dat "Bespreken met" een instelling per soort is.
|
||||
/// </summary>
|
||||
public static class SoortenChecks
|
||||
{
|
||||
private static async Task<User> BeheerderAsync(World w, string email = "beheer@example.nl")
|
||||
{
|
||||
var u = await w.MaakGebruikerAsync(email, "Beheer", "Er");
|
||||
w.Store.Users.Single(x => x.Id == u.Id).IsBeheerder = true;
|
||||
return u;
|
||||
}
|
||||
|
||||
private static async Task<int> MaakAsync(World w, User beheerder, string naam, bool bespreken = false)
|
||||
{
|
||||
var r = await w.Soorten.MaakAsync(beheerder.Id, naam, null, bespreken);
|
||||
if (!r.Succeeded) throw new AssertionException($"soort maken mislukte: {r.Error}");
|
||||
return r.Value;
|
||||
}
|
||||
|
||||
public static void Register(Runner runner)
|
||||
{
|
||||
runner.TestAsync("Soorten: de startlijst is precies wat er voorheen vast in de code stond", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
|
||||
var lijst = await w.Soorten.ZichtbaarVoorAsync(jan.PersonId);
|
||||
Assert.True(lijst.Count == 12, "twaalf soorten: elf ingebouwde en Overig");
|
||||
Assert.True(lijst.First().Naam == "Wachtwoord" && lijst.Last().Naam == "Overig",
|
||||
"de volgorde is die van de oude keuzelijst");
|
||||
|
||||
var bespreekbaar = lijst.Where(s => s.BesprekenMet).Select(s => s.Naam).OrderBy(n => n).ToArray();
|
||||
Assert.True(bespreekbaar.SequenceEqual(new[] { "Donorcodicil", "Uitvaartwens" }),
|
||||
"alleen uitvaartwens en donorcodicil kennen Bespreken met, zoals voorheen");
|
||||
Assert.True(lijst.All(s => s.Ingebouwd && s.Velden.Count == 0), "ingebouwde soorten hebben geen eigen velden");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: alleen een beheerder maakt of wijzigt soorten", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
Assert.True(!(await w.Soorten.MaakAsync(jan.Id, "Dementie", null, false)).Succeeded,
|
||||
"een gewone gebruiker maakt geen soort");
|
||||
Assert.True(!(await w.Soorten.OverzichtAsync(jan.Id)).Succeeded, "en ziet het beheeroverzicht niet");
|
||||
Assert.True(!(await w.Soorten.WijzigAsync(jan.Id, 3, "Wachtwoord", null, false, 10, false)).Succeeded,
|
||||
"en zet geen soort uit");
|
||||
|
||||
var id = await MaakAsync(w, beheer, "Dementie");
|
||||
Assert.True(id >= VaultCategoryDefinition.EersteEigenNummer, "een eigen soort begint bij 100");
|
||||
Assert.True(!(await w.Soorten.VerwijderAsync(jan.Id, id)).Succeeded, "een gewone gebruiker verwijdert er geen");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: een naam is verplicht en kan niet dubbel", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
Assert.True(!(await w.Soorten.MaakAsync(beheer.Id, " ", null, false)).Succeeded, "zonder naam kan het niet");
|
||||
Assert.True(!(await w.Soorten.MaakAsync(beheer.Id, "polis", null, false)).Succeeded,
|
||||
"Polis bestaat al, ook in kleine letters");
|
||||
await MaakAsync(w, beheer, "Dementie");
|
||||
Assert.True(!(await w.Soorten.MaakAsync(beheer.Id, "DEMENTIE", null, false)).Succeeded, "een tweede Dementie kan niet");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: een nieuwe soort staat meteen in de lijst van iedereen", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
var id = await MaakAsync(w, beheer, "Niet reanimeren");
|
||||
var lijst = await w.Soorten.ZichtbaarVoorAsync(jan.PersonId);
|
||||
Assert.True(lijst.Any(s => s.Id == id && s.Naam == "Niet reanimeren" && !s.Ingebouwd),
|
||||
"de nieuwe soort staat erbij");
|
||||
Assert.True(lijst.Last().Naam == "Niet reanimeren", "hij staat onderaan");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: het beheeroverzicht telt items en eigenaren, niet meer", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var piet = await w.MaakGebruikerAsync("piet@example.nl", "Piet");
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
await w.Vault.CreateAsync(jan.Id, VaultCategory.Polis, "A", new VaultPayload());
|
||||
await w.Vault.CreateAsync(jan.Id, VaultCategory.Polis, "B", new VaultPayload());
|
||||
await w.Vault.CreateAsync(piet.Id, VaultCategory.Polis, "C", new VaultPayload());
|
||||
var weg = (await w.Vault.CreateAsync(piet.Id, VaultCategory.Polis, "D", new VaultPayload())).Value!;
|
||||
await w.Vault.DeleteAsync(weg.Id, piet.Id);
|
||||
|
||||
var overzicht = (await w.Soorten.OverzichtAsync(beheer.Id)).Value!;
|
||||
var polis = overzicht.Single(s => s.Naam == "Polis");
|
||||
Assert.True(polis.Items == 3, "drie items: het verwijderde telt niet mee");
|
||||
Assert.True(polis.Eigenaren == 2, "van twee mensen");
|
||||
Assert.True(!polis.KanVerwijderen, "een ingebouwde soort in gebruik is niet te verwijderen");
|
||||
Assert.True(overzicht.Single(s => s.Naam == "Paspoort").Items == 0, "wat niemand gebruikt staat op nul");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: wat in gebruik is kan niet worden verwijderd, wat ongebruikt is wel", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
var gebruikt = await MaakAsync(w, beheer, "Dementie");
|
||||
var ongebruikt = await MaakAsync(w, beheer, "Proef");
|
||||
|
||||
var item = (await w.Vault.CreateAsync(jan.Id, (VaultCategory)gebruikt, "Mijn wens",
|
||||
new VaultPayload { Velden = new() })).Value!;
|
||||
Assert.True(item.Id != 0, "Jan maakt een item in de nieuwe soort");
|
||||
|
||||
var geweigerd = await w.Soorten.VerwijderAsync(beheer.Id, gebruikt);
|
||||
Assert.True(!geweigerd.Succeeded && geweigerd.Error!.Contains("niet-actief"),
|
||||
"een soort in gebruik wordt geweigerd, met de uitleg wat wel kan");
|
||||
Assert.True(await w.Soorten.VindAsync(gebruikt) is not null, "hij staat er nog");
|
||||
|
||||
Assert.True((await w.Soorten.VerwijderAsync(beheer.Id, ongebruikt)).Succeeded, "een ongebruikte kan weg");
|
||||
Assert.True(await w.Soorten.VindAsync(ongebruikt) is null, "en is weg");
|
||||
|
||||
Assert.True(!(await w.Soorten.VerwijderAsync(beheer.Id, 3)).Succeeded,
|
||||
"een ingebouwde soort verwijder je nooit, ook niet zonder items");
|
||||
|
||||
// En zodra het laatste item weg is, mag het weer.
|
||||
await w.Vault.DeleteAsync(item.Id, jan.Id);
|
||||
Assert.True((await w.Soorten.VerwijderAsync(beheer.Id, gebruikt)).Succeeded,
|
||||
"zonder items is hij weer te verwijderen");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: niet-actief verdwijnt alleen bij wie hem nooit gebruikte", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var piet = await w.MaakGebruikerAsync("piet@example.nl", "Piet");
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
var id = await MaakAsync(w, beheer, "Dementie");
|
||||
var item = (await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "Mijn wens",
|
||||
new VaultPayload { Velden = new() })).Value!;
|
||||
|
||||
Assert.True((await w.Soorten.WijzigAsync(beheer.Id, id, "Dementie", null, false, 1000, false)).Succeeded,
|
||||
"de beheerder zet hem op niet-actief");
|
||||
|
||||
Assert.True((await w.Soorten.ZichtbaarVoorAsync(jan.PersonId)).Any(s => s.Id == id),
|
||||
"Jan heeft er een item van en blijft de soort zien");
|
||||
Assert.True(!(await w.Soorten.ZichtbaarVoorAsync(piet.PersonId)).Any(s => s.Id == id),
|
||||
"Piet heeft hem nooit gebruikt en ziet hem niet meer");
|
||||
|
||||
Assert.True(!(await w.Vault.CreateAsync(piet.Id, (VaultCategory)id, "Nieuw", new VaultPayload { Velden = new() })).Succeeded,
|
||||
"Piet kan er ook geen nieuw item meer in maken");
|
||||
|
||||
var tweede = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "Nog een", new VaultPayload { Velden = new() });
|
||||
Assert.True(tweede.Succeeded, "Jan kan er nog wel nieuwe items in maken: het is een soort die hij kent");
|
||||
|
||||
var wijzigen = await w.Vault.UpdateAsync(item.Id, jan.Id, (VaultCategory)id, "Mijn wens (nieuw)",
|
||||
new VaultPayload { Velden = new() }, ReleasePolicy.AlleenIkzelf);
|
||||
Assert.True(wijzigen.Succeeded, "en zijn bestaande item kan hij gewoon wijzigen");
|
||||
|
||||
Assert.True((await w.Vault.OpenAsync(item.Id, jan.Id)).Succeeded, "en openen");
|
||||
|
||||
// Weer aanzetten: iedereen ziet hem weer.
|
||||
await w.Soorten.WijzigAsync(beheer.Id, id, "Dementie", null, true, 1000, false);
|
||||
Assert.True((await w.Soorten.ZichtbaarVoorAsync(piet.PersonId)).Any(s => s.Id == id),
|
||||
"na weer aanzetten ziet Piet hem weer");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: ook een ingebouwde soort kan op niet-actief, met dezelfde regel", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var piet = await w.MaakGebruikerAsync("piet@example.nl", "Piet");
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
await w.Vault.CreateAsync(jan.Id, VaultCategory.Paspoort, "Mijn paspoort", new VaultPayload());
|
||||
await w.Soorten.WijzigAsync(beheer.Id, (int)VaultCategory.Paspoort, "Paspoort", null, false, 90, false);
|
||||
|
||||
Assert.True((await w.Soorten.ZichtbaarVoorAsync(jan.PersonId)).Any(s => s.Naam == "Paspoort"),
|
||||
"Jan houdt Paspoort");
|
||||
Assert.True(!(await w.Soorten.ZichtbaarVoorAsync(piet.PersonId)).Any(s => s.Naam == "Paspoort"),
|
||||
"Piet ziet het niet meer");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: Bespreken met is een instelling per soort", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var opa = await w.MaakGebruikerAsync("opa@example.nl", "Klaas", "de Vries");
|
||||
var zoon = await w.MaakFamilielidAsync(opa, "Peter", "de Vries", "zoon@example.nl");
|
||||
await w.BeheerderAsync(opa, zoon);
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
// Standaard: een uitvaartwens kan het, een polis niet - zoals voorheen.
|
||||
var wens = (await w.Vault.CreateAsync(opa.Id, VaultCategory.Uitvaartwens, "Uitvaart", new VaultPayload(),
|
||||
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
|
||||
Assert.True((await w.Vault.OpenAsync(wens.Id, zoon.Id)).Succeeded, "de gekozen beheerder leest de uitvaartwens mee");
|
||||
|
||||
var polis = (await w.Vault.CreateAsync(opa.Id, VaultCategory.Polis, "Polis", new VaultPayload(),
|
||||
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
|
||||
Assert.True(polis.SharedManagerPersonId is null, "bij een polis wordt de keuze genegeerd");
|
||||
Assert.True(!(await w.Vault.OpenAsync(polis.Id, zoon.Id)).Succeeded, "en de beheerder ziet hem niet");
|
||||
|
||||
// De beheerder zet het bij Polis aan: nu werkt het ook daar.
|
||||
await w.Soorten.WijzigAsync(beheer.Id, (int)VaultCategory.Polis, "Polis", null, true, 50, true);
|
||||
var polis2 = (await w.Vault.CreateAsync(opa.Id, VaultCategory.Polis, "Polis 2", new VaultPayload(),
|
||||
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
|
||||
Assert.True(polis2.SharedManagerPersonId == zoon.PersonId, "bij Polis wordt de keuze nu bewaard");
|
||||
Assert.True((await w.Vault.OpenAsync(polis2.Id, zoon.Id)).Succeeded, "en de beheerder leest hem mee");
|
||||
|
||||
// En bij Uitvaartwens uit: dan niet meer.
|
||||
await w.Soorten.WijzigAsync(beheer.Id, (int)VaultCategory.Uitvaartwens, "Uitvaartwens", null, true, 60, false);
|
||||
var wens2 = (await w.Vault.CreateAsync(opa.Id, VaultCategory.Uitvaartwens, "Uitvaart 2", new VaultPayload(),
|
||||
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
|
||||
Assert.True(wens2.SharedManagerPersonId is null, "met de schakelaar uit wordt de keuze genegeerd");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: Bespreken met werkt ook bij een soort die de beheerder zelf maakte", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var opa = await w.MaakGebruikerAsync("opa@example.nl", "Klaas", "de Vries");
|
||||
var zoon = await w.MaakFamilielidAsync(opa, "Peter", "de Vries", "zoon@example.nl");
|
||||
await w.BeheerderAsync(opa, zoon);
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
var met = await MaakAsync(w, beheer, "Niet reanimeren", bespreken: true);
|
||||
var zonder = await MaakAsync(w, beheer, "Dementie", bespreken: false);
|
||||
|
||||
var a = (await w.Vault.CreateAsync(opa.Id, (VaultCategory)met, "NR", new VaultPayload { Velden = new() },
|
||||
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
|
||||
var b = (await w.Vault.CreateAsync(opa.Id, (VaultCategory)zonder, "DM", new VaultPayload { Velden = new() },
|
||||
ReleasePolicy.AlleenIkzelf, null, zoon.PersonId)).Value!;
|
||||
Assert.True((await w.Vault.OpenAsync(a.Id, zoon.Id)).Succeeded, "met de schakelaar aan leest hij mee");
|
||||
Assert.True(!(await w.Vault.OpenAsync(b.Id, zoon.Id)).Succeeded, "met de schakelaar uit niet");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: een soort die niet bestaat is geen soort", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var r = await w.Vault.CreateAsync(jan.Id, (VaultCategory)4242, "Onzin", new VaultPayload());
|
||||
Assert.True(!r.Succeeded, "een onbekend soortnummer wordt geweigerd");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: de sleutel van een veld komt uit het label en is uniek", () =>
|
||||
{
|
||||
Assert.True(VaultCategoryService.NieuweSleutel("Wil je gereanimeerd worden?", Array.Empty<string>())
|
||||
== "wil_je_gereanimeerd_worden", "een vraag wordt een leesbare sleutel");
|
||||
Assert.True(VaultCategoryService.NieuweSleutel("Café — één", Array.Empty<string>()) == "cafe_een",
|
||||
"accenten en streepjes verdwijnen");
|
||||
Assert.True(VaultCategoryService.NieuweSleutel("???", Array.Empty<string>()) == "veld",
|
||||
"zonder bruikbare tekens blijft 'veld' over");
|
||||
Assert.True(VaultCategoryService.NieuweSleutel("Arts", new[] { "arts" }) == "arts_2",
|
||||
"een bestaande sleutel krijgt een nummer");
|
||||
Assert.True(VaultCategoryService.NieuweSleutel(new string('x', 80), Array.Empty<string>()).Length <= 30,
|
||||
"en een lang label wordt bijgesneden");
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
runner.TestAsync("Velden: een eigen soort bewaart zijn velden versleuteld en geeft ze terug", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
var id = await MaakAsync(w, beheer, "Niet reanimeren");
|
||||
Assert.True((await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Wil je gereanimeerd worden?", VeldSoort.Keuze,
|
||||
"Ja\nNee\nAlleen na overleg", null, true)).Succeeded, "keuzeveld toevoegen");
|
||||
Assert.True((await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Datum verklaring", VeldSoort.Datum,
|
||||
null, null, false)).Succeeded, "datumveld toevoegen");
|
||||
Assert.True((await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Toelichting voor de arts", VeldSoort.Lang,
|
||||
null, "Zo precies mogelijk.", false)).Succeeded, "lang veld toevoegen");
|
||||
|
||||
var soort = (await w.Soorten.ZichtbaarVoorAsync(jan.PersonId)).Single(s => s.Id == id);
|
||||
Assert.True(soort.Velden.Select(v => v.Sleutel).SequenceEqual(
|
||||
new[] { "wil_je_gereanimeerd_worden", "datum_verklaring", "toelichting_voor_de_arts" }),
|
||||
"de velden staan in de volgorde van toevoegen");
|
||||
Assert.True(soort.Velden[0].Opties.SequenceEqual(new[] { "Ja", "Nee", "Alleen na overleg" }), "de opties kloppen");
|
||||
|
||||
var item = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "Mijn verklaring", new VaultPayload
|
||||
{
|
||||
Velden = new()
|
||||
{
|
||||
["wil_je_gereanimeerd_worden"] = "Nee",
|
||||
["datum_verklaring"] = "2026-10-12",
|
||||
["onbekend_veld"] = "hoort er niet"
|
||||
}
|
||||
});
|
||||
Assert.True(item.Succeeded, "het item wordt bewaard");
|
||||
|
||||
var open = (await w.Vault.OpenAsync(item.Value!.Id, jan.Id)).Value!;
|
||||
Assert.True(open.Velden is not null && open.Velden["wil_je_gereanimeerd_worden"] == "Nee", "de waarde komt terug");
|
||||
Assert.True(open.Velden!["datum_verklaring"] == "2026-10-12", "ook de datum");
|
||||
Assert.True(!open.Velden.ContainsKey("onbekend_veld"), "een veld dat niet bestaat wordt weggelaten");
|
||||
|
||||
// En het staat echt versleuteld in de opslag, niet leesbaar.
|
||||
var opgeslagen = w.Store.VaultItems.Single(v => v.Id == item.Value.Id);
|
||||
Assert.True(!System.Text.Encoding.UTF8.GetString(opgeslagen.Ciphertext).Contains("Nee"),
|
||||
"in de opslag staat niets leesbaars");
|
||||
});
|
||||
|
||||
runner.TestAsync("Velden: verplicht, datum en lengte worden op de server gecontroleerd", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
var id = await MaakAsync(w, beheer, "Niet reanimeren");
|
||||
await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Keuze", VeldSoort.Keuze, "Ja\nNee", null, true);
|
||||
await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Datum", VeldSoort.Datum, null, null, false);
|
||||
|
||||
var leeg = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "X", new VaultPayload { Velden = new() });
|
||||
Assert.True(!leeg.Succeeded && leeg.Error!.Contains("Keuze"), "een leeg verplicht veld wordt geweigerd, met de naam erbij");
|
||||
|
||||
var slechteDatum = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "X", new VaultPayload
|
||||
{ Velden = new() { ["keuze"] = "Ja", ["datum"] = "morgen" } });
|
||||
Assert.True(!slechteDatum.Succeeded && slechteDatum.Error!.Contains("datum"), "een datum die geen datum is wordt geweigerd");
|
||||
|
||||
var teLang = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "X", new VaultPayload
|
||||
{ Velden = new() { ["keuze"] = new string('a', VaultCategoryService.MaxWaardelengte + 1) } });
|
||||
Assert.True(!teLang.Succeeded, "een te lange waarde wordt geweigerd");
|
||||
|
||||
var goed = await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "X", new VaultPayload
|
||||
{ Velden = new() { ["keuze"] = "Ja", ["datum"] = "2026-02-28" } });
|
||||
Assert.True(goed.Succeeded, "met alles goed ingevuld lukt het");
|
||||
});
|
||||
|
||||
runner.TestAsync("Velden: een app die de soort niet kent kan geen gegevens overschrijven met niets", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
var id = await MaakAsync(w, beheer, "Dementie");
|
||||
await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Wens", VeldSoort.Lang, null, null, false);
|
||||
var item = (await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "Mijn wens", new VaultPayload
|
||||
{ Velden = new() { ["wens"] = "Thuis blijven wonen." } })).Value!;
|
||||
|
||||
// Een oudere app stuurt de inhoud zonder het onderdeel Velden mee.
|
||||
var oud = await w.Vault.UpdateAsync(item.Id, jan.Id, (VaultCategory)id, "Mijn wens",
|
||||
new VaultPayload { Notes = "alleen een notitie" }, ReleasePolicy.AlleenIkzelf);
|
||||
Assert.True(!oud.Succeeded && oud.Error!.Contains("app"), "het wijzigen wordt geweigerd met het advies de app bij te werken");
|
||||
|
||||
var open = (await w.Vault.OpenAsync(item.Id, jan.Id)).Value!;
|
||||
Assert.True(open.Velden!["wens"] == "Thuis blijven wonen.", "wat er stond is niet overschreven");
|
||||
});
|
||||
|
||||
runner.TestAsync("Velden: een ingebouwde soort bewaart geen eigen velden", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
|
||||
var item = (await w.Vault.CreateAsync(jan.Id, VaultCategory.Polis, "Polis", new VaultPayload
|
||||
{ Insurer = "Zilveren Kruis", Velden = new() { ["iets"] = "weg ermee" } })).Value!;
|
||||
var open = (await w.Vault.OpenAsync(item.Id, jan.Id)).Value!;
|
||||
Assert.True(open.Velden is null, "bij een ingebouwde soort wordt Velden leeggemaakt");
|
||||
Assert.True(open.Insurer == "Zilveren Kruis", "de eigen velden van de soort blijven gewoon");
|
||||
});
|
||||
|
||||
runner.TestAsync("Velden: ingebouwde soorten hebben geen velden om te wijzigen", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
var r = await w.Soorten.VeldToevoegenAsync(beheer.Id, (int)VaultCategory.Polis, "Extra", VeldSoort.Tekst, null, null, false);
|
||||
Assert.True(!r.Succeeded, "een veld toevoegen aan een ingebouwde soort kan niet");
|
||||
});
|
||||
|
||||
runner.TestAsync("Velden: een veld met ingevulde gegevens wordt niet verwijderd maar niet-actief", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var jan = await w.MaakGebruikerAsync("jan@example.nl", "Jan");
|
||||
var beheer = await BeheerderAsync(w);
|
||||
|
||||
var id = await MaakAsync(w, beheer, "Dementie");
|
||||
await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Wens", VeldSoort.Lang, null, null, false);
|
||||
await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Arts", VeldSoort.Tekst, null, null, false);
|
||||
var velden = (await w.Soorten.OverzichtAsync(beheer.Id)).Value!.Single(s => s.Id == id).Velden;
|
||||
var wens = velden.Single(v => v.Sleutel == "wens");
|
||||
var arts = velden.Single(v => v.Sleutel == "arts");
|
||||
|
||||
// Zonder items mag een veld gewoon weg.
|
||||
Assert.True((await w.Soorten.VeldVerwijderenAsync(beheer.Id, arts.Id)).Succeeded, "zonder items kan een veld weg");
|
||||
|
||||
await w.Vault.CreateAsync(jan.Id, (VaultCategory)id, "Mijn wens", new VaultPayload
|
||||
{ Velden = new() { ["wens"] = "Thuis blijven wonen." } });
|
||||
|
||||
var geweigerd = await w.Soorten.VeldVerwijderenAsync(beheer.Id, wens.Id);
|
||||
Assert.True(!geweigerd.Succeeded && geweigerd.Error!.Contains("niet-actief"),
|
||||
"met items erbij wordt verwijderen geweigerd, met de uitleg");
|
||||
|
||||
// Niet-actief mag. De waarde blijft bewaard en bij het wijzigen nog bruikbaar.
|
||||
Assert.True((await w.Soorten.VeldWijzigenAsync(beheer.Id, wens.Id, "Wens", null, null, false, false, 10)).Succeeded,
|
||||
"op niet-actief zetten kan");
|
||||
var item = w.Store.VaultItems.Single(v => v.Title == "Mijn wens");
|
||||
var wijzig = await w.Vault.UpdateAsync(item.Id, jan.Id, (VaultCategory)id, "Mijn wens",
|
||||
new VaultPayload { Velden = new() { ["wens"] = "Thuis blijven wonen, met hulp." } }, ReleasePolicy.AlleenIkzelf);
|
||||
Assert.True(wijzig.Succeeded, "het item is nog te wijzigen");
|
||||
var open = (await w.Vault.OpenAsync(item.Id, jan.Id)).Value!;
|
||||
Assert.True(open.Velden!["wens"] == "Thuis blijven wonen, met hulp.",
|
||||
"en de waarde van het niet-actieve veld blijft bewaard");
|
||||
});
|
||||
|
||||
runner.TestAsync("Velden: een keuzelijst heeft minstens twee opties, een uitleg heeft tekst", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var beheer = await BeheerderAsync(w);
|
||||
var id = await MaakAsync(w, beheer, "Dementie");
|
||||
|
||||
Assert.True(!(await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Keuze", VeldSoort.Keuze, "Alleen deze", null, false)).Succeeded,
|
||||
"één optie is geen keuze");
|
||||
Assert.True(!(await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Uitleg", VeldSoort.Uitleg, null, null, false)).Succeeded,
|
||||
"een uitleg zonder tekst kan niet");
|
||||
Assert.True((await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Uitleg", VeldSoort.Uitleg, null,
|
||||
"Een papieren verklaring is leidend.", true)).Succeeded, "met tekst kan het wel");
|
||||
var uitleg = (await w.Soorten.OverzichtAsync(beheer.Id)).Value!.Single(s => s.Id == id).Velden.Single();
|
||||
Assert.True(!uitleg.Verplicht, "een uitlegtekst kan nooit verplicht zijn");
|
||||
Assert.True(!(await w.Soorten.VeldToevoegenAsync(beheer.Id, id, "Raar", "zweef", null, null, false)).Succeeded,
|
||||
"een soort veld die we niet kennen wordt geweigerd");
|
||||
});
|
||||
|
||||
runner.TestAsync("Soorten: wijzigingen door de beheerder staan in het logboek", async () =>
|
||||
{
|
||||
var w = new World();
|
||||
var beheer = await BeheerderAsync(w);
|
||||
var id = await MaakAsync(w, beheer, "Dementie");
|
||||
await w.Soorten.WijzigAsync(beheer.Id, id, "Dementie", null, false, 1000, false);
|
||||
await w.Soorten.VerwijderAsync(beheer.Id, id);
|
||||
|
||||
var regels = w.Store.Audit.Where(a => a.Action == AuditAction.KluisSoortBeheerd).ToList();
|
||||
Assert.True(regels.Count == 3, "gemaakt, gewijzigd en verwijderd staan er alle drie in");
|
||||
Assert.True(regels.All(a => a.UserId == beheer.Id), "met de beheerder erbij");
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user