175 lines
5.7 KiB
Python
175 lines
5.7 KiB
Python
"""
|
|
Class for interfacing with mediawiki
|
|
"""
|
|
from typing import List, Optional
|
|
from pathlib import Path
|
|
from urllib.parse import urljoin
|
|
from dataclasses import dataclass
|
|
from wiki_postbot.creds import Mediawiki_Creds
|
|
from wiki_postbot.formats.wiki import WikiPage
|
|
from wiki_postbot.templates.wiki import TemplateMessage
|
|
from wiki_postbot.patterns.wikilink import Wikilink
|
|
from wiki_postbot.actions import Result
|
|
from wiki_postbot.logger import init_logger
|
|
from datetime import datetime
|
|
import requests
|
|
from discord.message import Message, Embed
|
|
import pdb
|
|
|
|
# creds = Mediawiki_Creds.from_json('mediawiki_creds.json')
|
|
|
|
|
|
class Wiki:
|
|
def __init__(self, url:str, creds:Mediawiki_Creds,
|
|
api_suffix:str="/api.php", index_page="Discord Messages",
|
|
log_dir:Path=Path('/var/www/wikibot')):
|
|
self.url = url
|
|
self.api_url = urljoin(self.url, api_suffix)
|
|
self.creds = creds
|
|
self.sess = None
|
|
self.index_page = index_page
|
|
self.logger = init_logger('wiki_interface', basedir=log_dir)
|
|
self.login(self.creds)
|
|
|
|
def login(self, creds:Mediawiki_Creds):
|
|
# get token to log in
|
|
sess = requests.Session()
|
|
|
|
login_token = sess.get(
|
|
self.api_url,
|
|
params={
|
|
"action":"query",
|
|
"meta":"tokens",
|
|
"type":"login",
|
|
"format":"json"
|
|
},
|
|
verify=False
|
|
).json()['query']['tokens']['logintoken']
|
|
|
|
|
|
login_result = sess.post(
|
|
self.api_url,
|
|
data = {
|
|
"action":"login",
|
|
"lgname":creds.user,
|
|
"lgpassword":creds.password,
|
|
"lgtoken": login_token,
|
|
"format": "json"
|
|
},
|
|
verify=False
|
|
)
|
|
assert login_result.json()['login']['result'] == "Success"
|
|
self.sess = sess
|
|
|
|
def get_page(self, page:str) -> Optional[WikiPage]:
|
|
|
|
content = self.sess.get(
|
|
self.api_url,
|
|
params={
|
|
'action':'parse',
|
|
'page': page,
|
|
'prop': 'wikitext',
|
|
'formatversion':'2',
|
|
'format':'json'
|
|
}
|
|
).json()
|
|
|
|
if content.get('error', {}).get('code', '') == 'missingtitle':
|
|
# Page does not exist!
|
|
self.logger.debug("Page does not exist")
|
|
return None
|
|
|
|
self.logger.debug(f"Got Page content:")
|
|
self.logger.debug(content)
|
|
return WikiPage.from_source(title=content['parse']['title'], source=content['parse']['wikitext'])
|
|
|
|
def insert_text(self, page, section, text):
|
|
|
|
# TODO: Move finding section IDs into the page class!
|
|
page_text = self.get_page(page)
|
|
matching_section = -1
|
|
if page_text is not None:
|
|
# find section number
|
|
sections = page_text.content.get_sections()
|
|
|
|
for i, page_section in enumerate(sections):
|
|
if page_section.title is not None and page_section.title.strip().lower() == section.lower():
|
|
matching_section = i
|
|
break
|
|
|
|
|
|
token = self.sess.get(
|
|
self.api_url,
|
|
params={
|
|
"action": "query",
|
|
"meta": "tokens",
|
|
"format": "json"
|
|
},
|
|
verify=False
|
|
).json()['query']['tokens']['csrftoken']
|
|
|
|
if matching_section >= 0:
|
|
print(f'found matching section {matching_section}')
|
|
result = self.sess.post(
|
|
self.api_url,
|
|
data={
|
|
"action":"edit",
|
|
"title":page,
|
|
"section":str(matching_section),
|
|
"appendtext":text,
|
|
"format":"json",
|
|
"token":token
|
|
}
|
|
)
|
|
else:
|
|
self.logger.debug('making new section')
|
|
result = self.sess.post(
|
|
self.api_url,
|
|
data={
|
|
"action":"edit",
|
|
"title":page,
|
|
"section":"new",
|
|
"sectiontitle":section,
|
|
"appendtext":text,
|
|
"format":"json",
|
|
"token":token
|
|
}
|
|
)
|
|
return result
|
|
|
|
def handle_discord(self, msg:Message) -> Result:
|
|
"""
|
|
Not being precious about this, just implementing
|
|
and will worry about generality later!
|
|
"""
|
|
self.login(self.creds)
|
|
# Get message in mediawiki template formatting
|
|
template_str = TemplateMessage.format_discord(msg)
|
|
|
|
# parse wikilinks, add to each page
|
|
wikilinks = Wikilink.parse(msg.content)
|
|
errored_pages = []
|
|
for link in wikilinks:
|
|
if link.section is None:
|
|
section = "Discord"
|
|
else:
|
|
section = link.section
|
|
|
|
res = self.insert_text(link.link, section, template_str)
|
|
if res.json()['edit']['result'] != 'Success':
|
|
errored_pages.append(res.json())
|
|
|
|
# Add to index page (only once)
|
|
self.add_to_index(template_str)
|
|
|
|
if len(errored_pages) == 0:
|
|
# gather links for a reply
|
|
reply = '\n'.join([f"[{l.link}]({urljoin(self.url, l.link.replace(' ', '_'))})" for l in wikilinks])
|
|
|
|
return Result(ok=True, log=f"Successfully posted message to {[l.link for l in wikilinks]}", reply=reply)
|
|
else:
|
|
return Result(ok=False, log=f"Got exceptions: {errored_pages}")
|
|
|
|
def add_to_index(self, message):
|
|
section = datetime.today().strftime("%y-%m-%d")
|
|
self.insert_text(page=self.index_page, section=section, text=message)
|