In our own implementation, and within the context of our OpenSocial
adoption, there is a need to be able to indicate that a particular
activity or object is actionable. As an alternative to the original
actionLinks proposal, I've come up with the following proposed
approach that is versatile, flexible, extensible and reasonably
simple. We've only started to kick this around as a possible solution
and I wanted to solicit feedback from the community on the overall
approach so we can evolve it as necessary. So feedback is requested.
Basically, the use case is simple: when an activity occurs, we need to
be able to indicate that some action in response is
required/requested. That action is likely specific to the object (e.g.
approval of a document, resolution of an issue, etc).
What I propose is the creation of a new optional "reaction" extension
property on all AS Objects. The value of this property is an array of
"task" objects that details the possible responses to the object. For
example:
"reaction": [ {
# "objectType":"task",
"id":"urn:tasks:123",
"for":{... object ...},
"actor":{...},
"supersedes":["urn:tasks:122"],
"required": true,
"by":"2011-12-12T12:12:12-08:00",
"options": [
{"verb":"comment","resourceLink":"http://..."},
{"verb":"follow","resourceLink":"http://..."},
{"verb":"share","resourceLink":"http://..."},
...
],
"selfLink":"http://..."
} ]
The core properties of the "task" object type are simple:
1. "id" ... self explanatory
2. "for" ... optional value that identifies the object that is the
subject of this task... more on this in a bit
3. "actor" ... optional indicator as to who is expected to take this action
4. "supersedes" ... an optional array of task object id's that are
superseded by this task... allowing us to override or update previous
requested actions
5. "required" ... optional boolean that indicates whether this task
should be considered optional or required
6. "by" ... optional ISO8601 date-time indicating when this task
should be completed by
7. "options" ... the array of verbs indicating acceptable or expected
reactions to the subject object.. each value is a simple object with,
at least, a "verb", an optional resourceLink IRI, and an arbitrary
collection of extension properties that provide additional,
application specific context for the option.
8. "selfLink" ... an optional URL reference that when GET, returns a
representation of the task object, allowing for lazy resolution of the
options.. more on this later...
The "for" and "actor" fields can be derived from context depending on
how exactly the task object appears in the object or stream...examples
below
For example, if I were to say something like...
{
"objectType":"file",
"id":"urn:files:123",
"reactions":[
{"id":"urn:files:tasks:123",
"required":false,
"options":[{"verb":"comment"},{"verb":"like"}]
]
}
What I'm saying is that the possible valid reactions to this object
are that the consumer of the stream can comment on it or like it. The
value of the "for" field is derived from the context (e.g. it's the
"file" object in this case).
An alternative way this could appear is as a property of the activity...
{
"actor":{"displayName":"joe"},
"verb":"post",
"object": {
"objectType":"file",
"id":"urn:files:123"},
"reactions":[
{"id":"urn:files:tasks:123",
"for": {"objectType":"file","id":"urn:files:123"},
"required":false,
"options":[{"verb":"comment"},{"verb":"like"}]}
]
}
Note the use of the "for" property here to explicitly indicate that
the reaction task is specifically relating to the file. If we had
omitted the "for", it would have indicated that the reaction task is
in relation to the activity itself and not the file object. The
reason for this distinction is simple: there are some reactions that
may be taken with regards to the activity that are independent of the
activities object.. for instance, we may wish to indicate that a user
can comment on the file and MUST acknowledge the activity.. two
completely distinct reactions...
{
"id":"urn:activities:1",
"actor":{"displayName":"joe"},
"verb":"post",
"object": {
"objectType":"file",
"id":"urn:files:123"},
"reactions":[
{"id":"urn:files:tasks:123",
"for":{"objectType":"file","id":"urn:files:123"},
"required":false,
"options":[{"verb":"comment"},{"verb":"like"}]},
{"id":"urn:activities:tasks:1",
"required":true,
"options":[{"verb":"acknowledge"}]}
]
}
In many cases, the reactions will likely need to be scoped to specific
individuals.. for instance, you may wish to indicate that anyone can
comment on a file, but only request a certain user to approve it...
{
"to":[{"objectType":"@public"}],
"bto":[{"id":"acct:j...@example.org"}],
"id":"urn:activities:1",
"actor":{"displayName":"joe"},
"verb":"post",
"object": {
"objectType":"file",
"id":"urn:files:123"},
"reactions":[
{"id":"urn:files:tasks:123",
"for":{"objectType":"file","id":"urn:files:123"},
"actor":{"objectType":"@public"},
"required":false,
"options":[...]},
{"id":"urn:files:tasks:123",
"for":{"objectType":"file","id":"urn:files:123"},
"actor":{"id":"acct:j...@example.org"},
"required":true,
"options":[...]}
]
}
Note that "acct:j...@example.org" is part of the collection of "bto"
targets.. which implies that any reactions specifically targeted to
him should also be removed from any redistributed copies of the
activity.
The "task" object is defined as a distinct object type in order to
allow us to create an Activity Stream view specifically of task
objects... what essentially amounts to a todo list of sorts... so I,
as a user, could request an activity stream containing the current
collection of tasks gathered from across my stream... e.g.
{
"totalItems":1,
"items":[
{
"actor":{"displayName":"joe"},
"verb":"post",
"object": {
"objectType":"task",
"id":"urn:files:tasks:123",
"for":{"objectType":"file","id":"urn:files:123"},
"actor":{"id":"acct:j...@example.org"},
"required":true,
"options":[...]}
}
]}
We'd also be able to use an Activity to report an the status of a task...
{
"totalItems":1,
"items":[
{
"actor":{"displayName":"joe"},
"verb":"ignore", (joe ignored the task)
"object": {
"objectType":"task",
"id":"urn:files:tasks:123",
"for":{"objectType":"file","id":"urn:files:123"},
"actor":{"id":"acct:j...@example.org"},
"required":true,
"options":[...]}
}
]}
In some scenarios, the list of available options may be based on
additional context that cannot be expressed within the activity
stream, or it may be tied to a third party application and not known
at the time the activity was generated. For those cases, lazy
resolution of the task options is necessary... for that , we can use
the "selfLink" property to specify a URI that, when GET, returns a
resolved task object... e.g.
{
"id":"urn:files:tasks:123",
"for":{"objectType":"file","id":"urn:files:123"},
"actor":{"id":"acct:j...@example.org"},
"selfLink":"http://example.org/foo/tasks/123"
}
This overall approach would give us a significant range of options for
expressing, handling and reporting on actionable items in an activity
stream. It's extensible, versatile and relatively simple.
Thoughts?
- James
I worked on it every once in a while, even trying to put together a demo site. Having recently seen other's interests in "Web Intents" or "Web Actions", I did a little more work on the site and came up with http://intended-action.appspot.com/ (I should put more work into... Like QR codes....)
The main take away from that work is to have URIs pointing at resources (I'm thinking partial Activty Stream objects) to represent actionable items. They could be embedded in web pages has links, etc. (Unfortunately I think my preferred implementation requires too much work at the user agent side, or lots of fallback options.)
Now I am wondering how much of that work would mesh with your concept of "reactions". In my opinion such "reactions" can also be apart of web pages (or the physical world via something like QR codes).
What are the pros and cons of embedding the reaction items in an activity stream as opposed to referencing URIs that represent actionable items (and can be linked from other resources, e.g. web pages)? Or how to make something that works for both use cases?
I'm also wondering what I can take away from this concept of "reactions" and apply to my current work (so as to not duplicate effort, etc).
I hope my little demo site has enough information to cover the background and basic concept, as well as links to my inspirations and other's related works. The actual demo bits are a bit thin (and hard coded just to try and cover the basic functionality).
-Tony Evans
- James
> --
> You received this message because you are subscribed to the Google Groups "Activity Streams" group.
> To view this discussion on the web visit https://groups.google.com/d/msg/activity-streams/-/BW8NgW7_aHoJ.
> To post to this group, send email to activity...@googlegroups.com.
> To unsubscribe from this group, send email to activity-strea...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/activity-streams?hl=en.
>
>
We can boil this down even further by eliminating the selfLink idea
and defining the resourceLink in such a way that it points to a
description of how to carry out the verb. For instance, the
resourceLink could point to an OpenSocial gadget specification...
effectively saying that the way to carry out the verb is encapsulated
in the gadget... or, the resourceLink could point to a service
description resource (ala Google's discovery service api) which could
define a REST API request for the verb... or, the resourceLink could
point to the API endpoint itself and the client would perform an
OPTIONS request on the URL to figure out what it can do with it. There
are a broad range of possibilities. Some additional metadata field
such as a mimeType for the resourceLink resource can be included to
allow the user to differentiate what type of thing is being pointed to
by the resourceLink... for instance...
{
"objectType":"person",
"displayName":"joe",
"reactions":[
{"verb":"follow",
"resourceLink":"http://example.org/foo/bar/followmegadget.xml",
"resourceMimeType":"application/gadget+xml" # or whatever
]
Yeah I was looking at that too. In the gadget/EE case, the most we can do practically is indicate that some action is required on the part of the user, then defer to the embedded experience for everything else so we don't duplicate things. Perhaps in that case, the presence of both the EE and a Task with just a verb but no link or additional data is sufficient? Upon seeing the task but not seeing a link, the app would need to know to go looking for an EE. I dunno yet if that makes complete sense or not.
--
You received this message because you are subscribed to the Google Groups "Activity Streams" group.
> --
> You received this message because you are subscribed to the Google Groups
> "Activity Streams" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/activity-streams/-/N7DroMF5GUwJ.