瀏覽代碼

major improvements to editing; fixes, cleanup, support for AssertEdit is complete w/ logging in following a failed assertion; bugfixes

tags/v0.1^2
Ben Kurtovic 13 年之前
父節點
當前提交
b1cf39ac64
共有 2 個檔案被更改,包括 89 行新增28 行删除
  1. +88
    -27
      bot/wiki/page.py
  2. +1
    -1
      bot/wiki/site.py

+ 88
- 27
bot/wiki/page.py 查看文件

@@ -2,7 +2,7 @@

from hashlib import md5
import re
from time import strftime
from time import gmtime, strftime
from urllib import quote

from wiki.exceptions import *
@@ -182,7 +182,7 @@ class Page(object):
except KeyError:
pass
else:
self._starttimestamp = strftime("%Y-%m-%dT%H:%M:%SZ")
self._starttimestamp = strftime("%Y-%m-%dT%H:%M:%SZ", gmtime())

# We've determined the namespace and talkpage status in __init__()
# based on the title, but now we can be sure:
@@ -225,37 +225,59 @@ class Page(object):
def _edit(self, params=None, text=None, summary=None, minor=None, bot=None,
force=None, section=None, captcha_id=None, captcha_word=None,
tries=0):
"""Edit a page!
"""Edit the page!

If `params` is given, we'll use it as our API query parameters.
Otherwise, we'll build params using the given kwargs via
_build_edit_params().
If `params` is given,
We'll then try to do the API query, and catch any errors the API raises
in _handle_edit_errors(). We'll then throw these back as subclasses of
EditError.
"""
# Try to get our edit token, and die if we can't:
if not self._token:
self._load_attributes()
if not self._token:
e = "You don't have permission to edit this page."
raise PermissionsError(e)
self._force_validity() # Weed these out before we get too far
# Weed out invalid pages before we get too far:
self._force_validity()

# Build our API query string:
if not params:
params = self._build_edit_params(text, summary, minor, bot, force,
section, captcha_id, captcha_word)
else: # Make sure we have the right token:
params["token"] = self._token

# Try the API query, catching most errors with our handler:
try:
result = self._site._api_query(params)
except SiteAPIError as error:
if not hasattr(error, code):
raise
result = self._handle_edit_exceptions(error, params, tries)

# These attributes are now invalidated:
self._content = None
self._basetimestamp = None

return result
if not hasattr(error, "code"):
raise # We can only handle errors with a code attribute
result = self._handle_edit_errors(error, params, tries)

# If everything was successful, reset invalidated attributes:
if result["edit"]["result"] == "Success":
self._content = None
self._basetimestamp = None
self._exists = 0
return

# If we're here, then the edit failed. If it's because of AssertEdit,
# handle that. Otherwise, die - something odd is going on:
try:
assertion = result["edit"]["assert"]
except KeyError:
raise EditError(result["edit"])
self._handle_assert_edit(assertion, params, tries)

def _build_edit_params(self, text, summary, minor, bot, force, section,
captcha_id, captcha_word):
"""Something."""
"""Given some keyword arguments, build an API edit query string."""
hashed = md5(text).hexdigest() # Checksum to ensure text is correct
params = {"action": "edit", "title": self._title, "text": text,
"token": self._token, "summary": summary, "md5": hashed}
@@ -271,40 +293,50 @@ class Page(object):
params["notminor"] = "true"
if bot:
params["bot"] = "true"
if self._exists == 2: # Page does not already exist
params["recreate"] = "true"

if not force:
params["starttimestamp"] = self._starttimestamp
if self._basetimestamp:
params["basetimestamp"] = self._basetimestamp
if self._exists == 3:
# Page exists; don't re-create it by accident if it's deleted:
params["nocreate"] = "true"
else:
if self._exists == 2:
# Page does not exist; don't edit if it already exists:
params["createonly"] = "true"
else:
params["recreate"] = "true"

return params

def _handle_edit_exceptions(self, error, params, tries):
"""Something."""
def _handle_edit_errors(self, error, params, tries):
"""If our edit fails due to some error, try to handle it.

We'll either raise an appropriate exception (for example, if the page
is protected), or we'll try to fix it (for example, if we can't edit
due to being logged out, we'll try to log in).
"""
if error.code in ["noedit", "cantcreate", "protectedtitle",
"noimageredirect"]:
raise PermissionsError(error.info)

elif error.code in ["noedit-anon", "cantcreate-anon",
"noimageredirect-anon"]:
if not all(self._site._login_info): # Insufficient login info
if not all(self._site._login_info):
# Insufficient login info:
raise PermissionsError(error.info)
if self.tries == 0: # We have login info; try to login:
if tries == 0:
# We have login info; try to login:
self._site._login(self._site._login_info)
self._token = None # Need a new token; old one is invalid now
return self._edit(params=params, tries=1)
else: # We already tried to log in and failed!
else:
# We already tried to log in and failed!
e = "Although we should be logged in, we are not. This may be a cookie problem or an odd bug."
raise LoginError(e)

elif error.code in ["editconflict", "pagedeleted", "articleexists"]:
# These attributes are now invalidated:
self._content = None
self._basetimestamp = None
self._exists = 0
raise EditConflictError(error.info)

elif error.code in ["emptypage", "emptynewsection"]:
@@ -319,7 +351,36 @@ class Page(object):
elif error.code == "filtered":
raise FilteredError(error.info)

raise EditError(", ".join((error.code, error.info)))
raise EditError(": ".join((error.code, error.info)))

def _handle_assert_edit(self, assertion, params, tries):
"""If we can't edit due to a failed AssertEdit assertion, handle that.

If the assertion was 'user' and we have valid login information, try to
log in. Otherwise, raise PermissionsError with details.
"""
if assertion == "user":
if not all(self._site._login_info):
# Insufficient login info:
e = "AssertEdit: user assertion failed, and no login info was provided."
raise PermissionsError(e)
if tries == 0:
# We have login info; try to login:
self._site._login(self._site._login_info)
self._token = None # Need a new token; old one is invalid now
return self._edit(params=params, tries=1)
else:
# We already tried to log in and failed!
e = "Although we should be logged in, we are not. This may be a cookie problem or an odd bug."
raise LoginError(e)

elif assertion == "bot":
e = "AssertEdit: bot assertion failed; we don't have a bot flag!"
raise PermissionsError(e)

# Unknown assertion, maybe "true", "false", or "exists":
e = "AssertEdit: assertion '{0}' failed.".format(assertion)
raise PermissionsError(e)

def title(self, force=False):
"""Returns the Page's title, or pagename.


+ 1
- 1
bot/wiki/site.py 查看文件

@@ -162,7 +162,7 @@ class Site(object):
try:
code = res["error"]["code"]
info = res["error"]["info"]
except KeyError:
except (TypeError, KeyError):
return res

if code == "maxlag":


Loading…
取消
儲存