|
|
@@ -1,6 +1,8 @@ |
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
|
|
from hashlib import md5 |
|
|
|
import re |
|
|
|
from time import strftime |
|
|
|
from urllib import quote |
|
|
|
|
|
|
|
from wiki.exceptions import * |
|
|
@@ -25,7 +27,9 @@ class Page(object): |
|
|
|
is_redirect -- returns True if the page is a redirect, else False |
|
|
|
toggle_talk -- returns a content page's talk page, or vice versa |
|
|
|
get -- returns page content |
|
|
|
get_redirect_target -- if the page is a redirect, returns its destination |
|
|
|
get_redirect_target -- if the page is a redirect, returns its destination |
|
|
|
edit -- replaces the page's content or creates a new page |
|
|
|
add_section -- add a new section at the bottom of the page |
|
|
|
""" |
|
|
|
|
|
|
|
def __init__(self, site, title, follow_redirects=False): |
|
|
@@ -54,6 +58,11 @@ class Page(object): |
|
|
|
self._content = None |
|
|
|
self._creator = None |
|
|
|
|
|
|
|
# Attributes used for editing/deleting/protecting/etc: |
|
|
|
self._token = None |
|
|
|
self._basetimestamp = None |
|
|
|
self._starttimestamp = None |
|
|
|
|
|
|
|
# Try to determine the page's namespace using our site's namespace |
|
|
|
# converter: |
|
|
|
prefix = self._title.split(":", 1)[0] |
|
|
@@ -124,16 +133,16 @@ class Page(object): |
|
|
|
"""Loads various data from the API in a single query. |
|
|
|
|
|
|
|
Loads self._title, ._exists, ._is_redirect, ._pageid, ._fullurl, |
|
|
|
._protection, ._namespace, ._is_talkpage, ._creator, and ._lastrevid |
|
|
|
using the API. It will do a query of its own unless `result` is |
|
|
|
provided, in which case we'll pretend `result` is what the query |
|
|
|
returned. |
|
|
|
._protection, ._namespace, ._is_talkpage, ._creator, ._lastrevid, |
|
|
|
._token, and ._starttimestamp using the API. It will do a query of |
|
|
|
its own unless `result` is provided, in which case we'll pretend |
|
|
|
`result` is what the query returned. |
|
|
|
|
|
|
|
Assuming the API is sound, this should not raise any exceptions. |
|
|
|
""" |
|
|
|
if result is None: |
|
|
|
params = {"action": "query", "rvprop": "user", "rvdir": "newer", |
|
|
|
"prop": "info|revisions", "rvlimit": 1, |
|
|
|
params = {"action": "query", "rvprop": "user", "intoken": "edit", |
|
|
|
"prop": "info|revisions", "rvlimit": 1, "rvdir": "newer", |
|
|
|
"titles": self._title, "inprop": "protection|url"} |
|
|
|
result = self._site._api_query(params) |
|
|
|
|
|
|
@@ -168,6 +177,13 @@ class Page(object): |
|
|
|
self._fullurl = res["fullurl"] |
|
|
|
self._protection = res["protection"] |
|
|
|
|
|
|
|
try: |
|
|
|
self._token = res["edittoken"] |
|
|
|
except KeyError: |
|
|
|
pass |
|
|
|
else: |
|
|
|
self._starttimestamp = strftime("%Y-%m-%dT%H:%M:%SZ") |
|
|
|
|
|
|
|
# We've determined the namespace and talkpage status in __init__() |
|
|
|
# based on the title, but now we can be sure: |
|
|
|
self._namespace = res["ns"] |
|
|
@@ -192,13 +208,13 @@ class Page(object): |
|
|
|
""" |
|
|
|
if result is None: |
|
|
|
params = {"action": "query", "prop": "revisions", "rvlimit": 1, |
|
|
|
"rvprop": "content", "titles": self._title} |
|
|
|
"rvprop": "content|timestamp", "titles": self._title} |
|
|
|
result = self._site._api_query(params) |
|
|
|
|
|
|
|
res = result["query"]["pages"].values()[0] |
|
|
|
try: |
|
|
|
content = res["revisions"][0]["*"] |
|
|
|
self._content = content |
|
|
|
self._content = res["revisions"][0]["*"] |
|
|
|
self._basetimestamp = res["revisions"][0]["timestamp"] |
|
|
|
except KeyError: |
|
|
|
# This can only happen if the page was deleted since we last called |
|
|
|
# self._load_attributes(). In that case, some of our attributes are |
|
|
@@ -206,6 +222,25 @@ class Page(object): |
|
|
|
self._load_attributes() |
|
|
|
self._force_existence() |
|
|
|
|
|
|
|
def _get_token(self): |
|
|
|
"""Tries to get an edit token for the page. |
|
|
|
|
|
|
|
This is actually the same as the delete and protect tokens, so we'll |
|
|
|
use it for everything. Raises PermissionError if we're not allowed to |
|
|
|
edit the page, otherwise sets self._token and self._starttimestamp. |
|
|
|
""" |
|
|
|
params = {"action": "query", "prop": "info", "intoken": "edit", |
|
|
|
"titles": self._title} |
|
|
|
result = self._site._api_query(params) |
|
|
|
|
|
|
|
try: |
|
|
|
self._token = result["query"]["pages"].values()[0]["edittoken"] |
|
|
|
except KeyError: |
|
|
|
e = "You don't have permission to edit this page." |
|
|
|
raise PermissionsError(e) |
|
|
|
else: |
|
|
|
self._starttimestamp = strftime("%Y-%m-%dT%H:%M:%SZ") |
|
|
|
|
|
|
|
def title(self, force=False): |
|
|
|
"""Returns the Page's title, or pagename. |
|
|
|
|
|
|
@@ -394,9 +429,9 @@ class Page(object): |
|
|
|
if force or self._exists == 0: |
|
|
|
# Kill two birds with one stone by doing an API query for both our |
|
|
|
# attributes and our page content: |
|
|
|
params = {"action": "query", "rvprop": "content", "rvlimit": 1, |
|
|
|
params = {"action": "query", "rvlimit": 1, "titles": self._title, |
|
|
|
"prop": "info|revisions", "inprop": "protection|url", |
|
|
|
"titles": self._title} |
|
|
|
"intoken": "edit", "rvprop": "content|timestamp"} |
|
|
|
result = self._site._api_query(params) |
|
|
|
self._load_attributes(result=result) |
|
|
|
self._force_existence() |
|
|
@@ -438,3 +473,45 @@ class Page(object): |
|
|
|
except IndexError: |
|
|
|
e = "The page does not appear to have a redirect target." |
|
|
|
raise RedirectError(e) |
|
|
|
|
|
|
|
def edit(self, text, summary, minor=False, bot=True, force=False): |
|
|
|
"""Replaces the page's content or creates a new page. |
|
|
|
|
|
|
|
`text` is the new page content, with `summary` as the edit summary. |
|
|
|
If `minor` is True, the edit will be marked as minor. If `bot` is true, |
|
|
|
the edit will be marked as a bot edit, but only if we actually have a |
|
|
|
bot flag. |
|
|
|
|
|
|
|
Use `force` to ignore edit conflicts and page deletions/recreations |
|
|
|
that occured between getting our edit token and editing our page. Be |
|
|
|
careful with this! |
|
|
|
""" |
|
|
|
if not self._token: |
|
|
|
self._get_token() |
|
|
|
|
|
|
|
hashed = md5(text).hexdigest() |
|
|
|
|
|
|
|
params = {"action": "edit", "title": self._title, "text": text, |
|
|
|
"token": self._token, "summary": summary, "md5": hashed} |
|
|
|
|
|
|
|
if minor: |
|
|
|
params["minor"] = "true" |
|
|
|
else: |
|
|
|
params["notminor"] = "true" |
|
|
|
if bot: |
|
|
|
params["bot"] = "true" |
|
|
|
|
|
|
|
if not force: |
|
|
|
params["starttimestamp"] = self._starttimestamp |
|
|
|
if self._basetimestamp: |
|
|
|
params["basetimestamp"] = self._basetimestamp |
|
|
|
else: |
|
|
|
params["recreate"] = "true" |
|
|
|
|
|
|
|
result = self._site._api_query(params) |
|
|
|
print result |
|
|
|
|
|
|
|
def add_section(self, text, title, minor=False, bot=True): |
|
|
|
""" |
|
|
|
""" |
|
|
|
pass |