@@ -719,7 +719,7 @@ protected ImageInfo getImageInfo(PageLocation loc, ArrayList<String> propertyNam
719719 try {
720720 rootNode = mapper .readValue (serverOutput , JsonNode .class );
721721 } catch (IOException e1 ) {
722- logError ("Was expecting JSON, but did not recieve JSON from server." );
722+ logError ("Was expecting JSON, but did not receive JSON from server." );
723723 return null ;
724724 }
725725
@@ -888,22 +888,16 @@ protected ArrayList<UserInfo> getUserInfo(ArrayList<User> users, ArrayList<Strin
888888 chunkOfUsers = new ArrayList <User >(users .subList (i , users .size ()));
889889 }
890890
891- //Extract usernames from users
892- ArrayList <String > chunkOfUserNames = new ArrayList <String >();
893- for (User u : chunkOfUsers ) {
894- chunkOfUserNames .add (u .getUserName ());
895- }
896-
897891 //Query the server.
898- String serverOutput = APIcommand (new QueryUserInfo (language , chunkOfUserNames , propertyNames ));
892+ String serverOutput = APIcommand (new QueryUserInfo (chunkOfUsers , propertyNames ));
899893
900894 // Read in the JSON!!!
901895 ObjectMapper mapper = new ObjectMapper ();
902896 JsonNode rootNode = null ;
903897 try {
904898 rootNode = mapper .readValue (serverOutput , JsonNode .class );
905899 } catch (IOException e1 ) {
906- logError ("Was expecting JSON, but did not recieve JSON from server." );
900+ logError ("Was expecting JSON, but did not receive JSON from server." );
907901 return null ;
908902 }
909903
@@ -1007,6 +1001,132 @@ protected ArrayList<UserInfo> getUserInfo(ArrayList<User> users, ArrayList<Strin
10071001 return toReturn ;
10081002 }
10091003
1004+ /**
1005+ * Get the contributions of a user, up to a certain limit.
1006+ * @param users The user to query.
1007+ * @param depth The max amount of revisions, per user, to return.
1008+ * @return An ArrayList of a user's contributions.
1009+ */
1010+ public ArrayList <Revision > getUserContribs (User user , int depth ) {
1011+ ArrayList <User > users = new ArrayList <User >();
1012+ users .add (user );
1013+ return getUserContribs (users , depth ).get (0 );
1014+ }
1015+
1016+ /**
1017+ * Get the contributions of multiple users, up to a certain limit.
1018+ * @param users The users to query.
1019+ * @param depth The max amount of revisions, per user, to return.
1020+ * @return An ArrayList of ArrayList of Revision. In other words, it is a list of a users' list of contributions.
1021+ */
1022+ public ArrayList <ArrayList <Revision >> getUserContribs (ArrayList <User > users , int depth ) {
1023+ //Logging
1024+ String userLogMessage = "Getting contribs for users: " ;
1025+ for (User u : users ) {
1026+ userLogMessage += u .getUserName () + ", " ;
1027+ }
1028+
1029+ logFine (userLogMessage );
1030+
1031+ //Method code below
1032+ ArrayList <ArrayList <Revision >> multiContribs = new ArrayList <ArrayList <Revision >>();
1033+
1034+ String language = users .get (0 ).getLanguage ();
1035+
1036+ //For now, we only query certain properties.
1037+ ArrayList <String > properties = new ArrayList <String >();
1038+ properties .add ("title" );
1039+ properties .add ("comment" );
1040+ properties .add ("timestamp" );
1041+ properties .add ("flags" );
1042+
1043+ //Query users individually.
1044+ int maxQuerySize = Math .min (50 , APIlimit );
1045+ for (int u = 0 ; u < users .size (); u ++) {
1046+ //Get a user.
1047+ User user = users .get (u );
1048+
1049+ //Query user's contributions.
1050+ int rev = 0 ;
1051+ boolean moreRevisionsExist = true ;
1052+ String queryContinue = null ; // User for continuing queries.
1053+ while (rev < depth && moreRevisionsExist ) {
1054+ //Query the server.
1055+ int querySize = -1 ;
1056+ if (rev + maxQuerySize < depth ) {
1057+ querySize = maxQuerySize ;
1058+ } else {
1059+ querySize = depth - rev ;
1060+ }
1061+ APIcommand queryUserContribs = new QueryUserContribs (user , properties , querySize );
1062+ if (queryContinue != null ) {
1063+ queryUserContribs .addParameter ("ucstart" , queryContinue );
1064+ }
1065+
1066+ String serverOutput = APIcommand (queryUserContribs );
1067+
1068+
1069+ // Read in the JSON!!!
1070+ ObjectMapper mapper = new ObjectMapper ();
1071+ JsonNode rootNode = null ;
1072+ try {
1073+ rootNode = mapper .readValue (serverOutput , JsonNode .class );
1074+ } catch (IOException e1 ) {
1075+ logError ("Was expecting JSON, but did not receive JSON from server." );
1076+ return null ;
1077+ }
1078+
1079+ //Parse JSON for contribs
1080+ ArrayList <Revision > contribs = new ArrayList <Revision >();
1081+
1082+ JsonNode queryNode = rootNode .findValue ("query" );
1083+ JsonNode userContribs = queryNode .findValue ("usercontribs" );
1084+
1085+ for (int contribID = 0 ; contribID < userContribs .size (); contribID ++) {
1086+ JsonNode contrib = userContribs .get (contribID );
1087+
1088+ //Parse for revision info
1089+ String title = unescape (contrib .findValue ("title" ).textValue ());
1090+ PageLocation loc = new PageLocation (title , language );
1091+ String userName = user .getUserName ();
1092+ String comment = unescape (contrib .findValue ("comment" ).textValue ());
1093+ Date date = createDate (unescape (contrib .findValue ("timestamp" ).textValue ()));
1094+
1095+ //Parse for flags
1096+ ArrayList <String > flags = new ArrayList <String >();
1097+
1098+ if (contrib .has ("new" )) {
1099+ flags .add ("new" );
1100+ }
1101+ if (contrib .has ("top" )) {
1102+ flags .add ("top" );
1103+ }
1104+ if (contrib .has ("minor" )) {
1105+ flags .add ("minor" );
1106+ }
1107+
1108+ //Package and ship the revision! Then have it sink due to a bunyip and cucumber sandwiches.
1109+ contribs .add (new Revision (loc , userName , comment , date , flags ));
1110+ }
1111+
1112+ multiContribs .add (contribs );
1113+
1114+ rev += querySize ;
1115+
1116+ //Parse for query continue
1117+ JsonNode queryContinueNode = rootNode .findValue ("query-continue" );
1118+ if (queryContinueNode == null ) {
1119+ moreRevisionsExist = false ;
1120+ } else {
1121+ JsonNode ucstartNode = queryContinueNode .findValue ("ucstart" );
1122+ queryContinue = ucstartNode .textValue ();
1123+ }
1124+ }
1125+ }
1126+
1127+ return multiContribs ;
1128+ }
1129+
10101130 /**
10111131 * Log into a wiki.
10121132 * @param user The username.
@@ -1138,7 +1258,7 @@ public String APIcommand(APIcommand command) {
11381258 }
11391259
11401260 if (textReturned .contains ("<warnings>" )) {
1141- logError ("Warnings were recieved when editing " + command .getTitle () + "." );
1261+ logError ("Warnings were received when editing " + command .getTitle () + "." );
11421262 } else {
11431263 //Check other possibilities for errors/warnings being returned..
11441264 String errorMessage = null ;
@@ -1171,15 +1291,15 @@ public String APIcommand(APIcommand command) {
11711291 }
11721292 } else if (command .getValue ("format" ).equalsIgnoreCase ("xml" )) {
11731293 //We are handling XML output. We do not do anything.
1174- logFinest ("XML recieved ." );
1294+ logFinest ("XML received ." );
11751295 if (textReturned .length () < 1000 ) {
11761296 logFinest ("XML: " + textReturned );
11771297 } else {
11781298 logFinest ("XML: " + textReturned .substring (0 , 1000 ));
11791299 }
11801300 } else if (command .getValue ("format" ).equalsIgnoreCase ("php" )) {
11811301 //We are handling PHP output. We do not do anything.
1182- logFinest ("PHP recieved ." );
1302+ logFinest ("PHP received ." );
11831303 if (textReturned .length () < 1000 ) {
11841304 logFinest ("PHP: " + textReturned );
11851305 } else {
@@ -1455,7 +1575,7 @@ private ArrayList<Revision> getRevisionsFromXML(String XMLdata, String openingTe
14551575 rev = new Revision (new PageLocation (forceTitle , mdm .getWikiPrefixFromURL (baseURL )), user , comment , date , flags );
14561576 }
14571577
1458- rev .setPageContent (content );
1578+ rev .setRevisionContent (content );
14591579
14601580 //For eventual return.
14611581 output .add (rev );
@@ -1480,6 +1600,34 @@ public Date createDate(String text) {
14801600 return date ;
14811601 }
14821602
1603+ /**
1604+ * Unescapes string literals and HTML.
1605+ * @param text The text to unescape.
1606+ * @return A String.
1607+ */
1608+ private String unescape (String text ) {
1609+ return unescape (text , true , true );
1610+ }
1611+
1612+ /**
1613+ * Unescapes text.
1614+ * @param text The text to unescape.
1615+ * @param unescapeText Unescapes string literals. Ex: \n, \s, \ u
1616+ * @param unescapeHTML Unescapes HTML text. Ex: & #039;
1617+ * @return A String.
1618+ */
1619+ private String unescape (String text , boolean unescapeText , boolean unescapeHTML ) {
1620+ String unescaped = text ;
1621+ if (unescapeText ) {
1622+ unescaped = StringEscapeUtils .unescapeJava (unescaped );
1623+ }
1624+ if (unescapeHTML ) {
1625+ unescaped = StringEscapeUtils .unescapeHtml4 (StringEscapeUtils .unescapeHtml4 (unescaped ));
1626+ }
1627+
1628+ return unescaped ;
1629+ }
1630+
14831631 /**
14841632 * This method makes sure that the bot does not do particular actions too quickly.
14851633 */
0 commit comments