@prefix this: . @prefix sub: . @prefix np: . @prefix grlc: . @prefix dct: . @prefix nt: . @prefix npx: . @prefix xsd: . @prefix rdfs: . @prefix orcid: . @prefix prov: . @prefix foaf: . sub:Head { this: a np:Nanopublication; np:hasAssertion sub:assertion; np:hasProvenance sub:provenance; np:hasPublicationInfo sub:pubinfo . } sub:assertion { sub:get-event-participation-actions a grlc:grlc-query; dct:description "Backs a call-to-action panel on an event Space, inviting the visitor to declare how they take part. Returns one row per way in that is still open to this particular viewer: taking part (planned attendance before the event's start date, actual participation from the start date onwards) and observing. Observing is offered only to a viewer who has declared neither attendance nor participation - somebody who is coming is not also an observer. A row is returned only when the space actually offers that way in - that is, when a role carrying the corresponding property is attached to the space - and only when the viewer has not already declared it, read from the viewer's validated role instantiations via the CURRENTUSER session parameter. A logged-out visitor has no role instantiations, so they are offered everything the space offers. When nothing is left to offer, a single row with empty content is returned instead of no rows at all, so the panel renders blank rather than showing \"(nothing found)\". The content column holds ready-made root-relative /publish links with template-version=latest, which Nanodash renders as buttons; no title column is returned, so the rows carry no headings of their own and the panel's own title does the labelling."; dct:license ; rdfs:label "Get the ways in still open to the viewer of an event"; grlc:endpoint ; grlc:sparql """prefix rdfs: prefix np: prefix npa: prefix npx: prefix gen: prefix wd: prefix xsd: select ?content where { values ?_space_multi_iri {} values ?__CURRENTUSER_multi_iri {} graph npa:graph { npa:thisRepo npa:hasCurrentSpaceState ?state . } # Has the event started? Read the start date off the space's current definition. optional { graph npa:graph { ?defNp npa:hasValidSignatureForPublicKeyHash ?defKey ; np:hasAssertion ?defA ; npx:introduces ?_space_multi_iri . filter not exists { ?defInv npx:invalidates ?defNp ; npa:hasValidSignatureForPublicKeyHash ?defKey . } filter not exists { ?defNewer npx:supersedes ?defNp . } } graph ?defA { ?_space_multi_iri ?startRaw . } } bind(coalesce(?startRaw, '9999-12-31T00:00:00Z'^^xsd:dateTime) as ?start) bind(now() >= ?start as ?started) # Which of the three ways in does this space actually offer? A role only takes # effect once it is attached to the space, so an unattached one is not offered. bind(exists { graph npa:graph { ?an1 npa:hasValidSignatureForPublicKeyHash ?ak1 ; np:hasAssertion ?aa1 . filter not exists { ?ai1 npx:invalidates ?an1 ; npa:hasValidSignatureForPublicKeyHash ?ak1 . } } graph ?aa1 { ?_space_multi_iri gen:hasRole ?role1 . } graph ?rd1 { ?role1 gen:hasRegularProperty gen:plansToAttend . } } as ?offersPlanned) bind(exists { graph npa:graph { ?an2 npa:hasValidSignatureForPublicKeyHash ?ak2 ; np:hasAssertion ?aa2 . filter not exists { ?ai2 npx:invalidates ?an2 ; npa:hasValidSignatureForPublicKeyHash ?ak2 . } } graph ?aa2 { ?_space_multi_iri gen:hasRole ?role2 . } graph ?rd2 { ?role2 gen:hasRegularProperty wd:P1344 . } } as ?offersParticipation) bind(exists { graph npa:graph { ?an3 npa:hasValidSignatureForPublicKeyHash ?ak3 ; np:hasAssertion ?aa3 . filter not exists { ?ai3 npx:invalidates ?an3 ; npa:hasValidSignatureForPublicKeyHash ?ak3 . } } graph ?aa3 { ?_space_multi_iri gen:hasRole ?role3 . } graph ?rd3 { ?role3 gen:hasInverseProperty gen:hasObserver . } } as ?offersObserver) # Which has the viewer already declared? With no viewer (logged out) the str() # comparison errors, the filter drops the row, and exists() is false - so a # logged-out visitor is offered everything the space offers. bind(exists { graph ?state { ?ri1 a gen:RoleInstantiation ; npa:forSpace ?_space_multi_iri ; npa:forAgent ?u1 ; npa:regularProperty gen:plansToAttend . } filter(str(?u1) = str(?__CURRENTUSER_multi_iri)) } as ?hasPlanned) bind(exists { graph ?state { ?ri2 a gen:RoleInstantiation ; npa:forSpace ?_space_multi_iri ; npa:forAgent ?u2 ; npa:regularProperty wd:P1344 . } filter(str(?u2) = str(?__CURRENTUSER_multi_iri)) } as ?hasParticipated) bind(exists { graph ?state { ?ri3 a gen:RoleInstantiation ; npa:forSpace ?_space_multi_iri ; npa:forAgent ?u3 ; npa:inverseProperty gen:hasObserver . } filter(str(?u3) = str(?__CURRENTUSER_multi_iri)) } as ?hasObserver) # One row per way in that is still open, plus a silent row so that a viewer who # has declared everything gets a blank panel rather than \"(nothing found)\". values (?slot ?sort) { ('take-part' 1) ('observe' 2) ('none' 3) } bind(if(?started, ?offersParticipation, ?offersPlanned) as ?takePartOffered) bind(if(?started, ?hasParticipated, ?hasPlanned) as ?takePartDone) bind(?takePartOffered && !?takePartDone as ?showTakePart) bind(?offersObserver && !?hasObserver && !?hasPlanned && !?hasParticipated as ?showObserve) filter(if(?slot = 'take-part', ?showTakePart, if(?slot = 'observe', ?showObserve, !?showTakePart && !?showObserve))) bind(concat('/publish?template-version=latest¶m_space=', encode_for_uri(str(?_space_multi_iri)), '&template=') as ?tail) bind(if(?slot = 'take-part', if(?started, concat('

This event is under way. Put it on record that you are taking part — one nanopublication, retractable at any time.

declare participation...

'), concat('

Planning to come? Saying so puts you on the list of expected participants — one nanopublication, retractable at any time.

declare planned attendance...

')), if(?slot = 'observe', concat('

Not coming, but want to follow what happens here?

observe...

'), '')) as ?content) } order by ?sort""" . } sub:provenance { sub:assertion prov:wasAttributedTo orcid:0000-0002-1267-0234 . } sub:pubinfo { orcid:0000-0002-1267-0234 foaf:name "Tobias Kuhn" . this: dct:created "2026-09-07T08:53:21Z"^^xsd:dateTime; dct:creator orcid:0000-0002-1267-0234; dct:license ; npx:embeds sub:get-event-participation-actions; npx:supersedes ; rdfs:label "Get the ways in still open to the viewer of an event"; nt:wasCreatedFromProvenanceTemplate ; nt:wasCreatedFromPubinfoTemplate , , , ; nt:wasCreatedFromTemplate . sub:sig npx:hasAlgorithm "RSA"; npx:hasPublicKey "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwUtewGCpT5vIfXYE1bmf/Uqu1ojqnWdYxv+ySO80ul8Gu7m8KoyPAwuvaPj0lvPtHrg000qMmkxzKhYknEjq8v7EerxZNYp5B3/3+5ZpuWOYAs78UnQVjbHSmDdmryr4D4VvvNIiUmd0yxci47dTFUj4DvfHnGd6hVe5+goqdcwIDAQAB"; npx:hasSignature "coIzSXaw/gkpvJaS3Id/AP7yo4BXNe1MddovJGKYlwXidH4fvAbfVi7ZVG++B6yWo4di4FQVbtwvx0L4PUpyr1sLe8JdeOREFBxLQFpXKXPwmStFsM7MALdSZ4Ir4qsISindoz1EfuSzOYob7Zs9Tvdv4QApMjXzH1puZ1bsqbI="; npx:hasSignatureTarget this:; npx:signedBy orcid:0000-0002-1267-0234 . }