From 311300283b67f63b0c28ff2bd6154e9103109043 Mon Sep 17 00:00:00 2001 From: JustAnotherArchivist Date: Mon, 12 Oct 2020 16:23:18 +0000 Subject: [PATCH] Add channel description and info page --- config.example.toml | 2 ++ irclog.py | 25 ++++++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/config.example.toml b/config.example.toml index 22899e1..7ad4df9 100644 --- a/config.example.toml +++ b/config.example.toml @@ -50,3 +50,5 @@ #hidden = false # Keys of other channels that should be searched in addition to this one when a query is sent against it. If auth is required on another channel referenced here, it must be equal to this channel's. #extrasearchchannels = [] + # A description (string) of the channel, will be shown on /path if specified + #description = diff --git a/irclog.py b/irclog.py index 1dacff1..85f4a06 100644 --- a/irclog.py +++ b/irclog.py @@ -165,7 +165,7 @@ class Config(dict): raise InvalidConfig(f'Invalid channel key {key!r}') if not isinstance(channel, collections.abc.Mapping): raise InvalidConfig(f'Invalid channel for {key!r}') - if any(x not in ('ircchannel', 'path', 'auth', 'active', 'hidden', 'extrasearchchannels') for x in channel): + if any(x not in ('ircchannel', 'path', 'auth', 'active', 'hidden', 'extrasearchchannels', 'description') for x in channel): raise InvalidConfig(f'Unknown key(s) found in channel {key!r}') if 'ircchannel' not in channel: @@ -223,6 +223,11 @@ class Config(dict): raise InvalidConfig(f'Invalid channel {key!r} extrasearchchannels: cannot refer to self') # Validation of the values is performed after reading everything + if 'description' not in channel: + channel['description'] = None + if not isinstance(channel['description'], str) and channel['description'] is not None: + raise InvalidConfig(f'Invalid channel {key!r} description: must be a str or None') + # extrasearchchannels validation after reading all channels for key, channel in obj['channels'].items(): if any(x not in obj['channels'] for x in channel['extrasearchchannels']): @@ -806,11 +811,12 @@ class WebServer: def __init__(self, config): self.config = config - self._paths = {} # '/path' => ('#channel', auth, hidden, extrasearchpaths) where auth is either False (no authentication) or the HTTP header value for basic auth + self._paths = {} # '/path' => ('#channel', auth, hidden, extrasearchpaths, description) where auth is either False (no authentication) or the HTTP header value for basic auth self._app = aiohttp.web.Application() self._app.add_routes([ aiohttp.web.get('/', self.get_homepage), + aiohttp.web.get(r'/{path:[^/]+}', functools.partial(self._channel_handler, handler = self.get_channel_info)), aiohttp.web.get(r'/{path:[^/]+}/{date:\d{4}-\d{2}-\d{2}}', functools.partial(self._channel_handler, handler = self.get_log)), aiohttp.web.get(r'/{path:[^/]+}/{date:today}', functools.partial(self._channel_handler, handler = self.get_log)), aiohttp.web.get('/{path:[^/]+}/search', functools.partial(self._channel_handler, handler = self.search)), @@ -824,7 +830,8 @@ class WebServer: channel['ircchannel'], f'Basic {base64.b64encode(channel["auth"].encode("utf-8")).decode("utf-8")}' if channel['auth'] else False, channel['hidden'], - [config['channels'][otherchannel]['path'] for otherchannel in channel['extrasearchchannels']] + [config['channels'][otherchannel]['path'] for otherchannel in channel['extrasearchchannels']], + channel['description'], ) for channel in config['channels'].values()} needRebind = self.config['web'] != config['web'] #TODO only if there are changes to web.host or web.port; everything else can be updated without rebinding self.config = config @@ -870,6 +877,18 @@ class WebServer: lines.append(f'{"(PW) " if auth else ""}{html.escape(channel)} (search)') return aiohttp.web.Response(text = f'IRC logs{"
".join(lines)}', content_type = 'text/html') + async def get_channel_info(self, request): + self.logger.info(f'Received request {id(request)} from {request.remote!r} for {request.path!r}') + return aiohttp.web.Response( + text = ''.join([ + '', + f'{html.escape(self._paths[request.match_info["path"]][0])}', + f'{html.escape(self._paths[request.match_info["path"]][4] or "")}', + '' + ]), + content_type = 'text/html' + ) + def _file_iter_with_path(self, fn, path): # Open fn, iterate over its lines yielding (path, line) tuples with open(fn, 'r') as fp: