Merge branch 'hooks-context' into 'testing'

Add `feed_type` to Context

See merge request piotrex43/RcGcDw!99
This commit is contained in:
MarkusRost 2022-06-14 21:56:15 +00:00
commit b4485dce38
8 changed files with 126 additions and 31 deletions

View file

@ -112,9 +112,10 @@ Context can consist of the following fields:
- `client` - [Client](#Client) object - `client` - [Client](#Client) object
- `webhook_url` - string - webhook url for given formatter - `webhook_url` - string - webhook url for given formatter
- `message_type` - string - can be either `embed` or `compact` - `message_type` - string - can be either `embed` or `compact`
- `feed_type` - string - type of the feed, can be either `recentchanges`, `abuselog` or `discussion`
- `event` - string - action called, should be the same as formatter event action
- `categories` - {"new": set(), "removed": set()} - each set containing strings of added or removed categories for given page - `categories` - {"new": set(), "removed": set()} - each set containing strings of added or removed categories for given page
- `parsedcomment` - string - contains escaped and Markdown parsed summary (parsed_comment) of a log/edit action - `parsedcomment` - string - contains escaped and Markdown parsed summary (parsed_comment) of a log/edit action
- `event` - string - action called, should be the same as formatter event action
- `comment_page` - dict - containing `fullUrl` and `article` with strings both to full article url and its name - `comment_page` - dict - containing `fullUrl` and `article` with strings both to full article url and its name
### Util ### Util

View file

@ -331,7 +331,7 @@ def embed_discussion_article_comment(ctx: Context, post: dict):
embed_author_discussions(post, embed) embed_author_discussions(post, embed)
article_paths = ctx.comment_page article_paths = ctx.comment_page
if article_paths is None: if article_paths is None:
article_page = {"title": _("unknown"), "fullUrl": settings["fandom_discussions"]["wiki_url"]} # No page known article_paths = {"title": _("unknown"), "fullUrl": settings["fandom_discussions"]["wiki_url"]} # No page known
if not post["isReply"]: if not post["isReply"]:
embed.event_type = "discussion/comment/post" embed.event_type = "discussion/comment/post"
embed["url"] = "{url}?commentId={commentId}".format(url=article_paths["fullUrl"], commentId=post["threadId"]) embed["url"] = "{url}?commentId={commentId}".format(url=article_paths["fullUrl"], commentId=post["threadId"])

View file

@ -13,4 +13,6 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with RcGcDw. If not, see <http://www.gnu.org/licenses/>. # along with RcGcDw. If not, see <http://www.gnu.org/licenses/>.
import extensions.hooks.example_hook #import extensions.hooks.example_hook
#import extensions.hooks.usertalk
#import extensions.hooks.edit_alerts

View file

@ -13,6 +13,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with RcGcDw. If not, see <http://www.gnu.org/licenses/>. # along with RcGcDw. If not, see <http://www.gnu.org/licenses/>.
import ipaddress
from src.api.hook import post_hook from src.api.hook import post_hook
from src.configloader import settings from src.configloader import settings
@ -27,6 +28,11 @@ from src.configloader import settings
# }, # },
# "requirements": [ # "requirements": [
# { # {
# "feed": [
# "recentchanges",
# "abuselog",
# "discussion"
# ],
# "action": [ # "action": [
# "edit", # "edit",
# "delete/delete", # "delete/delete",
@ -40,6 +46,14 @@ from src.configloader import settings
# "title": [ # "title": [
# "PAGETITLE" # "PAGETITLE"
# ], # ],
# "forum": [
# "FORUMNAME",
# null
# ],
# "is_reply": null,
# "namespace": [
# 0
# ],
# "tags": [ # "tags": [
# ["EDIT TAG", "AND EDIT TAG"], # ["EDIT TAG", "AND EDIT TAG"],
# ["OR EDIT TAG"] # ["OR EDIT TAG"]
@ -55,6 +69,16 @@ from src.configloader import settings
# ["OR CATEGORY"] # ["OR CATEGORY"]
# ] # ]
# } # }
# ],
# "filter": [
# "Section removal",
# "1"
# ],
# "af_action": [
# "edit"
# ],
# "result": [
# "disallow"
# ] # ]
# } # }
# ] # ]
@ -92,28 +116,79 @@ def edit_alerts_hook(message, metadata, context, change):
# For every requirement, if one of the requirements passes the alert gets executed # For every requirement, if one of the requirements passes the alert gets executed
for requirement in alert.get("requirements", []): for requirement in alert.get("requirements", []):
try: try:
req_feed = requirement.get("feed", [])
if req_feed and context.feed_type not in req_feed:
raise RequirementNotMet
req_action = requirement.get("action", []) req_action = requirement.get("action", [])
# If current action isn't in config for this requirement AND current event type is not in the requirements in settings skip this requirement # If current action isn't in config for this requirement AND current event type is not in the requirements in settings skip this requirement
if req_action and context.event not in req_action and context.event.split('/', 1)[0] not in req_action: if req_action and context.event not in req_action and context.event.split('/', 1)[0] not in req_action:
raise RequirementNotMet raise RequirementNotMet
req_user = requirement.get("user", []) req_user = requirement.get("user", [])
change_user = None
change_anon = False
if context.feed_type == "discussion":
if change["creatorIp"]:
change_user = change["creatorIp"][1:]
change_anon = True
elif change["createdBy"]["name"]:
change_user = change["createdBy"]["name"]
change_anon = False
else:
change_user = change["user"]
if context.feed_type == "recentchanges":
change_anon = "anon" in change
else:
try:
ipaddress.ip_address(change_user)
except ValueError:
change_anon = False
else:
change_anon = True
# If current user is not in config AND checkings for anon and user fail # If current user is not in config AND checkings for anon and user fail
if req_user and change["user"] not in req_user and ("@__anon__" if "anon" in change else "@__user__") not in req_user: if req_user and change_user and change_user not in req_user and ("@__anon__" if change_anon else "@__user__") not in req_user:
raise RequirementNotMet raise RequirementNotMet
req_title = requirement.get("title", []) req_title = requirement.get("title", [])
if req_title and change["title"] not in req_title: change_title = change["title"]
if context.feed_type == "discussion" and change_title is None:
change_title = change["_embedded"]["thread"][0]["title"]
if change_title is None and context.comment_page is not None:
change_title = context.comment_page["title"]
if req_title and change_title not in req_title:
raise RequirementNotMet raise RequirementNotMet
check_group_requirements(change.get("tags", []), requirement.get("tags", [])) if context.feed_type == "discussion":
if requirement.get("categories", []): req_forum = requirement.get("forum", [])
for req_cats in requirement.get("categories", []): if req_forum and change["forumName"] not in req_forum:
try: raise RequirementNotMet
check_group_requirements(context.categories.new, req_cats.get("added", [])) req_reply = requirement.get("is_reply", None)
check_group_requirements(context.categories.removed, req_cats.get("removed", [])) if req_reply is not None and change["isReply"] == req_reply:
except RequirementNotMet: raise RequirementNotMet
continue else:
req_namespace = requirement.get("namespace", [])
if req_namespace and change["ns"] not in req_namespace:
raise RequirementNotMet
if context.feed_type == "recentchanges":
check_group_requirements(change.get("tags", []), requirement.get("tags", []))
if requirement.get("categories", []):
for req_cats in requirement.get("categories", []):
try:
check_group_requirements(context.categories.new, req_cats.get("added", []))
check_group_requirements(context.categories.removed, req_cats.get("removed", []))
except RequirementNotMet:
continue
else:
break
else: else:
break raise RequirementNotMet
else: elif context.feed_type == "abuselog":
req_filter = requirement.get("filter", [])
# Allow both filter id and name as id might be hidden when logged out
if req_filter and change["filter"] not in req_filter and change["filter_id"] not in req_filter:
raise RequirementNotMet
af_action = requirement.get("af_action", [])
if af_action and change["action"] not in af_action:
raise RequirementNotMet
req_result = requirement.get("result", [])
if req_result and change["result"] not in req_result:
raise RequirementNotMet raise RequirementNotMet
except RequirementNotMet: except RequirementNotMet:
continue continue

View file

@ -25,14 +25,29 @@ from src.configloader import settings
# } # }
discord_users = settings.get("hooks", {}).get("usertalk", {}) discord_users = settings.get("hooks", {}).get("usertalk", {})
def add_mention(message, userid):
"""This function adds a mention for the userid"""
message.webhook_object["content"] = (message.webhook_object.get("content", "") or "") + " <@{}>".format(userid)
if message.webhook_object["allowed_mentions"].get("users", []):
if userid not in message.webhook_object["allowed_mentions"]["users"]:
message.webhook_object["allowed_mentions"]["users"].append(userid)
else:
message.webhook_object["allowed_mentions"]["users"] = [userid]
@post_hook @post_hook
def usertalk_hook(message, metadata, context, change): def usertalk_hook(message, metadata, context, change):
if discord_users and change["ns"] in [2, 3, 202] and not "/" in change["title"]: if not discord_users:
return
if context.feed_type in ["recentchanges", "abuselog"] and change["ns"] in [2, 3, 202, 1200] and "/" not in change["title"]:
username = change["title"].split(':', 1)[1] username = change["title"].split(':', 1)[1]
if discord_users.get(username, "") and username != change["user"]: if discord_users.get(username, "") and username != change["user"]:
message.webhook_object["content"] = (message.webhook_object.get("content", "") or "") + " <@{}>".format(discord_users[username]) add_mention(message, discord_users[username])
if message.webhook_object["allowed_mentions"].get("users", []): elif context.feed_type == "discussion" and context.event == "discussion/wall" and change["forumName"].endswith(' Message Wall'):
if discord_users[username] not in message.webhook_object["allowed_mentions"]["users"]: username = change["forumName"][:-13]
message.webhook_object["allowed_mentions"]["users"].append(discord_users[username]) author = None
else: if change["creatorIp"]:
message.webhook_object["allowed_mentions"]["users"] = [discord_users[username]] author = change["creatorIp"][1:]
elif change["createdBy"]["name"]:
author = change["createdBy"]["name"]
if discord_users.get(username, "") and username != author:
add_mention(message, discord_users[username])

View file

@ -22,10 +22,11 @@ if TYPE_CHECKING:
class Context: class Context:
"""Context object containing client and some metadata regarding specific formatter call, """Context object containing client and some metadata regarding specific formatter call,
they are mainly used as a bridge between part that fetches the changes and API's formatters""" they are mainly used as a bridge between part that fetches the changes and API's formatters"""
def __init__(self, message_type: str, webhook_url: str, client: Client): def __init__(self, message_type: str, feed_type: str, webhook_url: str, client: Client):
self.client = client self.client = client
self.webhook_url = webhook_url self.webhook_url = webhook_url
self.message_type = message_type self.message_type = message_type
self.feed_type = feed_type
self.categories = None self.categories = None
self.parsedcomment = None self.parsedcomment = None
self.event = None self.event = None
@ -41,4 +42,4 @@ class Context:
self.comment_page = page self.comment_page = page
def __str__(self): def __str__(self):
return f"<Context message_type={self.message_type} event={self.event} webhook_url={self.webhook_url}" return f"<Context message_type={self.message_type} feed_type={self.feed_type} event={self.event} webhook_url={self.webhook_url}"

View file

@ -107,7 +107,7 @@ def parse_discussion_post(post, comment_pages):
"""Initial post recognition & handling""" """Initial post recognition & handling"""
global client global client
post_type = post["_embedded"]["thread"][0]["containerType"] post_type = post["_embedded"]["thread"][0]["containerType"]
context = Context(display_mode, webhook_url, client) context = Context(display_mode, "discussion", webhook_url, client)
# Filter posts by forum # Filter posts by forum
if post_type == "FORUM" and settings["fandom_discussions"].get("show_forums", []): if post_type == "FORUM" and settings["fandom_discussions"].get("show_forums", []):
if not post["forumName"] in settings["fandom_discussions"]["show_forums"]: if not post["forumName"] in settings["fandom_discussions"]["show_forums"]:

View file

@ -202,10 +202,10 @@ def rc_processor(change, changed_categories):
metadata = DiscordMessageMetadata("POST", rev_id=change.get("revid", None), log_id=change.get("logid", None), metadata = DiscordMessageMetadata("POST", rev_id=change.get("revid", None), log_id=change.get("logid", None),
page_id=change.get("pageid", None)) page_id=change.get("pageid", None))
logger.debug(change) logger.debug(change)
context = Context(settings["appearance"]["mode"], settings["webhookURL"], client) context = Context(settings["appearance"]["mode"], "recentchanges", settings["webhookURL"], client)
run_hooks(pre_hooks, context, change)
if ("actionhidden" in change or "suppressed" in change) and "suppressed" not in settings["ignored"]: # if event is hidden using suppression if ("actionhidden" in change or "suppressed" in change) and "suppressed" not in settings["ignored"]: # if event is hidden using suppression
context.event = "suppressed" context.event = "suppressed"
run_hooks(pre_hooks, context, change)
try: try:
discord_message: Optional[DiscordMessage] = default_message("suppressed", formatter_hooks)(context, change) discord_message: Optional[DiscordMessage] = default_message("suppressed", formatter_hooks)(context, change)
except NoFormatter: except NoFormatter:
@ -242,6 +242,7 @@ def rc_processor(change, changed_categories):
if identification_string in settings["ignored"]: if identification_string in settings["ignored"]:
return return
context.event = identification_string context.event = identification_string
run_hooks(pre_hooks, context, change)
try: try:
discord_message: Optional[DiscordMessage] = default_message(identification_string, formatter_hooks)(context, change) discord_message: Optional[DiscordMessage] = default_message(identification_string, formatter_hooks)(context, change)
except: except:
@ -278,9 +279,9 @@ def abuselog_processing(entry):
action = "abuselog" action = "abuselog"
if action in settings["ignored"]: if action in settings["ignored"]:
return return
context = Context(settings["appearance"]["mode"], settings["webhookURL"], client) context = Context(settings["appearance"]["mode"], "abuselog", settings["webhookURL"], client)
run_hooks(pre_hooks, context, entry)
context.event = action context.event = action
run_hooks(pre_hooks, context, entry)
try: try:
discord_message: Optional[DiscordMessage] = default_message(action, formatter_hooks)(context, entry) discord_message: Optional[DiscordMessage] = default_message(action, formatter_hooks)(context, entry)
except NoFormatter: except NoFormatter: