mirror of
https://codeberg.org/vlw/vlw.se.git
synced 2025-09-13 21:13:40 +02:00
wip: 2025-07-30T17:29:51+0200 (1753889391)
This commit is contained in:
parent
f398d17f81
commit
eb2c7b7d82
16 changed files with 297 additions and 85 deletions
|
@ -11,5 +11,5 @@ reply_average_hours = 0;
|
||||||
available_from_hour = 0;
|
available_from_hour = 0;
|
||||||
|
|
||||||
[service_forgejo]
|
[service_forgejo]
|
||||||
base_url = ""
|
url = ""
|
||||||
scan_profiles = ""
|
profiles = ""
|
30
api/coffee/DELETE.php
Normal file
30
api/coffee/DELETE.php
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Reflect\{Response, Path};
|
||||||
|
use Reflect\Rules\{Ruleset, Rules, Type};
|
||||||
|
|
||||||
|
use VLW\API\API;
|
||||||
|
use VLW\Helpers\UUID;
|
||||||
|
use VLW\Database\Models\Coffee\Coffee;
|
||||||
|
use VLW\Database\Tables\Coffee\Coffee as CoffeeTable;
|
||||||
|
|
||||||
|
require_once Path::root("src/UUID.php");
|
||||||
|
require_once Path::root("src/API/API.php");
|
||||||
|
require_once Path::root("src/Database/Models/Coffee/Coffee.php");
|
||||||
|
require_once Path::root("src/Database/Tables/Coffee/Coffee.php");
|
||||||
|
|
||||||
|
final class POST_Coffee extends API {
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct(new Ruleset()->GET([
|
||||||
|
new Rules(CoffeeTable::ID->value)
|
||||||
|
->required()
|
||||||
|
->type(Type::STRING)
|
||||||
|
->min(UUID::LENGTH)
|
||||||
|
->max(UUID::LENGTH)
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function main(): Response {
|
||||||
|
return new Response(new Coffee($_GET[CoffeeTable::ID->value])->delete());
|
||||||
|
}
|
||||||
|
}
|
19
api/coffee/GET.php
Normal file
19
api/coffee/GET.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Reflect\{Response, Path};
|
||||||
|
|
||||||
|
use VLW\API\API;
|
||||||
|
use VLW\Database\Models\Coffee\Coffee;
|
||||||
|
|
||||||
|
require_once Path::root("src/API/API.php");
|
||||||
|
require_once Path::root("src/Database/Models/Coffee/Coffee.php");
|
||||||
|
|
||||||
|
final class GET_Coffee extends API {
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function main(): Response {
|
||||||
|
return new Response(Coffee::all());
|
||||||
|
}
|
||||||
|
}
|
37
api/coffee/POST.php
Normal file
37
api/coffee/POST.php
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Reflect\{Response, Path};
|
||||||
|
use Reflect\Rules\{Ruleset, Rules, Type};
|
||||||
|
|
||||||
|
use VLW\API\API;
|
||||||
|
use VLW\Database\Models\Coffee\Coffee;
|
||||||
|
use VLW\Database\Tables\Coffee\Coffee as CoffeeTable;
|
||||||
|
|
||||||
|
require_once Path::root("src/API/API.php");
|
||||||
|
require_once Path::root("src/Database/Models/Coffee/Coffee.php");
|
||||||
|
require_once Path::root("src/Database/Tables/Coffee/Coffee.php");
|
||||||
|
|
||||||
|
final class POST_Coffee extends API {
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct(new Ruleset()->POST([
|
||||||
|
new Rules(CoffeeTable::DATE_CREATED->value)
|
||||||
|
->type(Type::STRING)
|
||||||
|
->default(null)
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function main(): Response {
|
||||||
|
$datetime = new DateTimeImmutable();
|
||||||
|
|
||||||
|
// Parse DateTime from POST string
|
||||||
|
if ($_POST[CoffeeTable::DATE_CREATED->value]) {
|
||||||
|
try {
|
||||||
|
$datetime = new DateTimeImmutable($_POST[CoffeeTable::DATE_CREATED->value]);
|
||||||
|
} catch (DateMalformedStringException $error) {
|
||||||
|
return new Response($error->getMessage(), 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(Coffee::new($datetime));
|
||||||
|
}
|
||||||
|
}
|
19
api/languages/GET.php
Normal file
19
api/languages/GET.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Reflect\{Response, Path};
|
||||||
|
|
||||||
|
use VLW\API\API;
|
||||||
|
use VLW\Database\Models\Languages\Language;
|
||||||
|
|
||||||
|
require_once Path::root("src/API/API.php");
|
||||||
|
require_once Path::root("src/Database/Models/Languages/Language.php");
|
||||||
|
|
||||||
|
final class GET_Languages extends API {
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function main(): Response {
|
||||||
|
return new Response(Language::all());
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,15 +5,17 @@
|
||||||
use Reflect\Rules\{Ruleset, Rules, Type};
|
use Reflect\Rules\{Ruleset, Rules, Type};
|
||||||
|
|
||||||
use VLW\API\API;
|
use VLW\API\API;
|
||||||
use VLW\Helpers\GenerateTimeline;
|
use VLW\Helpers\{GenerateTimeline, Forgejo};
|
||||||
|
|
||||||
require_once Path::root("src/API/API.php");
|
require_once Path::root("src/API/API.php");
|
||||||
|
require_once Path::root("src/Helpers/Forgejo.php");
|
||||||
require_once Path::root("src/Helpers/GenerateTimeline.php");
|
require_once Path::root("src/Helpers/GenerateTimeline.php");
|
||||||
|
|
||||||
enum ServiceEnum: string {
|
enum ServiceEnum: string {
|
||||||
use xEnum;
|
use xEnum;
|
||||||
|
|
||||||
case ALL = "all";
|
case ALL = "all";
|
||||||
|
case FORGEJO = "forgejo";
|
||||||
case TIMELINE = "timeline";
|
case TIMELINE = "timeline";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,18 +30,28 @@
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update_timeline(): bool {
|
|
||||||
return new GenerateTimeline()->generate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function main(): Response {
|
public function main(): Response {
|
||||||
switch ($_GET[self::KEY_SERVICE]) {
|
switch ($_GET[self::KEY_SERVICE]) {
|
||||||
|
case ServiceEnum::FORGEJO->value:
|
||||||
|
return new Response($this->update_forgejo());
|
||||||
|
|
||||||
case ServiceEnum::TIMELINE->value:
|
case ServiceEnum::TIMELINE->value:
|
||||||
return new Response("OK");
|
return new Response($this->update_timeline());
|
||||||
|
|
||||||
case ServiceEnum::ALL->value:
|
case ServiceEnum::ALL->value:
|
||||||
default:
|
default:
|
||||||
return new Response($this->update_timeline());
|
return new Response(
|
||||||
|
$this->update_timeline() &&
|
||||||
|
$this->update_forgejo()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function update_timeline(): bool {
|
||||||
|
return new GenerateTimeline()->generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function update_forgejo(): bool {
|
||||||
|
return new Forgejo()->update();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,18 +1,15 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Vegvisir\Path;
|
use VLW\Database\Models\Messages\Message;
|
||||||
|
use VLW\Database\Tables\Messages\Messages;
|
||||||
use VLW\API\{Client, Endpoints};
|
|
||||||
use VLW\Database\Tables\Messages\MessagesTable;
|
require_once VV::root("src/Database/Models/Messages/Message.php");
|
||||||
|
|
||||||
require_once VV::root("src/API/API.php");
|
|
||||||
require_once VV::root("src/API/Endpoints.php");
|
|
||||||
require_once VV::root("src/Database/Tables/Messages/Messages.php");
|
require_once VV::root("src/Database/Tables/Messages/Messages.php");
|
||||||
|
|
||||||
$date = new class extends DateTimeImmutable {
|
$date = new class extends DateTimeImmutable {
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
// Set DateTime for configured timezone
|
// Set DateTime for configured timezone
|
||||||
parent::__construct("now", new DateTimeZone($_ENV["client_time_available"]["time_zone"]));
|
parent::__construct("now", new DateTimeZone($_ENV["config_time_available"]["time_zone"]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return current hour in 24-hour format
|
// Return current hour in 24-hour format
|
||||||
|
@ -22,20 +19,20 @@
|
||||||
|
|
||||||
// Returns true if current time is between available from and to hours
|
// Returns true if current time is between available from and to hours
|
||||||
public function is_available(): bool {
|
public function is_available(): bool {
|
||||||
return $this->hour() >= $_ENV["client_time_available"]["available_from_hour"] && $this->hour() < $_ENV["client_time_available"]["available_to_hour"];
|
return $this->hour() >= $_ENV["config_time_available"]["available_from_hour"] && $this->hour() < $_ENV["config_time_available"]["available_to_hour"];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_estimated_reply_hours(): int {
|
public function get_estimated_reply_hours(): int {
|
||||||
// I'm available! Return the estimated reply time for that
|
// I'm available! Return the estimated reply time for that
|
||||||
if ($this->is_available()) {
|
if ($this->is_available()) {
|
||||||
return $_ENV["client_time_available"]["reply_average_hours"];
|
return $_ENV["config_time_available"]["reply_average_hours"];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->hour() < $_ENV["client_time_available"]["available_from_hour"]
|
return $this->hour() < $_ENV["config_time_available"]["available_from_hour"]
|
||||||
// Return hours past midnight until I become available (clamped to estimated reply hours)
|
// Return hours past midnight until I become available (clamped to estimated reply hours)
|
||||||
? max($_ENV["client_time_available"]["available_from_hour"] - $this->hour(), $_ENV["client_time_available"]["reply_average_hours"])
|
? max($_ENV["config_time_available"]["available_from_hour"] - $this->hour(), $_ENV["config_time_available"]["reply_average_hours"])
|
||||||
// Return hours before midnight until I become available (clamped to estimated reply hours)
|
// Return hours before midnight until I become available (clamped to estimated reply hours)
|
||||||
: max($_ENV["client_time_available"]["available_from_hour"] + (24 - $this->hour()), $_ENV["client_time_available"]["reply_average_hours"]);
|
: max($_ENV["config_time_available"]["available_from_hour"] + (24 - $this->hour()), $_ENV["config_time_available"]["reply_average_hours"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,18 +81,9 @@
|
||||||
|
|
||||||
<?php // Send message on POST request ?>
|
<?php // Send message on POST request ?>
|
||||||
<?php if ($_SERVER["REQUEST_METHOD"] === "POST"): ?>
|
<?php if ($_SERVER["REQUEST_METHOD"] === "POST"): ?>
|
||||||
|
<?php $message = Message::new($_POST[Messages::MESSAGE->name] ?? "", $_POST[Messages::EMAIL->name] ?? null); ?>
|
||||||
|
|
||||||
<?php
|
<?php if ($message->date_created): ?>
|
||||||
|
|
||||||
// Send message via API
|
|
||||||
$send = (new Client())->call(Endpoints::MESSAGES->value)->post([
|
|
||||||
MessagesTable::EMAIL->value => $_POST[MessagesTable::EMAIL->value],
|
|
||||||
MessagesTable::MESSAGE->value => $_POST[MessagesTable::MESSAGE->value]
|
|
||||||
]);
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php if ($send->ok): ?>
|
|
||||||
<section class="form-message sent">
|
<section class="form-message sent">
|
||||||
<h3>🙏 Message sent!</h3>
|
<h3>🙏 Message sent!</h3>
|
||||||
</section>
|
</section>
|
||||||
|
@ -103,8 +91,6 @@
|
||||||
<?php // Show response body from endpoint as error if request failed ?>
|
<?php // Show response body from endpoint as error if request failed ?>
|
||||||
<section class="form-message error">
|
<section class="form-message error">
|
||||||
<h3>😟 Oh no, something went wrong</h3>
|
<h3>😟 Oh no, something went wrong</h3>
|
||||||
<p>Response from API:</p>
|
|
||||||
<pre><?= $send->output() ?></pre>
|
|
||||||
</section>
|
</section>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
@ -113,11 +99,11 @@
|
||||||
<form method="POST">
|
<form method="POST">
|
||||||
<input-group>
|
<input-group>
|
||||||
<label>your email (optional)</label>
|
<label>your email (optional)</label>
|
||||||
<input type="email" name="<?= MessagesTable::EMAIL->value ?>" placeholder="nissehult@example.com" autocomplete="off"></input>
|
<input type="email" name="<?= Messages::EMAIL->name ?>" placeholder="nissehult@example.com" autocomplete="off"></input>
|
||||||
</input-group>
|
</input-group>
|
||||||
<input-group>
|
<input-group>
|
||||||
<label title="this field is required">your message (required)</label>
|
<label title="this field is required">your message (required)</label>
|
||||||
<textarea name="<?= MessagesTable::MESSAGE->value ?>" required placeholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed molestie dignissim mauris vel dignissim. Sed et aliquet odio, id egestas libero. Vestibulum ut dui a turpis aliquam hendrerit id et dui. Morbi eu tristique quam, sit amet dictum felis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ac nibh a ex accumsan ullamcorper non quis eros. Nam at suscipit lacus. Nullam placerat semper sapien, vitae aliquet nisl elementum a. Duis viverra quam eros, eu vestibulum quam egestas sit amet. Duis lobortis varius malesuada. Mauris in fringilla mi. "></textarea>
|
<textarea name="<?= Messages::MESSAGE->name ?>" required placeholder="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed molestie dignissim mauris vel dignissim. Sed et aliquet odio, id egestas libero. Vestibulum ut dui a turpis aliquam hendrerit id et dui. Morbi eu tristique quam, sit amet dictum felis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin ac nibh a ex accumsan ullamcorper non quis eros. Nam at suscipit lacus. Nullam placerat semper sapien, vitae aliquet nisl elementum a. Duis viverra quam eros, eu vestibulum quam egestas sit amet. Duis lobortis varius malesuada. Mauris in fringilla mi. "></textarea>
|
||||||
</input-group>
|
</input-group>
|
||||||
<button class="inline solid">
|
<button class="inline solid">
|
||||||
<?= VV::embed("public/assets/media/icons/email.svg") ?>
|
<?= VV::embed("public/assets/media/icons/email.svg") ?>
|
||||||
|
|
|
@ -27,7 +27,4 @@
|
||||||
* # Forgejo
|
* # Forgejo
|
||||||
* Constants related to the fetching and caching of real-time prog. language use on Forgejo
|
* Constants related to the fetching and caching of real-time prog. language use on Forgejo
|
||||||
*/
|
*/
|
||||||
const FORGEJO_HREF = "https://git.vlw.se/explore/repos?q=&sort=recentupdate&language=";
|
|
||||||
const FORGEJO_ENDPOINT_USER = "/api/v1/users/%s";
|
|
||||||
const FORGEJO_ENDPOINT_SEARCH = "/api/v1/repos/search?uid=%s";
|
|
||||||
const FORGEJO_SI_BYTE_MULTIPLE = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
const FORGEJO_SI_BYTE_MULTIPLE = ["B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
@ -3,33 +3,52 @@
|
||||||
namespace VLW\Database\Models\Coffee;
|
namespace VLW\Database\Models\Coffee;
|
||||||
|
|
||||||
use \VV;
|
use \VV;
|
||||||
|
use \vlw\MySQL\Order;
|
||||||
use \DateTimeImmutable;
|
use \DateTimeImmutable;
|
||||||
|
|
||||||
use VLW\API\Endpoints;
|
use VLW\Helpers\UUID;
|
||||||
|
use VLW\Database\Database;
|
||||||
use VLW\Database\Models\Model;
|
use VLW\Database\Models\Model;
|
||||||
use VLW\Database\Tables\Coffee\CoffeeTable;
|
use VLW\Database\Tables\Coffee\Coffee as CoffeeTable;
|
||||||
|
|
||||||
require_once VV::root("src/API/Endpoints.php");
|
require_once VV::root("src/Helpers/UUID.php");
|
||||||
|
require_once VV::root("src/Database/Database.php");
|
||||||
require_once VV::root("src/Database/Models/Model.php");
|
require_once VV::root("src/Database/Models/Model.php");
|
||||||
require_once VV::root("src/Database/Tables/Coffee/Coffee.php");
|
require_once VV::root("src/Database/Tables/Coffee/Coffee.php");
|
||||||
require_once VV::root("src/Database/Models/Coffee/Coffee.php");
|
|
||||||
|
|
||||||
class Coffee extends Model {
|
class Coffee extends Model {
|
||||||
|
final public static function new(?DateTimeImmutable $datetime = null): self {
|
||||||
|
$id = UUID::v4();
|
||||||
|
|
||||||
|
if (!parent::create(CoffeeTable::TABLE, [
|
||||||
|
CoffeeTable::ID->value => $id,
|
||||||
|
CoffeeTable::DATE_CREATED->value => $datetime ? $datetime->format(parent::DATE_FORMAT) : date(parent::DATE_FORMAT)
|
||||||
|
])) { throw new Exception("Failed to create Work entity"); }
|
||||||
|
|
||||||
|
return new Coffee($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function all(): array {
|
||||||
|
return array_map(fn(array $work): Coffee => new Coffee($work[CoffeeTable::ID->value]), new Database()
|
||||||
|
->from(CoffeeTable::TABLE)
|
||||||
|
->order([CoffeeTable::DATE_CREATED->value => Order::DESC])
|
||||||
|
->select(CoffeeTable::ID->value)
|
||||||
|
->fetch_all(MYSQLI_ASSOC)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function __construct(public readonly string $id) {
|
public function __construct(public readonly string $id) {
|
||||||
parent::__construct(Endpoints::COFFEE, [
|
parent::__construct(CoffeeTable::TABLE, CoffeeTable::values(), [
|
||||||
CoffeeTable::ID->value => $this->id
|
CoffeeTable::ID->value => $this->id
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function all(array $params = []): array {
|
public function delete(): bool {
|
||||||
return array_map(fn(array $item): Coffee => new Coffee($item[CoffeeTable::ID->value]), parent::list(Endpoints::COFFEE, $params));
|
return $this->db->delete([CoffeeTable::ID->value => $this->id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function timestamp(): int {
|
final public DateTimeImmutable $date_created {
|
||||||
return $this->get(CoffeeTable::ID->value);
|
get => new DateTimeImmutable($this->get(CoffeeTable::DATE_CREATED->value));
|
||||||
}
|
set (DateTimeImmutable $date_created) => $this->set(CoffeeTable::DATE_CREATED->value, $date_created->format(parent::DATE_FORMAT));
|
||||||
|
|
||||||
public function datetime(): DateTimeImmutable {
|
|
||||||
return DateTimeImmutable::createFromFormat("U", $this->timestamp());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
use VLW\Helpers\UUID;
|
use VLW\Helpers\UUID;
|
||||||
use VLW\Database\Database;
|
use VLW\Database\Database;
|
||||||
use VLW\Database\Models\Model;
|
use VLW\Database\Models\Model;
|
||||||
use VLW\Database\Tables\Work\Languages;
|
use VLW\Database\Tables\Languages\Languages;
|
||||||
|
|
||||||
require_once VV::root("src/Helpers/UUID.php");
|
require_once VV::root("src/Helpers/UUID.php");
|
||||||
require_once VV::root("src/Database/Database.php");
|
require_once VV::root("src/Database/Database.php");
|
||||||
|
@ -28,6 +28,15 @@
|
||||||
return new Language($id);
|
return new Language($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public static function all(): array {
|
||||||
|
return array_map(fn(array $language): Language => new Language($language[Languages::ID->value]), new Database()
|
||||||
|
->from(Languages::TABLE)
|
||||||
|
->order([Languages::BYTES->value => Order::DESC])
|
||||||
|
->select(Languages::ID->value)
|
||||||
|
->fetch_all(MYSQLI_ASSOC)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final public static function from(string $name): ?self {
|
final public static function from(string $name): ?self {
|
||||||
return array_map(fn(array $language): Language => new Language($language[Languages::ID->value]), new Database()
|
return array_map(fn(array $language): Language => new Language($language[Languages::ID->value]), new Database()
|
||||||
->from(Languages::TABLE)
|
->from(Languages::TABLE)
|
||||||
|
@ -44,9 +53,9 @@
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
final public int $name {
|
final public string $name {
|
||||||
get => $this->get(Languages::NAME->value);
|
get => $this->get(Languages::NAME->value);
|
||||||
set (int $name) => $this->set(Languages::NAME->value, $name);
|
set (string $name) => $this->set(Languages::NAME->value, $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
final public int $bytes {
|
final public int $bytes {
|
||||||
|
|
62
src/Database/Models/Messages/Message.php
Normal file
62
src/Database/Models/Messages/Message.php
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace VLW\Database\Models\Messages;
|
||||||
|
|
||||||
|
use \VV;
|
||||||
|
use \vlw\MySQL\Order;
|
||||||
|
use \DateTimeImmutable;
|
||||||
|
|
||||||
|
use VLW\Helpers\UUID;
|
||||||
|
use VLW\Database\Database;
|
||||||
|
use VLW\Database\Models\Model;
|
||||||
|
use VLW\Database\Tables\Messages\Messages;
|
||||||
|
|
||||||
|
require_once VV::root("src/Helpers/UUID.php");
|
||||||
|
require_once VV::root("src/Database/Database.php");
|
||||||
|
require_once VV::root("src/Database/Models/Model.php");
|
||||||
|
require_once VV::root("src/Database/Tables/Messages/Messages.php");
|
||||||
|
|
||||||
|
class Message extends Model {
|
||||||
|
final public static function new(string $message, ?string $email = null): self {
|
||||||
|
$id = UUID::v4();
|
||||||
|
|
||||||
|
if (!parent::create(Messages::TABLE, [
|
||||||
|
Messages::ID->value => $id,
|
||||||
|
Messages::EMAIL->value => $email,
|
||||||
|
Messages::MESSAGE->value => $message,
|
||||||
|
Messages::DATE_CREATED->value => date(parent::DATE_FORMAT)
|
||||||
|
])) { throw new Exception("Failed to create Message entity"); }
|
||||||
|
|
||||||
|
return new Message($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function all(): array {
|
||||||
|
return array_map(fn(array $Message): Message => new Message($Message[Messages::ID->value]), new Database()
|
||||||
|
->from(Messages::TABLE)
|
||||||
|
->order([Messages::DATE_CREATED->value => Order::DESC])
|
||||||
|
->select(Messages::ID->value)
|
||||||
|
->fetch_all(MYSQLI_ASSOC)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __construct(public readonly string $id) {
|
||||||
|
parent::__construct(Messages::TABLE, Messages::values(), [
|
||||||
|
Messages::ID->value => $this->id
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public ?string $email {
|
||||||
|
get => $this->get(Messages::EMAIL->value);
|
||||||
|
set (?string $email) => $this->set(Messages::EMAIL->value, $email);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public string $message {
|
||||||
|
get => $this->get(Messages::MESSAGE->value);
|
||||||
|
set (string $message) => $this->set(Messages::MESSAGE->value, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public DateTimeImmutable $date_created {
|
||||||
|
get => new DateTimeImmutable($this->get(Messages::DATE_CREATED->value));
|
||||||
|
set (DateTimeImmutable $date_created) => $this->set(Messages::DATE_CREATED->value, $date_created->format(parent::DATE_FORMAT));
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,5 +9,6 @@
|
||||||
|
|
||||||
const TABLE = "coffee";
|
const TABLE = "coffee";
|
||||||
|
|
||||||
case ID = "id";
|
case ID = "id";
|
||||||
|
case DATE_CREATED = "date_created";
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace VLW\Database\Tables\About;
|
namespace VLW\Database\Tables\Languages;
|
||||||
|
|
||||||
use vlw\xEnum;
|
use vlw\xEnum;
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,15 @@
|
||||||
|
|
||||||
namespace VLW\Database\Tables\Messages;
|
namespace VLW\Database\Tables\Messages;
|
||||||
|
|
||||||
|
use vlw\xEnum;
|
||||||
|
|
||||||
enum Messages: string {
|
enum Messages: string {
|
||||||
|
use xEnum;
|
||||||
|
|
||||||
const TABLE = "messages";
|
const TABLE = "messages";
|
||||||
|
|
||||||
case EMAIL = "email";
|
case ID = "id";
|
||||||
case MESSAGE = "message";
|
case EMAIL = "email";
|
||||||
case TIMESTAMP_CREATED = "timestamp_created";
|
case MESSAGE = "message";
|
||||||
|
case DATE_CREATED = "date_created";
|
||||||
}
|
}
|
|
@ -2,12 +2,23 @@
|
||||||
|
|
||||||
namespace VLW\Helpers;
|
namespace VLW\Helpers;
|
||||||
|
|
||||||
use VLW\Database\Models\Languages\Language;
|
use \VV;
|
||||||
|
|
||||||
|
use VLW\Database\Database;
|
||||||
|
use VLW\Database\Models\Languages\Language;
|
||||||
|
use VLW\Database\Tables\Languages\Languages;
|
||||||
|
|
||||||
|
require_once VV::root("src/Database/Database.php");
|
||||||
require_once VV::root("src/Database/Models/Languages/Language.php");
|
require_once VV::root("src/Database/Models/Languages/Language.php");
|
||||||
|
require_once VV::root("src/Database/Tables/Languages/Languages.php");
|
||||||
|
|
||||||
class Forgejo {
|
class Forgejo {
|
||||||
private readonly array $languages;
|
private const FORGEJO_HREF = "https://git.vlw.se/explore/repos?q=&sort=recentupdate&language=";
|
||||||
|
private const FORGEJO_ENDPOINT_USER = "/api/v1/users/%s";
|
||||||
|
private const FORGEJO_ENDPOINT_SEARCH = "/api/v1/repos/search?uid=%s";
|
||||||
|
|
||||||
|
private array $languages;
|
||||||
|
private readonly Database $db;
|
||||||
|
|
||||||
// Fetch JSON from URL
|
// Fetch JSON from URL
|
||||||
private static function fetch_json(string $url): array {
|
private static function fetch_json(string $url): array {
|
||||||
|
@ -16,26 +27,39 @@
|
||||||
|
|
||||||
// Fetch JSON from a Forgejo endpoint
|
// Fetch JSON from a Forgejo endpoint
|
||||||
private static function fetch_endpoint(string $endpoint): array {
|
private static function fetch_endpoint(string $endpoint): array {
|
||||||
$url = $_ENV["server_forgejo"]["base_url"] . $endpoint;
|
$url = $_ENV["service_forgejo"]["url"] . $endpoint;
|
||||||
return self::fetch_json($url);
|
return self::fetch_json($url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
|
$this->db = new Database();
|
||||||
$this->languages = [];
|
$this->languages = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write $this->languages to a JSON file
|
// Add languages from all public repositories for profiles in config
|
||||||
private function cache_languages(): void {
|
public function update(): bool {
|
||||||
// Delete existing cache
|
foreach(explode(",", $_ENV["service_forgejo"]["profiles"]) as $profile) {
|
||||||
(new Call(Endpoints::ABOUT_LANGUAGES->value))->delete();
|
// Resolve user data from username
|
||||||
|
$user = self::fetch_endpoint(sprintf(self::FORGEJO_ENDPOINT_USER, $profile));
|
||||||
|
if (!$this->add_public_repositores($user["id"])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->db->for(LanguagesTable::NAME);
|
$this->save_languages();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function truncate(): bool {
|
||||||
|
return $this->db->from(Languages::TABLE)->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save languages from $this->languages to the database
|
||||||
|
private function save_languages(): void {
|
||||||
|
$this->truncate();
|
||||||
|
|
||||||
foreach ($this->languages as $language => $bytes) {
|
foreach ($this->languages as $language => $bytes) {
|
||||||
$this->db->insert([
|
Language::new($language, $bytes);
|
||||||
LanguagesTable::ID->value => $language,
|
|
||||||
LanguagesTable::BYTES->value => $bytes
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +78,7 @@
|
||||||
|
|
||||||
// Tally languages from public repositories for user id
|
// Tally languages from public repositories for user id
|
||||||
private function add_public_repositores(int $uid): bool {
|
private function add_public_repositores(int $uid): bool {
|
||||||
$resp = self::fetch_endpoint(sprintf(FORGEJO_ENDPOINT_SEARCH, $uid));
|
$resp = self::fetch_endpoint(sprintf(self::FORGEJO_ENDPOINT_SEARCH, $uid));
|
||||||
|
|
||||||
// Bail out if request failed or if response indicated a problem
|
// Bail out if request failed or if response indicated a problem
|
||||||
if (!$resp or $resp["ok"] === false) {
|
if (!$resp or $resp["ok"] === false) {
|
||||||
|
@ -68,14 +92,4 @@
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add languages from all public repositories for profiles in config
|
|
||||||
private function add_repositories_from_config_profiles(): void {
|
|
||||||
foreach(explode(",", $_ENV["server_forgejo"]["scan_profiles"]) as $profile) {
|
|
||||||
// Resolve user data from username
|
|
||||||
$user = self::fetch_endpoint(sprintf(FORGEJO_ENDPOINT_USER, $profile));
|
|
||||||
$this->add_public_repositores($user["id"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -3,6 +3,8 @@
|
||||||
namespace VLW\Helpers;
|
namespace VLW\Helpers;
|
||||||
|
|
||||||
class UUID {
|
class UUID {
|
||||||
|
public const LENGTH = 36;
|
||||||
|
|
||||||
public static function nil(): string {
|
public static function nil(): string {
|
||||||
return "00000000-0000-0000-0000-000000000000";
|
return "00000000-0000-0000-0000-000000000000";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue