From d0b7436da77230a961a5fd8f3bd744069c9fbe94 Mon Sep 17 00:00:00 2001 From: Cameron Ball Date: Sun, 16 Dec 2018 00:20:17 +0800 Subject: [PATCH] Implement script to warn about unfinished tasks --- common.php | 61 ++++++++++++++++++++++++++++++---- purjolok.php | 22 ++++--------- strings.php | 50 ++++++++++++++++++++++++---- taskMatrix.php | 2 +- tasks.php | 18 +++------- unfinished.php | 101 +++++++++++++++++++++++++++++++++++++++++++++++---------- 6 files changed, 193 insertions(+), 61 deletions(-) diff --git a/common.php b/common.php index a6e9212..f07c970 100644 --- a/common.php +++ b/common.php @@ -45,11 +45,11 @@ function partition(int $numPartitions, $array) { $partitionSize = (int)ceil(count($array) / $numPartitions); return - filter(notEmpty)( + array_values(filter(notEmpty)( map(function($p) use ($array, $partitionSize) { return array_slice($array, $p*$partitionSize, $partitionSize); })(range(0, $numPartitions-1)) - ); + )); } function getInbox($inbox) { @@ -216,14 +216,15 @@ function ∪($a, $b) { return array_merge($a, $b); } -function getSeason($monthNum) { - return ['summer', 'autumn', 'winter', 'spring'][floor(($monthNum)%12/3)]; +function getSeason(int $monthNum) { + return ['summer', 'autumn', 'winter', 'spring'][floor(($monthNum%12)/3)]; } function getMonthName($monthNum) { return ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'][$monthNum-1]; } +// XXX: Consider renaming these to "is[First/Last]WeekOf[Month/Season]" function isStartOfSeason($monthNum, $dayNum) { return ($monthNum)%3 == 0 && isStartOfMonth($dayNum); } @@ -232,6 +233,18 @@ function isStartOfMonth($dayNum) { return $dayNum < 8; } +function isEndOfSeason($yearNum, $monthNum, $dayNum) { + return ($monthNum+1)%3 == 0 && isEndOfMonth($yearNum, $monthNum, $dayNum); +} + +function isEndOfMonth($yearNum, $monthNum, $dayNum) { + return $dayNum + 7 > cal_days_in_month(CAL_GREGORIAN, $monthNum, $yearNum); +} + +function isEndOfYear($yearNum, $monthNum, $dayNum) { + return $monthNum == 12 && isEndOfMonth($yearNum, $monthNum, $dayNum); +} + function getTasksForTheSeason($season, $taskMatrix) { return array_unique( array_reduce( @@ -263,15 +276,49 @@ function getTasksForTheMonth($monthNum, $taskMatrix) { ); } -// NB weeknum is 1-4 (the week of the month, not consistent with other things) -function getTasksForTheWeek($weekNum, $monthNum, $taskMatrix) { +function getTasksForTheWeek(int $weekNum, int $monthNum, array $taskMatrix) { return array_merge( $weekNum % 2 == 0 ? $taskMatrix['bimonthly'] : [], $taskMatrix['annualy'][getSeason($monthNum)][getMonthName($monthNum)]['weekly'] ?? [], - partition(4, getTasksForTheMonth($monthNum, $taskMatrix))[$weekNum] + partition(4, getTasksForTheMonth($monthNum, $taskMatrix))[$weekNum-1] + ); +} + +const getFilePathForWeek = 'getFilePathForWeek'; +function getFilePathForWeek(int $year, int $monthNum, int $weekNum) { + // December is part of next year's summer + $seasonYear = $year; + return sprintf( + 'tasks/%s/%s/%s/week%s.txt', + $seasonYear, + getSeason($monthNum), + getMonthName($monthNum), + $weekNum ); } +function getFilePathsForMonth(int $year, int $monthNum) { + return map(function($week) use ($year, $monthNum){ + return getFilePathForWeek($year, $monthNum, $week); + })(range(1,4)); +} + +function getFilePathsForSeason(int $year, string $season) { + return array_merge(...map(function($monthNum) use ($year) { + // Summer of the current year includes december of the previous year. + $seasonYear = $year - ($monthNum == 12 ? 1 : 0); + return getFilePathsForMonth($seasonYear, $monthNum); + })(array_filter(range(1,12), function($month) use ($season) { + return getSeason($month) == $season; + }))); +} + +function getFilePathsForYear(int $year) { + return array_merge(...map(function($season) use ($year) { + return getFilePathsForSeason($year, $season); + })(['summer', 'winter', 'spring', 'autumn'])); +} + function closest($n, $list) { $a = array_filter($list, function($value) use ($n) { return $value <= $n; diff --git a/purjolok.php b/purjolok.php index 395f41d..5cab7de 100644 --- a/purjolok.php +++ b/purjolok.php @@ -142,21 +142,17 @@ getTelegram()->addCommand( $tasksForTheWeek = getTasksForTheWeek( array_search($closestMonday, $mondays), - $dt->format('m'), + (int)$dt->format('m'), require 'taskMatrix.php' ); $completedTasksFile = "$directory" . "/completed.txt"; $completedTasks = file_exists($completedTasksFile) ? lines(trim(file_get_contents($completedTasksFile))) : []; - $stringAndCode = function($string) { - return getString($string) . " (" . $string . ")"; - }; - $this->replyWithMessage([ 'text' => ununlines([ getString('tasksForTheWeek'), - unlines(map($stringAndCode)(array_diff($tasksForTheWeek, $completedTasks))) + unlines(map(getStringAndCode)(array_diff($tasksForTheWeek, $completedTasks))) ]) ]); } @@ -178,24 +174,18 @@ getTelegram()->addCommand( ]; $closestMonday = closest($dt->format('d'), $mondays); - $directory = sprintf( - "tasks/%s/%s/%s", - $dt->format('Y'), - $dt->format('F'), - $dt->format('W') - ); + $completedTasksFile = getFilePathForWeek((int)$dt->format('Y'), (int)$dt->format('n'), array_search($closestMonday, $mondays)); $tasksForTheWeek = getTasksForTheWeek( array_search($closestMonday, $mondays), - $dt->format('m'), + (int)$dt->format('m'), require 'taskMatrix.php' ); - $completedTasksFile = "$directory" . "/completed.txt"; $completedTasks = file_exists($completedTasksFile) ? lines(trim(file_get_contents($completedTasksFile))) : []; - if (!is_dir($directory)) { - mkdir($directory, 0777, true); + if (!is_dir(dirname($completedTasksFile))) { + mkdir(dirname($completedTasksFile), 0777, true); } if (in_array($arguments, $completedTasks)) { diff --git a/strings.php b/strings.php index a4e03c1..b9471c4 100644 --- a/strings.php +++ b/strings.php @@ -9,19 +9,53 @@ return [ 'goodnightNormal' => 'I\'m signing off for the night. Before I go; tomorrow it\'s going to be about %s when you get up and %s later in the day. Jumper and trousers, maybe?', 'goodnight' => 'Goodnight!', - 'beginningOfSummer' => 'It\'s the start of summer! To get you prepared, here are the unique things that will happen this season (in addition to regular weekly(ish) shit)...', - 'beginningOfWinter' => 'It\'s the start of winter (at last, fuck summer). Heads up lads, here are the unique tasks that are wanting doing this season (in addition to regular junk)...', + 'beginningOfSummer' => 'It\'s the start of summer! To get you prepared, here are the unique things that will happen this season...', + 'beginningOfWinter' => 'It\'s the start of winter (at last, fuck summer). Heads up lads, here are the unique tasks that are wanting doing this season...', + 'beginningOfAutumn' => 'Autumn is here 🍂🍃 Here\'s an overview of the unique tasks for this season...', + 'beginningOfSpring' => 'Spring has spring 🌻☀️ Here are the upcomming seasonal tasks...', - 'beginningOfDecember' => 'Welcome to December! Oh boy!', - 'beginningOfJanuary' => 'Welcome to January! Oh boy.', + 'beginningOfJanuary' => 'Welcome to January! Oh boy. Here\'s a summary of tasks for the month:', + 'beginningOfFebruary' => 'February is here! Here\'s an overview of what to expect:', + 'beginningOfMarch' => 'It\'s March! Here\'s what you\'re up against:', + 'beginningOfApril' => 'It\'s the start of April, you know what that means. Here\s the overview:', + 'beginningOfMay' => 'Welcome to May! Hooo geez. Check out the doozies you gotta do:', + 'beginningOfJune' => 'June is here, time to scope out the tasks for this month:', + 'beginningOfJuly' => 'Over halway through the year... It\'s July :O let\'s look at what needs to happen:', + 'beginningOfAugust' => 'It\'s the start of August, let\'s have a look at the tasks for the month:', + 'beginningOfSeptember' => 'Time to remember the September tasks!', + 'beinningOfOctober' => 'Välkommen till oktober! Here\'s the tasks for this month:', + 'beginningOfNovember' => 'Happy november! The year is almost gone D: Have a look at what needs doing this month:', + 'beginningOfDecember' => 'Less than a month left of the year. It\'s the home stretch, get through these bad boys!', 'anywayHeresTheMonth' => 'Anyway, here\'s the normal start of the month breakdown...', 'anywayHeresTheWeek' => 'Anyway, like normal here\'s some stuff I think you guys should do this week...', 'finallyHeresTheWeek' => 'And finally... Like always, here\'s some stuff I think you guys should do this week:', 'happyMonday' => 'Happy Monday! Here are some tasks I think should get nutted out this week:', + 'endOfYear' => 'The year is coming to an end, and it looks like there\'s some stuff that wasn\'t done. I hope none of it is critical; if it is, make sure to do it because I may not remind you again for a while!', + 'endOfYearGood' => 'The year is coming to a close, and it looks like you did everything! Good luck for next year :)', + + 'endOfSummer' => 'Summer is (finally) about to be over. That said, there\'s some outstanding stuff. Try get it done because I won\'t remind you about it again D:', + 'endOfSummerGood' => 'Summer is finally almost over, and to make it better, you managed to do all the tasks!', + 'endOfWinter' => 'Winter is coming to a close, but there\'s still some outstanding work to do... Try to finish these tasks because I won\'t be able to remind you again.', + 'endOfWinterGood' => 'Winter is wrapping up, and you managed to get through everything, nice :D', + 'endOfAutumn' => 'Autumn is coming to a close, but there\'s some outstanding work... Try to get through this stuff pls b0ss...', + 'endOfAutumnGood' => 'Autumn is neary aut-dumn (sorry). And you finished everytihng! Good work.', + 'endOfSpring' => 'Spring is almost over, and there are still some outstanding tasks. Try to get them done because I won\'t be reminding you again until next year :o', + 'endOfSpringGood' => 'Spring is about to end! And you did everything that needed doing. Epic!', + + 'endOfMonth' => 'November is coming to a close, and there are still some tasks outstanding. Try your best to get them done...', + 'endOfMonthGood' => 'November is almost over, and it looks like you\'ve completed everything! Nice one!', + 'andAlsoEndOfMonth' => 'Also, it\'s the end of the month, and there are these monthly tasks that still need doing...', + 'andAlsoEndOfMonthGood' => 'It\'s the end of the month too, and you did all the tasks! Nice.', + 'endOfWeek' => 'Aw geez Rick, it\'s Friday and these tasks still haven\'nt been completed, please try to do them over the weekend D:', + 'endOfWeekGood' => 'It\'s Friday and all the tasks are done! Nice', + 'andAlsoEndOfWeek' => 'Also, it\'s the end of a week, so here\'s the outstanding stuff...', + 'andAlsoEndOfWeekGood' => 'Also, it\'s the end of a week, but it looks like you got everything done, sick :D', + 'finallyEndOfWeek' => 'Finally, it\'s the end of a week, so here\'s the outstanding stuff...', + 'finallyEndOfWeekGood' => 'Finally, it\'s the end of a week, but it looks like you got everything done, sick :D', + 'thisMonthThereAre' => 'This month there are %d tasks that need completing (as well as the regular tasks). I\'ll try my best to space them out over the coming weeks. As a heads up, here they are:', - 'seasonalMeme' => 'Please also enjoy this seasonal meme I picked for you: %s', 'tasksForTheWeek' => 'Here are the incomplete tasks for this week...', 'taskAlreadyCompleted' => 'Hmm... It looks as though that task was already done this week.', 'taskCompleted' => 'Marked as completed, nice one!', @@ -51,7 +85,7 @@ return [ 'cleangutters' => 'Clean out gutters to prepare for rain', 'checkdrains' => 'Check down pipe drains for blockages', 'coverpool' => 'Cover the pool', - 'cleanchimeny' => 'Clean soot out of the chimney', + 'cleanchimney' => 'Clean soot out of the chimney', 'tightenfixings' => 'Inspect and tighten (if needed) any fixings', 'fanfilters' => 'Clean extractor fan filters (bathroom and air conditioner)', 'bulkrubbish' => 'Prepare for bulk rubbish collection', @@ -60,5 +94,7 @@ return [ 'shrubs' => 'Prune shrubs', 'palmtrees' => 'Remove dead branches and seeds from palm trees', 'uncoverpool' => 'Uncover the pool', - 'checktaps' => 'Inspect taps for leaks and repair as needed' + 'checktaps' => 'Inspect taps for leaks and repair as needed', + + 'unfinishedtasks' => 'Aw geez Rick, it\'s Friday and these tasks still haven\'nt been completed, please try to do them over the weekend D:' ]; diff --git a/taskMatrix.php b/taskMatrix.php index 408e845..4b4ef37 100644 --- a/taskMatrix.php +++ b/taskMatrix.php @@ -5,7 +5,7 @@ return [ 'monthly' => ['rangehoodfilters', 'poolwater', 'weeds', 'ants', 'leaves', 'cobwebs', 'fireextinguisher', 'mowlawn'], 'bimonthly' => ['vacuum', 'mop', 'kitchen'], - 'biannualy' => ['cleanhouse', 'cleangarage', 'testreliefevalve', 'smokealarmstest', 'smokealarmbatteries', 'fridgecoils'], + 'biannualy' => ['cleanhouse', 'cleangarage', 'testreliefevalve', 'testsmokealarms', 'smokealarmbatteries', 'fridgecoils'], 'quadriannualy' => ['chlorinatorplates'], 'annualy' => [ 'summer' => [ diff --git a/tasks.php b/tasks.php index b03ff5a..f58a7d4 100644 --- a/tasks.php +++ b/tasks.php @@ -9,14 +9,14 @@ $mondays = [ (int)(new DateTimeImmutable('third monday of this month'))->format('d'), (int)(new DateTimeImmutable('fourth monday of this month'))->format('d'), ]; -$currentMonth = (new DateTimeImmutable())->format('m'); +$currentMonth = (int)(new DateTimeImmutable())->format('m'); $currentDayOfMonth = closest((new DateTimeImmutable())->format('d'), $mondays); $currentWeekOfMonth = array_search($currentDayOfMonth, $mondays); $taskLists = array_merge( - isStartOfSeason($currentMonth, $currentDayOfMonth) ? [unlines(map(getString)(getTasksForTheSeason(getSeason($currentMonth), $taskMatrix)))] : [], - isStartOfMonth($currentDayOfMonth) ? [unlines(map(getString)(getTasksForTheMonth($currentMonth, $taskMatrix)))] : [], - [unlines(map(getString)(getTasksForTheWeek($currentWeekOfMonth, $currentMonth, $taskMatrix)))] + isStartOfSeason($currentMonth, $currentDayOfMonth) ? [unlines(map(getStringAndCode)(getTasksForTheSeason(getSeason($currentMonth), $taskMatrix)))] : [], + isStartOfMonth($currentDayOfMonth) ? [unlines(map(getStringAndCode)(getTasksForTheMonth($currentMonth, $taskMatrix)))] : [], + [unlines(map(getStringAndCode)(getTasksForTheWeek($currentWeekOfMonth, $currentMonth, $taskMatrix)))] ); $taskMessages = [ @@ -41,7 +41,7 @@ $messages = zipWith( ) ); }, - // Magic. startOfSeason implis startofMonth so we get 2, start of month without start of season gives 1 and + // Magic. startOfSeason implies startofMonth so we get 2, start of month without start of season gives 1 and // a regular week (not the start of a season or month) gives 0. And this is how the indicies are ordered in the array. $taskMessages[isStartOfSeason($currentMonth, $currentDayOfMonth) + isStartOfMonth($currentDayOfMonth)], $taskLists @@ -51,11 +51,3 @@ foreach ($messages as $message) { sendToGroupChat($message); sleep(rand(2,4)); } - -$seasonalMemes = [ - 'summer' => ['https://www.youtube.com/watch?v=NqktmrKB3ko'] -]; - -if (isStartOfSeason($currentMonth, $currentDayOfMonth)) { - sendToGroupChat(getString('seasonalMeme', $seasonalMemes[getSeason($currentMonth)][array_rand($seasonalMemes[getSeason($currentMonth)])])); -} diff --git a/unfinished.php b/unfinished.php index e637ba9..55cb519 100644 --- a/unfinished.php +++ b/unfinished.php @@ -1,8 +1,8 @@ -format('d'), @@ -11,25 +11,92 @@ $mondays = [ (int)(new DateTimeImmutable('fourth monday of this month'))->format('d'), ]; -$directory = sprintf( - "tasks/%s/%s/%s", - $dt->format('Y'), - $dt->format('F'), - $dt->format('W') +$currentMonth = (int)(new DateTimeImmutable())->format('n'); +$currentDayOfMonth = closest((new DateTimeImmutable())->format('d'), $mondays); +$currentSeason = getSeason($currentMonth); +$currentYear = (int)(new DateTimeImmutable())->format('Y'); +$currentWeekOfMonth = array_search($currentDayOfMonth, $mondays); + +$extractTasks = function($tasks, $path) { + return array_merge($tasks, file_exists($path) ? lines(trim(file_get_contents($path))) : []); +}; + +$unfinishedForYear = array_diff( + array_merge(...map( + function($season) use ($taskMatrix) { + return getTasksForTheSeason($season, $taskMatrix); + } + )(['summer', 'autumn', 'winter', 'spring'])), + array_reduce(getFilePathsForYear($currentYear), $extractTasks, []) +); + +$unfinishedForSeason = array_diff( + getTasksForTheSeason($currentSeason, $taskMatrix), + array_reduce(getFilePathsForSeason($currentYear, $currentSeason), $extractTasks, []) +); + +$unfinishedForMonth = array_diff( + getTasksForTheMonth($currentMonth, $taskMatrix), + array_reduce(getFilePathsForMonth($currentYear, $currentMonth), $extractTasks, []) ); -$completedTasksFile = "$directory" . "/completed.txt"; -$completedTasks = file_exists($completedTasksFile) ? lines(trim(file_get_contents($completedTasksFile))) : []; -$closestMonday = closest($dt->format('d'), $mondays); +$filePathForWeek = getFilePathForWeek($currentYear, $currentMonth, $currentWeekOfMonth); +$unfinishedForWeek = array_diff( + getTasksForTheWeek($currentWeekOfMonth, $currentMonth, $taskMatrix), + file_exists($filePathForWeek) ? lines(trim(file_get_contents($filePathForWeek))) : [] +); -$tasksForTheWeek = getTasksForTheWeek( - array_search($closestMonday, $mondays), - $dt->format('m'), - require 'taskMatrix.php' +//EOY => (EOM & EOW) & !EOS +//EOS => (EOM & EOW) & !EOY +$taskLists = array_merge( + isEndOfYear($currentYear, $currentMonth, $currentDayOfMonth) ? [unlines(map(getStringAndCode)($unfinishedForYear))] : [], + isEndOfSeason($currentYear, $currentMonth, $currentDayOfMonth) ? [unlines(map(getStringAndCode)($unfinishedForSeason))] : [], + isEndOfMonth($currentYear, $currentMonth, $currentDayOfMonth) ? [unlines(map(getStringAndCode)($unfinishedForMonth))] : [], + [unlines(map(getStringAndCode)($unfinishedForWeek))] ); -$unfinished = array_diff($tasksForTheWeek, $completedTasks); +$seasonName = ucfirst($currentSeason); +$goodOrBad = function($string, $goodOrBad) { + return getString($string . ($goodOrBad ? '' : 'Good')); +}; -print_r( - array_diff(['treeflowers', 'someothershit'], ['treeflowers']) +$taskMessages = [ + [$goodOrBad('endOfWeek', $unfinishedForWeek)], + [ + $goodOrBad('endOfMonth', $unfinishedForMonth), + $goodOrBad('andAlsoEndOfWeek', $unfinishedForWeek) + ], + [ + $goodOrBad('endOf' . $seasonName, $unfinishedForSeason), + $goodOrBad('andAlsoEndOfMonth', $unfinishedForMonth), + $goodOrBad('finallyEndOfWeek', $unfinishedForWeek) + ], + [ + $goodOrBad('endOfYear', $unfinishedForYear), + $goodOrBad('andAlsoEndOfMonth', $unfinishedForMonth), + $goodOrBad('finallyEndOfWeek', $unfinishedForWeek) + ] +]; + +$messages = zipWith( + function($message, $list) { + return ununlines( + array_merge( + is_array($message) ? $message : [$message], + [$list] + ) + ); + }, + // Similar magic to tasks.php + $taskMessages[ + isEndOfMonth($currentYear, $currentMonth, $currentDayOfMonth) + + isEndOfSeason($currentYear, $currentMonth, $currentDayOfMonth) + + (isEndOfYear($currentYear, $currentMonth, $currentDayOfMonth) ? 2 : 0) // EOY is independant of EOS, to get the right index need to add 2 instead of 1. + ], + $taskLists ); + +foreach ($messages as $message) { + sendToGroupChat($message); + sleep(rand(2,4)); +} -- 2.11.0