Compare commits

..

2 Commits

Author SHA1 Message Date
ea1814e166
Finish the base web doselog display
The issues are .. One can't load all the doses and then
filter dynamically via search. One has to limit records.
And it doesn't randomize.

Signed-off-by: Pratyush Desai <pratyush.desai@liberta.casa>
2024-12-15 21:00:42 +05:30
77030f9092
Doselog HTML Table Base
Added basic HTTP support to serve doselogs using
a simple HTML table. Currently hardcoded to one nick.

Signed-off-by: Pratyush Desai <pratyush.desai@liberta.casa>
2024-12-12 00:24:23 +05:30

231
plugin.py
View File

@ -31,7 +31,10 @@
from supybot import utils, plugins, ircutils, callbacks, world, conf, log
from supybot.commands import *
# HTTP Imports
from supybot import httpserver
# Misc
from num2words import num2words
import pickle
import datetime
@ -63,6 +66,110 @@ METHODS = {
"smoked": ["Smoked"]
}
class TripsitServerCallback(httpserver.SupyHTTPServerCallback):
name = 'Tripsit'
defaultResponse = """
This plugin handles only GET request, please don't use other requests."""
def __init__(self, plugin):
self.plugin = plugin # to access db
def doGet(self, handler, path):
if path == '/doses':
# Collect all dose logs from self.db
dose_logs = []
for nick, data in self.plugin.db.items():
for dose in data.get('doses', []):
dose_logs.append({
'nick': nick,
'time': dose['time'],
'dose': dose['dose'],
'drug': dose['drug'],
'method': dose['method'],
})
# Create HTML response
html_response = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Dose Logs</title>
<style>
table {
width: 100%;
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
th, td {
padding: 8px;
text-align: left;
}
#filter {
margin-bottom: 10px;
padding: 5px;
width: 300px;
}
</style>
</head>
<body>
<h1>Dose Logs</h1>
<input type="text" id="filter" placeholder="Search for nicknames, drugs, etc.">
<table id="doseTable">
<thead>
<tr>
<th>Nick</th>
<th>Time</th>
<th>Dose</th>
<th>Drug</th>
<th>Method</th>
</tr>
</thead>
<tbody>
"""
# Add rows for each dose log
for log in dose_logs:
html_response += f"""
<tr>
<td>{log['nick']}</td>
<td>{log['time']}</td>
<td>{log['dose']}</td>
<td>{log['drug']}</td>
<td>{log['method']}</td>
</tr>
"""
html_response += """
</tbody>
</table>
<script>
// Filter table rows based on input
document.getElementById('filter').addEventListener('input', function() {
const filter = this.value.toLowerCase();
const rows = document.querySelectorAll('#doseTable tbody tr');
rows.forEach(row => {
const text = row.innerText.toLowerCase();
row.style.display = text.includes(filter) ? '' : 'none';
});
});
</script>
</body>
</html>
"""
# Send the HTML response
handler.send_response(200)
handler.send_header('Content-type', 'text/html')
handler.end_headers()
handler.wfile.write(html_response.encode('utf-8'))
else:
# 404 response for unknown paths
handler.send_response(404)
handler.send_header('Content-type', 'text/html')
handler.end_headers()
handler.wfile.write(b"<h1>404 Not Found</h1>")
class Tripsit(callbacks.Plugin):
"""Harm-Reduction tools from tripsit's tripbot and the tripsitwiki"""
@ -74,6 +181,7 @@ class Tripsit(callbacks.Plugin):
self.db = {}
self._loadDb()
world.flushers.append(self._flushDb)
httpserver.hook('tripsit', TripsitServerCallback(self)) # register the callback at `/tripsit`
def _loadDb(self):
"""Loads the (flatfile) database mapping nicks to doses."""
@ -95,6 +203,7 @@ class Tripsit(callbacks.Plugin):
def die(self):
self._flushDb()
httpserver.unhook('tripsit')
world.flushers.remove(self._flushDb)
self.__parent.die()
@ -211,7 +320,102 @@ class Tripsit(callbacks.Plugin):
This command takes no arguments.
Retrieves the number of doses logged for a given nick
"""
""" def doGet(self, handler, path):
if path == '/doses':
# Collect all dose logs from self.db
dose_logs = []
for nick, data in self.plugin.db.items():
for dose in data.get('doses', []):
dose_logs.append({
'nick': nick,
'time': dose['time'],
'dose': dose['dose'],
'drug': dose['drug'],
'method': dose['method'],
})
# Create HTML response
html_response = """
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Dose Logs</title>
<style>
table {
width: 100%;
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
th, td {
padding: 8px;
text-align: left;
}
#filter {
margin-bottom: 10px;
padding: 5px;
width: 300px;
}
</style>
</head>
<body>
<h1>Dose Logs</h1>
<input type="text" id="filter" placeholder="Search for nicknames, drugs, etc.">
<table id="doseTable">
<thead>
<tr>
<th>Nick</th>
<th>Time</th>
<th>Dose</th>
<th>Drug</th>
<th>Method</th>
</tr>
</thead>
<tbody>
"""
# Add rows for each dose log
for log in dose_logs:
html_response += f"""
<tr>
<td>{log['nick']}</td>
<td>{log['time']}</td>
<td>{log['dose']}</td>
<td>{log['drug']}</td>
<td>{log['method']}</td>
</tr>
"""
html_response += """
</tbody>
</table>
<script>
// Filter table rows based on input
document.getElementById('filter').addEventListener('input', function() {
const filter = this.value.toLowerCase();
const rows = document.querySelectorAll('#doseTable tbody tr');
rows.forEach(row => {
const text = row.innerText.toLowerCase();
row.style.display = text.includes(filter) ? '' : 'none';
});
});
</script>
</body>
</html>
"""
# Send the HTML response
handler.send_response(200)
handler.send_header('Content-type', 'text/html')
handler.end_headers()
handler.wfile.write(html_response.encode('utf-8'))
else:
# 404 response for unknown paths
handler.send_response(404)
handler.send_header('Content-type', 'text/html')
handler.end_headers()
handler.wfile.write(b"<h1>404 Not Found</h1>")
nick = msg.nick
if nick in self.db:
try:
@ -278,16 +482,15 @@ class Tripsit(callbacks.Plugin):
doses = self.db[nick]['doses']
if drug_filter:
doses = [dose for dose in doses if dose['drug'].lower() == drug_filter.lower()]
if len(doses) == 0:
irc.error(f"No doses found for drug '{drug_filter}'.")
return
if drug_filter:
irc.reply(f"Here are your last {history} dose(s) for drug '{drug_filter}':", private=True)
else:
irc.reply(f"Here are your last {history} dose(s):", private=True)
try:
for number in range(0, history):
lastdose = doses[-(number + 1)]
irc.reply(f"Your last {history} dose(s) are:", private=True)
for number in range(history, 0, -1):
lastdose = doses[-number]
dose = lastdose['dose']
drug = lastdose['drug']
method = lastdose['method']
@ -297,13 +500,15 @@ class Tripsit(callbacks.Plugin):
time = datetime.datetime.now(tz=tz)
since_dose = time - dose_time
since_dose_seconds = since_dose.total_seconds()
hours, remainder = divmod(since_dose_seconds, 3600)
minutes, seconds = divmod(remainder, 60)
timedelta_str = f"{int(hours)} hours, {int(minutes)} minutes" if hours > 0 else f"{int(minutes)} minutes, {int(seconds)} seconds"
number_str = "The" if number == 0 else num2words(number + 1, to='ordinal')
if number == 1:
number = "The"
else:
number = num2words(number, to='ordinal')
re = utils.str.format(
"%s last dose: \x02Amount:\x0F %s of \x02%s\x0F \x02via\x0F %s | \x02Datetime:\x0F %s %s | \x02Time Since Last Dose:\x0F %s",
number_str, dose, drug, method, dose_time.strftime("%Y-%m-%d %H:%M:%S"), timezone, timedelta_str
"::> %s last dose: Amount: %s of \x02%s\x0F via %s | datetime: %s %s | timedelta %T",
number, dose, drug, method, dose_time.strftime("%c"), timezone, since_dose_seconds
)
irc.reply(re, private=True)
except IndexError: