1
0
mirror of https://github.com/moparisthebest/xeps synced 2024-11-24 18:22:24 -05:00
xeps/inbox/buddycloud-channels.xml
2017-08-23 14:45:07 +02:00

1158 lines
39 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xep SYSTEM "xep.dtd" [
<!ENTITY % ents SYSTEM "xep.ent">
%ents;
<!ENTITY actor "&lt;actor/&gt;">
<!ENTITY invalidactor "&lt;invalid-actor/&gt;">
<!ENTITY invalidnode "&lt;invalid-node/&gt;">
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Buddycloud Channels</title>
<abstract>This document describes a profile and conventions for usage of the PubSub protocol in the context of a new type of communication.</abstract>
&LEGALNOTICE;
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XEP-0059</spec>
<spec>XEP-0060</spec>
<spec>XEP-0313</spec>
<spec>XEP-0255</spec>
<spec>XEP-0107</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>NOT_YET_ASSIGNED</shortname>
<author>
<firstname>Simon</firstname>
<surname>Tennant</surname>
<email>simon@buddycloud.com</email>
<jid>simon@buddycloud.com</jid>
</author>
<author>
<firstname>Lloyd</firstname>
<surname>Watkin</surname>
<email>lloyd@evilprofessor.co.uk</email>
<jid>lloyd@evilprofessor.co.uk</jid>
</author>
<author>
<firstname>Ashley</firstname>
<surname>Ward</surname>
<email>ashley.ward@surevine.com</email>
<jid>ashley.ward@surevine.com</jid>
</author>
<revision>
<version>0.0.2</version>
<date>2014-04-29</date>
<initials>sdt</initials>
<remark>
<p>First draft.</p>
</remark>
</revision>
</header>
<section1 topic="Buddycloud Introduction" anchor="Buddycloud Introduction">
<section2 topic="About Buddycloud" anchor="about-buddycloud">
<p>The Buddycloud project is a set of independently deployable services, that
inter-operate to create a rich collaboration service.
</p>
<p>Buddycloud Channels build on XMPP's native federation and publish-subscribe
principles to connect to, and synchronise content with users on local and
remote domains. Services are designed to interoperate. For example, the Media
Server, Friend Finder, and content recommendation engine work together to help
developers build a unified collaboration services for individual and groups
of users.
</p>
<p>This XEP seeks to define how the Buddycloud Channel service currently
functions. It also seeks stay extensible for accommodate future, undefined
use cases.
</p>
</section2>
<section2 topic="Buddycloud Channels" anchor="Buddycloud Channels">
<p>
Buddycloud channels are a bundle of <cite>XEP-0060</cite> publish-subscribe nodes with
identical subscribers and permissions presented as a JID-like
name (example:
<link url="buddycloud:juliet@capulit.lit">juliet@capulet.lit</link>
. Content posted into channels is automatically synchronised to the correct
followers on other Buddycloud domains.
</p>
</section2>
<section2 topic="Glossary" anchor="glossary">
<dl>
<di>
<dt>Personal Channel</dt>
<dd> Personal channels are a group of pub-sub nodes that have the same
owner, followers and access permissions.
</dd>
</di>
<di>
<dt>Topic Channel</dt>
<dd>Topic channels are for group discussions and decoupled from the owners
jid. For example balcony-speeches@topics.montague.lit could be owned by
speechwriter@montague.lit.
</dd>
</di>
<di>
<dt>Ephemeral Channel</dt>
<dd>
Ephemeral channels, are generated for one-off use and automatically removed
by the Buddycloud service after the last participant unfollows them
(similar to the Google Hangout service) An example ephemeral channel would
be
<code>125bd2c4-afc2-4d4c-b869-efc0c0dad8c5@montague.lit</code>
.
</dd>
</di>
<di>
<dt>Buddycloud Service</dt>
<dd>An XMPP component which hosts channel nodes and provides an interface
conforming to this document to allow access to them via XMPP.
</dd>
</di>
<di>
<dt>Home server</dt>
<dd>The Buddycloud service responsible for a JID's channels and Inbox.
</dd>
</di>
<di>
<dt>Remote Server</dt>
<dd>Buddycloud service that run on other XMPP domains.
</dd>
</di>
<di>
<dt>Buddycloud Inbox</dt>
<dd>Service on the entity's home Buddycloud service which subscribes to
nodes on the Entity's behalf, and may cache node data and provide an
ability to replay recent messages.
</dd>
</di>
</dl>
</section2>
</section1>
<section1 topic="Service Discovery" anchor="Finding-the-right-Buddycloud-server">
<p>Each XMPP domain can have one Buddycloud server that serves user's channels.
Buddycloud clients and servers need to be able to discover the authoratative
Buddycloud server. find the
</p>
<section2 topic="Discovery order" anchor="DISCOthenDNS">
<p>
To find the correct remote Buddycloud service for a domain, the Buddycloud
server should:</p>
<ol>
<li>Use a disco#items query against the XMPP service for the remote
Buddycloud domain.
</li>
<li>If no answer is returned (perhaps the remote site doesn't run a full
XMPP service) the Buddycloud service should proceed to use the DNS
discovery method.
</li>
</ol>
</section2>
<section2 topic="Discovery using Disco" anchor="disco-discovery">
<p>The Buddycloud service first sends an items discovery request to the domain
to discover all the available components.
</p>
<example caption="The Entity sends a disco#items request to the domain">
<![CDATA[
<iq type='get' from='juliet@capulet.lit/balcony' to='capulet.lit' id='items1'>
<query xmlns='http://jabber.org/protocol/disco#items'/>
</iq>]]>
</example>
<p>The server replies with the list of available components, along with their
associated JIDs.
</p>
<example caption="The server replies with a list of available components.">
<![CDATA[
<iq type='result' from='capulet.lit' to='juliet@capulet.lit/balcony' id='items1'>
<query xmlns='http://jabber.org/protocol/disco#items'>
<item jid='muc.capulet.lit' name='Chatrooms' />
<item jid='buddycloud.capulet.lit' name='Buddycloud Server' />
</query>
</iq>
]]>
</example>
<p>The entity then iterates through the &lt;item/&gt; elements, sending an
info discovery request to each JID.
</p>
<example caption="The Entity sends a disco#info request to each component">
<![CDATA[
<iq type='get' from='juliet@capulet.lit/balcony' to='buddycloud.capulet.lit' id='info1'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>
]]>
</example>
<p>Each component replies with its identity. The Buddycloud server has an
identity of category 'pubsub' and type 'channels'.
</p>
<p>A domain MUST only host one component with an identity of category 'pubsub'
and type 'channels'.
</p>
<example caption="The Buddycloud server replies with its identity">
<![CDATA[
<iq type='result' from='buddycloud.capulet.lit' to='juliet@capulet.lit/BuddycloudApp' id='info2'>
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity category='pubsub' type='channels' />
<identity category='pubsub' type='inbox' />
<feature var='jabber:iq:register' />
<feature var='http://jabber.org/protocol/disco#info' />
<feature var='jabber:iq:search' />
</query>
</iq>
]]>
</example>
</section2>
<section2 topic="Discovery using DNS" anchor="DNS-discovery">
<p>In the case that no server is found via disco, DNS should be used to
discover the Buddycloud server. A PTR record can be used to delegate
Buddycloud services to a remote Buddycloud server.
</p>
<example caption="PTR record for buddycloud server discovery">
<![CDATA[
_buddycloud-server._tcp.montague.lit. PTR buddycloud-component.verona.lit.
]]>
</example>
<p>
This example delegates all the Buddycloud service to an XMPP component
running the Buddycloud named
<em>buddycloud-component.verona.lit</em>
.
</p>
</section2>
</section1>
<section1 topic="Register" anchor="register">
<p>Upon connection to the buddycloud server a user should send a register
stanza.</p>
<example caption="The Entity sends a register request to the domain">
<![CDATA[
<iq type='set'
from='juliet@capulet.lit/balcony'
to='channels.capulet.lit'
id='register1'>
<query xmlns='jabber:iq:register'/>
</iq>
]]>
</example>
<p>The register request creates the user's personal channels on first use
and has the additional benefit of creating additional new channel nodes
as they become available on the server (e.g. 'status' node, 'geoloc' nodes).
</p>
</section1>
<section1 topic="Channel and Node Configuration" anchor="channel-config">
<p>Node metadata is used to describe the channel to users. All nodes in a
channel have the same metadata and permission.
</p>
<section2 topic="Get Node Configuration" anchor="get-node-config">
<p>- using disco-info
with the node specified - using &xep0060; 5.4 Discover Node Metadata</p>
</section2>
<section2 topic="Set Node Configuration" anchor="set-node-config"><p> set Not sure what
goes here?</p>
</section2>
<section2 topic="Default roles" anchor="default-roles">
<p> minimum setting/optional recommended fallbacks
</p>
<p>Channel metadata is stored as node metadata against the /posts node of the
channel. It is recommended that all channel nodes have the same permissions
and an update to one updates the others.
</p>
<p>
Most metadata fields used for Channels are already defined in <cite>XEP-0060</cite>. The relevant ones are listed below.
</p>
<table caption="Channel Metadata Fields">
<tr>
<th>Metadata</th>
<th>Field</th>
<th>Example</th>
<th>Notes</th>
<th>Defaults</th>
</tr>
<tr>
<td>Channel Title</td>
<td>pubsub#title</td>
<td>"Juliet's musings"</td>
<td>Should be a brief single sentence</td>
<td>"juliet@capulet.lit's Buddycloud channel"</td>
</tr>
<tr>
<td>Channel Description</td>
<td>pubsub#description</td>
<td>"This is a channel about the things that I like to do."</td>
<td>A longer description of the channel</td>
<td>&lt;empty&gt;</td>
</tr>
<tr>
<td>Channel Access Model</td>
<td>pubsub#access_model</td>
<td>open, authorize, local</td>
<td>The channel subscriber model</td>
<td>Dependent on Node</td>
</tr>
<tr>
<td>Channel Creator</td>
<td>pubsub#creator</td>
<td>mercutio@capulet.lit</td>
<td>The channel creator's JID</td>
<td>Dependent on Node</td>
</tr>
<tr>
<td>Default Affiliation</td>
<td>buddycloud#default_affiliation</td>
<td>"publisher"</td>
<td>The role given to new channel followers</td>
<td>Dependent on Channel Type</td>
</tr>
<tr>
<td>Channel Type</td>
<td>buddycloud#channel_type</td>
<td>"personal"</td>
<td>The type of this channel. (see below). Set by the server at creation.
Not user changable.
</td>
<td>N.A.</td>
</tr>
<tr>
<td>Channel Creation Date</td>
<td>pubsub#creation_date</td>
<td>"1997-08-29T02:14:42-05:00Z"</td>
<td>When the channel was created in ISO 8601 time format. Set by the server
at creation. Not user changeable.
</td>
<td>N.A.</td>
</tr>
<tr>
<td>Channel Updated Date</td>
<td>buddycloud#updated_date</td>
<td>"2011-04-21T20:11:00-05:00Z"</td>
<td>The date the channel configuration was later updated in ISO 8601 time
format. Set by the server. Not user changable.
</td>
<td>N.A.</td>
</tr>
<tr>
<td>Node content type</td>
<td>pubsub#type</td>
<td>http://www.w3.org/2005/Atom</td>
<td>The type of content held within this node.</td>
<td>http://www.w3.org/2005/Atom</td>
</tr>
</table>
<p>Channel owners and moderators can also set the default affiliation for the
channel
</p>
<table caption="Channel Types">
<tr>
<th>Channel Type</th>
<th>Description</th>
<th>Example</th>
</tr>
<tr>
<td>personal channel</td>
<td>Channel named after and owned by the user's JID.</td>
<td> romeo@montague.lit</td>
</tr>
<tr>
<td>Topic channel</td>
<td>A channel features around a common topic.</td>
<td>cauldron-recipees@coven.shakespeare.lit</td>
</tr>
<tr>
<td>local</td>
<td>
<p>Appears as an open channel to local users on that domain.</p>
<p>Appears as a closed channel to users on remote Buddycloud domains.
</p>
</td>
<td>montague-family-channel@montague.lit
</td>
</tr>
</table>
<table caption="Channel Access Models">
<tr>
<th>Access Model</th>
<th>Description</th>
</tr>
<tr>
<td>authorize</td>
<td>The channel is only viewable by it's producer, followers,
followers+post and moderators.
</td>
</tr>
<tr>
<td>open</td>
<td>Anyone can view the channel.</td>
</tr>
<tr>
<td>local</td>
<td>
<p>Appears as an open channel to local users on that domain.</p>
<p>Appears as a closed channel to users on remote Buddycloud domains.
</p>
</td>
</tr>
</table>
</section2>
<section2 topic="Well known nodes" anchor="well-known-nodes">
<p>Buddycloud is designed to be extended with new node and content types. To
kickstart Buddycloud starts with some well known and used nodes. It is
recommended that new nodes are announced publicly on the XSF standards
mailing list and an informal registry will be kept.
</p>
<table caption="Well known Buddycloud nodes.">
<tr>
<th>Node Name</th>
<th>Use</th>
<th>Format</th>
<th>Notes</th>
</tr>
<tr>
<td>/user/&lt;jid&gt;&gt;/posts</td>
<td>Activity stream</td>
<td>Atom 1.0</td>
<td>Activty stream formatted posts</td>
</tr>
<tr>
<td>/user/&lt;jid&gt;&gt;/public-key</td>
<td>RFC 4880 OpenPGP public key
</td>
<td>Key is published using ASCII Armour encoding scheme as detailed in
RFC-2440, Section 6 and is encoded using the
http://xmpp.org/extensions/xep-0189.xml#schema-pubkey syntax.
</td>
<td>Applications use the Public Key to encode messages and posts to the node
owner.
</td>
</tr>
<tr>
<td>/user/&lt;jid&gt;&gt;/geoloc-past</td>
<td>Describes where the channel owner was previously.</td>
<td>XEP-0080</td>
<td>Show's key location or place "checkins".</td>
</tr>
<tr>
<td>/user/&lt;jid&gt;&gt;/geoloc</td>
<td>Describes where the channel owner is now.</td>
<td>XEP-0080</td>
<td>A single item.</td>
</tr>
<tr>
<td>/user/&lt;jid&gt;&gt;/geoloc-future</td>
<td>Describe where the channel owner plans to go.</td>
<td>XEP-0080</td>
<td>Show's an intended location or description (for example "Juliet's
Balcony" or "Going out this evening to read love poetry"). A good
application will clear the geoloc-future location when it matches the
current location.
</td>
</tr>
<tr>
<td>/user/&lt;jid&gt;&gt;/status</td>
<td>A one line descrition of the channels status.</td>
<td>
Atom 1.0
</td>
<td>For example a user might enter "Is happy" and a topic channel for a
development team might have a status line of "Code is building correctly"
</td>
</tr>
</table>
</section2>
</section1>
<section1 topic="Business Logic" anchor="biz-logic">
<section2 topic="PubSub for Humans" anchor="PubSub-for-humans">
<p> Buddycloud adapts <cite>XEP-0060</cite>'s machine-to-machine design goals with logic
and presets that work better in a social person-to-person and person-to-group
environment. For example, to discourage "glorifying the wicked", the list of
banned users is only presented to the channel's moderators.
</p>
<table caption="channel read permissions">
<tr>
<th>Property</th>
<th>Access model</th>
<th>Example</th>
<th>Channel Producer</th>
<th>Channel Moderator</th>
<th>Follower+post</th>
<th>Follower</th>
<th>Anonymous (e.g. web)</th>
<th>Banned users</th>
</tr>
<tr>
<td>channel name</td>
<td>all</td>
<td>juliet@capulet.lit</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>channel title</td>
<td>all</td>
<td>Posts about Romeo</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>channel description</td>
<td>all</td>
<td>Posts and photos of my darling Romeo. This is not a place for Verona
gossip.
</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>banned user list</td>
<td>all</td>
<td>father@montague.lit</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td>pending subscription list</td>
<td>all</td>
<td>nurse@capulet.lit</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td rowspan="3">channel posts</td>
<td>open</td>
<td rowspan="3">O Romeo, Romeo! Wherefore art thou Romeo? Deny thy father
and refuse thy name. Or, if thou wilt not, be but sworn my love, And Ill
no longer be a Capulet.
</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>authorize</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td>local</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td rowspan="3">followers, moderators and owner</td>
<td>open</td>
<td rowspan="3">tybalt@capulet.lit, servant@capulet.lit, peter@capulet.lit
</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>authorize</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td>local</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
</tr>
</table>
<table caption="channel write permissions">
<tr>
<th>Property</th>
<th>Producer</th>
<th>Moderator</th>
<th>Follower+post</th>
<th>Follower</th>
<th>Anonymous (e.g. web)</th>
<th>Banned users</th>
</tr>
<tr>
<td>change channel name</td>
<td>only at creation time</td>
<td>no</td>
<td>no</td>
<td>no</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td>channel channel title</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td>change channel description</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td>change banned user list</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td>approve pending subscriptions</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td>create posts</td>
<td>yes</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
<td>no</td>
<td>no</td>
</tr>
<tr>
<td>delete posts</td>
<td>yes</td>
<td>yes</td>
<td>own posts</td>
<td>no</td>
<td>no</td>
<td>no</td>
</tr>
</table>
</section2>
<section2 topic="Maintain Similar Affiliations across Channel Nodes" anchor="rules-nodeaffiliations">
<p>A Buddycloud server MUST maintain similar affiliations and permissions for a subscribed
entity across all nodes that comprise a channel. For example, following the "posts" node
would also follow the status node.
</p>
<p>The server should automatically ensure that all nodes belonging to that
channel are updated with the same permissions. This helps address a common
criticism of the "privacy confusion" of other social products where users
need to search settings on different clients to ensure that their profile
really is private.
</p>
</section2>
</section1>
<section1 topic="Pubsub Items" anchor="items">
<p>Many of the item use cases follow those from <cite>XEP-0060</cite>. This section notes
the departures from the parent XEP and specific requirements.
</p>
<section2 topic="Retrieving items" anchor="items-retrieve">
<section3 topic="Recent Items" anchor="items-recent">
<p>It is possible to retrieve any new items since last retrieval from all subscribed channels ('<em>/posts</em>' nodes specifically) since last retrieval using the <strong>recent items</strong> functionality.
</p>
<example caption="Recent items query">
<![CDATA[
<iq from="juliet@capulet.lit/bc-app" to="buddycloud.capulet.lit" type="get" id="recent-items:1">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<recent-items xmlns="http://buddycloud.org/v1"
since="2014-04-18T10:46.100Z"
max="50"
parent-only="true" />
</pubsub>
</iq>
]]>
</example>
<example caption="Recent items reply">
<![CDATA[
<iq to="juliet@capulet.lit/bc-app" from="buddycloud.capulet.lit" type="result" id="recent-items:1">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<items node="/user/romeo@montague.lit/posts">
<item id="tag:channels.capulet.lit,/users/juliet@montague.lit/posts,16584564008760001">
...atom payload...
</item>
<item id="tag:channels.capulet.lit,/users/juliet@montague.lit/posts,10070506450002">
...atom payload...
</item>
</items>
<items node="/user/juliet@capulet.lit/posts">
<item id="tag:channels.capulet.lit,/users/juliet@capulet.lit/posts,3252545492409">
...atom payload...
</item>
</items>
<items node="/user/romeo@montague.lit/posts">
<item id="tag:channels.capulet.lit,/users/juliet@montague.lit/posts,106876700003">
...atom payload...
</item>
</items>
</pubsub>
</iq>
]]>
</example>
<p>In this example <em>max</em> represents the maximum number of items the user wishes to retrieve
from any one channel, <em>since</em> is the datetime from which posts should start, and
<em>parent-only</em> allows users to requests posts which only start a discussion
(i.e. no reply posts).</p>
<section4 topic="Error Cases" anchor="items-recent-errorcases">
<p>The following extended error cases are used:
</p>
<ul>
<li>
<em>max-required</em>
: A maximum number of items per node is required
</li>
<li>
<em>invalid-max-value-provided</em>
: The value of <em>max</em> must be a positive integer
</li>
<li>
<em>since-required</em>
: A valid value for <em>since</em> must be provided
</li>
<li>
<em>invalid-since-value-provided</em>
: <em>since</em> must be a parsable date string (ISO-8601 format)
</li>
</ul>
</section4>
</section3>
</section2>
<section2 topic="Deleting items" anchor="items-delete">
<example caption="The client sends">
<![CDATA[
<iq from="juliet@capulet.lit/bc-app" to="buddycloud.capulet.lit" type="set" id="retractitem:32">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<retract node="/user/juliet@capulet.lit/posts" notify="1">
<item id="1291048772456"/>
</retract>
</pubsub>
</iq>
]]>
</example>
<example caption="Server replies">
<![CDATA[
<iq from="buddycloud.capulet.lit" to="juliet@capulet.lit/bc-app" type="result" id="retractitem:32"/>
]]>
</example>
<p>A retraction message is sent to all online clients, with an Atom tombstone to
replace the deleted post</p>
<example caption="The Buddycloud server sends retractions out to online clients">
<![CDATA[
<message from="buddycloud.capulet.lit" id="bc:MGV3B" to="benvolio@montague.lit">
<event xmlns="http://jabber.org/protocol/pubsub#event">
<items node="/user/channeluser@example.com/posts">
<retract id="1291048772456"/>
<item id="1291048772456">
<deleted-entry xmlns="http://purl.org/atompub/tombstones/1.0" ref="xmpp:buddycloud.capulet.lit?pubsub;action=retrieve;node=/user/juliet@capulet.lit/posts;item=1291048772456" when="2012-07-01T15:08:32.950Z">
<updated>2012-07-01T15:08:32.950Z</updated>
<id xmlns="http://www.w3.org/2005/Atom">1291048772456</id>
<link xmlns="http://www.w3.org/2005/Atom" href="xmpp:buddycloud.capulet.lit?pubsub;action=retrieve;node=/user/juliet@capulet.lit/posts;item=1291048772456" rel="self"/>
<published xmlns="http://www.w3.org/2005/Atom">2012-07-01T15:08:30.922Z</published>
<object xmlns="http://activitystrea.ms/spec/1.0/">
<object-type>comment</object-type>
</object>
<verb xmlns="http://activitystrea.ms/spec/1.0/">post</verb>
</deleted-entry>
</item>
</items>
</event>
</message>
]]>
</example>
</section2>
<section2 topic="Item Payload" anchor="item-payload">
<p>Buddycloud
item data are formatted according to &amp;
<strong>atom</strong>;
standards and optionally making use of &amp;
<strong>thread</strong>;
and &amp;
<strong>review</strong>
; extensions.
</p>
<section3 topic="Publishing" anchor="item-publishing">
<p>The minimal payload for a publish request must be formatted as follows:
</p>
<example caption="The Entity publishes to a node">
<![CDATA[
<iq from="juliet@montague.lit/balcony" to="channels.montague.lit" type="set" id="publish:20">
<pubsub xmlns="http://jabber.org/protocol/pubsub">
<publish node="/user/romeo@capulet.lit/posts">
<item>
<entry xmlns="http://www.w3.org/2005/Atom">
<content type="text">O Romeo, Romeo! wherefore art thou Romeo?</content>
</entry>
</item>
</publish>
</pubsub>
</iq>
]]>
</example>
<p>This payload will be extended with default data by the server if not
provided. The final payload looking as follows:
</p>
<example caption="Payload with server-added elements">
<![CDATA[
<entry xmlns="http://www.w3.org/2005/Atom">
<id>fc362eb42085f017ed9ccd9c4004b095</id>
<title>Post title</title>
<published>2014-01-01T00:00:00.000Z</published>
<updated>2014-01-01T00:00:00.000Z</updated>
<author>
<name>juliet@montague.lit</name>
<jid xmlns="http://buddycloud.com/atom-elements-0">juliet@montague.lit</jid>
</author>
<content type="text">O Romeo, Romeo! wherefore art thou Romeo?</content>
<activity:verb>post</activity:verb>
<activity:object>
<activity:object-type>post</activity:object-type>
</activity:object>
</entry>
]]>
</example>
<section4 topic="Error Cases" anchor="item-publishing-errorcases">
<p>Beyond
standard &amp;
<strong>xep0060</strong>
; error cases additional errors are used:
</p>
<ul>
<li>
<em>entry-element-required</em>
: Where no entry element has been provided in the payload
</li>
<li>
<em>content-element-required</em>
: Where no content element or an empty content element is provided
</li>
<li>
<em>unsupported-content-type</em>
: If provided the 'type' attribute of the content element must be either
'text' or 'xhtml'. If not provided value will default to 'text'
</li>
</ul>
</section4>
</section3>
<section3 topic="Threading" anchor="item-threading">
<p>
Posts in Buddycloud can be formed into threads consisting of a parent post
and comments to a maximum thread depth of 1. Posts follow the &rfc4685;
and utilise the &amp;
<strong>thread</strong>
; namespace with the 'ref' attribute referring to the full global ID of the
parent post.
</p>
<example caption="A valid payload for replying in a thread">
<![CDATA[
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/">
<id>96da02ee1baef61e767742844207bec4</id>
<title>Post title</title>
<published>2014-01-01T00:00:00.000Z</published>
<updated>2014-01-01T00:00:00.000Z</updated>
<author>
<name>romeo@capulet.lit</name>
<jid xmlns="http://buddycloud.com/atom-elements-0">romeo@capulet.lit</jid>
</author>
<content type="text">Shall I hear more, or shall I speak at this?</content>
<activity:verb>post</activity:verb>
<activity:object>
<activity:object-type>comment</activity:object-type>
</activity:object>
<thr:in-reply-to ref="tag:channels.capulet.lit,/users/romeo@capulet.lit/posts,fc362eb42085f017ed9ccd9c4004b095" />
</entry>
]]>
</example>
<section4 topic="Error Cases" anchor="item-threading-errorcases">
<ul>
<li>
<em>parent-item-not-found</em>
: A reply must be made to an existing post within the same node
</li>
<li>
<em>max-thread-depth-exceeded</em>
: An attempt to comment on a comment will result in this error response
</li>
</ul>
</section4>
</section3>
<section3 topic="Referencing" anchor="item-referencing">
<p>Within a single thread comments can reference other comments or the parent
item. This is for the purpose of making a comment to a post further back in
the thread.
</p>
<example caption="A valid payload for referencing another post within a thread">
<![CDATA[
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/">
<id>96da02ee1baef61e767742844207bec4</id>
<title>Post title</title>
<published>2014-01-01T00:00:00.000Z</published>
<updated>2014-01-01T00:00:00.000Z</updated>
<author>
<name>romeo@capulet.lit</name>
<jid xmlns="http://buddycloud.com/atom-elements-0">romeo@capulet.lit</jid>
</author>
<content type="text">Shall I hear more, or shall I speak at this?</content>
<activity:verb>post</activity:verb>
<activity:object>
<activity:object-type>comment</activity:object-type>
</activity:object>
<thr:in-reply-to ref="tag:channels.capulet.lit,/users/romeo@capulet.lit/posts,fc362eb42085f017ed9ccd9c4004b095" />
<activity:target> <id>tag:channels.capuet.lit,/users/romeo@capulet.lit/posts,fc362eb42085f017ed9ccd9c4004b095</id>
</activity:target>
</entry>
]]>
</example>
<section4 topic="Error Cases" anchor="item-referencing-errorcases">
<ul>
<li>
<em>missing-in-reply-to</em>
: As posts referencing other posts can only be comments then attempting to
do so results in this error
</li>
<li>
<em>missing-target-id</em>
: A target ID must be specificed as text to the target element
</li>
<li>
<em>targeted-item-not-found</em>
: If the targetted item can not be found in the current thread this error
response will be returned
</li>
<li>
<em>target-outside-thread</em>
: The targetted item must be within the same thread as the new post
</li>
</ul>
</section4>
</section3>
<section3 topic="Rating" anchor="item-rating">
<p>By
making use of the &amp;
<strong>review</strong>;
extension of activity streams and the &amp;
<strong>target</strong>
; element outline above Buddycloud is able to support 'rating' a post.
</p>
<p>Posts can be rated an integer value between 1 and 5, although may only
wish to provide a binary setting to match popular services which provide
'likes', '+1', etc.
</p>
<p>
Any post content is discarded and replaced with
<strong>rating:X.0</strong>
(where
<em>X</em>
is the rating value). The activity verb is also overwritten with 'rated'.
</p>
<example caption="A valid payload for rating another post">
<![CDATA[
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/">
<id>96da02ee1baef61e767742844207bec4</id>
<title>Post title</title>
<published>2014-01-01T00:00:00.000Z</published>
<updated>2014-01-01T00:00:00.000Z</updated>
<author>
<name>romeo@capulet.lit</name>
<jid xmlns="http://buddycloud.com/atom-elements-0">romeo@capulet.lit</jid>
</author>
<content type="text">rating:5.0</content>
<activity:verb>rated</activity:verb>
<activity:object>
<activity:object-type>comment</activity:object-type>
</activity:object>
<thr:in-reply-to ref="tag:channels.capulet.lit,/users/romeo@capulet.lit/posts,fc362eb42085f017ed9ccd9c4004b095" />
<activity:target> <id>tag:channels.capuet.lit,/users/romeo@capulet.lit/posts,fc362eb42085f017ed9ccd9c4004b095</id>
</activity:target>
<review:rating>5.0</review:rating>
</entry>
]]>
</example>
<section4 topic="Error cases" anchor="item-rating-errorcases">
<ul>
<li>
<em>invalid-rating</em>
: A non-numerically parsable rating value will result in this error
message
</li>
<li>
<em>rating-out-of-range</em>
: A rating can only have an integer value between 1 and 5 (inclusive)
</li>
<li>
<em>invalid-rating-request</em>
: Ratings can only be made against post types 'post' and 'comment' i.e. it
is not possible to rate a rating
</li>
<li>
<em>item-already-rated</em>
: A user can only rate a single post once
</li>
</ul>
</section4>
</section3>
</section2>
</section1>
<section1 topic="Channel subscriptions" anchor="subscriptions">
<p>Buddycloud clients follow <cite>XEP-0060</cite> subscription mechanisms for following and unfollowing a channel.</p>
</section1>
<section1 topic="Channel affiliations" anchor="affiliations">
<section2 topic="Buddycloud to XEP-0060 mappings" anchor="affiliation-to-xep-0060-mappings">
<p>
Buddycloud channels build on XEP-0060's node affiliations.</p>
<table caption="Channel Affiliations">
<tr>
<th>XEP-0060 Affiliation</th>
<th>Buddycloud Affiliation</th>
<th>Description</th>
<th>Required?</th>
</tr>
<tr>
<td>Owner</td>
<td>owner</td>
<td>The channel owner. Full access rights. Can add and delete
moderators.
</td>
<td>REQUIRED</td>
</tr>
<tr>
<td>-</td>
<td>moderator</td>
<td>A follower who has follower+post rights, rights to manage the
affiliation of entites with the node (except changing ownership),
and rights to manage the subscriptions of entities with the node.
</td>
<td>REQUIRED</td>
</tr>
<tr>
<td>Publisher</td>
<td>follower+post</td>
<td>Entity can view posts and replies, publish new posts, and publish
replies to posts.
</td>
<td>REQUIRED</td>
</tr>
<tr>
<td>Member</td>
<td>follower</td>
<td>Entity can view posts and replies for whitelist and open channels,
but cannot publish new posts or replies.
</td>
<td>REQUIRED</td>
</tr>
<tr>
<td>None</td>
<td>none</td>
<td>Entity can view posts and replies for open channels, but cannot
publish new posts or replies.
</td>
<td>REQUIRED</td>
</tr>
<tr>
<td>Outcast</td>
<td>outcast</td>
<td>Entity cannot view any posts or replies, and cannot publish new
posts or replies.
</td>
<td>RECOMMENDED</td>
</tr>
</table>
</section2>
</section1>
<section1 topic="Federation" anchor="federation">
<section2 topic="Inbox" anchor="inbox">
</section2>
<section2 topic="Interaction With Other Services" anchor="Interaction-With-Other-Services">
<p>The Buddycloud service is designed to work with interchangeable components
that offer discrete services and together form a complete communication
service.
</p>
<p>While the Buddycloud Server is designed to work independently of other
services but can be enhanced with helper services. Each helper communicates
with the Buddycloud server and other components using XEP-0114 connections.
Examples of helper services include: push notifications, media hosting,
contact matching, content search and channel recommendations.
</p>
<p>Helper services' specifications are covered in separate XEPs.
</p>
</section2>
</section1>
<section1 topic="Security Considerations" anchor="security-considerations">
<section2 topic="Server Trust" anchor="server-trust">
<p>
The Buddycloud server should make sure that the remote server
component is the authoritative Buddycloud server for the domain it
claims to represent. This is done by running the server discovery <!--
how do we reference a section in this document? -->
process and confirming the same XMPP component name.
</p>
</section2>
<section2 topic="Default Role" anchor="security-considerations-with-follower+post-role">
<p>Open channel where members join with a follow+post role present an
attractive target for spamming and malicious behaviour. This default
role should be use with caution especially when the Buddycloud server
federates with remote Buddycloud-enabled domains.
</p>
</section2>
</section1>
</xep>