diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarDateSlotEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarDateSlotEvent.kt index feed13b6b..2bd1eb054 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarDateSlotEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarDateSlotEvent.kt @@ -23,10 +23,22 @@ package com.vitorpamplona.quartz.nip52Calendar import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.core.firstTagValue -import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip31Alts.AltTag +import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag +import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHashTag +import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags +import com.vitorpamplona.quartz.nip01Core.tags.people.PTag +import com.vitorpamplona.quartz.nip01Core.tags.references.references +import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag +import com.vitorpamplona.quartz.nip23LongContent.tags.SummaryTag +import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag +import com.vitorpamplona.quartz.nip31Alts.alt +import com.vitorpamplona.quartz.nip52Calendar.tags.LocationTag import com.vitorpamplona.quartz.utils.TimeUtils +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class CalendarDateSlotEvent( @@ -37,25 +49,48 @@ class CalendarDateSlotEvent( content: String, sig: HexKey, ) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - fun location() = tags.firstTagValue("location") + fun title() = tags.firstNotNullOfOrNull(TitleTag::parse) + + fun location() = tags.firstNotNullOfOrNull(LocationTag::parse) + + fun locations() = tags.mapNotNull(LocationTag::parse) fun start() = tags.firstTagValue("start") fun end() = tags.firstTagValue("end") - // ["start", ""], - // ["end", ""], + fun summary() = tags.firstNotNullOfOrNull(SummaryTag::parse) + + fun image() = tags.firstNotNullOfOrNull(ImageTag::parse) + + fun geohash() = tags.firstNotNullOfOrNull(GeoHashTag::parse) + + fun hashtags() = tags.hashtags() + + fun participants() = tags.mapNotNull(PTag::parse) + + fun references() = tags.references() companion object { const val KIND = 31922 const val ALT = "Full-day calendar event" - suspend fun create( - signer: NostrSigner, + @OptIn(ExperimentalUuidApi::class) + fun build( + title: String, + start: String, + content: String = "", + end: String? = null, + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), - ): CalendarDateSlotEvent { - val tags = arrayOf(AltTag.assemble(ALT)) - return signer.sign(createdAt, KIND, tags, "") + initializer: TagArrayBuilder.() -> Unit = {}, + ) = eventTemplate(KIND, content, createdAt) { + dTag(dTag) + title(title) + startDate(start) + end?.let { endDate(it) } + alt(ALT) + initializer() } } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarEvent.kt index ba3bbe717..d14d87ac9 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarEvent.kt @@ -23,9 +23,15 @@ package com.vitorpamplona.quartz.nip52Calendar import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip31Alts.AltTag +import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder +import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate +import com.vitorpamplona.quartz.nip01Core.tags.aTag.taggedAddresses +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag +import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag +import com.vitorpamplona.quartz.nip31Alts.alt import com.vitorpamplona.quartz.utils.TimeUtils +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class CalendarEvent( @@ -36,16 +42,26 @@ class CalendarEvent( content: String, sig: HexKey, ) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { + fun title() = tags.firstNotNullOfOrNull(TitleTag::parse) + + fun calendarEventAddresses() = taggedAddresses() + companion object { const val KIND = 31924 const val ALT = "Calendar" - suspend fun create( - signer: NostrSigner, + @OptIn(ExperimentalUuidApi::class) + fun build( + title: String, + content: String = "", + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), - ): CalendarEvent { - val tags = arrayOf(AltTag.assemble(ALT)) - return signer.sign(createdAt, KIND, tags, "") + initializer: TagArrayBuilder.() -> Unit = {}, + ) = eventTemplate(KIND, content, createdAt) { + dTag(dTag) + title(title) + alt(ALT) + initializer() } } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarRSVPEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarRSVPEvent.kt index fa2482e83..2baf8c53d 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarRSVPEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarRSVPEvent.kt @@ -23,10 +23,21 @@ package com.vitorpamplona.quartz.nip52Calendar import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey -import com.vitorpamplona.quartz.nip01Core.core.firstTagValue -import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip31Alts.AltTag +import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder +import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate +import com.vitorpamplona.quartz.nip01Core.tags.aTag.ATag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.aTag +import com.vitorpamplona.quartz.nip01Core.tags.aTag.firstTaggedAddress +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag +import com.vitorpamplona.quartz.nip01Core.tags.events.ETag +import com.vitorpamplona.quartz.nip01Core.tags.events.firstTaggedEvent +import com.vitorpamplona.quartz.nip01Core.tags.people.PTag +import com.vitorpamplona.quartz.nip31Alts.alt +import com.vitorpamplona.quartz.nip52Calendar.tags.FreeBusyTag +import com.vitorpamplona.quartz.nip52Calendar.tags.RSVPStatusTag import com.vitorpamplona.quartz.utils.TimeUtils +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class CalendarRSVPEvent( @@ -37,27 +48,42 @@ class CalendarRSVPEvent( content: String, sig: HexKey, ) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - fun location() = tags.firstTagValue("location") + fun status() = tags.firstNotNullOfOrNull(RSVPStatusTag::parse) - fun start() = tags.firstTagValue("start") + fun statusValue() = tags.firstNotNullOfOrNull(RSVPStatusTag::parseValue) - fun end() = tags.firstTagValue("end") + fun freebusy() = tags.firstNotNullOfOrNull(FreeBusyTag::parse) - // ["L", "status"], - // ["l", "", "status"], - // ["L", "freebusy"], - // ["l", "", "freebusy"] + fun calendarEventAddress() = firstTaggedAddress() + + fun calendarEventId() = firstTaggedEvent() + + fun calendarEventAuthor() = tags.firstNotNullOfOrNull(PTag::parse) companion object { const val KIND = 31925 const val ALT = "Calendar event's invitation response" - suspend fun create( - signer: NostrSigner, + @OptIn(ExperimentalUuidApi::class) + fun build( + calendarEventAddress: ATag, + status: RSVPStatusTag.STATUS, + content: String = "", + calendarEventId: ETag? = null, + calendarEventAuthor: PTag? = null, + freebusy: FreeBusyTag.STATUS? = null, + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), - ): CalendarRSVPEvent { - val tags = arrayOf(AltTag.assemble(ALT)) - return signer.sign(createdAt, KIND, tags, "") + initializer: TagArrayBuilder.() -> Unit = {}, + ) = eventTemplate(KIND, content, createdAt) { + dTag(dTag) + aTag(calendarEventAddress) + status(status) + calendarEventId?.let { add(it.toTagArray()) } + calendarEventAuthor?.let { add(it.toTagArray()) } + freebusy?.let { freebusy(it) } + alt(ALT) + initializer() } } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarTimeSlotEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarTimeSlotEvent.kt index cebe4d70e..a6898ae28 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarTimeSlotEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/CalendarTimeSlotEvent.kt @@ -23,11 +23,23 @@ package com.vitorpamplona.quartz.nip52Calendar import androidx.compose.runtime.Immutable import com.vitorpamplona.quartz.nip01Core.core.BaseAddressableEvent import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.core.firstTagValue import com.vitorpamplona.quartz.nip01Core.core.firstTagValueAsLong -import com.vitorpamplona.quartz.nip01Core.signers.NostrSigner -import com.vitorpamplona.quartz.nip31Alts.AltTag +import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate +import com.vitorpamplona.quartz.nip01Core.tags.dTag.dTag +import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHashTag +import com.vitorpamplona.quartz.nip01Core.tags.hashtags.hashtags +import com.vitorpamplona.quartz.nip01Core.tags.people.PTag +import com.vitorpamplona.quartz.nip01Core.tags.references.references +import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag +import com.vitorpamplona.quartz.nip23LongContent.tags.SummaryTag +import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag +import com.vitorpamplona.quartz.nip31Alts.alt +import com.vitorpamplona.quartz.nip52Calendar.tags.LocationTag import com.vitorpamplona.quartz.utils.TimeUtils +import kotlin.uuid.ExperimentalUuidApi +import kotlin.uuid.Uuid @Immutable class CalendarTimeSlotEvent( @@ -38,31 +50,56 @@ class CalendarTimeSlotEvent( content: String, sig: HexKey, ) : BaseAddressableEvent(id, pubKey, createdAt, KIND, tags, content, sig) { - fun location() = tags.firstTagValue("location") + fun title() = tags.firstNotNullOfOrNull(TitleTag::parse) + + fun location() = tags.firstNotNullOfOrNull(LocationTag::parse) + + fun locations() = tags.mapNotNull(LocationTag::parse) fun start() = tags.firstTagValueAsLong("start") fun end() = tags.firstTagValueAsLong("end") - fun startTmz() = tags.firstTagValueAsLong("start_tzid") + fun startTzId() = tags.firstTagValue("start_tzid") - fun endTmz() = tags.firstTagValueAsLong("end_tzid") + fun endTzId() = tags.firstTagValue("end_tzid") - // ["start", ""], - // ["end", ""], - // ["start_tzid", ""], - // ["end_tzid", ""], + fun summary() = tags.firstNotNullOfOrNull(SummaryTag::parse) + + fun image() = tags.firstNotNullOfOrNull(ImageTag::parse) + + fun geohash() = tags.firstNotNullOfOrNull(GeoHashTag::parse) + + fun hashtags() = tags.hashtags() + + fun participants() = tags.mapNotNull(PTag::parse) + + fun references() = tags.references() companion object { const val KIND = 31923 const val ALT = "Calendar time-slot event" - suspend fun create( - signer: NostrSigner, + @OptIn(ExperimentalUuidApi::class) + fun build( + title: String, + start: Long, + content: String = "", + end: Long? = null, + startTzId: String? = null, + endTzId: String? = null, + dTag: String = Uuid.random().toString(), createdAt: Long = TimeUtils.now(), - ): CalendarTimeSlotEvent { - val tags = arrayOf(AltTag.assemble(ALT)) - return signer.sign(createdAt, KIND, tags, "") + initializer: TagArrayBuilder.() -> Unit = {}, + ) = eventTemplate(KIND, content, createdAt) { + dTag(dTag) + title(title) + startTimestamp(start) + end?.let { endTimestamp(it) } + startTzId?.let { startTzId(it) } + endTzId?.let { endTzId(it) } + alt(ALT) + initializer() } } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/TagArrayBuilderExt.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/TagArrayBuilderExt.kt new file mode 100644 index 000000000..c23ef6813 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/TagArrayBuilderExt.kt @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip52Calendar + +import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder +import com.vitorpamplona.quartz.nip01Core.tags.geohash.GeoHashTag +import com.vitorpamplona.quartz.nip01Core.tags.people.PTag +import com.vitorpamplona.quartz.nip23LongContent.tags.ImageTag +import com.vitorpamplona.quartz.nip23LongContent.tags.SummaryTag +import com.vitorpamplona.quartz.nip23LongContent.tags.TitleTag +import com.vitorpamplona.quartz.nip52Calendar.tags.FreeBusyTag +import com.vitorpamplona.quartz.nip52Calendar.tags.LocationTag +import com.vitorpamplona.quartz.nip52Calendar.tags.RSVPStatusTag + +// CalendarDateSlotEvent builder extensions + +fun TagArrayBuilder.title(title: String) = addUnique(TitleTag.assemble(title)) + +fun TagArrayBuilder.startDate(date: String) = addUnique(arrayOf("start", date)) + +fun TagArrayBuilder.endDate(date: String) = addUnique(arrayOf("end", date)) + +fun TagArrayBuilder.location(location: String) = add(LocationTag.assemble(location)) + +fun TagArrayBuilder.locations(locations: List) = addAll(locations.map { LocationTag.assemble(it) }) + +fun TagArrayBuilder.summary(summary: String) = addUnique(SummaryTag.assemble(summary)) + +fun TagArrayBuilder.image(imageUrl: String) = addUnique(ImageTag.assemble(imageUrl)) + +fun TagArrayBuilder.geohash(geohash: String) = addAll(GeoHashTag.assemble(geohash).toList()) + +fun TagArrayBuilder.participant(p: PTag) = add(p.toTagArray()) + +fun TagArrayBuilder.participants(ps: List) = addAll(ps.map { it.toTagArray() }) + +// CalendarTimeSlotEvent builder extensions + +fun TagArrayBuilder.title(title: String) = addUnique(TitleTag.assemble(title)) + +fun TagArrayBuilder.startTimestamp(timestamp: Long) = addUnique(arrayOf("start", timestamp.toString())) + +fun TagArrayBuilder.endTimestamp(timestamp: Long) = addUnique(arrayOf("end", timestamp.toString())) + +fun TagArrayBuilder.startTzId(tzId: String) = addUnique(arrayOf("start_tzid", tzId)) + +fun TagArrayBuilder.endTzId(tzId: String) = addUnique(arrayOf("end_tzid", tzId)) + +fun TagArrayBuilder.location(location: String) = add(LocationTag.assemble(location)) + +fun TagArrayBuilder.locations(locations: List) = addAll(locations.map { LocationTag.assemble(it) }) + +fun TagArrayBuilder.summary(summary: String) = addUnique(SummaryTag.assemble(summary)) + +fun TagArrayBuilder.image(imageUrl: String) = addUnique(ImageTag.assemble(imageUrl)) + +fun TagArrayBuilder.geohash(geohash: String) = addAll(GeoHashTag.assemble(geohash).toList()) + +fun TagArrayBuilder.participant(p: PTag) = add(p.toTagArray()) + +fun TagArrayBuilder.participants(ps: List) = addAll(ps.map { it.toTagArray() }) + +// CalendarEvent builder extensions + +fun TagArrayBuilder.title(title: String) = addUnique(TitleTag.assemble(title)) + +// CalendarRSVPEvent builder extensions + +fun TagArrayBuilder.status(status: RSVPStatusTag.STATUS) = addUnique(status.toTagArray()) + +fun TagArrayBuilder.freebusy(fb: FreeBusyTag.STATUS) = addUnique(fb.toTagArray()) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/tags/FreeBusyTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/tags/FreeBusyTag.kt new file mode 100644 index 000000000..7e6bf0dbc --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/tags/FreeBusyTag.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip52Calendar.tags + +import com.vitorpamplona.quartz.nip01Core.core.has +import com.vitorpamplona.quartz.utils.ensure + +class FreeBusyTag { + companion object { + const val TAG_NAME = "fb" + + fun parse(tag: Array): STATUS? { + ensure(tag.has(1)) { return null } + ensure(tag[0] == TAG_NAME) { return null } + ensure(tag[1].isNotEmpty()) { return null } + return STATUS.entries.firstOrNull { it.value == tag[1] } + } + } + + enum class STATUS( + val value: String, + ) { + FREE("free"), + BUSY("busy"), + ; + + fun toTagArray() = arrayOf(TAG_NAME, value) + } +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/tags/LocationTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/tags/LocationTag.kt new file mode 100644 index 000000000..987884778 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/tags/LocationTag.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip52Calendar.tags + +import com.vitorpamplona.quartz.nip01Core.core.has +import com.vitorpamplona.quartz.utils.ensure + +class LocationTag { + companion object { + const val TAG_NAME = "location" + + fun parse(tag: Array): String? { + ensure(tag.has(1)) { return null } + ensure(tag[0] == TAG_NAME) { return null } + ensure(tag[1].isNotEmpty()) { return null } + return tag[1] + } + + fun assemble(locationName: String) = arrayOf(TAG_NAME, locationName) + } +} diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/tags/RSVPStatusTag.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/tags/RSVPStatusTag.kt new file mode 100644 index 000000000..8827910f2 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip52Calendar/tags/RSVPStatusTag.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nip52Calendar.tags + +import com.vitorpamplona.quartz.nip01Core.core.has +import com.vitorpamplona.quartz.utils.ensure + +class RSVPStatusTag { + companion object { + const val TAG_NAME = "status" + + fun parse(tag: Array): STATUS? { + ensure(tag.has(1)) { return null } + ensure(tag[0] == TAG_NAME) { return null } + ensure(tag[1].isNotEmpty()) { return null } + return STATUS.entries.firstOrNull { it.value == tag[1] } + } + + fun parseValue(tag: Array): String? { + ensure(tag.has(1)) { return null } + ensure(tag[0] == TAG_NAME) { return null } + ensure(tag[1].isNotEmpty()) { return null } + return tag[1] + } + } + + enum class STATUS( + val value: String, + ) { + ACCEPTED("accepted"), + DECLINED("declined"), + TENTATIVE("tentative"), + ; + + fun toTagArray() = arrayOf(TAG_NAME, value) + } +}