Actionable items...

25 views
Skip to first unread message

James Snell

unread,
Nov 14, 2011, 6:36:42 PM11/14/11
to activity...@googlegroups.com
Back before we completed the version 1.0 of the JSON Activity Streams
spec, we removed the "actionLinks" mechanism because, at the time, it
was rather undercooked and we did not have enough collective
implementation experience to really drive standardization of the
mechanism. The intention was always to add that back into the standard
at a later date as an extension.

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

aevans

unread,
Nov 14, 2011, 7:39:41 PM11/14/11
to activity...@googlegroups.com
Sometime ago I wrote out some thoughts on how to handle sharing and other actions using a resource driven approach. The main goal was to allow users to decide which sharing (etc) services to use and under which of their identities to post. (And maybe an ultimate goal of using aggregation services to collect stats and other interesting things.)

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 Snell

unread,
Nov 14, 2011, 8:05:10 PM11/14/11
to activity...@googlegroups.com
Ok, some further refinements on this after thinking about it more...
we actually don't need the sub-listing of options, each task object
can have exactly one verb and resourceLink associated with it, then
for each verb we would have one task object... e.g.
"reactions":[  {"objectType":"task","id":"...","verb":"share","resourceLink":"http://...",...},
{"objectType":"task","id":"...","verb":"follow","resourceLink":"http://...",...},]
This achieves the same result and simplifies processing quite a bit.
Also, let's suppose a task is driven by an opensocial embedded
experience rather than a verb and a particular resource uri.. we could
do something like...
  {"objectType":"task","id":"...","opensocial":{"embed":{...EE
context...}},...},
Supposing we have to direct the user to the application to complete
the task, we could do...
  {"objectType":"task","id":"...","url":"http://example.org/myapp/...",...},


- James

James Snell

unread,
Nov 15, 2011, 12:45:47 PM11/15/11
to activity...@googlegroups.com
I'll have to study what you're doing here a bit more in depth but at
first glance there does appear to be some overlap. I'm not sure if I'm
comfortable with calling it an "intent" tho because I don't want to
muddy the waters with the whole WebIntents work that's been going on
with Chrome and Mozilla... yes they are related, but I'd rather avoid
the confusion. I'll take some time today to study what you've done a
bit more in depth and try to offer some concrete feedback after.

> --
> 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.
>
>

James Snell

unread,
Nov 16, 2011, 12:42:20 PM11/16/11
to activity...@googlegroups.com
Alright... additional refinements to the model based on some feedback
I've received...

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
]

rbaxter85

unread,
Nov 17, 2011, 7:21:42 AM11/17/11
to Activity Streams
For the gadget use case I don't see how this would work....
So we render the gadget when the user clicks on the action in the
stream, but that doesn't,t execut the action. The user would then
have to click on some other action inside the gadget. If that is the
case than I pretty much just described an embedded experience, so it
seems like we are defining two ways to do the same thing.

On Nov 16, 12:42 pm, James Snell <jasn...@gmail.com> wrote:
> Alright... additional refinements to the model based on some feedback
> I've received...
>
> 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 resources (ala Google's discovery service api) which could
> ...
>
> read more »

James Snell

unread,
Nov 17, 2011, 10:42:11 AM11/17/11
to activity...@googlegroups.com

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.

Bill Christian

unread,
Jan 6, 2012, 4:24:36 PM1/6/12
to activity...@googlegroups.com
Has there been any more movement in this area? I am curious on how to represent a task within activity streams e.g. "approval 1234 is pending joe's decision".

James Snell

unread,
Jan 6, 2012, 4:58:28 PM1/6/12
to activity...@googlegroups.com
Nothing significant. I implemented experimental support for my
reactions proposal within the Abdera2 code (check the code repository
at http://abdera.apache.org)... and I have worked through a number of
scenarios... the most significant challenge with it is figuring out
whether and how to make the reactions in the activity stream
*actionable* themselves... that is, if it's just a flag without any
information about how to actually carry out the action, is it still
useful... or do we need to introduce a mechanism for linking the
action to a specific api call. For this, I have been experimenting
with using a subset of the Google Discovery API JSON format as an
option... I need to write up the details in full tho. I will try to do
so over the coming couple of days.

> --
> 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.

Reply all
Reply to author
Forward
0 new messages