From f4279c03432d8b509be7c5d6938eac02313f5838 Mon Sep 17 00:00:00 2001 From: Victor Westerlund Date: Thu, 13 Mar 2025 15:16:53 +0000 Subject: [PATCH] feat: add coffee stats endpoints and counter to about page (#28) This PR refactors some texts on the about page (again), and also a adds two new endpoints for a database table that I have now made public that tracks the coffee cups I've had. The endpoint itself is not public now but I might make a page (something like `/about/coffee`) that presents it in a not-ugly way. Reviewed-on: https://codeberg.org/vlw/vlw.se/pulls/28 --- endpoints/coffee/GET.php | 38 ++++++++++++++++++++++++ endpoints/coffee/POST.php | 38 ++++++++++++++++++++++++ endpoints/coffee/stats/GET.php | 42 +++++++++++++++++++++++++++ endpoints/coffee/stats/POST.php | 35 ++++++++++++++++++++++ public/about.php | 40 ++++++++++++++++--------- public/assets/css/pages/about.css | 4 --- src/API/Endpoints.php | 2 ++ src/Consts.php | 6 ++++ src/Database/Models/Coffee/Coffee.php | 35 ++++++++++++++++++++++ src/Database/Models/Coffee/Stats.php | 32 ++++++++++++++++++++ src/Database/Tables/Coffee/Coffee.php | 13 +++++++++ src/Database/Tables/Coffee/Stats.php | 14 +++++++++ 12 files changed, 281 insertions(+), 18 deletions(-) create mode 100644 endpoints/coffee/GET.php create mode 100644 endpoints/coffee/POST.php create mode 100644 endpoints/coffee/stats/GET.php create mode 100644 endpoints/coffee/stats/POST.php create mode 100644 src/Database/Models/Coffee/Coffee.php create mode 100644 src/Database/Models/Coffee/Stats.php create mode 100644 src/Database/Tables/Coffee/Coffee.php create mode 100644 src/Database/Tables/Coffee/Stats.php diff --git a/endpoints/coffee/GET.php b/endpoints/coffee/GET.php new file mode 100644 index 0000000..e925438 --- /dev/null +++ b/endpoints/coffee/GET.php @@ -0,0 +1,38 @@ +ruleset = new Ruleset(strict: true); + + $this->ruleset->GET([ + (new Rules(CoffeeTable::ID->value)) + ->type(Type::NUMBER) + ->min(1) + ->max(parent::SIZE_UINT32) + ]); + + $this->ruleset->validate_or_exit(); + + parent::__construct(); + } + + public function main(): Response { + return $this->list(CoffeeTable::NAME, CoffeeTable::values(), [ + CoffeeTable::ID->value => Order::DESC + ]); + } + } \ No newline at end of file diff --git a/endpoints/coffee/POST.php b/endpoints/coffee/POST.php new file mode 100644 index 0000000..58e3964 --- /dev/null +++ b/endpoints/coffee/POST.php @@ -0,0 +1,38 @@ +ruleset = new Ruleset(strict: true); + + $this->ruleset->POST([ + (new Rules(CoffeeTable::ID->value)) + ->type(Type::NUMBER) + ->min(1) + ->max(parent::SIZE_UINT32) + ->default(time()), + ]); + + $this->ruleset->validate_or_exit(); + + parent::__construct(); + } + + public function main(): Response { + return $this->db->for(CoffeeTable::NAME)->insert($_POST) === true + ? new Response(null, 201) + : new Response("Database error", 500); + } + } \ No newline at end of file diff --git a/endpoints/coffee/stats/GET.php b/endpoints/coffee/stats/GET.php new file mode 100644 index 0000000..0514a0a --- /dev/null +++ b/endpoints/coffee/stats/GET.php @@ -0,0 +1,42 @@ +ruleset = new Ruleset(strict: true); + + $this->ruleset->GET([ + (new Rules(COFFEE_STATS_UPDATE_PARAM)) + ->type(Type::BOOLEAN) + ->default(false) + ]); + + $this->ruleset->validate_or_exit(); + + parent::__construct(); + } + + public function main(): Response { + // Freshen cache if update flag is set + if ($_GET[COFFEE_STATS_UPDATE_PARAM]) { + (new Call(Endpoints::COFFEE_STATS->value))->post(); + } + + return $this->list(StatsTable::NAME, StatsTable::values()); + } + } \ No newline at end of file diff --git a/endpoints/coffee/stats/POST.php b/endpoints/coffee/stats/POST.php new file mode 100644 index 0000000..43ca84f --- /dev/null +++ b/endpoints/coffee/stats/POST.php @@ -0,0 +1,35 @@ +ruleset = new Ruleset(strict: true); + $this->ruleset->validate_or_exit(); + + parent::__construct(); + } + + public function main(): Response { + $truncate = $this->db->execute_query("DELETE FROM `" . StatsTable::NAME . "`"); + + // Add a dummy row to run the MariaDB INSERT AFTER Trigger on the coffee database table + $insert = $this->db->for(CoffeeTable::NAME)->insert([CoffeeTable::ID->value => 0]); + // Remove the dummy row + $remove = $this->db->for(CoffeeTable::NAME)->where([CoffeeTable::ID->value => 0])->delete(); + + return $truncate && $insert && $remove ? new Response() : new Response("Error", 500); + } + } \ No newline at end of file diff --git a/public/about.php b/public/about.php index 5554450..5fe4c59 100644 --- a/public/about.php +++ b/public/about.php @@ -1,5 +1,6 @@ week() - $this->week_average(); + + return match (true) { + $diff < 1 => "less than", + $diff === 1 => "the same as", + $diff > 1 => "more than" + }; + } + }; ?> @@ -43,8 +57,9 @@
-

I​'m a full-stack web developer from Sweden.

-

I used to list the <programming/markup/command/whatever>-languages here that I use the most and order them by guesstimating how much I use each one. But then I thought it would be better to just show you instead using this chart that automatically pulls the total bytes for each language from my public mirrors and sources on Forgejo.

+

I​'m a full-stack web developer from Sweden, and welcome to my little personal corner of the Internet!

+

I used to list the <programming/markup/command/whatever>-languages here that I use the most and order them by guesstimating how much I use each one. But then I thought it would be better to just show you instead using this chart that automatically pulls the total bytes for each language from my public repos on Forgejo.

+

Some other noteworthy techologies that I work a decent amount with are: Debian, MariaDB, SQLite, DNS, Redis, and probably a few others as well. Check out this page for a comprehensive list of all the tech that I use.

@@ -81,30 +96,27 @@

This website

-

This site and all of its components are 100% free and open source software. The website is designed and built by me from the ground up using my web and API frameworks as the foundation. You will find no cookies or trackers here. The only information I have about you is your public IP-address and which resources on this site your browser requests. None of this data is used for any kind of analytics.

-

See detailed information about all servers/services on this domain

+

This site and all of its components, including texts and graphics have been created by me and are all 100% free and open source. Feel free to use anything you see on this website in your own projects as long as it's under the same GNU GPLv3-or-later license. The website is designed by me on top of my own web framework and API framework.

+

You will never find cookies or trackers on this site. The only information I have about you are in the standard NGINX web server logs, which get overwritten automatically after some time.

Personal

-

Coffee, of course.. and..

-

At times, I become a true, amateur, armchair detective for a variety of your typical-nerdy topics that I find interesting. And will spend a disproportionate to real-world-personal-use amount of time reading about that stuff too.

-

Another silent passion of mine that comes out every few years is building computers and fiddling with weird networking stuff.

-

And then of course I don't mind some occational gaming, and watching movies and TV-series.

+

One thing is true.. Coffee, lots of coffee. In fact, I've had week() ?> cupweek() === 1 ? "" : "s" ?> of coffee in the last 7 days! That's week_average_string() ?> my average of week_average() ?> per week, impressive! Even though you just read that.. I don't consider myself too much of a coffee snob! As long as it's dark roast and warm, I'm probably happy to have it.

+

At times, I become a true, amateur, armchair detective for a variety of your typical-nerdy topics that I find interesting and you can bet I spend way more time reading about those things than I will ever have use for in life.

+

My coding happens almost exclusivly in code-server, which is a fork of VSCode that runs entirely in the browser. I keep my development environment tucked away in a lightweight Debian VA that I can tote around to whatever host machine I happen to work on. If I can't do that for whatever reason, I have my dotfiles ready to get things set up the way I like it.

+

Another silent passion of mine that comes out every few years is building computers and fiddling with networking stuff.

Projects

Here are some projects I'm working on right now:

* Vegvisir: A web navigation framework for PHP.

* Reflect: A REST API framework for PHP developers.

-

There is more stuff on my works page and even more stuff on my Codeberg profile.

-

and even EVEN more stuff on my Forgejo

+

Check out this timeline for a somewhat complete list of everything I have done.


GitHub

-

I have given up GitHub for their increasing number of injustices againts its users, last betrayal being GitHub's for-profit "Copilot" product which was illegaly trained on copylefted software on its platform.

-

I signed up and started using GitHub before I became aware of how opressive to to its users and deceptive their business model is. I wasn't aware of the situation.

-

While I am a bit skeptical to do this in case history repeats itself; [most of] my work is now on Codeberg instead. Unfortunately some things like old pull-requests, issues, and branch archives can not be migrated completely.

+

I have given up GitHub and moved most of my free software to Codeberg. You can still find my GitHub profile here but I don't use it for source control anymore.


diff --git a/public/assets/css/pages/about.css b/public/assets/css/pages/about.css index 47248b3..7e89f2d 100644 --- a/public/assets/css/pages/about.css +++ b/public/assets/css/pages/about.css @@ -60,10 +60,6 @@ section.about span.interests { animation: interests-hue 5s infinite linear; } -section.about p i:not(:hover) { - opacity: .3; -} - /* ## Languages */ section.languages { diff --git a/src/API/Endpoints.php b/src/API/Endpoints.php index 2fb97e2..efd1012 100644 --- a/src/API/Endpoints.php +++ b/src/API/Endpoints.php @@ -10,9 +10,11 @@ case WORK = "/work"; case SEARCH = "/search"; + case COFFEE = "/coffee"; case MESSAGES = "/messages"; case WORK_TAGS = "/work/tags"; case WORK_ACTIONS = "/work/actions"; + case COFFEE_STATS = "/coffee/stats"; case WORK_TIMELINE = "/work/timeline"; case ABOUT_LANGUAGES = "/about/languages"; } \ No newline at end of file diff --git a/src/Consts.php b/src/Consts.php index f4700f1..f954031 100644 --- a/src/Consts.php +++ b/src/Consts.php @@ -24,6 +24,12 @@ const TIMELINE_PREVIEW_LIMIT_PARAM = "limit"; const TIMELINE_PREVIEW_LIMIT_COUNT = 5; + /** + * # Coffee + * Constants related to the coffee endpoints + */ + const COFFEE_STATS_UPDATE_PARAM = "update"; + /** * # Forgejo * Constants related to the fetching and caching of real-time prog. language use on Forgejo diff --git a/src/Database/Models/Coffee/Coffee.php b/src/Database/Models/Coffee/Coffee.php new file mode 100644 index 0000000..e1adb6a --- /dev/null +++ b/src/Database/Models/Coffee/Coffee.php @@ -0,0 +1,35 @@ +value => $this->id + ]); + } + + public static function all(array $params = []): array { + return array_map(fn(array $item): Coffee => new Coffee($item[CoffeeTable::ID->value]), parent::list(Endpoints::COFFEE, $params)); + } + + public function timestamp(): int { + return $this->get(CoffeeTable::ID->value); + } + + public function datetime(): DateTimeImmutable { + return DateTimeImmutable::createFromFormat("U", $this->timestamp()); + } + } \ No newline at end of file diff --git a/src/Database/Models/Coffee/Stats.php b/src/Database/Models/Coffee/Stats.php new file mode 100644 index 0000000..8e777a7 --- /dev/null +++ b/src/Database/Models/Coffee/Stats.php @@ -0,0 +1,32 @@ +get(StatsTable::COUNT_WEEK->value) ?? 0; + } + + public function week_average(): int { + return $this->get(StatsTable::COUNT_WEEK_AVERAGE->value) ?? 0; + } + } \ No newline at end of file diff --git a/src/Database/Tables/Coffee/Coffee.php b/src/Database/Tables/Coffee/Coffee.php new file mode 100644 index 0000000..a4abc6b --- /dev/null +++ b/src/Database/Tables/Coffee/Coffee.php @@ -0,0 +1,13 @@ +