groupware: some fixes accordingly to the latest JMAP and jscalendarbis RFCs

This commit is contained in:
Pascal Bleser
2025-11-04 21:48:49 +01:00
parent 188fa0fb6f
commit 78f03f7d82
4 changed files with 21 additions and 98 deletions

View File

@@ -17,6 +17,7 @@ type LocalDateTime struct {
}
*/
type LocalDateTime string
type UTCDateTime string
type TypeOfRelation string
type TypeOfLink string
@@ -41,7 +42,6 @@ type Relationship string
type Display string
type Rel string
type LocationTypeOption string
type LocationRelation string
type VirtualLocationFeature string
type Frequency string
type Skip string
@@ -301,9 +301,6 @@ const (
LocationTypeOptionWaterFacility = LocationTypeOption("water-facility")
LocationTypeOptionYouthCamp = LocationTypeOption("youth-camp")
LocationRelationStart = LocationRelation("start")
LocationRelationEnd = LocationRelation("end")
VirtualLocationFeatureAudio = VirtualLocationFeature("audio")
VirtualLocationFeatureChat = VirtualLocationFeature("chat")
VirtualLocationFeatureFeed = VirtualLocationFeature("feed")
@@ -611,11 +608,6 @@ var (
LocationTypeOptionYouthCamp,
}
LocationRelations = []LocationRelation{
LocationRelationStart,
LocationRelationEnd,
}
Frequencies = []Frequency{
FrequencyYearly,
FrequencyMonthly,
@@ -645,7 +637,6 @@ var (
"relatedTo",
"replyTo",
"sentBy",
"timeZones",
"uid",
}
@@ -836,13 +827,6 @@ type Link struct {
// server to avoid embedding arbitrarily large data in JSCalendar object instances.
Href string `json:"href"`
// This MUST be a valid content-id value according to the definition of Section 2 of [RFC2392].
//
// The value MUST be unique within this `Link` object but has no meaning beyond that.
//
// It MAY be different from the link id for this `Link` object.
Cid string `json:"cid,omitempty"`
// This is the media type [RFC6838] of the resource, if known.
ContentType string `json:"contentType,omitempty"`
@@ -897,21 +881,6 @@ type Location struct {
// The value for each key in the map MUST be `true`.
LocationTypes map[LocationTypeOption]bool `json:"locationTypes,omitempty"`
// This specifies the relation between this location and the time of the JSCalendar object.
//
// This is primarily to allow events representing travel to specify the location of departure (at the
// start of the event) and location of arrival (at the end); this is particularly important if these
// locations are in different time zones, as a client may wish to highlight this information for the user.
//
// This MUST be one of the following values; any value the client or server doesn't understand
// should be treated the same as if this property is omitted:
// !- `start`: The event/task described by this JSCalendar object occurs at this location at the time the event/task starts.
// !- `end`: The event/task described by this JSCalendar object occurs at this location at the time the event/task ends.
RelativeTo LocationRelation `json:"relativeTo,omitempty"`
// This is a time zone for this location.
TimeZone string `json:"timeZone,omitempty"`
// This is a geo: URI [RFC5870] for the location.
Coordinates string `json:"coordinates,omitempty"`
@@ -1645,15 +1614,11 @@ type CommonObject struct {
ProdId string `json:"prodId,omitempty"`
// This is the date and time this object was initially created.
//
// TODO serialize as UTCDateTime
Created time.Time `json:"created,omitzero"`
Created UTCDateTime `json:"created,omitzero"`
// This is the date and time the data in this object was last modified (or its creation date/time
// if not modified since).
//
// TODO serialize as UTCDateTime
Updated time.Time `json:"updated,omitzero"`
Updated UTCDateTime `json:"updated,omitzero"`
// This is a short summary of the object.
Title string `json:"title,omitempty"`
@@ -1719,35 +1684,6 @@ type CommonObject struct {
// [Section 4.3 of CSS Color Module Level 3]: https://www.w3.org/TR/css-color-3/#svg-color
// [Section 4.2.1 of CSS Color Module Level 3]: https://www.w3.org/TR/css-color-3/#rgb-color
Color string `json:"color,omitempty"`
// This maps identifiers of custom time zones to their time zone definitions.
//
// The following restrictions apply for each key in the map:
// !- To avoid conflict with names in the IANA Time Zone Database [TZDB], it MUST start with the `/` character.
// !- It MUST be a valid `paramtext` value, as specified in Section 3.1 of [RFC5545].
// !- At least one other property in the same JSCalendar object MUST reference a time zone using this identifier (i.e.,
// orphaned time zones are not allowed).
//
// An identifier need only be unique to this JSCalendar object.
//
// It MAY differ from the tzId property value of the TimeZone object it maps to.
//
// A JSCalendar object may be part of a hierarchy of other JSCalendar objects (say, an `Event` is an entry in a `Group`).
//
// In this case, the set of time zones is the sum of the time zone definitions of this object and its parent objects.
//
// If multiple time zones with the same identifier exist, then the definition closest to the calendar object in relation
// to its parents MUST be used.
//
// (In context of `Event`, a time zone definition in its `timeZones` property has precedence over a definition of the
// same id in the `Group`).
//
// Time zone definitions in any children of the calendar object MUST be ignored.
//
// A `TimeZone` object maps a `VTIMEZONE` component from iCalendar, and the semantics are as defined in [RFC5545].
//
// A valid time zone MUST define at least one transition rule in the `standard` or `daylight` property.
TimeZones map[string]TimeZone `json:"timeZones,omitempty"`
}
// TODO
@@ -2128,6 +2064,14 @@ type Event struct {
// the `Event`'s Location objects (see Section 4.2.5).
Duration Duration `json:"duration,omitempty"`
// This identifies the time zone in which this event ends, for cases where the start and time zones of the event differ
// (e.g., a transcontinental flight).
//
// If this property is not set, then the event starts and ends in the same time zone.
//
// This property MUST NOT be set if the timeZone property value is null or not set.
EndTimeZone string `json:"endTimeZone,omitempty"`
// This is the scheduling status (Section 4.4) of an Event.
//
// If set, it MUST be one of the following values, another value registered in the IANA

View File

@@ -74,7 +74,6 @@ func TestLink(t *testing.T) {
}`, Link{
Type: LinkType,
Href: "https://opencloud.eu.example.com/f72ae875-40be-48a4-84ff-aea9aed3e085.png",
Cid: "c1",
ContentType: "image/png",
Size: 128912,
Rel: RelIcon,
@@ -115,14 +114,11 @@ func TestLocation(t *testing.T) {
LocationTypeOptionLandmarkAddress: true,
LocationTypeOptionIndustrial: true,
},
RelativeTo: LocationRelationStart,
TimeZone: "Europe/Paris",
Coordinates: "geo:48.8559324,2.2932441",
Links: map[string]Link{
"l1": {
Type: LinkType,
Href: "https://upload.wikimedia.org/wikipedia/commons/f/fd/Eiffel_blue.PNG",
Cid: "cl1",
ContentType: "image/png",
Size: 12345,
Rel: RelIcon,
@@ -340,7 +336,6 @@ func TestParticipant(t *testing.T) {
"l1": {
Type: LinkType,
Href: "https://opa.org/opa.png",
Cid: "c1",
ContentType: "image/png",
Size: 182912,
Rel: RelIcon,
@@ -608,11 +603,13 @@ func TestTimeZone(t *testing.T) {
}
func TestEvent(t *testing.T) {
ts1, err := time.Parse(time.RFC3339, "2025-09-25T18:26:14+02:00")
local1 := "2025-09-25T18:26:14"
ts1, err := time.Parse(time.RFC3339, local1+"+02:00")
require.NoError(t, err)
ts1 = ts1.UTC()
ts2, err := time.Parse(time.RFC3339, "2025-09-29T15:53:01+02:00")
local2 := "2025-09-29T15:53:01"
ts2, err := time.Parse(time.RFC3339, local2+"+02:00")
require.NoError(t, err)
ts2 = ts2.UTC()
@@ -692,8 +689,8 @@ func TestEvent(t *testing.T) {
CommonObject: CommonObject{
Uid: "b422cfec-f7b4-4e04-8ec6-b794007f63f1",
ProdId: "OpenCloud 1.0",
Created: ts1,
Updated: ts2,
Created: UTCDateTime(local1),
Updated: UTCDateTime(local2),
Title: "End of year party",
Description: "It's the party at the end of the year.",
DescriptionContentType: "text/plain",
@@ -713,12 +710,6 @@ func TestEvent(t *testing.T) {
"cat": true,
},
Color: "oil",
TimeZones: map[string]TimeZone{
"cest": {
Type: TimeZoneType,
TzId: "cest",
},
},
},
RelatedTo: map[string]Relation{
"a": {
@@ -738,8 +729,6 @@ func TestEvent(t *testing.T) {
LocationTypes: map[LocationTypeOption]bool{
LocationTypeOptionBar: true,
},
RelativeTo: LocationRelationStart,
TimeZone: "cest",
Coordinates: "geo:16.7685657,-4.8629852",
Links: map[string]Link{
"l1": {

View File

@@ -80,8 +80,8 @@ var E1 = jmap.CalendarEvent{
CommonObject: jscalendar.CommonObject{
Uid: "9a7ab91a-edca-4988-886f-25e00743430d",
ProdId: "Mock 0.0",
Created: mustParseTime("2025-09-29T16:17:18Z"),
Updated: mustParseTime("2025-09-29T16:17:18Z"),
Created: "2025-09-29T16:17:18",
Updated: "2025-09-29T16:17:18",
Title: "Meeting of the Minds",
Description: "Internal meeting about the grand strategy for the future",
DescriptionContentType: "text/plain",
@@ -103,12 +103,6 @@ var E1 = jmap.CalendarEvent{
"internal": true,
},
Color: "purple",
TimeZones: map[string]jscalendar.TimeZone{
"airee8ai": {
Type: jscalendar.TimeZoneType,
TzId: "CEST",
},
},
},
RelatedTo: map[string]jscalendar.Relation{},
Sequence: 0,
@@ -121,8 +115,6 @@ var E1 = jmap.CalendarEvent{
LocationTypes: map[jscalendar.LocationTypeOption]bool{
jscalendar.LocationTypeOptionOffice: true,
},
RelativeTo: jscalendar.LocationRelationStart,
TimeZone: "CEST",
Coordinates: "geo:52.5334956,13.4079872",
Links: map[string]jscalendar.Link{
"eefe2pax": {

View File

@@ -82,8 +82,8 @@ var T1 = jmap.Task{
CommonObject: jscalendar.CommonObject{
Uid: "7da0d4a2-385c-430f-9022-61db302734d9",
ProdId: "Mock 0.0",
Created: mustParseTime("2025-10-01T17:31:49Z"),
Updated: mustParseTime("2025-10-01T17:35:12Z"),
Created: "2025-10-01T17:31:49",
Updated: "2025-10-01T17:35:12",
Title: "Crossing the Ring",
Description: "We need to cross the Ring the protomolecule opened.",
DescriptionContentType: "text/plain",
@@ -117,8 +117,6 @@ var T1 = jmap.Task{
LocationTypes: map[jscalendar.LocationTypeOption]bool{
jscalendar.LocationTypeOptionLandmarkAddress: true,
},
RelativeTo: jscalendar.LocationRelationStart,
TimeZone: "UTC",
Coordinates: "geo:40.4165583,-3.7063595",
Links: map[string]jscalendar.Link{
"jeeshei5": {