From ad5266670b6609c029afad08e8e96913fc767a24 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Sat, 23 Apr 2022 11:25:56 -0500 Subject: [PATCH] Implement --change-time flag --- jrnl/FolderJournal.py | 12 ++ jrnl/Journal.py | 8 ++ jrnl/args.py | 8 ++ jrnl/jrnl.py | 34 +++++- tests/bdd/features/change_time.feature | 163 +++++++++++++++++++++++++ tests/bdd/test_features.py | 1 + tests/unit/test_parse_args.py | 8 ++ 7 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 tests/bdd/features/change_time.feature diff --git a/jrnl/FolderJournal.py b/jrnl/FolderJournal.py index 74f6291b..62b7ade5 100644 --- a/jrnl/FolderJournal.py +++ b/jrnl/FolderJournal.py @@ -8,6 +8,7 @@ import fnmatch import os from . import Journal +from . import time def get_files(journal_config): @@ -89,6 +90,17 @@ class Folder(Journal.Journal): self.entries.remove(entry) self._diff_entry_dates.append(entry.date) + def change_date_entries(self, date): + """Changes entry dates to given date.""" + + date = time.parse(date) + + self._diff_entry_dates.append(date) + + for entry in self.entries: + self._diff_entry_dates.append(entry.date) + entry.date = date + def parse_editable_str(self, edited): """Parses the output of self.editable_str and updates its entries.""" mod_entries = self._parse(edited) diff --git a/jrnl/Journal.py b/jrnl/Journal.py index bf446a92..5da79c4b 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -279,6 +279,14 @@ class Journal: return to_delete + def change_date_entries(self, date): + """Changes entry dates to given date.""" + + date = time.parse(date) + + for entry in self.entries: + entry.date = date + def new_entry(self, raw, date=None, sort=True): """Constructs a new entry from some raw text input. If a date is given, it will parse and use this, otherwise scan for a date in the input first.""" diff --git a/jrnl/args.py b/jrnl/args.py index dba5a749..37feb015 100644 --- a/jrnl/args.py +++ b/jrnl/args.py @@ -267,6 +267,14 @@ def parse_args(args=[]): action="store_true", help="Interactively deletes selected entries", ) + exporting.add_argument( + "--change-time", + dest="change_time", + nargs="?", + metavar="DATE", + const="now", + help="Change timestamp for seleted entries (default: now)", + ) exporting.add_argument( "--format", metavar="TYPE", diff --git a/jrnl/jrnl.py b/jrnl/jrnl.py index 8014b628..439237c6 100644 --- a/jrnl/jrnl.py +++ b/jrnl/jrnl.py @@ -79,6 +79,7 @@ def _is_write_mode(args, config, **kwargs): args.contains, args.delete, args.edit, + args.change_time, args.export, args.end_date, args.today_in_history, @@ -152,7 +153,9 @@ def write_mode(args, config, journal, **kwargs): def search_mode(args, journal, **kwargs): """ Search for entries in a journal, then either: - 1. Send them to configured editor for user manipulation + 1. Send them to configured editor for user manipulation (and also + change their timestamps if requested) + 2. Change their timestamps 2. Delete them (with confirmation for each entry) 3. Display them (with formatting options) """ @@ -169,6 +172,16 @@ def search_mode(args, journal, **kwargs): # Where do the search results go? if args.edit: _edit_search_results(**kwargs) + # If we want to both edit and change time in one action + if args.change_time: + # Re-filter the journal enties (_edit_search_results puts + # the filtered entries back) + kwargs["old_entries"] = journal.entries + _search_journal(**kwargs) + _change_time_search_results(**kwargs) + + elif args.change_time: + _change_time_search_results(**kwargs) elif args.delete: _delete_search_results(**kwargs) @@ -238,6 +251,11 @@ def _search_journal(args, journal, **kwargs): journal.limit(args.limit) +def _other_entries(journal, entries): + """Find entries that are not in journal""" + return [e for e in entries if e not in journal.entries] + + def _edit_search_results(config, journal, old_entries, **kwargs): """ 1. Send the given journal entries to the user-configured editor @@ -254,7 +272,7 @@ def _edit_search_results(config, journal, old_entries, **kwargs): ) # separate entries we are not editing - other_entries = [e for e in old_entries if e not in journal.entries] + other_entries = _other_entries(journal, old_entries) # Get stats now for summary later old_stats = _get_predit_stats(journal) @@ -320,6 +338,18 @@ def _delete_search_results(journal, old_entries, **kwargs): journal.write() +def _change_time_search_results(args, journal, old_entries, **kwargs): + # separate entries we are not editing + other_entries = _other_entries(journal, old_entries) + + date = time.parse(args.change_time) + journal.change_date_entries(date) + + journal.entries += other_entries + journal.sort() + journal.write() + + def _display_search_results(args, journal, **kwargs): if args.short or args.export == "short": print(journal.pprint(short=True)) diff --git a/tests/bdd/features/change_time.feature b/tests/bdd/features/change_time.feature new file mode 100644 index 00000000..5754664d --- /dev/null +++ b/tests/bdd/features/change_time.feature @@ -0,0 +1,163 @@ +Feature: Change entry times in journal + Scenario Outline: Change time flag changes single entry timestamp + Given we use the config "" + And we use the password "test" if prompted + When we run "jrnl -1" + Then the output should contain "2020-09-24 09:14 The third entry finally" + When we run "jrnl -1 --change-time '2022-04-23 10:30'" + When we run "jrnl -99 --short" + Then the output should be + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2022-04-23 10:30 The third entry finally after weeks without writing. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + | basic_encrypted.yaml | + | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Change time flag with nonsense input changes nothing + Given we use the config "" + When we run "jrnl --change-time now asdfasdf" + When we run "jrnl -99 --short" + Then the output should be + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | + | basic_dayone.yaml | + + + Scenario Outline: Change time flag with tag only changes tagged entries + Given we use the config "" + When we run "jrnl --change-time '2022-04-23 10:30' @ipsum" + When we run "jrnl -99 --short" + Then the output should be + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + 2022-04-23 10:30 Entry the first. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Change time flag with multiple tags changes all entries matching any of the tags + Given we use the config "" + When we run "jrnl --change-time '2022-04-23 10:30' @ipsum @tagthree" + When we run "jrnl -99 --short" + Then the output should be + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2022-04-23 10:30 Entry the first. + 2022-04-23 10:30 The third entry finally after weeks without writing. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Change time flag with -and changes boolean AND of tagged entries + Given we use the config "" + When we run "jrnl --change-time '2022-04-23 10:30' -and @tagone @tagtwo" + When we run "jrnl -99 --short" + Then the output should be + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + 2022-04-23 10:30 Entry the first. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Change time flag with -not does not change entries from given tag + Given we use the config "" + When we run "jrnl --change-time '2022-04-23 10:30' @tagone -not @ipsum" + When we run "jrnl -99 --short" + Then the output should be + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2022-04-23 10:30 The third entry finally after weeks without writing. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Change time flag with -from search operator only changes entries since that date + Given we use the config "" + When we run "jrnl --change-time '2022-04-23 10:30' -from 2020-09-01" + When we run "jrnl -99 --short" + Then the output should be + 2020-08-29 11:11 Entry the first. + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2022-04-23 10:30 The third entry finally after weeks without writing. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Change time flag with -to only changes entries up to specified date + Given we use the config "" + When we run "jrnl --change-time '2022-04-23 10:30' -to 2020-08-31" + When we run "jrnl -99 --short" + Then the output should be + 2020-09-24 09:14 The third entry finally after weeks without writing. + 2022-04-23 10:30 Entry the first. + 2022-04-23 10:30 A second entry in what I hope to be a long series. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Change time flag with -starred only changes starred entries + Given we use the config "" + When we run "jrnl --change-time '2022-04-23 10:30' -starred" + When we run "jrnl -99 --short" + Then the output should be + 2020-08-29 11:11 Entry the first. + 2020-09-24 09:14 The third entry finally after weeks without writing. + 2022-04-23 10:30 A second entry in what I hope to be a long series. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo + + + Scenario Outline: Change time flag with -contains only changes entries containing expression + Given we use the config "" + When we run "jrnl --change-time '2022-04-23 10:30' -contains dignissim" + When we run "jrnl -99 --short" + Then the output should be + 2020-08-31 14:32 A second entry in what I hope to be a long series. + 2020-09-24 09:14 The third entry finally after weeks without writing. + 2022-04-23 10:30 Entry the first. + + Examples: Configs + | config_file | + | basic_onefile.yaml | + | basic_folder.yaml | @todo + # | basic_dayone.yaml | @todo diff --git a/tests/bdd/test_features.py b/tests/bdd/test_features.py index 5ef3506e..04f9d46f 100644 --- a/tests/bdd/test_features.py +++ b/tests/bdd/test_features.py @@ -5,6 +5,7 @@ scenarios("features/config_file.feature") scenarios("features/core.feature") scenarios("features/datetime.feature") scenarios("features/delete.feature") +scenarios("features/change_time.feature") scenarios("features/encrypt.feature") scenarios("features/file_storage.feature") scenarios("features/format.feature") diff --git a/tests/unit/test_parse_args.py b/tests/unit/test_parse_args.py index f408c9aa..ab50df2b 100644 --- a/tests/unit/test_parse_args.py +++ b/tests/unit/test_parse_args.py @@ -17,6 +17,7 @@ def expected_args(**kwargs): "contains": None, "debug": False, "delete": False, + "change_time": None, "edit": False, "end_date": None, "today_in_history": False, @@ -58,6 +59,13 @@ def test_delete_alone(): assert cli_as_dict("--delete") == expected_args(delete=True) +def test_change_time_alone(): + assert cli_as_dict("--change-time") == expected_args(change_time="now") + assert cli_as_dict("--change-time yesterday") == expected_args( + change_time="yesterday" + ) + + def test_diagnostic_alone(): from jrnl.commands import preconfig_diagnostic