This task will create monthly categories for {{OTRS pending}} and {{OTRS received}}. It will check for templates missing a date and add it to them.
public class OtrsDatedFiler : BBotBase
{
/// <summary>
/// Gets the name for this job
/// </summary>
/// <returns></returns>
public override string GetJobName()
{
return "OTRS dated filer";
}
/// <summary>
/// Both tasks will do this many. (If you want 50 edits, make this 25.)
/// </summary>
public int MaximumImagesToProcess = 1000;
/// <summary>
/// This function creates the requested category if it does not already exist
/// </summary>
/// <param name="CategoryName"></param>
/// <param name="StarterTemplate"></param>
/// <returns></returns>
public bool CreateCatIfNeeded(ref Site site, Page pgUserspaceTest, String CategoryName, String StarterTemplate)
{
try
{
// Make sure that this month's and next month's dated categories exist
Page cat = new Page(site, CategoryName);
cat.Load();
SleepApiDelay();
if (!cat.Exists())
{
cat.text = StarterTemplate;
if (UserspaceTest)
{
pgUserspaceTest.text += "|-\r\n| [[:" + cat.title + "]] || ~~~~~ || <pre>" + cat.text.Substring(0, Math.Min(300, cat.text.Length)) + "</pre>\r\n";
pgUserspaceTest.Save("Creating monthly category", false);
}
else
{
cat.Save(cat.text, "Creating monthly category", false);
}
SleepApiDelay();
LogToEventLog(ref site, MessageType.Informational, "Created category [[:" + CategoryName + "]] using <code><nowiki>" + StarterTemplate + "</nowiki></code>.", null);
}
SleepApiDelay();
return true;
}
catch (Exception ex)
{
LogToEventLog(ref site, MessageType.Informational, "Error creating category [[:" + CategoryName + "]] using <code><nowiki>" + StarterTemplate + "</nowiki></code>.", ex);
return false;
}
}
/// <summary>
/// This function will add the date to the requested
/// </summary>
/// <param name="site"></param>
/// <param name="pg"></param>
/// <param name="strRegex"></param>
/// <param name="strTagName">"OTRS Pending", "OTRS received", etc</param>
/// <param name="pgUserspaceTest">If this is a userspace test, the page on which that is being conducted</param>
/// <param name="strCategoryFormatString">Format string to be used if we need to create the category</param>
/// <param name="StarterTemplate">Starter template, if we need to create the category</param>
/// <returns>True if the tag was modified, false otherwise</returns>
public bool DateTag(Site site, Page pg, String strRegex, String strTagName, Page pgUserspaceTest, String strCategoryFormatString, String StarterTemplate)
{
try
{
// If this is a user talk base page, then {{OTRS pending}} has probably been added to the wrong place
if (pg.title.ToLower().StartsWith("user talk:") && !pg.title.Contains("/"))
{
LogToEventLog(ref site, MessageType.Error, "Error: [[" + pg.title + "]] has a {{tl|" + strTagName + "}} tag. " +
"This tag should only be placed on file pages or article talk pages (including talk pages of draft articles). " +
"It should not be placed directly on user talk pages.", null);
return false;
}
pg.Load();
// Find the OTRS pending tag
Match match = Regex.Match(pg.text, strRegex, RegexOptions.IgnoreCase);
if (null != match && 0 < match.Length)
{
// Remove the tag from the string
String strNewText = "";
if (0 < match.Index)
{
strNewText = pg.text.Substring(0, match.Index);
}
// This is the tag, without the close
String strTag = pg.text.Substring(match.Index, match.Length).Replace("}}", "");
// If the tag appears to already have a date, then move on
if (strTag.Contains("date") ||
strTag.Contains("year") ||
strTag.Contains("month") ||
strTag.Contains("day"))
{
LogToEventLog(ref site, MessageType.Error, "Wanted to add a date to the " + strTagName + " tag of [[:" + pg.title + "]], but it seems to already have one. Maybe the page has multiple tags?", null);
return false;
}
// Grab the timestamp (it gets blown away once we save)
DateTime dtmTimestamp = pg.timestamp;
// Add the date
strTag += "|year=" + dtmTimestamp.Year.ToString() +
"|month=" + dtmTimestamp.Month.ToString("00") +
"|day=" + dtmTimestamp.Day.ToString("00") + "}}";
strNewText += strTag;
// Add everything after the tag
if (match.Index + match.Length < pg.text.Length - 1)
{
strNewText += pg.text.Substring(match.Index + match.Length);
}
// Trim whitespace
strNewText = strNewText.Trim();
String strEditSummary = "Adding date to [[Template:" + strTagName + "|" + strTagName + "]] tag.";
if (UserspaceTest)
{
pgUserspaceTest.text += "|-\r\n| [[:" + pg.title + "]] || ~~~~~ || <pre>" +
pg.text.Substring(0, Math.Min(1500, pg.text.Length)) +
"</pre> || <pre>" + strNewText.Substring(0, Math.Min(1500, strNewText.Length)) + "</pre>\r\n";
pgUserspaceTest.Save(strEditSummary, false);
}
else
{
pg.Save(strNewText, strEditSummary, false);
}
// Now, if that tag is more than a month ago, we need to check the category name to see if it exists
if ((DateTime.Now - dtmTimestamp).TotalDays > 30)
{
CreateCatIfNeeded(ref site, pgUserspaceTest,
String.Format(strCategoryFormatString, dtmTimestamp),
String.Format(StarterTemplate, dtmTimestamp));
}
return true;
}
else
{
LogToEventLog(ref site, MessageType.Error, "Error: though [[:" + pg.title + "]] is categorized as having an undated {{tl|" + strTagName + "}} tag, the tag could not be located.", null);
}
}
catch (Exception ex)
{
LogToEventLog(ref site, MessageType.Error, "Error dating " + strTagName + " tag for page [[:" + pg.title + "]].", ex);
}
return false;
}
/// <summary>
/// This function will perform the task
/// </summary>
public void PerformTask()
{
// OTRS pending categories
const String csOtrsPendingUnknownDateCategoryName = "Category:Items pending OTRS confirmation of permission as of unknown date";
const String csDatedOtrsPendingCategoryFormatString = "Category:Items pending OTRS confirmation of permission as of {0:MMMM yyyy}";
String strDatedOtrsPendingCategoryThisMonth = String.Format(csDatedOtrsPendingCategoryFormatString, DateTime.Now);
String strDatedOtrsPendingCategoryNextMonth = String.Format(csDatedOtrsPendingCategoryFormatString, DateTime.Now.AddMonths(1));
const String csDatedOtrsPendingCategoryStarterString = "{{{{subst:OTRS pending subcat starter|date={0:yyyy-MM-dd}}}}}";
String strDatedOtrsPendingCategoryStarterThisMonth = String.Format(csDatedOtrsPendingCategoryStarterString, DateTime.Parse(DateTime.Now.AddMonths(1).ToString("MM-01-yyyy")).AddDays(-1));
String strDatedOtrsPendingCategoryStarterNextMonth = String.Format(csDatedOtrsPendingCategoryStarterString, DateTime.Parse(DateTime.Now.AddMonths(2).ToString("MM-01-yyyy")).AddDays(-1));
// OTRS received categories (files)
const String csOtrsReceivedFilesUnknownDateCategoryName = "Category:Wikipedia files with unconfirmed permission received by OTRS as of unknown date";
const String csDatedOtrsReceivedFilesCategoryFormatString = "Category:Wikipedia files with unconfirmed permission received by OTRS as of {0:MMMM yyyy}";
String strDatedOtrsReceivedFilesCategoryThisMonth = String.Format(csDatedOtrsReceivedFilesCategoryFormatString, DateTime.Now);
String strDatedOtrsReceivedFilesCategoryNextMonth = String.Format(csDatedOtrsReceivedFilesCategoryFormatString, DateTime.Now.AddMonths(1));
const String csDatedOtrsReceivedFilesCategoryStarterString = "{{{{subst:OTRS received subcat starter|date={0:yyyy-MM-dd}|type=files}}}}";
String strDatedOtrsReceivedFilesCategoryStarterThisMonth = String.Format(csDatedOtrsReceivedFilesCategoryStarterString, DateTime.Parse(DateTime.Now.AddMonths(1).ToString("MM-01-yyyy")).AddDays(-1));
String strDatedOtrsReceivedFilesCategoryStarterNextMonth = String.Format(csDatedOtrsReceivedFilesCategoryStarterString, DateTime.Parse(DateTime.Now.AddMonths(2).ToString("MM-01-yyyy")).AddDays(-1));
// OTRS received categories (pages)
const String csOtrsReceivedPagesUnknownDateCategoryName = "Category:Wikipedia pages with unconfirmed permission received by OTRS as of unknown date";
const String csDatedOtrsReceivedPagesCategoryFormatString = "Category:Wikipedia pages with unconfirmed permission received by OTRS as of {0:MMMM yyyy}";
String strDatedOtrsReceivedPagesCategoryThisMonth = String.Format(csDatedOtrsReceivedPagesCategoryFormatString, DateTime.Now);
String strDatedOtrsReceivedPagesCategoryNextMonth = String.Format(csDatedOtrsReceivedPagesCategoryFormatString, DateTime.Now.AddMonths(1));
const String csDatedOtrsReceivedPagesCategoryStarterString = "{{{{subst:OTRS received subcat starter|date={0:yyyy-MM-dd}|type=pages}}}}";
String strDatedOtrsReceivedPagesCategoryStarterThisMonth = String.Format(csDatedOtrsReceivedPagesCategoryStarterString, DateTime.Parse(DateTime.Now.AddMonths(1).ToString("MM-01-yyyy")).AddDays(-1));
String strDatedOtrsReceivedPagesCategoryStarterNextMonth = String.Format(csDatedOtrsReceivedPagesCategoryStarterString, DateTime.Parse(DateTime.Now.AddMonths(2).ToString("MM-01-yyyy")).AddDays(-1));
// Connect to Wikipedia
Site site = TryToConnect("https://en.wikipedia.org", Properties.Settings.Default.BotUserName, Properties.Settings.Default.BotPassword);
// Use a separate connection for our API calls - this seems to time out less frequently
Site site2 = TryToConnect("https://en.wikipedia.org", Properties.Settings.Default.BotUserName, Properties.Settings.Default.BotPassword);
// Grab the list of pages in the category
PageList pl = new PageList(site);
pl.FillAllFromCategory(csOtrsPendingUnknownDateCategoryName);
SleepApiDelay();
if (UserspaceTest)
{
LogToEventLog(ref site, MessageType.Start, "B-Bot \"OTRS Dated Filer\" process now commencing <font color='red'>'''IN TEST MODE'''</font>. This process checks pages from [[:"
+ csOtrsPendingUnknownDateCategoryName + "]] to add the date stamp where it is missing.", null);
}
else
{
LogToEventLog(ref site, MessageType.Start, "B-Bot \"OTRS Dated Filer\" process now commencing. This process checks pages from [[:"
+ csOtrsPendingUnknownDateCategoryName + "]] to add the date stamp where it is missing.", null);
}
int intPagesTagged = 0;
Page pgUserspaceTest = new Page(site, Properties.Settings.Default.UserspaceTestPage);
// Add the userspace test header
if (UserspaceTest)
{
pgUserspaceTest.text = "Now beginning OTRS Dated Filer task on " + DateTime.Now.ToString() + " (local time) ...\r\n\r\n";
pgUserspaceTest.text += "{| class=\"wikitable sortable\"\r\n|-\r\n! Page !! Timestamp !! Former text !! Proposed text\r\n";
pgUserspaceTest.Save();
}
SleepApiDelay();
// Make sure that this month's and next month's dated categories exist
CreateCatIfNeeded(ref site, pgUserspaceTest, strDatedOtrsPendingCategoryThisMonth, strDatedOtrsPendingCategoryStarterThisMonth);
SleepApiDelay();
CreateCatIfNeeded(ref site, pgUserspaceTest, strDatedOtrsPendingCategoryNextMonth, strDatedOtrsPendingCategoryStarterNextMonth);
SleepApiDelay();
// Loop through each page
foreach (Page pgCurrentImagePage in pl)
{
// Ignore things that are not in a valid namespace
if (pgCurrentImagePage.GetNamespace() != 6 && // file
pgCurrentImagePage.GetNamespace() != 119 && // draft talk
pgCurrentImagePage.GetNamespace() != 118 && // draft
pgCurrentImagePage.GetNamespace() != 3 && // user talk
pgCurrentImagePage.GetNamespace() != 5) // WP: talk
{
continue;
}
// Find the OTRS pending tag
DateTag(site, pgCurrentImagePage, @"\{\{\s*(template\:|)otrs(\s|-|)pending([^\{^\}]*|)\}\}", "OTRS pending", pgUserspaceTest, csDatedOtrsPendingCategoryFormatString, csDatedOtrsPendingCategoryStarterString);
SleepApiDelay();
if (BotStop(site))
{
LogToEventLog(ref site, MessageType.Error, "I was ordered to abort.", null);
return;
}
intPagesTagged++;
SleepApiDelay();
if (intPagesTagged >= MaximumImagesToProcess)
{
break;
}
}
LogToEventLog(ref site2, MessageType.Informational, "B-Bot finished adding OTRS pending dates. " + intPagesTagged.ToString() + " pages were edited. Will now check category [[:" + csOtrsReceivedFilesUnknownDateCategoryName + "]]", null);
// Now, do OTRS received (files)
// Grab the list of pages in the category
pl = new PageList(site);
pl.FillAllFromCategory(csOtrsReceivedFilesUnknownDateCategoryName);
SleepApiDelay();
intPagesTagged = 0;
SleepApiDelay();
// Make sure that this month's and next month's dated categories exist
CreateCatIfNeeded(ref site, pgUserspaceTest, strDatedOtrsReceivedFilesCategoryThisMonth, strDatedOtrsReceivedFilesCategoryStarterThisMonth);
SleepApiDelay();
CreateCatIfNeeded(ref site, pgUserspaceTest, strDatedOtrsReceivedFilesCategoryNextMonth, strDatedOtrsReceivedFilesCategoryStarterNextMonth);
SleepApiDelay();
// Loop through each page
foreach (Page pgCurrentImagePage in pl)
{
// Find the OTRS pending tag
DateTag(site, pgCurrentImagePage, @"\{\{\s*(template\:|)otrs(\s|-|)(received|insufficient)([^\{^\}]*|)\}\}", "OTRS received", pgUserspaceTest, csDatedOtrsReceivedFilesCategoryFormatString, csDatedOtrsReceivedFilesCategoryStarterString);
SleepApiDelay();
if (BotStop(site))
{
LogToEventLog(ref site, MessageType.Error, "I was ordered to abort.", null);
return;
}
intPagesTagged++;
SleepApiDelay();
if (intPagesTagged >= MaximumImagesToProcess)
{
break;
}
}
LogToEventLog(ref site2, MessageType.Informational, "B-Bot finished adding OTRS received dates to files. " + intPagesTagged.ToString() + " files were edited. Will now check category [[:" + csOtrsReceivedPagesUnknownDateCategoryName + "]]", null);
intPagesTagged = 0;
// Now OTRS received pages
// Grab the list of pages in the category
pl = new PageList(site);
pl.FillAllFromCategory(csOtrsReceivedPagesUnknownDateCategoryName);
SleepApiDelay();
// Make sure that this month's and next month's dated categories exist
CreateCatIfNeeded(ref site, pgUserspaceTest, strDatedOtrsReceivedPagesCategoryThisMonth, strDatedOtrsReceivedPagesCategoryStarterThisMonth);
SleepApiDelay();
CreateCatIfNeeded(ref site, pgUserspaceTest, strDatedOtrsReceivedPagesCategoryNextMonth, strDatedOtrsReceivedPagesCategoryStarterNextMonth);
SleepApiDelay();
// Loop through each page
foreach (Page pgCurrentImagePage in pl)
{
// Find the OTRS pending tag
DateTag(site, pgCurrentImagePage, @"\{\{\s*(template\:|)otrs(\s|-|)(received|insufficient)([^\{^\}]*|)\}\}", "OTRS received", pgUserspaceTest, csDatedOtrsReceivedPagesCategoryFormatString, csDatedOtrsReceivedPagesCategoryStarterString);
SleepApiDelay();
if (BotStop(site))
{
LogToEventLog(ref site, MessageType.Error, "I was ordered to abort.", null);
return;
}
intPagesTagged++;
SleepApiDelay();
if (intPagesTagged >= MaximumImagesToProcess)
{
break;
}
}
LogToEventLog(ref site2, MessageType.Informational, "B-Bot finished adding OTRS received dates to pages. " + intPagesTagged.ToString() + " pages were edited.", null);
LogToEventLog(ref site2, MessageType.Finish, "B-Bot OTRS Dated Filer process completed.", null);
if (UserspaceTest)
{
pgUserspaceTest.text += "|}\r\n";
pgUserspaceTest.Save();
}
}