29

This morning I flagged something on one of the sites where I have fairly low rep. Now I can't remember which site it was. I've checked my flag history on about half of them, even editing the URL for the site where I have no helpful flags, and I can't find this flag. I've been to my network profile and looked at the Activity tab, but it only shows public things like asking, answering, commenting, editing, and reviewing.

Is there a way to see my flagging history across sites? Can we have such a feature, if it's not possible?

2
  • Not out of the box. Userscript might be handy for this though. Commented May 26, 2015 at 19:57
  • 2
    Probably a bit late now, but I generally find just checking my browser history to be useful in these situations; a rarely-visited site will stick out like a sore thumb.
    – Shog9
    Commented Jun 1, 2015 at 22:52

2 Answers 2

20
+50

I'm sorry it took a little longer than I anticipated but I'm in the 6-8 days range so....

tl;dr; You can't see your flagging history across sites

There is no current functionality on your account (network profile) that let you see all your flags across all sites. As flags are private this info is also not available in the Stack Exchange Data Explorer. Looking at the StackAPI it turns out that even that endpoint keeps the flags private. As a consequence users of the native Android and iOS apps are not able to check their flag status in the app (this is confirmed by @ShadowWizard)

That leaves only one option to get this solved today: (web)scraping. It is not hard to do but becomes a challenge if the pages you need to scrape are behind a login, which is true for the flag-summary page.

I have ventured into three directions. The first was an userscript. The cross-site scripting security measures didn't make this option feasible at all. The second was a commandline tooling solution. The third a c# solution.

All here presented solutions require an Stack Exchange account. Figuring out how to authenticate with Google/facebook or any other (open)id provider is left for future revisions.

Command line

The tool curl is available on several platforms, including windows. I wrote a small windows command script that for a particular site:

  1. does an initial get of the users/login route
  2. gets the o so important fkey
  3. posts the username and the password AND the fkey to users/login
  4. get the /users/flag-summary

Curl is capable in writing its output to a file and that is basically where I stopped. I couldn't find a quick and reliable way without adding extra tools to parse the html result and transform the data into information. Here is the script in all its glory:

set [email protected]
set [email protected]

rem output from SEDE query
rem https://data.stackexchange.com/stackoverflow/query/321563/find-all-userids-across-databases-for-an-account-id

call :singlesite https://meta.stackexchange.com 269324 
call :singlesite https://stackoverflow.com 3972324 
    
rem end output from sede query
goto :EOF

:singlesite
curl -k -c so.cookies -o login.html %1/users/login 
findstr /C:"input type=\"hidden\" name=\"fkey\"" login.html > fkey.txt

for /F "delims==> tokens=4"   %%a in (fkey.txt) do  call :fkeyp "%%a"

curl -v -L -k -c so.cookies -o login-post.html -d fkey=%fkey% --data-urlencode email%SEEmail% --data-urlencode password%SEPwd% %1/users/login  

curl  -v -k -b so.cookies -o %2-flags.html %1/users/flag-summary/%2

goto :EOF

:fkeyp
set p1=%1
set fkey=%p1:"=%
rem echo %fkey%
goto :EOF

For the script to work properly you need to store your username in a text called se-user.txt and your password in se-pwd.txt. You need to run this SEDE query with your own accounted (found on your network profile) so the script only scrapes sites that you have an account on.

C# tooling

As the parsing and transformation became an obstacle I switched to a c# program where I could use CsQuery. I will not include all details here, I created a github repository for that. A couple of things to point out:

To get the associated accounts we can leverage the StackAPI:

/// <summary>
/// Call the StackApi https://api.stackexchange.com/docs/associated-users
/// </summary>
/// <param name="accountid">your account id</param>
/// <returns>network-users</returns>
public List<network_user> GetAssociatedAccounts(int accountid)
{
    var users = new List<network_user>();
    using( var wc = new EnhancedWebclient() )
    {
        var serializer = new DataContractJsonSerializer(typeof(Wrapper));

        using (var ms = new MemoryStream(
            wc.DownloadData(
                String.Format("https://api.stackexchange.com/2.2/users/{0}/associated?pagesize=100&filter=!6PboxJ(eCNnSz", accountid))))
        {
            var wrapper = (Wrapper) serializer.ReadObject(ms);
            foreach(var user in wrapper.items)
            {
                users.Add(user);
            }
        }
    }
    return users;
}

and the fetching, parsing and transforming of the flag-summary:

/// <summary>
/// Visit flag-summary for a user
/// </summary>
/// <param name="user">the network user</param>
/// <returns>all flags on the first page</returns>
public List<Flag> GetFlags(network_user user)
{
    var flags = new List<Flag>();
    // get the flag-summary page and CQ 
    var flagSummary = CQ.Create(
        Get(String.Format(
                "{0}/users/flag-summary/{1}", 
                user.site_url, 
                user.user_id)));
    // itererate over each flaggesd post
    flagSummary
        .Find("#mainbar div.flagged-post")
        .Each(ele => {
            // handle a single post
            var flagdata = new Flag();
            
            var flagpost = CQ.Create(ele);
            // the flagged post
            var post = flagpost.Find("div.answer-link a");
            flagdata.Url = user.site_url + post.Attr("href");
            flagdata.Title = post.Text();

            // the OP (and date)
            var op = flagpost.Find("div.post-user-info span").Attr("title");
            DateTime creationdate;
            DateTime.TryParse(op, out creationdate);
            flagdata.CreationDate = creationdate;

            // spam flags look different
            // our own flag data
            var me = flagpost.Find("div.cbt");
            var time = me.Find("span.relativetime").Attr("title");
            DateTime flagdate;
            DateTime.TryParse(time, out flagdate);
            flagdata.FlagDate = flagdate;

            // in the collection
            flags.Add(flagdata);
        });

    return flags;
}

It is all controlled by a simple commandline tool that takes 3 arguments (or an userinfo.user file)

const int username = 0;
const int password = 1;
const int accountid = 2;

// ONLY WORKS WITH AN STACK EXCHANGE ID!
var client = new ClientStack(args[username], args[password]);
client.Login();

// collect all flags
var flags = new List<Flag>();

// ask the api to give all associated accounts
foreach (var user in client.GetAssociatedAccounts(Int32.Parse(args[accountid])))
{   
    // login per site
    client.LoginSite(user.site_url);

    // visit the first page of flags
    flags.AddRange(client.GetFlags(user));
}

// order all flags, most recent first
var recentFlags = from flag in flags
                  orderby flag.FlagDate descending
                  select flag;

// output to the console
foreach(var recentFlag in recentFlags)
{
    Console.WriteLine("\"{0}\",\"{1}\",\"{2}\"",recentFlag.FlagDate, recentFlag.CreationDate, recentFlag.Url);
}

If run the results are ordered by most recent flagged posts (my test account doesn't have spam flags and those look different in the html but I don't expect this to break). The output is comma separated so it's easy to be consumed by Excel.

The result will look like this:

excel flag-summary network wide

Conclusion

It is quite an hassle to get your flagged-posts networkwide. Although the presented solution do work to some degree, a feature request to implement this in the site or in the API would be very helpful.

19
+150

I wrote a userscript that generates a network wide flag summary for you. (It doesn't list single flagged posts though). It's available on StackApps.

If you are logged into the Stack Exchange network and you have this script installed, you can visit the new flags tab in your Stack Exchange profile.

The script scans your network profile for all Stack Exchange accounts you created. For each account it tries to access the flag summary page. Since that page is private, i.e. only visible to you (and mods), you need be logged in. From there it extracts the flag summary of the individual site and sums it all up in a generated table.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .