WIP
This commit is contained in:
parent
7813d1a7f0
commit
b6953cf52f
|
@ -30,19 +30,32 @@ def call(params: dict[str, str | int]) -> dict[str, Any]:
|
||||||
return data.json()
|
return data.json()
|
||||||
|
|
||||||
|
|
||||||
def get_content(title: str) -> str:
|
def article_exists(title: str) -> bool:
|
||||||
|
"""Get article text."""
|
||||||
|
params: dict[str, str | int] = {
|
||||||
|
"action": "query",
|
||||||
|
"format": "json",
|
||||||
|
"formatversion": 2,
|
||||||
|
"titles": title,
|
||||||
|
}
|
||||||
|
return not call(params)["query"]["pages"][0].get("missing")
|
||||||
|
|
||||||
|
|
||||||
|
def get_content(title: str) -> tuple[str, int]:
|
||||||
"""Get article text."""
|
"""Get article text."""
|
||||||
params: dict[str, str | int] = {
|
params: dict[str, str | int] = {
|
||||||
"action": "query",
|
"action": "query",
|
||||||
"format": "json",
|
"format": "json",
|
||||||
"formatversion": 2,
|
"formatversion": 2,
|
||||||
"prop": "revisions|info",
|
"prop": "revisions|info",
|
||||||
"rvprop": "content|timestamp",
|
"rvprop": "content|timestamp|ids",
|
||||||
"titles": title,
|
"titles": title,
|
||||||
}
|
}
|
||||||
data = call(params)
|
data = call(params)
|
||||||
rev: str = data["query"]["pages"][0]["revisions"][0]["content"]
|
rev = data["query"]["pages"][0]["revisions"][0]
|
||||||
return rev
|
content: str = rev["content"]
|
||||||
|
revid: int = int(rev["revid"])
|
||||||
|
return content, revid
|
||||||
|
|
||||||
|
|
||||||
def compare(title: str, new_text: str) -> str:
|
def compare(title: str, new_text: str) -> str:
|
||||||
|
@ -58,3 +71,21 @@ def compare(title: str, new_text: str) -> str:
|
||||||
}
|
}
|
||||||
diff: str = call(params)["compare"]["body"]
|
diff: str = call(params)["compare"]["body"]
|
||||||
return diff
|
return diff
|
||||||
|
|
||||||
|
|
||||||
|
def edit_page(
|
||||||
|
title: str, text: str, summary: str, baserevid: str, token: str
|
||||||
|
) -> dict[str, str | int]:
|
||||||
|
"""Edit a page on Wikipedia."""
|
||||||
|
params: dict[str, str | int] = {
|
||||||
|
"format": "json",
|
||||||
|
"formatversion": 2,
|
||||||
|
"action": "edit",
|
||||||
|
"title": title,
|
||||||
|
"text": text,
|
||||||
|
"baserevid": baserevid,
|
||||||
|
"token": token,
|
||||||
|
"summary": summary,
|
||||||
|
}
|
||||||
|
edit: str = call(params)["edit"]
|
||||||
|
return edit
|
||||||
|
|
|
@ -163,9 +163,9 @@ class Article:
|
||||||
self.parse: Optional[dict[str, Any]] = None
|
self.parse: Optional[dict[str, Any]] = None
|
||||||
self.dab_html: dict[str, str] = {}
|
self.dab_html: dict[str, str] = {}
|
||||||
|
|
||||||
def save_endpoint(self) -> str:
|
def preview_endpoint(self) -> str:
|
||||||
"""Endpoint for saving changes."""
|
"""Endpoint for saving changes."""
|
||||||
href: str = flask.url_for("save", enwiki=self.enwiki.replace(" ", "_"))
|
href: str = flask.url_for("preview", enwiki=self.enwiki.replace(" ", "_"))
|
||||||
return href
|
return href
|
||||||
|
|
||||||
def load(self) -> None:
|
def load(self) -> None:
|
||||||
|
|
|
@ -53,7 +53,7 @@ a.new { color: red; }
|
||||||
<div id="dabs" class="p-3">
|
<div id="dabs" class="p-3">
|
||||||
<h1>{{ article.enwiki }}</h1>
|
<h1>{{ article.enwiki }}</h1>
|
||||||
<div id="save-panel" class="d-none">
|
<div id="save-panel" class="d-none">
|
||||||
<form method="POST" action="{{ article.save_endpoint() }}">
|
<form method="POST" action="{{ article.preview_endpoint() }}">
|
||||||
<button class="btn btn-primary" id="save-btn">Preview before save</button>
|
<button class="btn btn-primary" id="save-btn">Preview before save</button>
|
||||||
<span id="edit-count"></span>
|
<span id="edit-count"></span>
|
||||||
<input type="hidden" value="{}" id="save-edits" name="edits">
|
<input type="hidden" value="{}" id="save-edits" name="edits">
|
||||||
|
|
|
@ -1,7 +1,21 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}DAB Mechanic{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="m-3">
|
<div class="m-3">
|
||||||
|
|
||||||
|
<form>
|
||||||
|
article title:
|
||||||
|
<input name="title" value="{{ request.args.get("title", "") }}">
|
||||||
|
<button class="btn btn-sm btn-primary">go</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if title and not exists %}
|
||||||
|
<p>No article titled "{{ title }}" found in Wikipedia.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
{% for enwiki, count in articles %}
|
{% for enwiki, count in articles %}
|
||||||
<li>
|
<li>
|
||||||
|
|
|
@ -15,13 +15,7 @@
|
||||||
<a class="navbar-brand" href="{{ url_for('index') }}">Dab Mechanic</a>
|
<a class="navbar-brand" href="{{ url_for('index') }}">Dab Mechanic</a>
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link active" aria-current="page" href="#">Home</a>
|
<a class="nav-link active" aria-current="page" href="/">Home</a>
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="#">Link</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link disabled">Disabled</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,10 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ url_for("save", enwiki=title) }}">
|
||||||
<button class="btn btn-primary" id="save-btn">Save changes</button>
|
<button class="btn btn-primary" id="save-btn">Save changes</button>
|
||||||
|
<input type="hidden" value="{{ request.form.edits }}" id="save-edits" name="edits">
|
||||||
|
</form>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
99
web_view.py
99
web_view.py
|
@ -5,6 +5,7 @@ import json
|
||||||
import re
|
import re
|
||||||
from typing import Optional, TypedDict
|
from typing import Optional, TypedDict
|
||||||
import mwparserfromhell
|
import mwparserfromhell
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
import lxml.html
|
import lxml.html
|
||||||
|
@ -65,13 +66,25 @@ def parse_articles_with_dab_links(root: lxml.html.Element) -> list[tuple[str, in
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
def index():
|
def index():
|
||||||
|
title = flask.request.args.get("title")
|
||||||
|
exists = None
|
||||||
|
if title:
|
||||||
|
title = title.strip()
|
||||||
|
exists = mediawiki_api.article_exists(title)
|
||||||
|
if exists:
|
||||||
|
return flask.redirect(
|
||||||
|
flask.url_for("article_page", enwiki=title.replace(" ", "_"))
|
||||||
|
)
|
||||||
|
|
||||||
r = requests.get(awdl_url, params={"limit": 100})
|
r = requests.get(awdl_url, params={"limit": 100})
|
||||||
root = lxml.html.fromstring(r.content)
|
root = lxml.html.fromstring(r.content)
|
||||||
articles = parse_articles_with_dab_links(root)
|
articles = parse_articles_with_dab_links(root)
|
||||||
|
|
||||||
# articles = [line[:-1] for line in open("article_list")]
|
# articles = [line[:-1] for line in open("article_list")]
|
||||||
|
|
||||||
return flask.render_template("index.html", articles=articles)
|
return flask.render_template(
|
||||||
|
"index.html", title=title, exists=exists, articles=articles,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Edit(TypedDict):
|
class Edit(TypedDict):
|
||||||
|
@ -82,7 +95,7 @@ class Edit(TypedDict):
|
||||||
title: str
|
title: str
|
||||||
|
|
||||||
|
|
||||||
def apply_edits(article_text: str, edits: list[Edit]) -> str:
|
def old_apply_edits(article_text: str, edits: list[Edit]) -> str:
|
||||||
"""Apply edits to article text."""
|
"""Apply edits to article text."""
|
||||||
|
|
||||||
def escape(s: str) -> str:
|
def escape(s: str) -> str:
|
||||||
|
@ -114,49 +127,92 @@ def build_edit_summary(edits: list[Edit]) -> str:
|
||||||
|
|
||||||
return f"Disambiguate {titles} using [[User:Edward/Dab mechanic]]"
|
return f"Disambiguate {titles} using [[User:Edward/Dab mechanic]]"
|
||||||
|
|
||||||
def get_links(wikicode, edits):
|
|
||||||
|
def get_links(wikicode, dab_links):
|
||||||
|
edits = [edit for edit in dab_links if edit.get("title")]
|
||||||
|
|
||||||
dab_titles = {dab["link_to"] for dab in edits}
|
dab_titles = {dab["link_to"] for dab in edits}
|
||||||
return [
|
return [
|
||||||
link for link in wikicode.filter_wikilinks() if str(link.title) in dab_titles
|
link for link in wikicode.filter_wikilinks() if str(link.title) in dab_titles
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@app.route("/preview/<path:enwiki>", methods=["POST"])
|
def apply_edits(text, dab_links):
|
||||||
def preview(enwiki: str) -> Response | str:
|
|
||||||
"""Save edits to article."""
|
|
||||||
enwiki = enwiki.replace("_", " ")
|
|
||||||
|
|
||||||
dab_links = json.loads(flask.request.form["edits"])
|
|
||||||
edits = [edit for edit in dab_links if edit.get("title")]
|
|
||||||
|
|
||||||
edit_summary = build_edit_summary(edits)
|
|
||||||
# return flask.jsonify(edits=dab_links, edit_summary=edit_summary)
|
|
||||||
|
|
||||||
text = mediawiki_api.get_content(enwiki)
|
|
||||||
wikicode = mwparserfromhell.parse(text)
|
wikicode = mwparserfromhell.parse(text)
|
||||||
links = get_links(wikicode, dab_links)
|
links = get_links(wikicode, dab_links)
|
||||||
|
if len(links) != len(dab_links):
|
||||||
|
print("links:", len(links))
|
||||||
|
print("dab_links:", len(dab_links))
|
||||||
|
print("dab_links:", dab_links)
|
||||||
assert len(links) == len(dab_links)
|
assert len(links) == len(dab_links)
|
||||||
|
|
||||||
for wikilink, edit in zip(links, dab_links):
|
for wikilink, edit in zip(links, dab_links):
|
||||||
print(edit, wikilink)
|
|
||||||
if not edit.get("title"):
|
if not edit.get("title"):
|
||||||
continue
|
continue
|
||||||
if not wikilink.text:
|
if not wikilink.text:
|
||||||
wikilink.text = wikilink.title
|
wikilink.text = wikilink.title
|
||||||
wikilink.title = edit["title"]
|
wikilink.title = edit["title"]
|
||||||
|
|
||||||
diff = mediawiki_api.compare(enwiki, str(wikicode))
|
return str(wikicode)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/preview/<path:enwiki>", methods=["POST"])
|
||||||
|
def preview(enwiki: str) -> Response | str:
|
||||||
|
"""Preview article edits."""
|
||||||
|
enwiki = enwiki.replace("_", " ")
|
||||||
|
|
||||||
|
dab_links = json.loads(flask.request.form["edits"])
|
||||||
|
dab_links = [link for link in dab_links if "title" in link]
|
||||||
|
cur_text, baserevid = mediawiki_api.get_content(enwiki)
|
||||||
|
|
||||||
|
text = apply_edits(cur_text, dab_links)
|
||||||
|
diff = mediawiki_api.compare(enwiki, text)
|
||||||
|
|
||||||
return flask.render_template(
|
return flask.render_template(
|
||||||
"peview.html",
|
"preview.html",
|
||||||
edit_summary=edit_summary,
|
edit_summary=build_edit_summary(dab_links),
|
||||||
title=enwiki,
|
title=enwiki,
|
||||||
edits=dab_links,
|
edits=dab_links,
|
||||||
# text=str(wikicode),
|
|
||||||
diff=diff,
|
diff=diff,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def do_save(enwiki: str):
|
||||||
|
"""Update page on Wikipedia."""
|
||||||
|
dab_links = json.loads(flask.request.form["edits"])
|
||||||
|
dab_links = [link for link in dab_links if "title" in link]
|
||||||
|
|
||||||
|
cur_text, baserevid = mediawiki_api.get_content(enwiki)
|
||||||
|
|
||||||
|
new_text = apply_edits(cur_text, dab_links)
|
||||||
|
token = wikidata_oauth.get_token()
|
||||||
|
|
||||||
|
summary = build_edit_summary(dab_links)
|
||||||
|
print(summary)
|
||||||
|
|
||||||
|
edit = mediawiki_api.edit_page(
|
||||||
|
title=enwiki,
|
||||||
|
text=new_text,
|
||||||
|
summary=summary,
|
||||||
|
baserevid=baserevid,
|
||||||
|
token=token,
|
||||||
|
)
|
||||||
|
|
||||||
|
return edit
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/save/<path:enwiki>", methods=["GET", "POST"])
|
||||||
|
def save(enwiki: str) -> Response | str:
|
||||||
|
"""Save edits to article."""
|
||||||
|
enwiki_norm = enwiki.replace("_", " ")
|
||||||
|
|
||||||
|
if flask.request.method == "GET":
|
||||||
|
return flask.render_template("edit_saved.html", title=enwiki_norm)
|
||||||
|
|
||||||
|
do_save(enwiki_norm)
|
||||||
|
return flask.redirect(flask.url_for(flask.request.endpoint, enwiki=enwiki))
|
||||||
|
|
||||||
|
|
||||||
def redirect_if_needed(enwiki: str) -> Optional[Response]:
|
def redirect_if_needed(enwiki: str) -> Optional[Response]:
|
||||||
"""Check if there are spaces in the article name and redirect."""
|
"""Check if there are spaces in the article name and redirect."""
|
||||||
return (
|
return (
|
||||||
|
@ -175,6 +231,9 @@ def article_page(enwiki: str) -> Response:
|
||||||
if redirect:
|
if redirect:
|
||||||
return redirect
|
return redirect
|
||||||
|
|
||||||
|
if "owner_key" not in flask.session:
|
||||||
|
return flask.render_template("login_needed.html")
|
||||||
|
|
||||||
article = wikipedia.Article(enwiki)
|
article = wikipedia.Article(enwiki)
|
||||||
article.load()
|
article.load()
|
||||||
article.process_links()
|
article.process_links()
|
||||||
|
|
Loading…
Reference in a new issue