/* * WPCleaner: A tool to help on Wikipedia maintenance tasks. * Copyright (C) 2013 Nicolas Vervelle * * See README.txt file for licensing information. */ package org.wikipediacleaner.gui.swing.bot; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.wikipediacleaner.api.API; import org.wikipediacleaner.api.APIException; import org.wikipediacleaner.api.APIFactory; import org.wikipediacleaner.api.check.CheckError; import org.wikipediacleaner.api.check.CheckErrorPage; import org.wikipediacleaner.api.check.CheckWiki; import org.wikipediacleaner.api.check.algorithm.CheckErrorAlgorithm; import org.wikipediacleaner.api.constants.EnumWikipedia; import org.wikipediacleaner.api.constants.WPCConfiguration; import org.wikipediacleaner.api.constants.WPCConfigurationStringList; import org.wikipediacleaner.api.data.AutomaticFormatter; import org.wikipediacleaner.api.data.Page; import org.wikipediacleaner.api.data.PageAnalysis; import org.wikipediacleaner.api.data.PageElementTemplate; import org.wikipediacleaner.gui.swing.Controller; import org.wikipediacleaner.gui.swing.basic.BasicWindow; import org.wikipediacleaner.gui.swing.basic.BasicWorker; import org.wikipediacleaner.gui.swing.basic.Utilities; import org.wikipediacleaner.i18n.GT; /** * SwingWorker for automatic Check Wiki fixing. */ public class AutomaticCWWorker extends BasicWorker { /** Algorithms for which to fix pages. */ private final List<CheckErrorAlgorithm> selectedAlgorithms; /** Maximum number of pages. */ private final int max; /** True to ignore limit for non Labs errors. */ private final boolean noLimit; /** List of potential algorithms to fix. */ private final List<CheckErrorAlgorithm> allAlgorithms; /** Extra comment. */ private final String extraComment; /** True if modifications should be saved. */ private final boolean saveModifications; /** True if pages that couldn't be fixed should be analyzed. */ private final boolean analyzeNonFixed; /** Count of modified pages. */ private int countModified; /** Count of marked pages. */ private int countMarked; /** Count of marked pages for other algorithms. */ private int countMarkedOther; /** * @param wiki Wiki. * @param window Window. * @param selectedAlgorithms List of selected algorithms. * @param max Maximum number of pages for each algorithm. * @param noLimit Ignore limit for non Labs errors. * @param allAlgorithms List of possible algorithms. * @param extraComment Extra comment. * @param saveModifications True if modifications should be saved. * @param analyzeNonFixed True if pages that couldn't be fixed should be analyzed. */ public AutomaticCWWorker( EnumWikipedia wiki, BasicWindow window, List<CheckErrorAlgorithm> selectedAlgorithms, int max, boolean noLimit, List<CheckErrorAlgorithm> allAlgorithms, String extraComment, boolean saveModifications, boolean analyzeNonFixed) { super(wiki, window); this.selectedAlgorithms = selectedAlgorithms; this.max = max; this.noLimit = noLimit; this.allAlgorithms = allAlgorithms; this.extraComment = extraComment; this.saveModifications = saveModifications; this.analyzeNonFixed = analyzeNonFixed; this.countModified = 0; this.countMarked = 0; this.countMarkedOther = 0; } /** * Compute the value to be returned by the <code>get</code> method. * * @return Object returned by the <code>get</code> method. * @see org.wikipediacleaner.gui.swing.basic.BasicWorker#construct() */ @Override public Object construct() { try { for (CheckErrorAlgorithm algorithm : selectedAlgorithms) { if (!shouldContinue()) { return null; } analyzeAlgorithm(algorithm); } } catch (APIException e) { return e; } return null; } /** * Analyze an algorithm. * * @param algorithm Algorithm. * @throws APIException */ private void analyzeAlgorithm(CheckErrorAlgorithm algorithm) throws APIException { // Check if analysis is useful if (!saveModifications) { if (algorithm.getErrorNumber() >= CheckErrorAlgorithm.MAX_ERROR_NUMBER_WITH_LIST) { return; } } // Configuration setText( GT._("Checking for errors n°{0}", Integer.toString(algorithm.getErrorNumber())) + " - " + algorithm.getShortDescriptionReplaced()); int maxSize = max; if (noLimit && algorithm.hasSpecialList()) { maxSize = Integer.MAX_VALUE; } // Analysis List<CheckError> errors = new ArrayList<>(); CheckWiki checkWiki = APIFactory.getCheckWiki(); checkWiki.retrievePages(algorithm, maxSize, getWikipedia(), errors); while (!errors.isEmpty()) { CheckError error = errors.remove(0); int maxErrors = error.getPageCount(); for (int numPage = 0; (error.getPageCount() > 0) && shouldContinue(); numPage++) { try { Page page = error.getPage(0); error.remove(page); analyzePage( page, algorithm, algorithm.getErrorNumberString() + " - " + (numPage + 1) + "/" + maxErrors); } catch (APIException e) { // } } } } /** * Analyze and fix a page. * * @param page Page. * @param algorithm Main algorithm. * @param prefix Prefix for the message * @throws APIException */ private void analyzePage( Page page, CheckErrorAlgorithm algorithm, String prefix) throws APIException { setText(prefix + " - " + GT._("Analyzing page {0}", page.getTitle())); // Retrieve page content API api = APIFactory.getAPI(); api.retrieveContents(getWikipedia(), Collections.singletonList(page), true, false); PageAnalysis analysis = page.getAnalysis(page.getContents(), true); // Check that robots are authorized to change this page boolean preventBot = false; if (saveModifications) { WPCConfiguration config = getWikipedia().getConfiguration(); List<String[]> nobotTemplates = config.getStringArrayList( WPCConfigurationStringList.NOBOT_TEMPLATES); if ((nobotTemplates != null) && (!nobotTemplates.isEmpty())) { for (String[] nobotTemplate : nobotTemplates) { String templateName = nobotTemplate[0]; List<PageElementTemplate> templates = analysis.getTemplates(templateName); if ((templates != null) && (!templates.isEmpty())) { preventBot = true; } } } } // Analyze page to check if an error has been found CheckErrorPage errorPage = CheckError.analyzeError(algorithm, analysis); boolean found = false; if (errorPage != null) { if (errorPage.getErrorFound()) { found = true; } } CheckWiki checkWiki = APIFactory.getCheckWiki(); if (found) { if (!saveModifications) { return; } // Fix all errors that can be fixed String newContents = page.getContents(); List<CheckError.Progress> errorsFixed = new ArrayList<>(); if (!preventBot) { newContents = AutomaticFormatter.tidyArticle(page, newContents, allAlgorithms, true, errorsFixed); } // Check if error has been fixed boolean isFixed = false; if (!newContents.equals(page.getContents())) { for (CheckError.Progress errorFixed : errorsFixed) { if ((algorithm != null) && (algorithm.equals(errorFixed.algorithm))) { isFixed = true; } } } // Save page if errors have been fixed if (isFixed) { StringBuilder comment = new StringBuilder(); if ((extraComment != null) && (extraComment.trim().length() > 0)) { comment.append(extraComment.trim()); comment.append(" - "); } comment.append(getWikipedia().getCWConfiguration().getComment(errorsFixed)); setText(prefix + " - " + GT._("Fixing page {0}", page.getTitle())); api.updatePage( getWikipedia(), page, newContents, comment.toString(), true, false); countModified++; for (CheckError.Progress errorFixed : errorsFixed) { CheckErrorAlgorithm usedAlgorithm = errorFixed.algorithm; errorPage = CheckError.analyzeError(usedAlgorithm, page.getAnalysis(newContents, true)); if ((errorPage != null) && (!errorPage.getErrorFound())) { checkWiki.markAsFixed(page, usedAlgorithm.getErrorNumberString()); if (selectedAlgorithms.contains(usedAlgorithm)) { countMarked++; } else { countMarkedOther++; } } } } else if (analyzeNonFixed) { Controller.runFullAnalysis(page.getTitle(), null, getWikipedia()); } } else if (algorithm.getErrorNumber() < CheckErrorAlgorithm.MAX_ERROR_NUMBER_WITH_LIST) { Boolean errorDetected = checkWiki.isErrorDetected( page, algorithm.getErrorNumber()); if (Boolean.FALSE.equals(errorDetected)) { checkWiki.markAsFixed(page, algorithm.getErrorNumberString()); countMarked++; } } } /** * Called on the event dispatching thread (not on the worker thread) * after the <code>construct</code> method has returned. * * @see org.wikipediacleaner.gui.swing.basic.BasicWorker#finished() */ @Override public void finished() { super.finished(); if (getWindow() != null) { StringBuilder message = new StringBuilder(); message.append(GT.__( "{0} page has been modified", "{0} pages have been modified", countModified, Integer.toString(countModified))); message.append("\n"); message.append(GT.__( "{0} page has been marked as fixed for the selected algorithms", "{0} pages have been marked as fixed for the selected algorithms", countMarked, Integer.toString(countMarked))); message.append("\n"); message.append(GT.__( "{0} page has been marked as fixed for other algorithms", "{0} pages have been marked as fixed for other algorithms", countMarkedOther, Integer.toString(countMarkedOther))); Utilities.displayInformationMessage( getWindow().getParentComponent(), message.toString()); } } }