From a8b5d9f8a80a82efb36f7d8a202f3fb20f2da73f Mon Sep 17 00:00:00 2001
From: Pascal Bleser
Date: Fri, 6 Feb 2026 09:42:29 +0100
Subject: [PATCH] groupware: add jscontact examples, and move them to
jmap/model_examples.go to avoid dependency recursion
---
pkg/jmap/jscontact_model_examples_test.go | 28 -
pkg/jmap/model_examples.go | 751 ++++++++++++++++++++++
services/groupware/Makefile | 8 +-
3 files changed, 755 insertions(+), 32 deletions(-)
delete mode 100644 pkg/jmap/jscontact_model_examples_test.go
diff --git a/pkg/jmap/jscontact_model_examples_test.go b/pkg/jmap/jscontact_model_examples_test.go
deleted file mode 100644
index 1bd0aae18b..0000000000
--- a/pkg/jmap/jscontact_model_examples_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-//go:build groupware_examples
-
-package jmap
-
-import c "github.com/opencloud-eu/opencloud/pkg/jscontact"
-
-func JSContactExample() {
- SerializeExamples(JSContactExemplarInstance)
- //Output:
-}
-
-type JSContactExemplar struct {
-}
-
-var JSContactExemplarInstance = JSContactExemplar{}
-
-func (e JSContactExemplar) Name() c.Name {
- return c.Name{
- Type: c.NameType,
- Components: []c.NameComponent{
- {Type: c.NameComponentType, Value: "Drummer", Kind: c.NameComponentKindGiven},
- {Type: c.NameComponentType, Value: "Camina", Kind: c.NameComponentKindGiven},
- },
- IsOrdered: true,
- DefaultSeparator: ", ",
- Full: "Camina Drummer",
- }
-}
diff --git a/pkg/jmap/model_examples.go b/pkg/jmap/model_examples.go
index b9ac184d83..372eeb869b 100644
--- a/pkg/jmap/model_examples.go
+++ b/pkg/jmap/model_examples.go
@@ -9,6 +9,8 @@ import (
"reflect"
"strings"
"time"
+
+ c "github.com/opencloud-eu/opencloud/pkg/jscontact"
)
func SerializeExamples(e any) {
@@ -804,3 +806,752 @@ func (e Exemplar) VacationResponseGetResponse() VacationResponseGetResponse {
},
}
}
+
+func (e Exemplar) AddressBook() AddressBook {
+ return AddressBook{
+ Id: "bar5kike",
+ Name: "My Friends",
+ Description: "An address book of the people I trust",
+ IsDefault: true,
+ IsSubscribed: true,
+ MyRights: AddressBookRights{
+ MayRead: true,
+ MayWrite: true,
+ MayAdmin: true,
+ MayDelete: true,
+ },
+ }
+}
+
+func (e Exemplar) AddressBookGetResponse() AddressBookGetResponse {
+ a := e.AddressBook()
+ return AddressBookGetResponse{
+ AccountId: e.AccountId,
+ State: "liew7dah",
+ NotFound: []string{},
+ List: []AddressBook{a},
+ }
+}
+
+func (e Exemplar) JSContactEmailAddress() c.EmailAddress {
+ return c.EmailAddress{
+ Type: c.EmailAddressType,
+ Address: "camina@opa.org",
+ Contexts: map[c.EmailAddressContext]bool{
+ c.EmailAddressContextWork: true,
+ c.EmailAddressContextPrivate: true,
+ },
+ Pref: 1,
+ Label: "bosmang",
+ }
+}
+
+func (e Exemplar) NameComponent() c.NameComponent {
+ return c.NameComponent{Type: c.NameComponentType, Value: "Camina", Kind: c.NameComponentKindGiven}
+}
+
+func (e Exemplar) OtherNameComponent() (c.NameComponent, string, string) {
+ return c.NameComponent{Type: c.NameComponentType, Value: "Drummer", Kind: c.NameComponentKindSurname}, "A surname NameComponent", "surname"
+}
+
+func (e Exemplar) NameComponents() []c.NameComponent {
+ a := e.NameComponent()
+ b, _, _ := e.OtherNameComponent()
+ return []c.NameComponent{a, b}
+}
+
+func (e Exemplar) Name() c.Name {
+ return c.Name{
+ Type: c.NameType,
+ Components: []c.NameComponent{
+ {Type: c.NameComponentType, Value: "Drummer", Kind: c.NameComponentKindSurname},
+ {Type: c.NameComponentType, Value: "Camina", Kind: c.NameComponentKindGiven},
+ },
+ IsOrdered: true,
+ DefaultSeparator: ", ",
+ }
+}
+
+func (e Exemplar) OtherName() (c.Name, string, string) {
+ return c.Name{
+ Type: c.NameType,
+ Components: []c.NameComponent{
+ {Type: c.NameComponentType, Value: "Klaes", Kind: c.NameComponentKindGiven},
+ {Type: c.NameComponentType, Value: "Ashford", Kind: c.NameComponentKindSurname},
+ },
+ IsOrdered: false,
+ DefaultSeparator: " ",
+ Full: "Klaes Ashford",
+ }, "Another Name", "other"
+}
+
+func (e Exemplar) ComplexName() (c.Name, string, string) {
+ return c.Name{
+ Type: c.NameType,
+ Components: []c.NameComponent{
+ {
+ Type: c.NameComponentType,
+ Value: "Diego",
+ Kind: c.NameComponentKindGiven,
+ Phonetic: "/diˈeɪɡəʊ/",
+ },
+ {
+ Value: "Rivera",
+ Kind: c.NameComponentKindSurname,
+ },
+ {
+ Value: "Barrientos",
+ Kind: c.NameComponentKindSurname2,
+ },
+ },
+ IsOrdered: true,
+ DefaultSeparator: " ",
+ Full: "Diego Rivera Barrientos",
+ SortAs: map[string]string{
+ string(c.NameComponentKindSurname): "Rivera Barrientos",
+ string(c.NameComponentKindGiven): "Diego",
+ },
+ }, "A complex name", "complex"
+}
+
+func (e Exemplar) Names() []c.Name {
+ a := e.Name()
+ b, _, _ := e.OtherName()
+ d, _, _ := e.ComplexName()
+ return []c.Name{a, b, d}
+}
+
+func (e Exemplar) Calendar() c.Calendar {
+ return c.Calendar{
+ Type: c.CalendarType,
+ Kind: c.CalendarKindCalendar,
+ Uri: "https://opa.example.com/cal/3051dd3f-065a-4087-ab86-a790510aebe1.ics",
+ MediaType: "text/calendar",
+ Contexts: map[c.CalendarContext]bool{
+ c.CalendarContextPrivate: true,
+ },
+ }
+}
+
+func (e Exemplar) OtherCalendar() (c.Calendar, string, string) {
+ return c.Calendar{
+ Type: c.CalendarType,
+ Kind: c.CalendarKindCalendar,
+ Uri: "https://opencloud.example.com/calendar/d05779b6-9638-4694-9869-008a61df6025",
+ MediaType: "application/jscontact+json",
+ Contexts: map[c.CalendarContext]bool{
+ c.CalendarContextWork: true,
+ },
+ Pref: 0,
+ Label: "business-contacts",
+ }, "A JSContact Calendar", "other"
+}
+
+func (e Exemplar) Calendars() []c.Calendar {
+ a := e.Calendar()
+ b, _, _ := e.OtherCalendar()
+ return []c.Calendar{a, b}
+}
+
+func (e Exemplar) Link() c.Link {
+ return c.Link{
+ Type: c.LinkType,
+ Kind: c.LinkKindContact,
+ Uri: "https://opencloud.example.com/calendar/d05779b6-9638-4694-9869-008a61df6025",
+ MediaType: "application/jscontact+json",
+ Contexts: map[c.LinkContext]bool{
+ c.LinkContextWork: true,
+ },
+ Pref: 0,
+ Label: "sample",
+ }
+}
+
+func (e Exemplar) CryptoKey() c.CryptoKey {
+ return c.CryptoKey{
+ Type: c.CryptoKeyType,
+ Uri: "https://opencloud.example.com/keys/53c25ae8-2800-4905-86a9-92d765b9efb9.pgp",
+ MediaType: "application/pgp-keys",
+ Contexts: map[c.CryptoKeyContext]bool{
+ c.CryptoKeyContextWork: true,
+ },
+ Pref: 0,
+ Label: "work",
+ }
+}
+
+func (e Exemplar) Directory() c.Directory {
+ return c.Directory{
+ Type: c.DirectoryType,
+ Kind: c.DirectoryKindEntry,
+ Uri: "https://opencloud.example.com/dir/38b850ea-f6ac-419d-8a26-1d19615cfa9b.vcf",
+ MediaType: "text/vcard",
+ Contexts: map[c.DirectoryContext]bool{
+ c.DirectoryContextWork: true,
+ },
+ Pref: 0,
+ Label: "work",
+ ListAs: 3,
+ }
+}
+
+func (e Exemplar) Media() c.Media {
+ return c.Media{
+ Type: c.MediaType,
+ Kind: c.MediaKindLogo,
+ Uri: "https://opencloud.eu/opencloud.svg",
+ MediaType: "image/svg+xml",
+ Contexts: map[c.MediaContext]bool{
+ c.MediaContextWork: true,
+ },
+ Pref: 0,
+ Label: "logo",
+ BlobId: "1d92cf97e32b42ceb5538f0804a41891",
+ }
+}
+
+func (e Exemplar) Relation() c.Relation {
+ return c.Relation{
+ Type: c.RelationType,
+ Relation: map[c.Relationship]bool{
+ c.RelationCoWorker: true,
+ c.RelationFriend: true,
+ },
+ }
+}
+
+func (e Exemplar) Nickname() c.Nickname {
+ return c.Nickname{
+ Type: c.NicknameType,
+ Name: "Bob",
+ Contexts: map[c.NicknameContext]bool{
+ c.NicknameContextPrivate: true,
+ },
+ Pref: 3,
+ }
+}
+
+func (e Exemplar) OrgUnit() c.OrgUnit {
+ return c.OrgUnit{
+ Type: c.OrgUnitType,
+ Name: "Skynet",
+ SortAs: "SKY",
+ }
+}
+
+func (e Exemplar) Organization() c.Organization {
+ return c.Organization{
+ Type: c.OrganizationType,
+ Name: "Cyberdyne",
+ SortAs: "CYBER",
+ Units: []c.OrgUnit{
+ {
+ Type: c.OrgUnitType,
+ Name: "Skynet",
+ SortAs: "SKY",
+ },
+ {
+ Type: c.OrgUnitType,
+ Name: "Cybernics",
+ },
+ },
+ Contexts: map[c.OrganizationContext]bool{
+ c.OrganizationContextWork: true,
+ },
+ }
+}
+
+func (e Exemplar) Pronouns() c.Pronouns {
+ return c.Pronouns{
+ Type: c.PronounsType,
+ Pronouns: "they/them",
+ Contexts: map[c.PronounsContext]bool{
+ c.PronounsContextWork: true,
+ c.PronounsContextPrivate: true,
+ },
+ Pref: 1,
+ }
+}
+
+func (e Exemplar) Title() c.Title {
+ return c.Title{
+ Type: c.TitleType,
+ Name: "Doctor",
+ Kind: c.TitleKindTitle,
+ OrganizationId: "407e1992-9a2b-4e4f-a11b-85a509a4b5ae",
+ }
+}
+
+func (e Exemplar) SpeakToAs() c.SpeakToAs {
+ return c.SpeakToAs{
+ Type: c.SpeakToAsType,
+ GrammaticalGender: c.GrammaticalGenderNeuter,
+ Pronouns: map[string]c.Pronouns{
+ "a": {
+ Type: c.PronounsType,
+ Pronouns: "they/them",
+ Contexts: map[c.PronounsContext]bool{
+ c.PronounsContextPrivate: true,
+ },
+ Pref: 1,
+ },
+ "b": {
+ Type: c.PronounsType,
+ Pronouns: "he/him",
+ Contexts: map[c.PronounsContext]bool{
+ c.PronounsContextWork: true,
+ },
+ Pref: 99,
+ },
+ },
+ }
+}
+
+func (e Exemplar) OnlineService() c.OnlineService {
+ return c.OnlineService{
+ Type: c.OnlineServiceType,
+ Service: "OPA Network",
+ Contexts: map[c.OnlineServiceContext]bool{
+ c.OnlineServiceContextWork: true,
+ },
+ Uri: "https://opa.org/cdrummer",
+ User: "cdrummer@opa.org",
+ Pref: 12,
+ Label: "opa",
+ }
+}
+
+func (e Exemplar) Phone() c.Phone {
+ return c.Phone{
+ Type: c.PhoneType,
+ Number: "+15551234567",
+ Features: map[c.PhoneFeature]bool{
+ c.PhoneFeatureText: true,
+ c.PhoneFeatureMainNumber: true,
+ c.PhoneFeatureMobile: true,
+ c.PhoneFeatureVideo: true,
+ c.PhoneFeatureVoice: true,
+ },
+ Contexts: map[c.PhoneContext]bool{
+ c.PhoneContextWork: true,
+ c.PhoneContextPrivate: true,
+ },
+ Pref: 42,
+ Label: "opa",
+ }
+}
+
+func (e Exemplar) LanguagePref() c.LanguagePref {
+ return c.LanguagePref{
+ Type: c.LanguagePrefType,
+ Language: "fr-BE",
+ Contexts: map[c.LanguagePrefContext]bool{
+ c.LanguagePrefContextPrivate: true,
+ },
+ Pref: 2,
+ }
+}
+
+func (e Exemplar) SchedulingAddress() c.SchedulingAddress {
+ return c.SchedulingAddress{
+ Type: c.SchedulingAddressType,
+ Uri: "mailto:camina@opa.org",
+ Label: "opa",
+ Contexts: map[c.SchedulingAddressContext]bool{
+ c.SchedulingAddressContextWork: true,
+ },
+ Pref: 3,
+ }
+}
+
+func (e Exemplar) AddressComponent() c.AddressComponent {
+ return c.AddressComponent{
+ Type: c.AddressComponentType,
+ Kind: c.AddressComponentKindPostcode,
+ Value: "20190",
+ }
+}
+func (e Exemplar) Address() c.Address {
+ return c.Address{
+ Type: c.AddressType,
+ Contexts: map[c.AddressContext]bool{
+ c.AddressContextDelivery: true,
+ c.AddressContextWork: true,
+ },
+ Components: []c.AddressComponent{
+ {Type: c.AddressComponentType, Kind: c.AddressComponentKindNumber, Value: "54321"},
+ {Kind: c.AddressComponentKindSeparator, Value: " "},
+ {Kind: c.AddressComponentKindName, Value: "Oak St"},
+ {Kind: c.AddressComponentKindLocality, Value: "Reston"},
+ {Kind: c.AddressComponentKindRegion, Value: "VA"},
+ {Kind: c.AddressComponentKindSeparator, Value: " "},
+ {Kind: c.AddressComponentKindPostcode, Value: "20190"},
+ {Kind: c.AddressComponentKindCountry, Value: "USA"},
+ },
+ CountryCode: "US",
+ DefaultSeparator: ", ",
+ IsOrdered: true,
+ }
+}
+
+func (e Exemplar) PartialDate() c.PartialDate {
+ return c.PartialDate{
+ Type: c.PartialDateType,
+ Year: 2025,
+ Month: 9,
+ Day: 25,
+ CalendarScale: "iso8601",
+ }
+}
+
+func (e Exemplar) Anniversary() (c.Anniversary, string, string) {
+ return c.Anniversary{
+ Type: c.AnniversaryType,
+ Kind: c.AnniversaryKindBirth,
+ Date: &c.PartialDate{
+ Type: c.PartialDateType,
+ Year: 2026,
+ Month: 3,
+ Day: 14,
+ },
+ }, "An anniversary with a PartialDate", "partialdate"
+}
+
+func (e Exemplar) OtherAnniversary() (c.Anniversary, string, string) {
+ ts, _ := time.Parse(time.RFC3339, "2025-09-25T18:26:14.094725532+02:00")
+ return c.Anniversary{
+ Type: c.AnniversaryType,
+ Kind: c.AnniversaryKindBirth,
+ Date: &c.Timestamp{
+ Type: c.TimestampType,
+ Utc: ts,
+ },
+ }, "An anniversary with a Timestamp", "timestamp"
+}
+
+func (e Exemplar) Author() c.Author {
+ return c.Author{
+ Type: c.AuthorType,
+ Name: "Camina Drummer",
+ Uri: "https://opa.org/cdrummer",
+ }
+}
+
+func (e Exemplar) Note() c.Note {
+ ts, _ := time.Parse(time.RFC3339, "2025-09-25T18:26:14.094725532+02:00")
+ a := e.Author()
+ return c.Note{
+ Type: c.NoteType,
+ Note: "this is a note",
+ Created: ts,
+ Author: &a,
+ }
+}
+
+func (e Exemplar) PersonalInfo() c.PersonalInfo {
+ return c.PersonalInfo{
+ Type: c.PersonalInfoType,
+ Kind: c.PersonalInfoKindExpertise,
+ Value: "motivation",
+ Level: c.PersonalInfoLevelHigh,
+ ListAs: 1,
+ Label: "opa",
+ }
+}
+
+func (e Exemplar) ContactCard() c.ContactCard {
+ created, _ := time.Parse(time.RFC3339, "2025-09-25T18:26:14.094725532+02:00")
+ updated, _ := time.Parse(time.RFC3339, "2025-09-26T09:58:01+02:00")
+ return c.ContactCard{
+ Type: c.ContactCardType,
+ Kind: c.ContactCardKindGroup,
+ Id: "20fba820-2f8e-432d-94f1-5abbb59d3ed7",
+ AddressBookIds: map[string]bool{
+ "79047052-ae0e-4299-8860-5bff1a139f3d": true,
+ "44eb6105-08c1-458b-895e-4ad1149dfabd": true,
+ },
+ Version: c.JSContactVersion_1_0,
+ Created: created,
+ Language: "fr-BE",
+ Members: map[string]bool{
+ "314815dd-81c8-4640-aace-6dc83121616d": true,
+ "c528b277-d8cb-45f2-b7df-1aa3df817463": true,
+ "81dea240-c0a4-4929-82e7-79e713a8bbe4": true,
+ },
+ ProdId: "OpenCloud Groupware 1.0",
+ RelatedTo: map[string]c.Relation{
+ "urn:uid:ca9d2a62-e068-43b6-a470-46506976d505": {
+ Type: c.RelationType,
+ Relation: map[c.Relationship]bool{
+ c.RelationContact: true,
+ },
+ },
+ "urn:uid:72183ec2-b218-4983-9c89-ff117eeb7c5e": {
+ Relation: map[c.Relationship]bool{
+ c.RelationEmergency: true,
+ c.RelationSpouse: true,
+ },
+ },
+ },
+ Uid: "1091f2bb-6ae6-4074-bb64-df74071d7033",
+ Updated: updated,
+ Name: &c.Name{
+ Type: c.NameType,
+ Components: []c.NameComponent{
+ {Type: c.NameComponentType, Value: "OpenCloud", Kind: c.NameComponentKindSurname},
+ {Value: " ", Kind: c.NameComponentKindSeparator},
+ {Value: "Team", Kind: c.NameComponentKindSurname2},
+ },
+ IsOrdered: true,
+ DefaultSeparator: ", ",
+ SortAs: map[string]string{
+ string(c.NameComponentKindSurname): "OpenCloud Team",
+ },
+ Full: "OpenCloud Team",
+ },
+ Nicknames: map[string]c.Nickname{
+ "a": {
+ Type: c.NicknameType,
+ Name: "The Team",
+ Contexts: map[c.NicknameContext]bool{
+ c.NicknameContextWork: true,
+ },
+ Pref: 1,
+ },
+ },
+ Organizations: map[string]c.Organization{
+ "o": {
+ Type: c.OrganizationType,
+ Name: "OpenCloud GmbH",
+ Units: []c.OrgUnit{
+ {Type: c.OrgUnitType, Name: "Marketing", SortAs: "marketing"},
+ {Type: c.OrgUnitType, Name: "Sales"},
+ {Name: "Operations", SortAs: "ops"},
+ },
+ SortAs: "opencloud",
+ Contexts: map[c.OrganizationContext]bool{
+ c.OrganizationContextWork: true,
+ },
+ },
+ },
+ SpeakToAs: &c.SpeakToAs{
+ Type: c.SpeakToAsType,
+ GrammaticalGender: c.GrammaticalGenderInanimate,
+ Pronouns: map[string]c.Pronouns{
+ "p": {
+ Type: c.PronounsType,
+ Pronouns: "it",
+ Contexts: map[c.PronounsContext]bool{
+ c.PronounsContextWork: true,
+ },
+ Pref: 1,
+ },
+ },
+ },
+ Titles: map[string]c.Title{
+ "t": {
+ Type: c.TitleType,
+ Name: "The",
+ Kind: c.TitleKindTitle,
+ OrganizationId: "o",
+ },
+ },
+ Emails: map[string]c.EmailAddress{
+ "e": {
+ Type: c.EmailAddressType,
+ Address: "info@opencloud.eu.example.com",
+ Contexts: map[c.EmailAddressContext]bool{
+ c.EmailAddressContextWork: true,
+ },
+ Pref: 1,
+ Label: "work",
+ },
+ },
+ OnlineServices: map[string]c.OnlineService{
+ "s": {
+ Type: c.OnlineServiceType,
+ Service: "The Misinformation Game",
+ Uri: "https://misinfogame.com/91886aa0-3586-4ade-b9bb-ec031464a251",
+ User: "opencloudeu",
+ Contexts: map[c.OnlineServiceContext]bool{
+ c.OnlineServiceContextWork: true,
+ },
+ Pref: 1,
+ Label: "imaginary",
+ },
+ },
+ Phones: map[string]c.Phone{
+ "p": {
+ Type: c.PhoneType,
+ Number: "+1-804-222-1111",
+ Features: map[c.PhoneFeature]bool{
+ c.PhoneFeatureVoice: true,
+ c.PhoneFeatureText: true,
+ },
+ Contexts: map[c.PhoneContext]bool{
+ c.PhoneContextWork: true,
+ },
+ Pref: 1,
+ Label: "imaginary",
+ },
+ },
+ PreferredLanguages: map[string]c.LanguagePref{
+ "wa": {
+ Type: c.LanguagePrefType,
+ Language: "wa-BE",
+ Contexts: map[c.LanguagePrefContext]bool{
+ c.LanguagePrefContextPrivate: true,
+ },
+ Pref: 1,
+ },
+ "de": {
+ Language: "de-DE",
+ Contexts: map[c.LanguagePrefContext]bool{
+ c.LanguagePrefContextWork: true,
+ },
+ Pref: 2,
+ },
+ },
+ Calendars: map[string]c.Calendar{
+ "c": {
+ Type: c.CalendarType,
+ Kind: c.CalendarKindCalendar,
+ Uri: "https://opencloud.eu/calendars/521b032b-a2b3-4540-81b9-3f6bccacaab2",
+ MediaType: "application/jscontact+json",
+ Contexts: map[c.CalendarContext]bool{
+ c.CalendarContextWork: true,
+ },
+ Pref: 1,
+ Label: "work",
+ },
+ },
+ SchedulingAddresses: map[string]c.SchedulingAddress{
+ "s": {
+ Type: c.SchedulingAddressType,
+ Uri: "mailto:scheduling@opencloud.eu.example.com",
+ Contexts: map[c.SchedulingAddressContext]bool{
+ c.SchedulingAddressContextWork: true,
+ },
+ Pref: 1,
+ Label: "work",
+ },
+ },
+ Addresses: map[string]c.Address{
+ "k26": {
+ Type: c.AddressType,
+ Components: []c.AddressComponent{
+ {Type: c.AddressComponentType, Kind: c.AddressComponentKindBlock, Value: "2-7"},
+ {Kind: c.AddressComponentKindSeparator, Value: "-"},
+ {Kind: c.AddressComponentKindNumber, Value: "2"},
+ {Kind: c.AddressComponentKindSeparator, Value: " "},
+ {Kind: c.AddressComponentKindDistrict, Value: "Marunouchi"},
+ {Kind: c.AddressComponentKindLocality, Value: "Chiyoda-ku"},
+ {Kind: c.AddressComponentKindRegion, Value: "Tokyo"},
+ {Kind: c.AddressComponentKindSeparator, Value: " "},
+ {Kind: c.AddressComponentKindPostcode, Value: "100-8994"},
+ },
+ IsOrdered: true,
+ DefaultSeparator: ", ",
+ Full: "2-7-2 Marunouchi, Chiyoda-ku, Tokyo 100-8994",
+ CountryCode: "JP",
+ Coordinates: "geo:35.6796373,139.7616907",
+ TimeZone: "JST",
+ Contexts: map[c.AddressContext]bool{
+ c.AddressContextDelivery: true,
+ c.AddressContextWork: true,
+ },
+ Pref: 2,
+ },
+ },
+ CryptoKeys: map[string]c.CryptoKey{
+ "k1": {
+ Type: c.CryptoKeyType,
+ Uri: "https://opencloud.eu.example.com/keys/d550f57c-582c-43cc-8d94-822bded9ab36",
+ MediaType: "application/pgp-keys",
+ Contexts: map[c.CryptoKeyContext]bool{
+ c.CryptoKeyContextWork: true,
+ },
+ Pref: 1,
+ Label: "keys",
+ },
+ },
+ Directories: map[string]c.Directory{
+ "d1": {
+ Type: c.DirectoryType,
+ Kind: c.DirectoryKindEntry,
+ Uri: "https://opencloud.eu.example.com/addressbook/8c2f0363-af0a-4d16-a9d5-8a9cd885d722",
+ ListAs: 1,
+ },
+ },
+ Links: map[string]c.Link{
+ "r1": {
+ Type: c.LinkType,
+ Kind: c.LinkKindContact,
+ Contexts: map[c.LinkContext]bool{
+ c.LinkContextWork: true,
+ },
+ Uri: "mailto:contact@opencloud.eu.example.com",
+ },
+ },
+ Media: map[string]c.Media{
+ "m": {
+ Type: c.MediaType,
+ Kind: c.MediaKindLogo,
+ Uri: "https://opencloud.eu.example.com/opencloud.svg",
+ MediaType: "image/svg+xml",
+ Contexts: map[c.MediaContext]bool{
+ c.MediaContextWork: true,
+ },
+ Pref: 123,
+ Label: "svg",
+ BlobId: "53feefbabeb146fcbe3e59e91462fa5f",
+ },
+ },
+ Anniversaries: map[string]c.Anniversary{
+ "birth": {
+ Type: c.AnniversaryType,
+ Kind: c.AnniversaryKindBirth,
+ Date: &c.PartialDate{
+ Type: c.PartialDateType,
+ Year: 2025,
+ Month: 9,
+ Day: 26,
+ CalendarScale: "iso8601",
+ },
+ },
+ },
+ Keywords: map[string]bool{
+ "imaginary": true,
+ "test": true,
+ },
+ Notes: map[string]c.Note{
+ "n1": {
+ Type: c.NoteType,
+ Note: "This is a note.",
+ Created: created,
+ Author: &c.Author{
+ Type: c.AuthorType,
+ Name: "Test Data",
+ Uri: "https://isbn.example.com/a461f292-6bf1-470e-b08d-f6b4b0223fe3",
+ },
+ },
+ },
+ PersonalInfo: map[string]c.PersonalInfo{
+ "p1": {
+ Type: c.PersonalInfoType,
+ Kind: c.PersonalInfoKindExpertise,
+ Value: "Clouds",
+ Level: c.PersonalInfoLevelHigh,
+ ListAs: 1,
+ Label: "experts",
+ },
+ },
+ Localizations: map[string]c.PatchObject{
+ "fr": {
+ "personalInfo": map[string]any{
+ "value": "Nuages",
+ },
+ },
+ },
+ }
+}
diff --git a/services/groupware/Makefile b/services/groupware/Makefile
index 48044459d6..017bbb32b0 100644
--- a/services/groupware/Makefile
+++ b/services/groupware/Makefile
@@ -40,7 +40,7 @@ apidoc-static: api.html
.PHONY: examples
examples:
- cd ../../pkg/jmap/ && go test -tags=groupware_examples . -v -count=1 -run Example
- cd ../../pkg/jscontact/ && go test -tags=groupware_examples . -v -count=1 -run Example
- cd ../../pkg/jscalendar/ && go test -tags=groupware_examples . -v -count=1 -run Example
- cd ./pkg/groupware/ && go test -tags=groupware_examples . -v -count=1 -run Example
+ cd ../../pkg/jmap/ && go test -tags=groupware_examples . -v -count=1 -run '^.*Example$''
+ cd ../../pkg/jscontact/ && go test -tags=groupware_examples . -v -count=1 -run '^.*Example$''
+ cd ../../pkg/jscalendar/ && go test -tags=groupware_examples . -v -count=1 -run '^.*Example$''
+ cd ./pkg/groupware/ && go test -tags=groupware_examples . -v -count=1 -run '^.*Example$''