Add additional timeline posts to MatchPoint Snow
Date: 08. Oct 2015
It may be desired for certain actions like creating and editing documents or adding new workspace members, that timeline posts are created automatically (instead of only manual creations by users). By doing this other users can easily track these actions on their timeline.
This can be accomplished by using custom Workflow Configurations and / or custom Workspace Event Handlers. New timeline posts can then be generated by using the MatchPoint Snow expression method MPSTimelineHelper.AddPost
.
This blog post will give an overview and provide some examples of how to do that.
Please note that this works only with MatchPoint Snow 1.0.7 / MatchPoint 4.0.9 and above!
The expression variable MPSTimelineHelper.AddPost
The expression method MPSTimelineHelper.AddPost
exists since earlier versions of MatchPoint Snow, however the problem with this method is that it cannot be called without an HttpContext
and cannot be used to generate a post in behalf of a different user than the one who is calling the method. The new overload has additional parameters and can be called from places without an HttpContext
(e.g. workflows).
The method's signature looks like this:
public static IClientResult AddPost(string post, string targetId, string userName, string contextUrl, SPSocialAttachment attachment)
The meaning of the parameters are:
- post: The post to add.
- targetId: Specifies where to store the post. The ID represents the endpoint for the root post, reply post, or site feed post.
The value of the targetId parameter can be one of the following::null
- to publish a root post for the user. The post will be posted on the my site of the user.- The thread ID of a post to reply to.
- The URL of a site feed to post to (for example: http://siteURL/newsfeed.aspx ).
- userName:The user name of the user as which the post should be created. If null the current user will be used.
- contextUrl: The context URL which is used to open the SPServiceContext (which is needed for the UserProfileManager and the SPSocialFeedManager).
If null and 'SPServiceContext.Current' is not null, 'SPServiceContext.Current' is used.
If null and 'SPServiceContext.Current' is also null, the targetId is used. - attachment:The attachment for the created post.
The return value is of the type IClientResult
. This interface provides information if the execution of the method has been successful and an error message if it wasn't.
Scenario 1: Creating posts when a new document is created using workflows
If you want to use workflows there are a few pre-conditions which have to be fulfilled.
In MatchPoint Snow almost all pre-conditions are already fulfilled. Except that the "Workflow Kit" (5787fd56-2f95-4126-876c-e1e0d4a07146
) is not activated on the workspaces by default.
So if you want to use workflows you have to activate this feature on every workspace (you can use a PowerShell script for this). Also if you want that future workspaces have this feature activated by default you have to edit the MPSnow.Workspaces.BaseProvisioning.xml
file and add the site feature Colygon.MatchPoint.WorkflowKit.
If you have done that you can configure a workflow which creates a post whenever a document is created within a workspace:
<?xml version="1.0" encoding="utf-8"?>
<WorkflowConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Hidden>true</Hidden>
<Id>ef25ec40-a12c-4f58-ae91-1fb69246cced</Id>
<EnableVersions>false</EnableVersions>
<Name>CreatePostWhenDocumentIsCreatedInWS</Name>
<States>
<WorkflowState>
<Id>b7aeec89-198d-49af-b8e2-f88103eb0230</Id>
<Name>CreatePost</Name>
<EntryActions>
<Action xsi:type="EvaluateAction">
<Expression>
<![CDATA[
MPSTimelineHelper.AddPost(String.Format("I created a new document: <[{0}]{1}>",
Updatable["Name"],
Updatable["EncodedAbsUrl"]),
Updatable["EncodedAbsUrl"],
Updatable["Author"].User.LoginName,
null,
null)
]]>
</Expression>
<ContinueOnError>false</ContinueOnError>
</Action>
</EntryActions>
</WorkflowState>
</States>
<NewItemTrigger>
<InitialStateId>b7aeec89-198d-49af-b8e2-f88103eb0230</InitialStateId>
<UrlPrefix>/Workspaces</UrlPrefix>
<ContentType>Document</ContentType>
<Tag ProviderId="7df3f749-4b3c-4d4d-a4a0-36c052727af1" Expression=""Workspace"" />
<Recursive>true</Recursive>
</NewItemTrigger>
<EnableMultipleInstances>false</EnableMultipleInstances>
</WorkflowConfiguration>
- The workflow is triggered whenever a new document is created and contains the tag
Workspace
or a child tag of it, also the URL prefix/Workspaces
has to be matched - The workflow then goes to the first state and immediately executes an entry action and is then already finished after that
Some explanations to the action itself:
- As you can see the
AddPost
method, which is described above, is used. - Since Microsoft has a special syntax for links within timeline posts we have write the link in a specific way (
<[LinkName]LinkUrl>
). - We also pass the
Updatable["EncodedAbsUrl"]
astargetId
. This means the timeline posts will be created within the corresponding workspace (if we would passnull
, the timeline post would be created on the user's MySite). - For the
userName
parameter we passUpdatable["Author"]
of the document; this means the post is created as the author of the document. - If desired, you can also introduce your own expression method to create posts, which explicitly accepts an
IUpdatable
object. You could then move the post creation logic into this method (this would simplify the workflow config shown above).
Obviously you can adapt this configuration to almost all other types of list items (e.g. task, issues, etc.). You can either create a new workflow configuration for each "Content Type" or you can also generalize the workflow from above and add a SwitchAction
to determine which post with which details should be created.
Scenario 2: Creating posts when new users are added to a workspace using a custom WorkspaceEventHandler
Even though the workflows are quite powerful, there are some scenarios where they can't be used properly. One of this scenarios is when new users are added to a workspace (using the "Manage Participants" page).
The problem here is, that new members are not added to the workspace list item but instead they are given permission on the web. So even if you would configure a workflow which triggers when an item on the WorkspaceList is changed you would not get notified of the changes (except if there are role tags defined for all roles, because this would then update the tag string, which is stored on the workspace list item).
If you still would like to have posts generated for this, you can create a custom class which implements IWorkspaceEventHandler
. Note that after you created this class you have to register your handler within the workspace template configuration (MPSnow.Workspace.Template.xml
).
An example of a custom workspace event handler can be as follows:
public class MemberAddedWorkspaceEventHandler : IWorkspaceEventHandler
{
private static readonly string addedMembersKey = $"Added{MPSConstants.MemberRoleName}";
public void OnAdding(WorkspaceEventArgs args){}
public void OnAdded(WorkspaceEventArgs args){}
public void OnUpdating(WorkspaceEventArgs args)
{
Workspace beforeWS = new Workspace(args.Workspace.Web.Url);
Workspace afterWS = args.Workspace;
IEnumerable<string> newlyAddedMembers = GetAddedUsers(MPSConstants.MemberRoleName,
beforeWS.UserRoleAssignments,
afterWS.UserRoleAssignments);
args.CustomProperties.Add(addedMembersKey, newlyAddedMembers);
}
public void OnUpdated(WorkspaceEventArgs args)
{
Workspace ws = args.Workspace;
object addedMembersObj;
if (!args.CustomProperties.TryGetValue(addedMembersKey, out addedMembersObj))
{
return;
}
string[] addedMembers = ((IEnumerable<string>) addedMembersObj).ToArray();
if (addedMembers.Length <= 0)
{
return;
}
MPSTimelineHelper.AddPost($"Welcome our new members: {string.Join(", ", addedMembers.Select(l => $"@[{l}]"))}",
ws.Web.Url,
((AccountChoiceItem) ws["Editor"]).LoginName,
null,
null);
}
public static IEnumerable<string> GetAddedUsers(string roleName,
UserRoleAssignments beforeAssignments,
UserRoleAssignments afterAssignments)
{
List<string> beforeLoginNames = beforeAssignments[roleName];
return afterAssignments[roleName].Where(l => !beforeLoginNames.Contains(l));
}
}
Explanations:
- In the
OnUpdating
method we reopen the already opened workspace to get the workspace (and all it's properties) before it has been changed. - We then compare if new users with the role
Member
were added. If so, we add these users to theCustomProperties
of theWorkspaceEventArgs
(the eventArgs are automatically passed on to theOnUpdated
method). - In the
OnUpdated
method we then check if there are any newly added users in theCustomProperties
. If so, we create a timeline post. - Note, that we could also have created the post within the
OnUpdating
method - however this is not 100% correct, since it could happen that an error occurs while updating the workspace and the workspace is not really updated. In this case we would have created a timeline post which contains wrong information.
Conclusion
With the help of the new AddPost
method additional timeline posts can be created from various places.
The scenarios described above describe only two places where this method can be used. However, you can use the method from any other place (e.g. from a form).
If you have any questions please post them in the comments below.