update notes

This commit is contained in:
Zodiac 2025-02-18 19:51:12 -08:00
parent 21c37d46c7
commit bbca41c406

View File

@ -6,18 +6,23 @@ IRC Bot Plugin for Note Taking using TinyDB.
This plugin provides a single !note command with subcommands to manage both This plugin provides a single !note command with subcommands to manage both
daily and general notes. It supports the following subcommands: daily and general notes. It supports the following subcommands:
today [<content>...] today [--add|--replace] [<content>...]
View or update today's daily note. View or update today's daily note. If content is provided and a note for
today already exists, a warning is shown unless you specify --add (to append)
or --replace (to replace).
daily [--date <date>] [<content>...] daily [--date <date>] [--add|--replace] [<content>...]
View or update a daily note for the specified date (default is today). View or update a daily note for the specified date (default is today). If
content is provided and a note already exists, a warning is shown unless you
specify --add (to append) or --replace (to replace).
general <title> [--tags <tags>] [<content>...] general <title> [--tags <tags>] [<content>...]
View or update a general note with the given title. View or update a general note with the given title.
Optionally specify tags. Optionally specify tags.
list <type> list <type>
List all notes of the specified type (either 'daily' or 'general'). List all notes of the specified type (either 'daily' or 'general'). The
content of each note is displayed truncated.
search <type> <keyword> search <type> <keyword>
Search for a keyword in notes of the specified type. Search for a keyword in notes of the specified type.
@ -34,8 +39,8 @@ Dependencies:
- tinydb - tinydb
Author: Your Name Author: Your Name
Version: 1.1 Version: 1.3
Date: 2025-02-17 Date: 2025-02-18
""" """
import re import re
@ -121,12 +126,27 @@ def default_general_template(title, tags):
""" """
tag_line = f"Tags: {tags}" if tags else "" tag_line = f"Tags: {tags}" if tags else ""
return f"""# General Note: {title} return f"""# General Note: {title}
{tag_line} {tag_line} Created on: {now_str()}
Created on: {now_str()}
""" """
def truncate(text, length=50):
"""
Truncate the text to a specified length, appending "..." if truncated.
Args:
text (str): The text to truncate.
length (int): Maximum length of the returned text.
Returns:
str: The truncated text.
"""
if not isinstance(text, str):
text = str(text)
return text if len(text) <= length else text[:length] + "..."
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# NoteTaking Plugin # NoteTaking Plugin
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@ -171,17 +191,21 @@ class NoteTaking:
@command(aliases=['notes'], public=True, options_first=False, use_shlex=True) @command(aliases=['notes'], public=True, options_first=False, use_shlex=True)
async def note(self, mask, target, args): async def note(self, mask, target, args):
""" """
%%note %%note today [--add|--replace] [<content>...]
%%note today [<content>...] %%note daily [--date=<date>] [--add|--replace] [<content>...]
%%note daily [<content>...] [--date=<date>] %%note general <title> [--tags=<tags>] [<content>...]
%%note general <title> [<content>...] [--tags <tags>] %%note list [<type>]
%%note list <type>
%%note search <type> <keyword> %%note search <type> <keyword>
%%note summary %%note summary
%%note
""" """
# If no subcommand is provided, show the help message. # If no subcommand is provided, show the help message.
if not any(args.get(key) for key in ('today', 'daily', 'general', 'list', 'search', 'summary')): if not any(args.get(key) for key in ('today', 'daily', 'general', 'list', 'search', 'summary')):
self._show_help(target) # If there's content provided without a subcommand, treat it as a daily note update.
if args.get('<content>'):
await self._note_today(mask, target, args)
else:
self._show_help(target)
return return
try: try:
@ -208,10 +232,10 @@ class NoteTaking:
help_lines = [ help_lines = [
ircstyle.style("Usage: !note <subcommand> [options]", fg="red", bold=True), ircstyle.style("Usage: !note <subcommand> [options]", fg="red", bold=True),
"Subcommands:", "Subcommands:",
f"{ircstyle.style(' today', fg='yellow')} - View or update today's daily note.", f"{ircstyle.style(' today [--add|--replace] [<content>...]', fg='yellow')} - View or update today's daily note.",
f"{ircstyle.style(' daily [--date <date>]', fg='yellow')} - View or update a daily note for a specific date (default is today).", f"{ircstyle.style(' daily [--date <date>] [--add|--replace] [<content>...]', fg='yellow')} - View or update a daily note for a specific date (default is today).",
f"{ircstyle.style(' general <title> [--tags <tags>]', fg='yellow')} - View or update a general note with the given title. Optionally, specify tags.", f"{ircstyle.style(' general <title> [--tags <tags>] [<content>...]', fg='yellow')} - View or update a general note with the given title. Optionally, specify tags.",
f"{ircstyle.style(' list [daily|general]', fg='yellow')} - List all notes of a specific type.", f"{ircstyle.style(' list [daily|general]', fg='yellow')} - List all notes of a specific type with truncated content.",
f"{ircstyle.style(' search <type> <keyword>', fg='yellow')} - Search for a keyword in notes of a specific type.", f"{ircstyle.style(' search <type> <keyword>', fg='yellow')} - Search for a keyword in notes of a specific type.",
f"{ircstyle.style(' summary', fg='yellow')} - Display a summary of note counts.", f"{ircstyle.style(' summary', fg='yellow')} - Display a summary of note counts.",
] ]
@ -223,7 +247,9 @@ class NoteTaking:
""" """
Handle the 'today' subcommand for daily notes. Handle the 'today' subcommand for daily notes.
If content is provided, update today's note; otherwise, display it. If content is provided, update today's note.
If a note already exists and content is provided, warn the user unless
--add or --replace is specified.
""" """
day = today_str() day = today_str()
content_list = args.get('<content>') content_list = args.get('<content>')
@ -231,21 +257,50 @@ class NoteTaking:
note = self._get_daily_note(day) note = self._get_daily_note(day)
if content_list: if content_list:
new_content = " ".join(content_list) new_content = " ".join(content_list)
if note: # Check if both flags are provided
self.daily_table.update( if args.get('--add') and args.get('--replace'):
{'content': new_content, 'updated': now_str()}, self.bot.privmsg(
self.User.date == day target,
ircstyle.style("❌ Error: Cannot use both --add and --replace simultaneously. Please choose one.", fg="red", bold=True)
) )
return
if note:
# If note exists but neither flag is provided, warn the user.
if not (args.get('--add') or args.get('--replace')):
warning = ircstyle.style(
f"⚠️ Warning: Daily note for {day} already exists. Use --add to append to it or --replace to overwrite it.", fg="red", bold=True
)
self.bot.privmsg(target, warning)
return
if args.get('--add'):
appended_content = note.get('content') + "\n" + new_content
self.daily_table.update(
{'content': appended_content, 'updated': now_str()},
self.User.date == day
)
msg = ircstyle.style("", fg="green") + ircstyle.style(
f"Daily note for {day} updated (content added).", fg="blue", bold=True
)
elif args.get('--replace'):
self.daily_table.update(
{'content': new_content, 'updated': now_str()},
self.User.date == day
)
msg = ircstyle.style("", fg="green") + ircstyle.style(
f"Daily note for {day} replaced.", fg="blue", bold=True
)
else: else:
# No existing note; create a new one.
self.daily_table.insert({ self.daily_table.insert({
'date': day, 'date': day,
'content': new_content, 'content': new_content,
'created': now_str(), 'created': now_str(),
'updated': now_str() 'updated': now_str()
}) })
msg = ircstyle.style("", fg="green") + ircstyle.style( msg = ircstyle.style("", fg="green") + ircstyle.style(
f"Daily note for {day} updated.", fg="blue", bold=True f"Daily note for {day} created.", fg="blue", bold=True
) )
else: else:
if not note: if not note:
default_content = self.daily_template(day) default_content = self.daily_template(day)
@ -272,7 +327,9 @@ class NoteTaking:
""" """
Handle the 'daily' subcommand for daily notes with an optional date. Handle the 'daily' subcommand for daily notes with an optional date.
If content is provided, update the note; otherwise, display it. If content is provided, update the note.
If a note already exists and content is provided, warn the user unless
--add or --replace is specified.
""" """
day = args.get('--date') or today_str() day = args.get('--date') or today_str()
try: try:
@ -290,21 +347,49 @@ class NoteTaking:
note = self._get_daily_note(day) note = self._get_daily_note(day)
if content_list: if content_list:
new_content = " ".join(content_list) new_content = " ".join(content_list)
if note: # Check if both flags are provided
self.daily_table.update( if args.get('--add') and args.get('--replace'):
{'content': new_content, 'updated': now_str()}, self.bot.privmsg(
self.User.date == day target,
ircstyle.style("❌ Error: Cannot use both --add and --replace simultaneously. Please choose one.", fg="red", bold=True)
) )
return
if note:
if not (args.get('--add') or args.get('--replace')):
self.bot.privmsg(
target,
ircstyle.style(f"⚠️ Warning: Daily note for {day} already exists. Use --add to append or --replace to overwrite.", fg="red", bold=True)
)
return
if args.get('--add'):
appended_content = note.get('content') + "\n" + new_content
self.daily_table.update(
{'content': appended_content, 'updated': now_str()},
self.User.date == day
)
msg = ircstyle.style("", fg="green") + ircstyle.style(
f"Daily note for {day} updated (content added).", fg="blue", bold=True
)
elif args.get('--replace'):
self.daily_table.update(
{'content': new_content, 'updated': now_str()},
self.User.date == day
)
msg = ircstyle.style("", fg="green") + ircstyle.style(
f"Daily note for {day} replaced.", fg="blue", bold=True
)
else: else:
# Create new note if none exists.
self.daily_table.insert({ self.daily_table.insert({
'date': day, 'date': day,
'content': new_content, 'content': new_content,
'created': now_str(), 'created': now_str(),
'updated': now_str() 'updated': now_str()
}) })
msg = ircstyle.style("", fg="green") + ircstyle.style( msg = ircstyle.style("", fg="green") + ircstyle.style(
f"Daily note for {day} updated.", fg="blue", bold=True f"Daily note for {day} created.", fg="blue", bold=True
) )
else: else:
if not note: if not note:
default_content = self.daily_template(day) default_content = self.daily_template(day)
@ -410,7 +495,7 @@ class NoteTaking:
async def _note_list(self, target, args): async def _note_list(self, target, args):
""" """
Handle the 'list' subcommand to list notes. Handle the 'list' subcommand to list notes with truncated content.
Usage: Usage:
%%note list [<type>] %%note list [<type>]
@ -420,43 +505,63 @@ class NoteTaking:
note_type = args.get('<type>') note_type = args.get('<type>')
try: try:
if not note_type: if not note_type:
# List both daily and general notes # List both daily and general notes with content truncated.
daily_notes = self.daily_table.all() daily_notes = self.daily_table.all()
general_notes = self.general_table.all() general_notes = self.general_table.all()
# Filter valid daily notes if not daily_notes and not general_notes:
valid_daily_dates = [n.get('date') for n in daily_notes if isinstance(n.get('date'), str)]
# Filter valid general notes
valid_general_titles = [n.get('title') for n in general_notes if isinstance(n.get('title'), str)]
if not valid_daily_dates and not valid_general_titles:
msg = ircstyle.style("No notes found.", fg="red", bold=True) msg = ircstyle.style("No notes found.", fg="red", bold=True)
else: else:
msg = ircstyle.style("📝 All Notes:", fg="blue", bold=True) + "\n" msg_lines = [ircstyle.style("📝 All Notes:", fg="blue", bold=True)]
if valid_daily_dates: if daily_notes:
msg += ircstyle.style("📅 Daily Notes:", fg="yellow", bold=True) + "\n" msg_lines.append(ircstyle.style("📅 Daily Notes:", fg="yellow", bold=True))
msg += "\n".join([f"{date}" for date in sorted(valid_daily_dates)]) + "\n" # Sort daily notes by date.
if valid_general_titles: daily_sorted = sorted(
msg += ircstyle.style("📋 General Notes:", fg="cyan", bold=True) + "\n" [n for n in daily_notes if isinstance(n.get('date'), str)],
msg += "\n".join([f"{title}" for title in sorted(valid_general_titles)]) key=lambda x: x['date']
)
for note in daily_sorted:
date_str = note.get('date')
snippet = truncate(note.get('content', ''))
msg_lines.append(f"{ircstyle.style(date_str, fg='green')}: {ircstyle.style(snippet, fg='white')}")
if general_notes:
msg_lines.append(ircstyle.style("📋 General Notes:", fg="cyan", bold=True))
# Sort general notes by title.
general_sorted = sorted(
[n for n in general_notes if isinstance(n.get('title'), str)],
key=lambda x: x['title']
)
for note in general_sorted:
title = note.get('title')
snippet = truncate(note.get('content', ''))
msg_lines.append(f"{ircstyle.style(title, fg='green')}: {ircstyle.style(snippet, fg='white')}")
msg = "\n".join(msg_lines)
elif note_type == 'daily': elif note_type == 'daily':
notes = self.daily_table.all() notes = self.daily_table.all()
# Filter only notes with a valid date string valid_notes = [n for n in notes if isinstance(n.get('date'), str)]
valid_dates = [n.get('date') for n in notes if isinstance(n.get('date'), str)] if not valid_notes:
if not valid_dates:
msg = ircstyle.style("No daily notes found.", fg="red", bold=True) msg = ircstyle.style("No daily notes found.", fg="red", bold=True)
else: else:
dates = sorted(valid_dates) msg_lines = [ircstyle.style("📅 Daily Notes:", fg="blue", bold=True)]
msg = ircstyle.style("📅 Daily Notes:", fg="blue", bold=True) + "\n" daily_sorted = sorted(valid_notes, key=lambda x: x['date'])
msg += "\n".join([f"{date}" for date in dates]) for note in daily_sorted:
date_str = note.get('date')
snippet = truncate(note.get('content', ''))
msg_lines.append(f"{ircstyle.style(date_str, fg='green')}: {ircstyle.style(snippet, fg='white')}")
msg = "\n".join(msg_lines)
elif note_type == 'general': elif note_type == 'general':
notes = self.general_table.all() notes = self.general_table.all()
if not notes: valid_notes = [n for n in notes if isinstance(n.get('title'), str)]
if not valid_notes:
msg = ircstyle.style("No general notes found.", fg="red", bold=True) msg = ircstyle.style("No general notes found.", fg="red", bold=True)
else: else:
titles = sorted(n['title'] for n in notes if isinstance(n.get('title'), str)) msg_lines = [ircstyle.style("📋 General Notes:", fg="blue", bold=True)]
msg = ircstyle.style("📋 General Notes:", fg="blue", bold=True) + "\n" general_sorted = sorted(valid_notes, key=lambda x: x['title'])
msg += "\n".join([f"{title}" for title in titles]) for note in general_sorted:
title = note.get('title')
snippet = truncate(note.get('content', ''))
msg_lines.append(f"{ircstyle.style(title, fg='green')}: {ircstyle.style(snippet, fg='white')}")
msg = "\n".join(msg_lines)
else: else:
msg = ircstyle.style("Usage: !note list [daily|general]", fg="red", bold=True) msg = ircstyle.style("Usage: !note list [daily|general]", fg="red", bold=True)
for line in msg.split('\n'): for line in msg.split('\n'):