cleaned up code and removed debugging statements
[backwash] / backwash.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import sys
5 import re
6 from simplemediawiki import MediaWiki
7 import interwiki
8
9 # TODO/bugs:
10
11 # - the bot should loginto the system. the simplemediawiki library
12 #   should help us with that
13 # - we need to de-interwikify any interwiki links given to Wiki
14 # - the interwiki stuff isn't working for a few reason. i think we should turn it off
15 #   we should only add interwiki links to the api
16 #   we should only do it when we create an account on the wiki for the bot
17 # - normalize messages for non-unix linebreaks
18 # - get_revid_for_date is not being called at the moment a date w/o a
19 #   a revision is not showing up
20
21 class Wiki:
22     def __init__(self, url):
23         self.url = url
24         self.wiki = MediaWiki(self.url + 'api.php')
25
26     def get_revid_for_date(self, page, date):
27         wc = self.wiki.call({
28             'action': 'query',
29             'prop': 'revisions',
30             'titles': page,
31             'rvlimit': 1,
32             'redirects': 'true',
33             'rvstart': date,
34             'rvdir' : 'newer',
35             'rvprop' : 'timestamp|ids'})
36         pages = wc['query']['pages']
37         return pages[pages.keys()[0]]['revisions'][0]['revid']
38
39     def get_edit_token(self, page):
40         wc = self.wiki.call({
41             'action' : 'query',
42             'prop': 'info|revisions',
43             'titles': page,
44             'intoken' : 'edit'})
45         pages = wc['query']['pages']
46         page = pages[pages.keys()[0]]
47
48         return page['edittoken']
49
50     def normalize_title(self, page):
51         wc = self.wiki.call({
52             'action': 'query',
53             'prop': 'info',
54             'titles': page,
55             'redirects': 'true'})
56         pages = wc['query']['pages']
57         page = pages[pages.keys()[0]]
58
59         return page['title'].replace(" ", "_")
60         
61     def get_talk_page(self, page):
62        normalized = self.normalize_title(page)
63        
64        if ':' in normalized:
65           (namespace, rest) = normalized.split(':', 1)
66           return '%s_talk:%s' % (namespace, rest)
67        else:
68           return 'Talk:%s' % page
69
70     def get_page_text(self, page):
71         wc = self.wiki.call({
72             'action': 'query',
73             'prop': 'revisions',
74             'titles': page,
75             'redirects': 'true',
76             'rvprop' : 'content'})
77         pages = wc['query']['pages']
78         # something here:LP
79         page = pages[pages.keys()[0]]
80         return page['revisions'][0]['*']
81         
82     def append_to_talk_page(self, page, text):
83         talk_page = self.get_talk_page(page)
84         edit_token = self.get_edit_token(talk_page)
85
86         wc = self.wiki.call({
87             'action' : 'edit',
88             'title': talk_page,
89             'bot' : 'true',
90             'token' : edit_token,
91             'notminor': 'true',
92             'section' : 'new',
93             'summary': 'Suggestion from an offline user (via [[User:BackWashBot|BackWashBot]])',
94             'text': text })
95
96 def make_link(wiki, page, revision):
97     return '%sindex.php?title=%s&oldid=%s' % (wiki, page.replace(' ', '_'), revision)
98
99 class WikiEdit:
100     fields = ['page', 'date', 'e-mail', 'export-date', 'redirect', 'page-revision', 'user-agent', 'username', 'wiki']
101     datefields = ['date', 'export-date']
102
103     def __init__(self, headers={}, body='', normalize=True):
104         self.headers = headers
105         self.body = body
106
107         if normalize:
108             self.normalize_headers()
109
110     def normalize_headers(self):
111         self.headers.setdefault('wiki', 'http://en.wikipedia.org/wiki/')
112         if self.headers['wiki'] in interwiki.mapping.keys():
113             self.headers['wiki'] = interwiki.mapping[self.headers['wiki']]
114
115     def to_comment(self):
116         assembly = [('date', ' on %s,'),
117                     ('username', ' [[User:%s]]', ' an anonymous user'),
118                     ('e-mail', ' (e-mail: %s)'),
119                     (' made the following comment',),
120                     ('page-revision', 
121         lambda x: ' on [' + make_link(self.headers['wiki'], self.headers['page'], self.headers['page-revision']) + ' this revision]'),
122                     ('user-agent', ' (using %s)')
123                     ]
124
125         comment = ""
126         for stage in assembly:
127             if len(stage) == 1:
128                 comment += stage[0]
129             elif self.headers.has_key(stage[0]):
130                 if isinstance(stage[1], str):
131                     comment += stage[1] % (self.headers[stage[0]])
132                 else:
133                     comment += stage[1](stage[0])
134             elif len(stage) == 3:
135                 comment += stage[2]
136
137         comment = comment.strip()
138         return ":''" + comment[0].capitalize() + comment[1:] + \
139                " using an offline wikireader:''\n\n" + self.body.strip() + \
140                "\n\n—via [[User:BackWashBot|BackWashBot]] ~~~~~"
141
142     @classmethod
143     def from_string(cls, s):
144         body_index = s.index('\n\n')
145         # headers = dict([(X[:X.index(':')], X[X.index(':')+1:].strip()) for X in s[:body_index].split('\n')])
146         kvs = [re.split(': *', key_value, 1) for key_value in s[:body_index].splitlines()]
147         headers = dict([(key.lower(), value) for (key, value) in kvs])
148         body = s[body_index+2:]
149         return cls(headers, body)
150
151 def parse_edits(lines):
152     edits = []
153     acc = ""
154     for line in lines:
155         if '\n\n' in acc and line.startswith('Page:'):
156             we = WikiEdit.from_string(acc)
157             edits.append(we)
158             #print we, we.headers, we.body
159             acc = ""
160         acc += line
161     
162     if acc != '':
163         we = WikiEdit.from_string(acc)
164         edits.append(we)
165         #print (we, we.headers, we.body)
166
167     return edits
168
169 if __name__ =='__main__':
170     # parse the .wpe file on standard
171     edits = parse_edits(sys.stdin)
172
173     for edit in edits:
174         wiki = Wiki(edit.headers['wiki'])
175         wiki.append_to_talk_page(edit.headers['page'], edit.to_comment())
176
177                      

Benjamin Mako Hill || Want to submit a patch?