wiki-postbot/wiki_postbot/interfaces/mediawiki.py

233 lines
7.7 KiB
Python
Raw Normal View History

"""
Class for interfacing with mediawiki
"""
2023-05-26 08:18:54 +00:00
from typing import List, Optional, TYPE_CHECKING
2022-11-01 01:39:15 +00:00
from pathlib import Path
from urllib.parse import urljoin
from dataclasses import dataclass
from wiki_postbot.creds import Mediawiki_Creds
2022-10-17 01:35:49 +00:00
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
2022-11-01 01:39:15 +00:00
from wiki_postbot.logger import init_logger
2022-10-17 01:35:49 +00:00
from datetime import datetime
import requests
2023-10-16 23:41:23 +00:00
2022-10-17 01:35:49 +00:00
import pdb
2023-05-26 08:18:54 +00:00
if TYPE_CHECKING:
2023-10-16 23:41:23 +00:00
try:
from wiki_postbot.clients.slack import SlackMessage
except ImportError:
SlackMessage = None
try:
from discord.message import Message, Embed
except ImportError:
Message = None
Embed = None
2023-05-26 08:18:54 +00:00
# creds = Mediawiki_Creds.from_json('mediawiki_creds.json')
class Wiki:
2022-11-02 06:40:48 +00:00
def __init__(self, url:str, creds:Mediawiki_Creds,
api_suffix:str="/api.php", index_page="Discord Messages",
2022-11-01 01:39:15 +00:00
log_dir:Path=Path('/var/www/wikibot')):
self.url = url
self.api_url = urljoin(self.url, api_suffix)
2022-11-02 06:40:48 +00:00
self.creds = creds
self.sess = None
2022-10-17 01:35:49 +00:00
self.index_page = index_page
2022-11-01 01:39:15 +00:00
self.logger = init_logger('wiki_interface', basedir=log_dir)
2022-11-02 06:40:48 +00:00
self.login(self.creds)
2022-10-17 01:35:49 +00:00
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
2022-11-01 01:39:15 +00:00
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()
2022-11-01 01:39:15 +00:00
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)
2022-10-17 01:35:49 +00:00
return WikiPage.from_source(title=content['parse']['title'], source=content['parse']['wikitext'])
2023-10-16 21:56:02 +00:00
def insert_text(self, page, section, text, overwrite:bool=False):
2022-10-17 01:35:49 +00:00
# TODO: Move finding section IDs into the page class!
page_text = self.get_page(page)
matching_section = -1
2022-11-01 01:39:15 +00:00
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
2022-10-17 01:35:49 +00:00
token = self.sess.get(
self.api_url,
params={
"action": "query",
"meta": "tokens",
"format": "json"
},
verify=False
).json()['query']['tokens']['csrftoken']
2022-10-17 01:35:49 +00:00
if matching_section >= 0:
print(f'found matching section {matching_section}')
2023-10-16 23:24:30 +00:00
if overwrite:
page_text.content.sections[matching_section].contents = text
result = self.sess.post(
self.api_url,
data={
"action":"edit",
"title":page,
"text": page_text.content.string,
"format":"json",
"token":token
}
)
else:
result = self.sess.post(
self.api_url,
data={
"action":"edit",
"title":page,
"section":str(matching_section),
"appendtext":text,
"format":"json",
"token":token
}
)
2022-10-17 01:35:49 +00:00
else:
2022-11-01 01:39:15 +00:00
self.logger.debug('making new section')
2022-10-17 01:35:49 +00:00
result = self.sess.post(
self.api_url,
data={
"action":"edit",
"title":page,
"section":"new",
"sectiontitle":section,
2023-10-16 23:24:30 +00:00
"appendtext":text,
2022-10-17 01:35:49 +00:00
"format":"json",
"token":token
}
)
return result
2023-10-16 23:41:23 +00:00
def handle_discord(self, msg:'Message') -> Result:
2022-10-17 01:35:49 +00:00
"""
Not being precious about this, just implementing
and will worry about generality later!
"""
2022-11-02 06:40:48 +00:00
self.login(self.creds)
2022-10-17 01:35:49 +00:00
# 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}")
2023-05-26 08:18:54 +00:00
def handle_slack(self, msg:'SlackMessage') -> Result:
"""
Brooooo it's getting laaaaaaaaaate and I think it's obvious how this should be refactored
but I want to play some zeldaaaaaaaaaaaa so I am copy and pasting for now
"""
self.login(self.creds)
# Get message in mediawiki template formatting
template_str = TemplateMessage.format_slack(msg)
# parse wikilinks, add to each page
wikilinks = Wikilink.parse(msg.content)
errored_pages = []
for link in wikilinks:
if link.section is None:
section = "Slack"
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}")
2022-10-17 01:35:49 +00:00
def add_to_index(self, message):
section = datetime.today().strftime("%y-%m-%d")
self.insert_text(page=self.index_page, section=section, text=message)