Dave Burke : Freelance .NET Web Developer specializing in Online Communities

In lieu of a Community Server UserList SortBy "Points" Property

One of my Community Server projects is very User Points-centric.  More of my clients are asking for integrated points-based functionality in their communities, and I am starting to see how a rich points API would add a lot of value to Community Server.  I know there's been more work done on Points in CS2008.5 by the smart guys on the CS Core Team, and I'm looking forward to building cool features on it.  But there's one small item still missing in Community Server CS2008.5 that would make a lot of peoples' lives a bit brighter: a SortBy="Points" QueryOverrides property option for the UserList control.

I needed to generate a UserList sorted by points this week.  It was one of those things you think is Community Server Cake until you discover it's an afternoon.  I didn't tell my client it would be cake as I often mistakenly do, so I was in the clear.

After discovering there was indeed no SortBy.Points option, I figured I had two roads I could take with this.  1) Generate a DBVTUser Chameleon control set with my CodeSmith templates (DBVTUserData, DBVTUserList, etc.) with the DBVTUserList's DataSource being a point-sorted UserSet from a single SQL Data Provider call, or 2) take the opportunity to explore "the Community Server Way." And when I say "opportunity," I really mean it.  Option #1 would have been quicker, but walking through the CS source in #2 is always more enlightening. 

The Chameleon HTML would have been similar whether I chose path #1 or #2, but getting there was the fun. 



I won't bore you with the details of the journey, but scenic points along the way included custom UserQuery, UserQueryType, and UserSorter objects, as well as a Points-enhanced users.Filter() method.

This is what we're after in the UserList DataSource, an attractive, ample-breasted UserSet of Active Users and filtered by a new Points-aware QueryType object.  We couldn't interject a simple DBVTSortBy.Points here because CommunityServer.UserQuery is the baseQuery of the UserList's UserQuery. A CS.UserQuery.SortBy = this.DBVTSortBy wouldn't cut object casting muster. That's okay. UserQueryType can do the job.


 

We need to pass our UserSet to our local equivalent of CommunityServer.UserSorter, but we need to filter it along the way mostly to add paging goodness. 



The fact that the User object contains a Points property makes it easy to modify a custom CommunityServer.UserSorter class to compare users by their Points property.



I like simple, and this solution, though it works great, ain't it. Perhaps someone smarter than me can bring to light some detour I followed or a course I hadn't considered for simplicity sake.  I don't know though.  Some things in Community Server are just fricken' hard.

Comments (9) | Post RSS RSS comment feed

Posted on 9/19/2008 7:30:04 PM by Dave Burke
Categories: Community Server
Tags: no tags for this post

Related posts

Comments (9) -

9/19/2008 8:50:37 PM Permalink

Good to know - and I agree some things in Community Server are hard to get around

Kevin Tunis United States |

9/19/2008 9:10:31 PM Permalink

Kevin, Thanks for relating and confirming I'm not alone.  It's really funny how some things in CS can be drop-dead simple and others that you'd think should be simple are adventures in coding.  

p.s. I'm enjoying your Tweets!

Dave Burke United States |

9/20/2008 5:53:53 AM Permalink

Have you had a look a CustomQueryControls - they're a nice feature of CS2008.

<QueryOverrides>
   <DBVT:SortByUserPointsQuery runat="server" />
</QueryOverrides>

I used a custom query control to sort posts in order of the forum they came from so I could display an improved Active Topics page - see nintendowiikly.com/.../?Sort=SortOrder as an example.

Alex United Kingdom |

9/20/2008 6:13:59 AM Permalink

CustomQueryControls?  Afscrome, your Community Server expertise knows no bounds!  I'll definitely check into it.  Sounds like something that will become a part of my toolset.  Serves me right for spending so much time in CS2007.

Dave Burke United States |

9/20/2008 6:32:38 AM Permalink

Or, even use the existing CustomQueryImplementation control and implement inline --

<script runat="server">
public List<User> PointsQuery(object query, out int totalResults)
{
  List<User> users = CSContext.Current.Statistics.ActiveUsers;
  totalResults = users.Count;
  users = CommunityServer.Users.Filter(users, query as CommunityServer.UserQuery);
  users.Sort(delegate(User u1, User u2) { return -u1.Points.CompareTo(u2.Points); });
  return users;
}
</script>

<CSControl:UserList runat="server">
  <QueryOverrides PageSize="10">
    <CSControl:CustomQueryImplementation runat="server" OnExecute="PointsQuery" />
  </QueryOverrides>
</CSControl:UserList>

Ben Tiedt United States |

9/20/2008 6:39:06 AM Permalink

I appologize... to properly support paging, the following implementation of PointsQuery should be used:

public List<User> PointsQuery(object query, out int totalResults)
{
    List<User> users = CSContext.Current.Statistics.ActiveUsers;

    totalResults = users.Count;
    users.Sort(delegate(User u1, User u2) { return -u1.Points.CompareTo(u2.Points); });
    
    CommunityServer.UserQuery userQuery = query as CommunityServer.UserQuery;
    if (userQuery.PageSize > 0 && users.Count > userQuery.PageSize)
    {
        int start = userQuery.PageSize * userQuery.PageIndex;
        if (start > users.Count)
            start = 0;

        int length = userQuery.PageSize;
        if (start + length > users.Count)
            length = users.Count - start;

        users = users.GetRange(start, length);
    }
  
    return users;
}

Ben Tiedt United States |

9/20/2008 7:15:45 AM Permalink

Ben, One word on your two posts.  WOW!  I'm going to study these closely, because they provide more good tips than just to address my SortBy issue.  Thanks so much!

Dave Burke United States |

10/7/2008 3:07:51 AM Permalink

Hey Guys, am using Ben's solution above but am getting an error, which is probably a very simple issue to fix -

The type or namespace name 'User' could not be found (are you missing a using directive or an assembly reference?)

Any pointers at all please?

Many thanks

Chris

Chris |

10/7/2008 3:26:15 AM Permalink

hey guys - solved it thanks!

Chris |

Pingbacks and trackbacks (1)+


Powered by BlogEngine.NET 2.0.0.36
Theme by Dave Burke