GuildWiki:Bot tasks/License reminder

Purpose
This bot's purpose is to remind users who have uploaded new images without licensing information to add that information to their images.

Functioning
Unlike other bot tasks, this task would be an ongoing one. Every the bot would scan Special:Newimages (it can compile a list of files created since the last time the bot was run). Any files lacking licensing information will cause the bot to leave the following message on the uploader's talk page:

"Thank you for uploading . Please provide licensing information in accordance with Image use policy and Image license guide to prevent your file from being deleted. This is an automated message from . "

Language
This bot is intended to be programmed and run in Java and use the Java Wiki Bot Framework.

Issues

 * Perhaps this should be its own bot?
 * How often should this run?
 * If a user uploaded multiple files, do they get a message for each?
 * One message listing all images that need licenses found in that run.
 * Can we also check that certain licenses include all fields?
 * Can we also check that images aren't named GW###.jpg or similar?

Code
/** * The following is NOT released under CC 2.0 by-nc-sa license. It may only be used with the expressed consent of the copyright holder(s). * @author Heather Arbiter (c) * @version 1.0 */ import net.sourceforge.jwbf.bots.MediaWikiBot; import net.sourceforge.jwbf.contentRep.mw.SimpleArticle; import org.w3c.dom.*; import javax.xml.parsers.*; import java.util.ArrayList; import java.util.*;

/**TODO: * remove stuff from methods that have specifics for testing. * remember that if there are extra divs (such as a message notice) will throw off GAL_DIV_ONE_ROOT * make sure all exceptions are properly caught/thrown * Correct that it only check the first 48 files. * Use last run date and release this current run date. **/

