Added #24 however still not usable

This commit is contained in:
Frisk 2021-10-30 13:53:35 +02:00
parent 468c381883
commit fda8e6c25a
No known key found for this signature in database
GPG key ID: 213F7C15068AF8AC
4 changed files with 55 additions and 6 deletions

View file

@ -12,5 +12,6 @@ setup(
keywords=['MediaWiki', 'recent changes', 'Discord', 'webhook'],
package_dir={"": "src"},
install_requires=["beautifulsoup4 >= 4.6.0", "requests >= 2.18.4", "schedule >= 0.5.0", "lxml >= 4.2.1"],
extras_require=["matplotlib => 3.4.3"],
python_requires="3.7"
)

View file

@ -17,6 +17,8 @@ import json
import math
import random
from collections import defaultdict
from typing import Tuple, Dict, Union
from io import BytesIO
from src.configloader import settings
@ -36,6 +38,7 @@ class DiscordMessage:
self.message_type = message_type
self.event_type = event_type
self.files: Dict[str, Tuple[str, Union[BytesIO, str], str]] = {}
def __setitem__(self, key, value):
"""Set item is used only in embeds."""
@ -63,6 +66,9 @@ class DiscordMessage:
self.finish_embed()
self.__setup_embed()
def add_file(self, filename: str, content: Union[str, BytesIO]):
self.files[filename] = (None if isinstance(content, str) else filename, content, "application/json" if isinstance(content, str) else "image/" + filename.split(".")[1])
def finish_embed(self):
if self.message_type != "embed":
return

View file

@ -129,10 +129,18 @@ def update_ratelimit(request):
def send_to_discord_webhook(data: Optional[DiscordMessage], metadata: DiscordMessageMetadata):
global rate_limit
header = settings["header"]
header['Content-Type'] = 'application/json'
if data.files:
header['Content-Type'] = 'multipart/form-data'
else:
header['Content-Type'] = 'application/json'
standard_args = dict(headers=header)
if metadata.method == "POST":
req = requests.Request("POST", data.webhook_url+"?wait=" + ("true" if AUTO_SUPPRESSION_ENABLED else "false"), data=repr(data), **standard_args)
if data.files:
data.add_file("payload_json", repr(data))
logger.debug(data.files)
req = requests.Request("POST", data.webhook_url+"?wait=" + ("true" if AUTO_SUPPRESSION_ENABLED else "false"), files=data.files, **standard_args)
else:
req = requests.Request("POST", data.webhook_url+"?wait=" + ("true" if AUTO_SUPPRESSION_ENABLED else "false"), data=repr(data), **standard_args)
elif metadata.method == "DELETE":
req = requests.Request("DELETE", metadata.webhook_url, **standard_args)
elif metadata.method == "PATCH":

View file

@ -18,13 +18,13 @@
# WARNING! SHITTY CODE AHEAD. ENTER ONLY IF YOU ARE SURE YOU CAN TAKE IT
# You have been warned
import time, logging.config, requests, datetime, math, os.path, schedule, sys, re, importlib
import io
import time, logging.config, requests, datetime, math, os.path, schedule, sys, importlib
import src.misc
from collections import defaultdict, Counter, OrderedDict
from typing import Optional
from typing import Optional, List
import src.api.client
from src.api.context import Context
from src.api.hooks import formatter_hooks, pre_hooks, post_hooks
@ -42,15 +42,23 @@ ngettext = rcgcdw.ngettext
TESTING = True if "--test" in sys.argv else False # debug mode, pipeline testing
AUTO_SUPPRESSION_ENABLED = settings.get("auto_suppression", {"enabled": False}).get("enabled")
PLOTTING_ENABLED = settings.get("event_appearance", {}).get("daily_overview", {}).get("plot", False)
if AUTO_SUPPRESSION_ENABLED:
from src.discord.redaction import delete_messages, redact_messages
# Prepare logging
logging.config.dictConfig(settings["logging"])
logger = logging.getLogger("rcgcdw")
logger.debug("Current settings: {settings}".format(settings=settings))
if PLOTTING_ENABLED:
try:
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
except ImportError:
logger.error("matplotlib is not installed. Install matplotlib with pip install matplotlib if you want to use plots in daily overview.")
def load_extensions():
"""Loads all of the extensions, can be a local import because all we need is them to register"""
@ -121,6 +129,27 @@ def daily_overview_sync(data: dict) -> dict:
return data_output
def overview_plot_generation(hours: defaultdict[int, int]) -> io.BytesIO:
"""Generates plot image using matplotlib"""
output = io.BytesIO()
current_hour, axes_data = datetime.datetime.utcnow().hour, [[], []]
for __ in range(24):
axes_data[0].append(current_hour)
axes_data[1].append(hours.get(current_hour, 0))
current_hour += 1
if current_hour > 23:
current_hour = 0
fig, ax = plt.subplots()
plt.bar(axes_data[0], axes_data[1])
plt.xlabel(_('Hour (UTC)'))
plt.ylabel(_('Actions'))
ax.set_xlim(-0.5, 23.5)
ax.set_xticklabels([str(axes_data[0][0])] + [str(x) for x in axes_data[0]])
ax.xaxis.set_major_locator(MultipleLocator(1))
plt.savefig(output, format="png")
return output
def day_overview():
try:
result = day_overview_request()
@ -146,7 +175,7 @@ def day_overview():
if "actionhidden" in item or "suppressed" in item or "userhidden" in item:
continue # while such actions have type value (edit/new/log) many other values are hidden and therefore can crash with key error, let's not process such events
activity = add_to_dict(activity, item["user"])
hours = add_to_dict(hours, datetime.datetime.strptime(item["timestamp"], "%Y-%m-%dT%H:%M:%SZ").hour)
hours = add_to_dict(hours, datetime.datetime.strptime(item["timestamp"], "%Y-%m-%dT%H:%M:%SZ").hour) # Edits can overlap between days at same hour if overview executes in non full hour, but let's ignore that
if item["type"] == "edit":
edits += 1
changed_bytes += item["newlen"] - item["oldlen"]
@ -190,6 +219,11 @@ def day_overview():
)
for name, value in fields:
embed.add_field(name, value, inline=True)
if PLOTTING_ENABLED:
file = overview_plot_generation(hours)
file_name = "_" + datetime.datetime.now().strftime("%Y-%m-%d_%H:%M") + "_wiki_overview.png"
embed.add_file(file_name, file)
embed["image"]["url"] = "attachment://" + file_name
embed.finish_embed()
send_to_discord(embed, meta=DiscordMessageMetadata("POST"))