diff --git a/gitlab_matrix/types.py b/gitlab_matrix/types.py
index f48174f..553144b 100644
--- a/gitlab_matrix/types.py
+++ b/gitlab_matrix/types.py
@@ -14,15 +14,20 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-from typing import List, Union, Dict, Optional, Type, NewType, ClassVar, Tuple, Iterable
from datetime import datetime
+from typing import ClassVar, Dict, Iterable, List, NewType, Optional, Tuple, Type, Union
-from jinja2 import TemplateNotFound
+import attr
from attr import dataclass
+from jinja2 import TemplateNotFound
+from mautrix.types import (
+ JSON,
+ ExtensibleEnum,
+ SerializableAttrs,
+ deserializer,
+ serializer,
+)
from yarl import URL
-import attr
-
-from mautrix.types import JSON, ExtensibleEnum, SerializableAttrs, serializer, deserializer
from .util import contrast, hex_to_rgb
@@ -929,3 +934,58 @@ def build_url(self) -> str:
"BuildStatus": BuildStatus,
"FailureReason": FailureReason,
}
+
+@dataclass
+class UserFilter(SerializableAttrs):
+ user_id: Optional[int]
+ user_name: Optional[str]
+
+
+def is_userid_in_event(evt: GitlabEventType, userid:int|None):
+ if userid is None:
+ return False
+ if hasattr(evt, 'user') and isinstance(evt.user, GitlabUser):
+ if evt.user.id is not None and evt.user.id == userid:
+ return True
+ if isinstance(evt, (GitlabIssueEvent)) and evt.assignees is not None:
+ if any(user.id == userid for user in evt.assignees):
+ return True
+ if isinstance(evt, (GitlabPushEvent)) and evt.user_id is not None and evt.user_id == userid:
+ return True
+ if isinstance(evt, (GitlabCommentEvent)):
+ if evt.merge_request is not None:
+ if evt.merge_request.assignee is not None and evt.merge_request.assignee.id == userid:
+ return True
+ if evt.issue is not None:
+ if evt.issue.author_id == userid:
+ return True
+ if evt.issue.assignee_id is not None and evt.issue.assignee_id == userid:
+ return True
+ if evt.issue.assignee_ids is not None and userid in evt.issue.assignee_ids :
+ return True
+ if evt.snippet is not None and evt.snippet.author_id == userid:
+ return True
+
+ return False
+
+def is_username_in_event(evt: GitlabEventType, username:str|None):
+ if username is None:
+ return False
+ if hasattr(evt, 'user') and isinstance(evt.user, GitlabUser):
+ if evt.user.username is not None and evt.user.username == username:
+ return True
+ if isinstance(evt, (GitlabIssueEvent)) and evt.assignees is not None:
+ if any(user.username == username for user in evt.assignees):
+ return True
+ if isinstance(evt, (GitlabPushEvent)) and evt.user_username is not None and evt.user_username == username:
+ return True
+ if isinstance(evt, (GitlabCommentEvent)):
+ if evt.merge_request is not None:
+ if evt.merge_request.assignee is not None and evt.merge_request.assignee.username == username:
+ return True
+ if evt.merge_request.last_commit.author is not None and evt.merge_request.last_commit.author.name == username:
+ return True
+ if evt.commit is not None:
+ if evt.commit.author is not None and evt.commit.author.name == username:
+ return True
+ return False
\ No newline at end of file
diff --git a/gitlab_matrix/webhook.py b/gitlab_matrix/webhook.py
index aa69a32..4e35b48 100644
--- a/gitlab_matrix/webhook.py
+++ b/gitlab_matrix/webhook.py
@@ -1,6 +1,6 @@
# gitlab - A GitLab client and webhook receiver for maubot
# Copyright (C) 2019 Lorenz Steinert
-# Copyright (C) 2021 Tulir Asokan
+# opyright (C) 2021 Tulir Asokan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@@ -14,22 +14,39 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import json
-from typing import List, Set, TYPE_CHECKING
-from asyncio import Task
import asyncio
+import json
import re
-
+from typing import List, Set
+from typing import TYPE_CHECKING
+from asyncio import Task
import attr
+from maubot.handlers import web, event
+from aiohttp.web import Request, Response
from jinja2 import TemplateNotFound
-from aiohttp.web import Response, Request
-
-from mautrix.types import (EventType, RoomID, StateEvent, Membership, MessageType, JSON,
- TextMessageEventContent, Format, ReactionEventContent, RelationType)
+from mautrix.types import (
+ JSON,
+ EventType,
+ Format,
+ Membership,
+ MessageType,
+ ReactionEventContent,
+ RelationType,
+ RoomID,
+ StateEvent,
+ TextMessageEventContent,
+)
from mautrix.util.formatter import parse_html
-from maubot.handlers import web, event
-from .types import GitlabJobEvent, EventParse, Action, OTHER_ENUMS
+from .types import (
+ OTHER_ENUMS,
+ Action,
+ EventParse,
+ GitlabJobEvent,
+ UserFilter,
+ is_userid_in_event,
+ is_username_in_event,
+)
from .util import TemplateManager, TemplateUtil
if TYPE_CHECKING:
@@ -69,6 +86,9 @@ async def post_handler(self, request: Request) -> Response:
except KeyError:
return Response(text="401: Unauthorized\n"
"Missing auth token header\n", status=401)
+
+ user_filter : str | None = None
+ userid_filter: int | None = None
if token == self.bot.config["secret"]:
try:
room_id = RoomID(request.query["room"])
@@ -76,11 +96,25 @@ async def post_handler(self, request: Request) -> Response:
return Response(text="400: Bad request\nNo room specified. "
"Did you forget the ?room query parameter?\n",
status=400)
+ try:
+ user_filter = request.query["username_filter"]
+ self.bot.log.trace(f"Query User name filter is {user_filter}")
+ except KeyError:
+ # user_filter is a optional query parameter, that will be ignored if it does not exist
+ pass
+ try:
+ userid_filter = int(request.query["userid_filter"])
+ self.bot.log.trace(f"Query User id filter is {userid_filter}")
+ except KeyError:
+ # userid_filter is a optional query parameter, that will be ignored if it does not exist
+ pass
+
else:
room_id = self.bot.db.get_webhook_room(token)
if not room_id:
return Response(text="401: Unauthorized\n", status=401)
+ filter = UserFilter(user_name= user_filter,user_id = userid_filter)
try:
evt_type = request.headers["X-Gitlab-Event"]
except KeyError:
@@ -107,14 +141,14 @@ async def post_handler(self, request: Request) -> Response:
headers={"Accept": "application/json"})
self.bot.log.trace("Accepted processing of %s", request.headers["X-Gitlab-Event"])
- task = asyncio.create_task(self.try_process_hook(body, evt_type, room_id))
+ task = asyncio.create_task(self.try_process_hook(body, evt_type, room_id, filter))
self.task_list += [task]
return Response(status=202, text="202: Accepted\nWebhook processing started.\n")
- async def try_process_hook(self, body: JSON, evt_type: str, room_id: RoomID) -> None:
+ async def try_process_hook(self, body: JSON, evt_type: str, room_id: RoomID, filter: UserFilter ) -> None:
try:
- await self.process_hook(body, evt_type, room_id)
+ await self.process_hook(body, evt_type, room_id, filter)
except Exception:
self.bot.log.warning("Failed to process webhook", exc_info=True)
finally:
@@ -125,10 +159,18 @@ async def try_process_hook(self, body: JSON, evt_type: str, room_id: RoomID) ->
if task:
self.task_list.remove(task)
- async def process_hook(self, body: JSON, evt_type: str, room_id: RoomID) -> None:
+ async def process_hook(self, body: JSON, evt_type: str, room_id: RoomID, filter: UserFilter) -> None:
msgtype = MessageType.NOTICE if self.bot.config["send_as_notice"] else MessageType.TEXT
evt = EventParse[evt_type].deserialize(body)
+ self.bot.log.trace(f" User id filter {filter.user_id} {filter.user_name}")
+ if filter.user_id is None and filter.user_name is None:
+ send_message = True
+ self.bot.log.trace(" User id filter is nothing")
+ else:
+ send_message = is_userid_in_event(evt, filter.user_id) | is_username_in_event(evt, filter.user_name)
+ self.bot.log.trace(f" User id filter has info. {send_message}")
+
was_manually_handled = True
if isinstance(evt, GitlabJobEvent):
await self.handle_job_event(evt, evt_type, room_id)
@@ -180,9 +222,10 @@ def abort() -> None:
edit_evt = self.bot.db.get_event(subevt.message_id, room_id)
if edit_evt:
content.set_edit(edit_evt)
- event_id = await self.bot.client.send_message(room_id, content)
- if not edit_evt and subevt.message_id:
- self.bot.db.put_event(subevt.message_id, room_id, event_id)
+ if send_message:
+ event_id = await self.bot.client.send_message(room_id, content)
+ if not edit_evt and subevt.message_id:
+ self.bot.db.put_event(subevt.message_id, room_id, event_id)
async def handle_job_event(self, evt: GitlabJobEvent, evt_type: str, room_id: RoomID) -> None:
push_evt = self.bot.db.get_event(evt.push_id, room_id)