diff --git a/allianceauth/templatetags/admin_status.py b/allianceauth/templatetags/admin_status.py
index d7084dc5..d576d474 100644
--- a/allianceauth/templatetags/admin_status.py
+++ b/allianceauth/templatetags/admin_status.py
@@ -1,4 +1,7 @@
import logging
+from dataclasses import dataclass
+from enum import Enum, auto
+from urllib.parse import quote_plus
import requests
from packaging.version import InvalidVersion, Version as Pep440Version
@@ -7,10 +10,11 @@ from django import template
from django.conf import settings
from django.core.cache import cache
-from allianceauth import __version__
+from allianceauth import __version__, hooks
from allianceauth.authentication.task_statistics.counters import (
dashboard_results,
)
+from allianceauth.hooks import get_hooks
register = template.Library()
@@ -32,6 +36,63 @@ GITLAB_AUTH_ANNOUNCEMENT_ISSUES_URL = (
logger = logging.getLogger(__name__)
+class RepositoryKind(Enum):
+ """What kind of repository is being used"""
+ GITLAB = auto()
+ GITHUB = auto()
+
+@dataclass
+class AppAnnouncementHook:
+ """Hook for an application to send GitHub/GitLab issues as announcements"""
+ app_name: str
+ repository_namespace: str
+ repository_kind: RepositoryKind
+ label: str = "announcement"
+
+
+ def get_announcement_list(self) -> list:
+ """
+ Checks the application repository to find issues with the `Announcement` tag and return their title and link to
+ be displayed.
+ """
+ match self.repository_kind:
+ case RepositoryKind.GITHUB:
+ announcement_list = self._get_github_announcement_list()
+ case RepositoryKind.GITLAB:
+ announcement_list = self._get_gitlab_announcement_list()
+ case _:
+ return []
+
+ for announcement in announcement_list:
+ announcement["app_name"] = self.app_name
+
+ return announcement_list
+
+
+ def _get_github_announcement_list(self) -> list:
+ """
+ Return the issue list for a GitHub repository
+ Will filter if the `pull_request` attribute is present
+ """
+ raw_list = _fetch_list_from_github(
+ f"https://api.github.com/repos/{self.repository_namespace}/issues"
+ f"?labels={self.label}&state=all"
+ )
+ return [element for element in raw_list if not element.get("pull_request")]
+
+ def _get_gitlab_announcement_list(self) -> list:
+ """Return the issues list for a GitLab repository"""
+ return _fetch_list_from_gitlab(
+ f"https://gitlab.com/api/v4/projects/{quote_plus(self.repository_namespace)}/issues"
+ f"?labels={self.label}")
+
+@hooks.register("app_announcement_hook")
+def test_hook():
+ return AppAnnouncementHook("test GitHub app", "r0kym/allianceauth-example-plugin", RepositoryKind.GITLAB)
+
+@hooks.register("app_announcement_hook")
+def test_hook_2():
+ return AppAnnouncementHook("test GitHub app", "r0kym/test", RepositoryKind.GITHUB)
@register.simple_tag()
def decimal_widthratio(this_value, max_value, max_width) -> str:
@@ -80,17 +141,36 @@ def _current_notifications() -> dict:
_fetch_notification_issues_from_gitlab,
NOTIFICATION_CACHE_TIME
)
+ app_notifications = []
+ hooks = get_hooks("app_announcement_hook")
+ items = [fn() for fn in hooks]
+ for hook in items:
+ app_notifications.extend(hook.get_announcement_list())
+ """
+ app_notifications.extend(cache.get_or_set(
+ f"{hook.app_name}_notification_issues",
+ hook.get_announcement_list,
+ NOTIFICATION_CACHE_TIME,
+ ))
+ """
except requests.HTTPError:
logger.warning('Error while getting gitlab notifications', exc_info=True)
top_notifications = []
+ application_notifications = []
else:
if notifications:
top_notifications = notifications[:5]
else:
top_notifications = []
+ if app_notifications:
+ application_notifications = app_notifications[:10]
+ else:
+ application_notifications = []
+
response = {
'notifications': top_notifications,
+ 'application_notifications': application_notifications,
}
return response
@@ -123,7 +203,7 @@ def _current_version_summary() -> dict:
has_current_beta = \
current_version <= latest_beta_version \
and latest_patch_version <= latest_beta_version \
- if latest_beta_version else False
+ if latest_beta_version else False
response = {
'latest_patch': has_latest_patch,
@@ -199,3 +279,38 @@ def _fetch_list_from_gitlab(url: str, max_pages: int = MAX_PAGES) -> list:
break
return result
+
+def _fetch_list_from_github(url: str, max_pages: int = MAX_PAGES) -> list:
+ """returns a list from the GitHub API. Supports paging"""
+ # TODO actual paging
+
+ result = []
+ for page in range(1, max_pages+1):
+ try:
+ request = requests.get(
+ url,
+ params={'page': page},
+ headers={
+ "Accept": "application/vnd.github+json",
+ "X-GitHub-Api-Version": "2022-11-28"
+ }
+ )
+ request.raise_for_status()
+ except requests.exceptions.RequestException as e:
+ error_str = str(e)
+
+ logger.warning(
+ f'Unable to fetch from GitHub API. Error: {error_str}',
+ exc_info=True,
+ )
+
+ return result
+
+ result += request.json()
+
+ if 'link' in request.headers and 'rel=\"next\"' in request.headers['link']:
+ continue
+
+ break
+
+ return result