Source Code:
As is the case with any application written using Soapi for api access, the code needed to get the data you want from the API is the least amount of code you have to write and by far the easiest to understand.
Here is the source code for single page of the application. (There are several helper classes like value converters to format dates, but they are not relevant)
//
// Project: SOAPI
// http://soapics.codeplex.com
// http://stackapps.com/questions/386
//
// Copyright 2010, Sky Sanders
// Licensed under the GPL Version 2 license.
// http://soapics.codeplex.com/license
//
// Date: Aug 08 2010
// API ver 1.0 rev 2010.0709.04
//
#region
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using Soapi;
using Soapi.Domain;
using Soapi.Net;
using Soapi.Parameters;
#endregion
namespace FindUser
{
public partial class MainPage
{
#region Constants
private const string ApiKey = "qgAq_KfDu0KYzlNG-qaTuw";
#endregion
#region Fields
private readonly ApiContext _context;
private ObservableCollection<SiteListItem> _sitesToSearch;
#endregion
#region Constructors
public MainPage()
{
InitializeComponent();
SearchButton.IsEnabled = false;
FuqqinBusyIndicator.IsBusy = true;
FuqqinBusyIndicator.BusyContent = "Initializing";
RequestCache.Instance.DefaultDuration = new TimeSpan(0, 0, 0, 1);
// set up an ApiContext
_context = new ApiContext(ApiKey);
_context.Initialized += (e, s) => Dispatcher.BeginInvoke(() =>
{
_sitesToSearch = new ObservableCollection<SiteListItem>();
_context.Sites.ForEach(site =>
{
if (site.ApiEndpoint.IndexOf("stackauth") == -1)
{
// _sitesToSearch.Add(new SiteListItem { Enabled = true, Site = site });
// as per steffen's suggestion
_sitesToSearch.Add(new SiteListItem
{
Enabled = site.State != SiteState.Linked_Meta,
Site = site
});
}
});
FuqqinBusyIndicator.IsBusy = false;
});
_context.Initialize(true);
}
#endregion
#region Private Methods
private void EnsureSiteButtonState()
{
SearchButton.IsEnabled = SearchTermTextBox.Text.Length > 2 && _sitesToSearch.Any(ss => ss.Enabled);
}
private void SearchButtonClick(object sender, RoutedEventArgs e)
{
FuqqinBusyIndicator.IsBusy = true;
FuqqinBusyIndicator.BusyContent = "Spinning up....";
string searchTerm = SearchTermTextBox.Text;
var users = new List<User>();
var sites = _sitesToSearch.Where(s => s.Enabled).Select(s => s.Site).ToList();
var state = new CounterState { _count = sites.Count };
ThreadPool.QueueUserWorkItem(o =>
{
// enumerate sites to be searched
foreach (var site in sites)
{
// I tried running each site in parallel but
// it just all goes pear shaped and it actually
// takes longer.
string siteName = site.Name;
Dispatcher.BeginInvoke(
() =>
{
FuqqinBusyIndicator.BusyContent =
String.Format("searching {0} ({1} sites remaining)", siteName, state._count);
});
// Get a list of all users that match the criteria
var possibleMatches = site
.Users
.Filter(searchTerm)
.PageCount(-1)
.Sort(UserSort.Name).ToList();
// And that is it. The rest of the code is related
// to presenting the data in an appealing format
var gate = new AutoResetEvent(false);
foreach (var user in possibleMatches)
{
users.Add(user);
}
state._count--;
if (state._count == 0)
{
Dispatcher.BeginInvoke(() =>
{
UserListView.ItemsSource = users;
FuqqinBusyIndicator.IsBusy = false;
});
}
}
});
}
private void SearchTermTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
EnsureSiteButtonState();
}
private void SitesButtonClick(object sender, RoutedEventArgs e)
{
var ssw = new SiteSelectorWindow { SitesToSearch = _sitesToSearch };
ssw.Closed += (s, ev) =>
{
_sitesToSearch = ssw.SitesToSearch;
EnsureSiteButtonState();
};
ssw.Show();
}
private void SortByActivityButtonClick(object sender, RoutedEventArgs e)
{
UserListView.ItemsSource = UserListView.ItemsSource.Cast<User>().ToList()
.OrderBy(u => u.CreationDate)
.OrderByDescending(u => u.Reputation)
.OrderBy(u => u.DisplayName)
.OrderByDescending(u => u.LastAccessDate);
}
private void SortByMembershipButtonClick(object sender, RoutedEventArgs e)
{
UserListView.ItemsSource = UserListView.ItemsSource.Cast<User>().ToList()
.OrderByDescending(u => u.LastAccessDate)
.OrderByDescending(u => u.Reputation)
.OrderBy(u => u.DisplayName)
.OrderBy(u => u.CreationDate);
}
private void SortByNameButtonClick(object sender, RoutedEventArgs e)
{
UserListView.ItemsSource = UserListView.ItemsSource.Cast<User>().ToList()
.OrderBy(u => u.CreationDate)
.OrderByDescending(u => u.LastAccessDate)
.OrderByDescending(u => u.Reputation)
.OrderBy(u => u.DisplayName);
}
private void SortByRepButtonClick(object sender, RoutedEventArgs e)
{
UserListView.ItemsSource = UserListView.ItemsSource.Cast<User>().ToList()
.OrderBy(u => u.CreationDate)
.OrderByDescending(u => u.LastAccessDate)
.OrderBy(u => u.DisplayName)
.OrderByDescending(u => u.Reputation);
}
private void UserListViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (UserListView.SelectedItem != null)
{
var user = (User)UserListView.SelectedItem;
HtmlPage.Window.Navigate(new Uri(string.Format("{0}users/{1}", user.Site.SiteUrl, user.UserId)),
"__blank");
}
}
#endregion
}
}
_sitesToSearch.Add(new SiteListItem { Enabled = true , Site = site });
to_sitesToSearch.Add(new SiteListItem { Enabled = site.State != SiteState.Linked_Meta, Site = site });
and published.#CC9966
[ ](google.com)