November Happy Hour will be moved to Thursday December 5th.

Magnus Rahl
May 4, 2011
  6674
(2 votes)

Creating feeds in Clubs and for external events

This post actually explains two ideas: Feeds for clubs and (feed) stories for objects external to the EPiServer Community platform.

Aggregating a feed for a Club

The EPiServer Community NewsFeed system is, in it’s vanilla form, very user-centric. Either you aggregate feeds for a particular user (the minifeed) or for a user’s friends (the newsfeed).

A quick recap of the NewsFeed system:

  • The newsfeed aggregates Stories.
  • You as a developer decide how Stories are created when something “happens” in your site, they aren’t auto-generated.
  • A Story stores tuplets of the type actor – action – target, or: someone (“User A”) performed some action on (“commented on”) something (“user B’s blog post”).
  • Stories can have multiple actors and multiple targets. The actors are IAuthors (generally a UserAuthor) and the Targets are Community entities.
  • Stories can have Attachments (actually the are attached to the actor) that are other entities.

 

The key to (more easily) creating a news feed for something other than a user (the actor) is the NewsFeedHandler.GetNewsFeedStoriesByTarget method. As the method name indicates it aggregates stories by their target rather than the actor as is the case when building mini- and newsfeeds. This can be used to create a feed in a Club which for example shows the stories created when users join the Club, because those stories should generally include the Club in it’s targets. “User A joined this club”, could be an interesting piece of information, but what if you want more…

In Wonderland: Targets as “actors”

In a current project the Clubs are not created by site users or moderators which is common, but are created in code to reflect “departments”. So the Clubs could be seen as profiles for the departments just like the user profiles (MyPages).

Without going in to details, the Clubs can even act on their own, which should make them actors in Stories, right? But instead we use the target feed to get those stories. As actor we simply use the Club’s Author (which is a system user since the Clubs are created by the system but have to have an author) and the Club is still the target. But then we stuff whatever is the “real” target of the action in the StoryAttachments:

// Get some club to create a story for
Club club = GetClub();
// Get some entity to attach and some action used for this entity
IEntity realTarget = GetRealTarget();
string action = "MyAction";
// Create attachments to the story
var storyAttachments = new EntityCollection();
storyAttachments.Add(realTarget);
// Use the club's Author as actor
var author = AuthorHandler.Instance.ChangeAuthor(null, club.Author);
// Create the story with attachment
var story = new NewsFeedStory(
    new NewsFeedAction(action, NewsFeedActionCapability.MultipleTargets
                                | NewsFeedActionCapability.MultipleActors),
    author, storyAttachments, club);
// Persist the story to database
NewsFeedHandler.Instance.AddStory(story);

Then we can pull out a feed for the Club using GetNewsFeedStoriesByTarget and render stuff like “Club A [target] posted [action] a new KPI [story attachment]”.

We can even mix these things in the users’ newsfeeds by getting the target feeds for Clubs in which they have memberships. That requires several calls and makes the paging features useless, but as the number of memberships is generally limited and the newsfeed only shows a few items without paging we accepted this performance penalty.

Creating stories for actions outside the Community

Since the departments also use other systems other actions that are of interest to the users can happen to “entities” outside the Community platform. In a deep integration scenario we would create custom Entity Providers for these external entities and either reflect the actual entities in the external systems or create mirror entities in the Community. However, we found that such a deep integration isn’t often needed.

Instead, since the other systems are also web-based we found it was enough to be able to link to the original content/entity in the external system. For this we need only one type of custom entity, and a simple one too. Say hello to the UrlEntity, which only has the string properties Url and Title and is stored in the DDS.

We currently use a scheduled job which polls the external systems for changes and creates stories for the appropriate Club and adds story attachments using the UrlEntity. The code is basically the same as I have already demonstrated, but imagine realTarget created by something like this:

// Pick up the external object to process and create a UrlEntity
var externalObject = GetExternalObjectFromContext();
IEntity realTarget = new UrlEntity(GetUrl(externalObject), GetTitle(externalObject));
realTarget = UrlEntityHandler.Instance.AddEntity(realTarget);

We could save just the URL and instead construct the title by calling the URL or some service related to it, but that would add external calls when rendering. By saving a descriptive text in the entity we add some data but skip external calls in rendering.

Source code

You can find the source code for the UrlEntity can be found in the code section. It is based on the DynamicDataStoreEntity which is distributed in the templates of the Relate 2 R2 package. I chose not to include the classes from there to avoid copyright hassles.

May 04, 2011

Comments

May 4, 2011 09:13 AM

Brilliant! This is exactly the same concept as Facebook Like. All you need is an url, which is the unique identifier. Much simpler than the usual GUIDs that needs to be known by both systems. A lightweight integration that will do the trick in many cases.

patrick.livbom@uppsala.se
patrick.livbom@uppsala.se Aug 2, 2011 04:45 PM

Hi
I have a question that bugs me. I am kinda new to the newsfeedstuff. I want to add to the newsfeed that a blog have a new post. The story should be seen on all users newsfeed where the user have decided to follow that blog (the blogs are not personal, they can have several writers and one owner).

I made a attribute on the blog, containing list of userIds, so when you follow the blog you simply add your userId to the blog. I pick them up and so on but i cannot for my life publish the story to the users newsfeed. i have looked in to the medstore templates but i cannot see how this should be done without having a club as owner to the blog.

private void Writestory(NewsFeedAction action, IEnumerable targets, UserAuthor actor, params IEntity[] attachments)
{
NewsFeedStory story = new NewsFeedStory(action, actor, new EntityCollection(attachments), targets.FirstOrDefault());
story.Targets.Clear();
targets.ToList().ForEach(t => story.Targets.Add(t));

NewsFeed newsFeed = NewsFeedHandler.Instance.GetNewsFeedByUser(actor.User, NewsFeedType.MiniFeed);
NewsFeedHandler.Instance.PublishStory(newsFeed, story);
}

Any help would be appreciated :)

Please login to comment.
Latest blogs
Optimizely SaaS CMS + Coveo Search Page

Short on time but need a listing feature with filters, pagination, and sorting? Create a fully functional Coveo-powered search page driven by data...

Damian Smutek | Nov 21, 2024 | Syndicated blog

Optimizely SaaS CMS DAM Picker (Interim)

Simplify your Optimizely SaaS CMS workflow with the Interim DAM Picker Chrome extension. Seamlessly integrate your DAM system, streamlining asset...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Optimizely CMS Roadmap

Explore Optimizely CMS's latest roadmap, packed with developer-focused updates. From SaaS speed to Visual Builder enhancements, developer tooling...

Andy Blyth | Nov 21, 2024 | Syndicated blog

Set Default Culture in Optimizely CMS 12

Take control over culture-specific operations like date and time formatting.

Tomas Hensrud Gulla | Nov 15, 2024 | Syndicated blog

I'm running Optimizely CMS on .NET 9!

It works 🎉

Tomas Hensrud Gulla | Nov 12, 2024 | Syndicated blog

Recraft's image generation with AI-Assistant for Optimizely

Recraft V3 model is outperforming all other models in the image generation space and we are happy to share: Recraft's new model is now available fo...

Luc Gosso (MVP) | Nov 8, 2024 | Syndicated blog