-
Notifications
You must be signed in to change notification settings - Fork 1
added Meeting object - for review #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f3d8886
fc6b44a
36dec9b
1014dd7
d4cf43b
7bfd1c6
569b956
a8f21f3
afa7837
ffdc508
338e9c2
8370142
06b70a1
e8f205d
998a568
273f23c
aa5a61b
fd67108
fcd9ed4
9916e3d
dfb67d1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| export * from "./acp/mod.js" | ||
| export * from "./solid/mod.js" | ||
| export * from "./webid/mod.js" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import { TermMappings, ValueMappings, TermWrapper, DatasetWrapper } from "rdfjs-wrapper" | ||
| import { ICAL } from "../vocabulary/mod.js" | ||
|
|
||
| export class Meeting extends TermWrapper { | ||
| get summary(): string | undefined { | ||
| return this.singularNullable(ICAL.summary, ValueMappings.literalToString) | ||
| } | ||
|
|
||
| set summary(value: string | undefined) { | ||
| this.overwriteNullable(ICAL.summary, value, TermMappings.stringToLiteral) | ||
| } | ||
|
|
||
| get location(): string | undefined { | ||
| return this.singularNullable(ICAL.location, ValueMappings.literalToString) | ||
| } | ||
|
|
||
| set location(value: string | undefined) { | ||
| this.overwriteNullable(ICAL.location, value, TermMappings.stringToLiteral) | ||
| } | ||
|
|
||
| get comment(): string | undefined { | ||
| return this.singularNullable(ICAL.comment, ValueMappings.literalToString) | ||
| } | ||
|
|
||
| set comment(value: string | undefined) { | ||
| this.overwriteNullable(ICAL.comment, value, TermMappings.stringToLiteral) | ||
| } | ||
|
|
||
| get startDate(): Date | undefined { | ||
| return this.singularNullable(ICAL.dtstart, ValueMappings.literalToDate) | ||
| } | ||
|
|
||
| set startDate(value: Date | undefined) { | ||
| this.overwriteNullable(ICAL.dtstart, value, TermMappings.dateToLiteral) | ||
| } | ||
|
|
||
| get endDate(): Date | undefined { | ||
| return this.singularNullable(ICAL.dtend, ValueMappings.literalToDate) | ||
| } | ||
|
|
||
| set endDate(value: Date | undefined) { | ||
| this.overwriteNullable(ICAL.dtend, value, TermMappings.dateToLiteral) | ||
| } | ||
| } | ||
tgra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import { DatasetWrapper } from "rdfjs-wrapper" | ||
| import { ICAL } from "../vocabulary/mod.js" | ||
| import { Meeting } from "./Meeting.js" | ||
|
|
||
| export class MeetingDataset extends DatasetWrapper { | ||
| get meeting(): Iterable<Meeting> { | ||
| return this.instancesOf(ICAL.Vevent, Meeting) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,5 @@ | ||
| export * from "./Container.js" | ||
| export * from "./ContainerDataset.js" | ||
| export * from "./Resource.js" | ||
| export * from "./Meeting.js" | ||
| export * from "./MeetingDataset.js" |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that it would be worth considering a test pattern for mutations where
This is more robust in a way because it does not rely on ther wrappers for reading out values modified by the wrapper itself. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,229 @@ | ||
| import { DataFactory, Parser, Store } from "n3" | ||
| import assert from "node:assert" | ||
| import { describe, it } from "node:test" | ||
| import { MeetingDataset } from "@solid/object"; | ||
|
|
||
| describe("MeetingDataset / Meeting tests", () => { | ||
| const sampleRDF = ` | ||
tgra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @prefix cal: <http://www.w3.org/2002/12/cal/ical#> . | ||
| @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . | ||
|
|
||
| <https://example.org/meeting/1> a cal:Vevent ; | ||
|
|
||
| cal:summary "Team Sync" ; | ||
| cal:location "Zoom Room 123" ; | ||
| cal:comment "Discuss project updates" ; | ||
| cal:dtstart "2026-02-09T10:00:00Z"^^xsd:dateTime ; | ||
| cal:dtend "2026-02-09T11:00:00Z"^^xsd:dateTime . | ||
|
Comment on lines
+11
to
+17
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know that is what corresponds to the current shape in the pane. However, could you find a few slightly more comprehensive ical events examples so that we create a class that might be a bit more usable? I wonder if we can get at least the properties corresponding to the main fields in all well known calendar systems. See maybe RFC5545 section 4 for examples.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "get at least the properties corresponding to the main fields in all well known calendar systems" Just to confirm @matthieubosquet, you'd like to add new properties to Meeting.ts and then add corresponding test cases? The existing properties are based on the SolidOS shape for Meeting at https://github.com/solid/shape-generation-artefacts/tree/main/shapes/Meeting with ref to https://github.com/SolidOS/meeting-pane/blob/main/src/meetingDetailsForm.ttl |
||
| `; | ||
|
|
||
| it("should parse and retrieve meeting properties", () => { | ||
| const store = new Store(); | ||
| store.addQuads(new Parser().parse(sampleRDF)); | ||
|
|
||
| const dataset = new MeetingDataset(store, DataFactory); | ||
| const meetings = Array.from(dataset.meeting); | ||
|
|
||
| const meeting = meetings[0]; | ||
| assert.ok(meeting, "No meeting found") | ||
|
|
||
| // Check property types and values | ||
| assert.equal(meeting.summary, "Team Sync"); | ||
tgra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| assert.equal(meeting.location, "Zoom Room 123"); | ||
| assert.equal(meeting.comment, "Discuss project updates"); | ||
|
|
||
| assert.ok(meeting.startDate instanceof Date); | ||
tgra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| assert.ok(meeting.endDate instanceof Date); | ||
|
|
||
| assert.equal(meeting.startDate?.toISOString(), "2026-02-09T10:00:00.000Z"); | ||
| assert.equal(meeting.endDate?.toISOString(), "2026-02-09T11:00:00.000Z"); | ||
| }); | ||
|
|
||
| it("should allow setting of meeting properties", () => { | ||
tgra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const store = new Store(); | ||
| store.addQuads(new Parser().parse(sampleRDF)); | ||
|
|
||
| const dataset = new MeetingDataset(store, DataFactory); | ||
| const meetings = Array.from(dataset.meeting); | ||
|
|
||
| assert.ok(meetings.length > 0, "No meetings found"); | ||
|
|
||
| const meeting = Array.from(dataset.meeting)[0]!; | ||
|
|
||
| // Set new values | ||
| meeting.summary = "Updated Meeting"; | ||
| meeting.location = "Conference Room A"; | ||
| meeting.comment = "New agenda"; | ||
| const newStart = new Date("2026-02-09T12:00:00Z"); | ||
| const newEnd = new Date("2026-02-09T13:00:00Z"); | ||
| meeting.startDate = newStart; | ||
| meeting.endDate = newEnd; | ||
|
|
||
| // Retrieve again | ||
| assert.equal(meeting.summary, "Updated Meeting"); | ||
| assert.equal(meeting.location, "Conference Room A"); | ||
| assert.equal(meeting.comment, "New agenda"); | ||
| assert.equal(meeting.startDate.toISOString(), newStart.toISOString()); | ||
| assert.equal(meeting.endDate.toISOString(), newEnd.toISOString()); | ||
| }); | ||
|
|
||
| it("should ensure all properties are correct type", () => { | ||
tgra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const store = new Store(); | ||
| store.addQuads(new Parser().parse(sampleRDF)); | ||
|
|
||
| const dataset = new MeetingDataset(store, DataFactory); | ||
| const meeting = Array.from(dataset.meeting)[0]; | ||
|
|
||
| assert.ok(meeting, "No meeting found") | ||
|
|
||
| // Check property types | ||
| assert.equal(typeof meeting.summary, "string"); | ||
tgra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| assert.equal(typeof meeting.location, "string"); | ||
| assert.equal(typeof meeting.comment, "string"); | ||
|
|
||
| assert.ok(meeting.startDate instanceof Date, "startDate should be a Date"); | ||
| assert.ok(meeting.endDate instanceof Date, "endDate should be a Date"); | ||
| }); | ||
|
|
||
| it("should ensure all properties are unique text or date values", () => { | ||
| const duplicateRDF = ` | ||
tgra marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @prefix cal: <http://www.w3.org/2002/12/cal/ical#> . | ||
| @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . | ||
|
|
||
| <https://example.org/meeting/1> a cal:Vevent ; | ||
| cal:summary "Team Sync" ; | ||
| cal:summary "Duplicate Summary" ; | ||
| cal:location "Zoom Room 123" ; | ||
| cal:location "Duplicate Location" ; | ||
| cal:comment "Discuss project updates" ; | ||
| cal:comment "Duplicate Comment" ; | ||
| cal:dtstart "2026-02-09T10:00:00Z"^^xsd:dateTime ; | ||
| cal:dtstart "2026-02-09T09:00:00Z"^^xsd:dateTime ; | ||
| cal:dtend "2026-02-09T11:00:00Z"^^xsd:dateTime ; | ||
| cal:dtend "2026-02-09T12:00:00Z"^^xsd:dateTime . | ||
| `; | ||
|
|
||
| const store = new Store(); | ||
| store.addQuads(new Parser().parse(duplicateRDF)); | ||
|
|
||
| const dataset = new MeetingDataset(store, DataFactory); | ||
| const meeting = Array.from(dataset.meeting)[0]; | ||
|
|
||
| assert.ok(meeting, "No meeting found"); | ||
|
|
||
| // Ensure exposed values are single (unique) and correct type | ||
| assert.equal(typeof meeting.summary, "string"); | ||
| assert.equal(typeof meeting.location, "string"); | ||
| assert.equal(typeof meeting.comment, "string"); | ||
|
|
||
| assert.ok(meeting.startDate instanceof Date); | ||
| assert.ok(meeting.endDate instanceof Date); | ||
|
|
||
| // Ensure no arrays are returned | ||
| assert.ok(!Array.isArray(meeting.summary)); | ||
| assert.ok(!Array.isArray(meeting.location)); | ||
| assert.ok(!Array.isArray(meeting.comment)); | ||
| assert.ok(!Array.isArray(meeting.startDate)); | ||
| assert.ok(!Array.isArray(meeting.endDate)); | ||
| }); | ||
|
|
||
|
|
||
|
|
||
| // RFC 5545 requires DTSTART and UID - test the required date behaviour | ||
|
|
||
| it("should parse a minimal RFC5545-style VEVENT", () => { | ||
| const minimalRDF = ` | ||
| @prefix cal: <http://www.w3.org/2002/12/cal/ical#> . | ||
| @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . | ||
|
|
||
| <https://example.org/meeting/minimal> | ||
| a cal:Vevent ; | ||
| cal:dtstart "2026-06-01T09:00:00Z"^^xsd:dateTime . | ||
| `; | ||
|
|
||
| const store = new Store(); | ||
| store.addQuads(new Parser().parse(minimalRDF)); | ||
|
|
||
| const dataset = new MeetingDataset(store, DataFactory); | ||
| const meeting = Array.from(dataset.meeting)[0]; | ||
|
|
||
| assert.ok(meeting); | ||
| assert.ok(meeting.startDate instanceof Date); | ||
| assert.equal(meeting.startDate?.toISOString(), "2026-06-01T09:00:00.000Z"); | ||
|
|
||
| // Optional fields should be undefined | ||
| assert.equal(meeting.summary, undefined); | ||
| assert.equal(meeting.location, undefined); | ||
| assert.equal(meeting.comment, undefined); | ||
| assert.equal(meeting.endDate, undefined); | ||
| }); | ||
|
|
||
|
|
||
| // With ref to common VEVENT examples in RFC 5545 3.6.1. | ||
|
|
||
| it("should parse an RFC-style VEVENT with summary, description, and location", () => { | ||
| const rfcStyleRDF = ` | ||
| @prefix cal: <http://www.w3.org/2002/12/cal/ical#> . | ||
| @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . | ||
|
|
||
| <https://example.org/meeting/rfc1> | ||
| a cal:Vevent ; | ||
| cal:summary "Meeting" ; | ||
| cal:comment "Discuss events" ; | ||
| cal:location "Conference Room 1" ; | ||
| cal:dtstart "2026-07-10T13:00:00Z"^^xsd:dateTime ; | ||
| cal:dtend "2026-07-10T15:30:00Z"^^xsd:dateTime . | ||
| `; | ||
|
|
||
| const store = new Store(); | ||
| store.addQuads(new Parser().parse(rfcStyleRDF)); | ||
|
|
||
| const dataset = new MeetingDataset(store, DataFactory); | ||
| const meeting = Array.from(dataset.meeting)[0]; | ||
|
|
||
| assert.ok(meeting); | ||
|
|
||
| assert.equal(meeting.summary, "Meeting"); | ||
| assert.equal(meeting.comment, "Discuss events"); | ||
| assert.equal(meeting.location, "Conference Room 1"); | ||
|
|
||
| assert.equal(meeting.startDate?.toISOString(), "2026-07-10T13:00:00.000Z"); | ||
| assert.equal(meeting.endDate?.toISOString(), "2026-07-10T15:30:00.000Z"); | ||
| }); | ||
|
|
||
|
|
||
| // RFC 5545 allows DATE values for all-day events. This tests literalToDate handling. | ||
|
|
||
| it("should parse an all-day RFC-style event (DATE value)", () => { | ||
| const allDayRDF = ` | ||
| @prefix cal: <http://www.w3.org/2002/12/cal/ical#> . | ||
| @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . | ||
|
|
||
| <https://example.org/meeting/allday> | ||
| a cal:Vevent ; | ||
| cal:summary "Company Holiday" ; | ||
| cal:dtstart "2026-12-25"^^xsd:date ; | ||
| cal:dtend "2026-12-26"^^xsd:date . | ||
| `; | ||
|
|
||
| const store = new Store(); | ||
| store.addQuads(new Parser().parse(allDayRDF)); | ||
|
|
||
| const dataset = new MeetingDataset(store, DataFactory); | ||
| const meeting = Array.from(dataset.meeting)[0]; | ||
|
|
||
| assert.ok(meeting); | ||
| assert.ok(meeting.startDate instanceof Date); | ||
| assert.ok(meeting.endDate instanceof Date); | ||
|
|
||
| // Ensure correct calendar date | ||
| assert.equal(meeting.startDate?.getUTCFullYear(), 2026); | ||
| assert.equal(meeting.startDate?.getUTCMonth(), 11); // December (0-based) | ||
| assert.equal(meeting.startDate?.getUTCDate(), 25); | ||
| }); | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
| }); | ||
Uh oh!
There was an error while loading. Please reload this page.