public class Main { //Used to parse the DOM retrieved from Special:Newimages in various methods static final int GAL_DIV_ONE_ROOT = 11; //number of divs until the first gallery node static final int GAL_DIV_USER = 4; //index user as a child of gallerytext node static final int GAL_DIV_NAME = 1; //index name as a child of gallerytext node static final int GALTEXT_INTERVAL = 4; //number of divs between galtext nodes static final int NUM_FILES_PER_PAGE = 48; //number of files per pageview public static void main(String[] args) throws Exception { MediaWikiBot bot = getNewBot(args[0], args[1]); //String oldDate = getLastRunDate(bot); Document doc = getDocument("http://guildwars.wikia.com/index.php?title=Special:Newimages"); //to get list as off the last run date user: //"http://guildwars.wikia.com/index.php?title=Special:Newimages&from=" + oldDate; NodeList el = doc.getElementsByTagName("div"); ArrayList userList = getUserList(el); ArrayList imageList = getImageList(el); printResultList(userList, imageList); HashMap remindList = getReminderList(bot, userList, imageList); leaveTestSummery(bot, remindList); } /** * Instantiate the bot and log it in. * @param botName username of the bot * @param pass the password for the bot * @return MediaWikiBot the logged in bot */   public static MediaWikiBot getNewBot(String botName, String pass){ try{ MediaWikiBot b = new MediaWikiBot("http://guildwars.wikia.com"); b.login(botName, pass); return b;       }catch(Exception e){ System.out.println("check login info"); return null; }   }        /**     * returns the last edit date from GuildWiki:Bot_tasks/License_reminder * @param b botname * @return the last edit date. */   public static String getLastRunDate(MediaWikiBot b) throws Exception{ SimpleArticle sa = new SimpleArticle(b.readContent("GuildWiki:Bot_tasks/License_reminder")); String s = sa.getText; int x = s.indexOf("==Last run=="); x = x + 13; //cut off "==last run==\n" s = s.substring(x); s.trim; return s;   } /**    * creates a new DOM document (to help parse special pages) * @param pageName the name of the page you want to parse * @return new DOM document based on given pagename * @throws java.lang.Exception */   public static Document getDocument(String pageName) throws Exception{ DocumentBuilderFactory domBF = DocumentBuilderFactory.newInstance; DocumentBuilder domB = domBF.newDocumentBuilder; return domB.parse(pageName); }   /**     * leaves a message on the given user's talk page. * @param b the current bot * @param userName userName of page to leave message one (EXCLUDING namespace) * @throws java.lang.Exception */   public static void leaveMessage(MediaWikiBot b, String userName) throws Exception{ SimpleArticle sa = new SimpleArticle(b.readContent("User talk:" + userName)); sa.addText("\n==Test edit==\n" +               "You are receiving this edit as a test. " +                "This is a test edit from ~"); sa.setEditSummary("test edit using JWBF"); sa.setMinorEdit(true); b.writeContent(sa); }       /**     * leaves a message on the given user's talk page. * @param b the current bot * @param userName userName of page to leave message one (EXCLUDING namespace) * @param msg the message to leave * @throws java.lang.Exception */   public static void leaveMessage(MediaWikiBot b, String userName, String msg) throws Exception{ SimpleArticle sa = new SimpleArticle(b.readContent("User talk:" + userName)); sa.addText(msg +               " This is an automated message from ~ "); sa.setEditSummary("Test edit using JWBF"); sa.setMinorEdit(true); b.writeContent(sa); }   /**     * constructs a list of all usernames. * @param n the nodelist of all divs * @return an ArrayList consisting of all usernames who recently uploaded files */   public static ArrayList getUserList(NodeList n){ ArrayList list = new ArrayList; for(int i=0; i<GALTEXT_INTERVAL*NUM_FILES_PER_PAGE-4; i = i+GALTEXT_INTERVAL){ try{ list.add(getUserName(n.item(GAL_DIV_ONE_ROOT + i))); }catch(Exception e){ System.out.println(e.toString + " thrown at i = " + i + ". User list truncated."); return list; }       }        return list; }   /**     * constructs a list of all images * @param n the nodelist of all divs * @return an ArrayList consisting of all images who were recently uploaded */   public static ArrayList getImageList(NodeList n){ ArrayList list = new ArrayList; for(int i=0; i<GALTEXT_INTERVAL*NUM_FILES_PER_PAGE-4; i = i+GALTEXT_INTERVAL){ try{ list.add(getImageName(n.item(GAL_DIV_ONE_ROOT + i))); }catch(Exception e){ System.out.println(e.toString + " thrown at i = " + i + ". Image list truncated."); return list; }       }        return list; }    /**     * gets the username of a single entry on the new images list * @param n current gallerytext node in the list of divs * @return the name of the user in that gallerytext box. EXCLUDES namespace */   public static String getUserName(Node n){ String fullname = n.getChildNodes.item(GAL_DIV_USER).getAttributes.getNamedItem("title").toString; return fullname.substring(12, fullname.length-1); //trim +namespace before returning }   /**     * gets the image name of a single entry on the new images list * @param n current gallerytext node in the list of divs * @return the name of the image in that gallerytext box. INCLUDES namespace */   public static String getImageName(Node n){ String imagename = n.getChildNodes.item(GAL_DIV_NAME).getAttributes.getNamedItem("title").toString; return imagename.substring(7, imagename.length-1); //trim before returning }   /**     * prints out a summery of users and the files they uploaded as constructed by this bot. to console * @param users users * @param images images they uploaded */   public static void printResultList(ArrayList users, ArrayList images){ for(int i=0; i<users.size; i++){ System.out.println(users.get(i) + " uploaded " + images.get(i)); }   }    /**     * Determines if the given image is lacking licensing information * @param bot the bot * @param imageName the name of the image to check (INCLUDING namespace) * @return true if lacking info; false if info is okay */   public static boolean isNeedingLicense(MediaWikiBot bot, String imageName) throws Exception{ SimpleArticle sa = new SimpleArticle(bot.readContent(imageName)); String info = sa.getText; if(    info.contains("{{screenshot") ||                info.contains("{{Screenshot") ||                info.contains("{{Fansite kit image") ||                info.contains("{{User-created image") ||                info.contains("{{Public domain image") ||                info.contains("{{Mediawiki Screenshot")){ return false; }       return true; }   /**     * Builds a HashMap of String User --> ArrayList Images of images that need licensing information * @param bot the bot * @param users the list of all users who uploaded files * @param images the list of all files recently uploaded * @return the built HashMap * @throws java.lang.Exception */   public static HashMap getReminderList(MediaWikiBot bot, ArrayList users, ArrayList images) throws Exception{ HashMap hm = new HashMap; for(int i=0; i<images.size; i++){ String curImage = (String) images.get(i); if(isNeedingLicense(bot, curImage)){ //if the image needs licensing if(hm.containsKey(users.get(i))){ //if the user is already in teh map ArrayList imgvals = (ArrayList) hm.get(users.get(i)); //get teh list of images going for that user imgvals.add(curImage); //add this image }else{ //start a new user and list ArrayList a = new ArrayList; a.add(curImage); hm.put(users.get(i), a); }              }        }        return hm; }   /**     * Leaves a test summery on RogueJedi's page. Indicates what users will receive what messages. * @param bot the bot * @param map mapping of users to image lists to navigate * @throws java.lang.Exception */   public static void leaveTestSummery(MediaWikiBot bot, HashMap map) throws Exception{ Set userSet = map.keySet; Iterator iter = userSet.iterator; String curKey; String imgs = ""; while(iter.hasNext){ curKey = (String) iter.next; //next user imgs = ""; //reset per user ArrayList imgList = (ArrayList) map.get(curKey); //users image list for(int i=0; i<imgList.size; i++){ //add each entry to a string String aImg = imgs + "" + imgList.get(i) + ", "; imgs = aImg; //avoid concat }                      leaveMessage(bot, "RogueJedi", "\n==Image licensing reminder to " + curKey + "==\n" +                    "Hello, " + curKey + ". You are receiving this automated message because you " +                    "recently uploaded files to GuildWiki. " +                    "The following images appear to be missing licensing information: " + imgs +                    ". Please see Image license guide for more information. " +                    "Thank you for your contributions. "                    ); }   } }

Sample output
Testing and sample outputs are usually shown on User talk:RogueJedi. Currently only checks the first page of new images.

following info to run tests

Last run
20080529204129