summaryrefslogtreecommitdiff
path: root/src/web/helpers
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2024-05-24 09:05:42 -0400
committerFreya Murphy <freya@freyacat.org>2024-05-24 09:05:42 -0400
commitc5f39ea2cd7cf02246705ea8872d3b350526165c (patch)
tree2694f9fdc5d83b529a01f2997c1d89c271c86592 /src/web/helpers
downloadwebsite-c5f39ea2cd7cf02246705ea8872d3b350526165c.tar.gz
website-c5f39ea2cd7cf02246705ea8872d3b350526165c.tar.bz2
website-c5f39ea2cd7cf02246705ea8872d3b350526165c.zip
initial
Diffstat (limited to 'src/web/helpers')
-rw-r--r--src/web/helpers/aria.php16
-rw-r--r--src/web/helpers/database.php282
-rw-r--r--src/web/helpers/image.php94
-rw-r--r--src/web/helpers/lang.php79
-rw-r--r--src/web/helpers/markdown.php33
-rw-r--r--src/web/helpers/sanitize.php8
6 files changed, 512 insertions, 0 deletions
diff --git a/src/web/helpers/aria.php b/src/web/helpers/aria.php
new file mode 100644
index 0000000..8ebfcc5
--- /dev/null
+++ b/src/web/helpers/aria.php
@@ -0,0 +1,16 @@
+<?php /* Copyright (c) 2024 Freya Murphy */
+
+function aria_section($id, $title = NULL): string {
+ $out = '';
+ if ($title) {
+ $idh = $id . '_heading';
+ $out .= sprintf('<div id="%s" class="section" role="region" aria-labelledby="%s">',
+ $id, $idh);
+ $out .= sprintf('<h2 class="heading" id="%s">%s</h2>',
+ $idh, $title);
+ } else {
+ $out .= sprintf('<div id="%s" class="section" role="region">',
+ $id);
+ }
+ return $out;
+}
diff --git a/src/web/helpers/database.php b/src/web/helpers/database.php
new file mode 100644
index 0000000..25cb5ba
--- /dev/null
+++ b/src/web/helpers/database.php
@@ -0,0 +1,282 @@
+<?php /* Copyright (c) 2024 Freya Murphy */
+
+class DatabaseQuery {
+
+ private $conn;
+ private $query;
+
+ private $where;
+ private $set;
+
+ private $param;
+
+ function __construct($conn) {
+ $this->conn = $conn;
+ $this->query = '';
+
+ $this->set = FALSE;
+ $this->where = FALSE;
+ $this->param = array();
+ }
+
+ ///
+ /// ARBITRARY QUERY
+ ///
+
+ public function query($query) {
+ $this->query .= $query;
+ return $this;
+ }
+
+ ///
+ /// SELECT
+ ///
+
+ public function select($select) {
+ $this->query .= "SELECT $select\n";
+ return $this;
+ }
+
+ public function from($from) {
+ $this->query .= "FROM $from\n";
+ return $this;
+ }
+
+ ///
+ /// INSERT
+ ///
+
+ public function insert_into($insert, ...$columns) {
+ $this->query .= "INSERT INTO $insert\n (";
+ foreach ($columns as $idx => $column) {
+ if ($idx !== 0) {
+ $this->query .= ",";
+ }
+ $this->query .= $column;
+ }
+ $this->query .= ")\n";
+ return $this;
+ }
+
+ public function values(...$values) {
+ $this->query .= "VALUES (";
+ foreach ($values as $idx => $value) {
+ if ($idx !== 0) {
+ $this->query .= ",";
+ }
+ $this->query .= "?";
+ array_push($this->param, $value);
+ }
+ $this->query .= ")\n";
+ return $this;
+ }
+
+ ///
+ /// WHERE
+ ///
+
+ public function where($cond) {
+ if (!$this->where) {
+ $this->where = TRUE;
+ $this->query .= "WHERE ";
+ } else {
+ $this->query .= "AND ";
+ }
+ $this->query .= "$cond ";
+ return $this;
+ }
+
+ public function where_in($column, $array) {
+ if (!$this->where) {
+ $this->where = TRUE;
+ $this->query .= "WHERE ";
+ } else {
+ $this->query .= "AND ";
+ }
+ if (empty($array)) {
+ $this->query .= "FALSE\n";
+ return $this;
+ }
+ $in = $this->in($array);
+ $this->query .= "$column $in\n";
+ return $this;
+ }
+
+ private function in($array) {
+ $in = 'IN (';
+ foreach ($array as $idx => $item) {
+ if ($idx != 0) {
+ $in .= ",";
+ }
+ $in .= "?";
+ array_push($this->param, $item);
+ }
+ $in .= ")";
+ return $in;
+ }
+
+ ///
+ /// OPERATORS
+ ///
+
+ public function like($item) {
+ $this->query .= "LIKE ?\n";
+ array_push($this->param, $item);
+ return $this;
+ }
+
+ public function eq($item) {
+ $this->query .= "= ?\n";
+ array_push($this->param, $item);
+ return $this;
+ }
+
+ public function ne($item) {
+ $this->query .= "<> ?\n";
+ array_push($this->param, $item);
+ return $this;
+ }
+
+ public function lt($item) {
+ $this->query .= "< ?\n";
+ array_push($this->param, $item);
+ return $this;
+ }
+
+ public function le($item) {
+ $this->query .= "<= ?\n";
+ array_push($this->param, $item);
+ return $this;
+ }
+
+ ///
+ /// JOINS
+ ///
+
+ public function join($table, $on, $type = 'LEFT') {
+ $this->query .= "$type JOIN $table ON $on\n";
+ return $this;
+ }
+
+ ///
+ /// LIMIT, OFFSET, ORDER
+ ///
+
+ public function limit($limit) {
+ $this->query .= "LIMIT ?\n";
+ array_push($this->param, $limit);
+ return $this;
+ }
+
+ public function offset($offset) {
+ $this->query .= "OFFSET ?\n";
+ array_push($this->param, $offset);
+ return $this;
+ }
+
+ public function order_by($column, $order = 'ASC') {
+ $this->query .= "ORDER BY " . $column . ' ' . $order . ' ';
+ return $this;
+ }
+
+ ///
+ /// COLLECT
+ ///
+
+ public function rows(...$params) {
+ $args = $this->param;
+ foreach ($params as $param) {
+ array_push($args, $param);
+ }
+ $stmt = $this->conn->prepare($this->query);
+ try {
+ $stmt->execute($args);
+ } catch (Exception $ex) {
+ echo $ex;
+ echo '<br> >> caused by <<<br>';
+ echo str_replace("\n", "<br>", $this->query);
+ }
+ return $stmt->fetchAll(PDO::FETCH_ASSOC);
+ }
+
+ public function row(...$params) {
+ $args = $this->param;
+ foreach ($params as $param) {
+ array_push($args, $param);
+ }
+ $stmt = $this->conn->prepare($this->query);
+ $stmt->execute($args);
+ return $stmt->fetch(PDO::FETCH_ASSOC);
+ }
+
+ public function execute(...$params) {
+ $args = $this->param;
+ foreach ($params as $param) {
+ array_push($args, $param);
+ }
+ $stmt = $this->conn->prepare($this->query);
+ try {
+ $stmt->execute($args);
+ return TRUE;
+ } catch (Exception $_e) {
+ echo $_e;
+ echo '<br> >> caused by <<<br>';
+ echo str_replace("\n", "<br>", $this->query);
+ return FALSE;
+ }
+ }
+}
+
+/**
+ * DatabaseHelper
+ * allows queries on the
+ * postgres database
+ */
+class DatabaseHelper {
+
+ private $conn;
+
+ function __construct() {
+ $this->conn = NULL;
+ }
+
+ private function connect() {
+ if ($this->conn === NULL) {
+ $user = getenv("POSTGRES_USER");
+ $pass = getenv("POSTGRES_PASSWORD");
+ $db = getenv("POSTGRES_DB");
+ $host = 'db';
+ $port = '5432';
+
+ $conn_str = sprintf("pgsql:host=%s;port=%d;dbname=%s;user=%s;password=%s",
+ $host,
+ $port,
+ $db,
+ $user,
+ $pass
+ );
+ $this->conn = new \PDO($conn_str);
+ $this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+ }
+ return $this->conn;
+ }
+
+ public function select($select) {
+ $conn = $this->connect();
+ $query = new DatabaseQuery($conn);
+ return $query->select($select);
+ }
+
+ public function insert_into($insert, ...$columns) {
+ $conn = $this->connect();
+ $query = new DatabaseQuery($conn);
+ return $query->insert_into($insert, ...$columns);
+ }
+
+ public function query($query_str) {
+ $conn = $this->connect();
+ $query = new DatabaseQuery($conn);
+ return $query->query($query_str);
+ }
+}
+
diff --git a/src/web/helpers/image.php b/src/web/helpers/image.php
new file mode 100644
index 0000000..c18154a
--- /dev/null
+++ b/src/web/helpers/image.php
@@ -0,0 +1,94 @@
+<?php /* Copyright (c) 2024 Freya Murphy */
+
+function __get_mime($type) {
+ switch ($type) {
+ case 'mp4':
+ return 'video/mp4';
+ case 'webm':
+ return 'video/webm';
+ case 'gif':
+ return 'image/gif';
+ case 'png':
+ return 'image/png';
+ case 'jpg':
+ return 'image/jpeg';
+ case 'webp':
+ return 'image/webp';
+ default:
+ return NULL;
+ }
+}
+
+function __make_source(
+ $name,
+ $format,
+ $media
+) {
+ if ($media) {
+ $media = "media=\"$media\"";
+ } else {
+ $media = '';
+ }
+ $main = $GLOBALS['main_model'];
+ $path = $main->get_url('public/' . $name . '.' . $format);
+ $mime = __get_mime($format);
+ return sprintf('<source type="%s" srcset="%s" %s>',
+ $mime, $path, $media);
+}
+
+function image(
+ $name,
+ $alt,
+ $formats = array('webp', 'png'),
+ $animated = FALSE,
+ $attrs = array(),
+
+ $height = NULL,
+ $width = NULL,
+ $size = NULL,
+) :string {
+
+ if ($animated === TRUE) {
+ $animated = array('gif');
+ }
+
+ if (!$animated) {
+ $animated = array();
+ }
+
+ $out = "<picture>";
+
+ foreach ($formats as $format) {
+ $media = count($animated) ? '(prefers-reduced-motion: reduce)' : NULL;
+ $out .= __make_source($name, $format, $media);
+ }
+
+ foreach ($animated as $format) {
+ $out .= __make_source($name, $format, NULL);
+ }
+
+ $format = end($formats);
+ $main = $GLOBALS['main_model'];
+ $path = $main->get_url('public/' . $name . '.' . $format);
+ $out .= "<img src=\"$path\"";
+ if ($alt) {
+ $alt = lang($alt);
+ $attrs['alt'] = $alt;
+ }
+ if ($width) {
+ $attrs['width'] = $width;
+ }
+ if ($height) {
+ $attrs['height'] = $height;
+ }
+ if ($size) {
+ $attrs['width'] = $size;
+ $attrs['height'] = $size;
+ }
+ foreach ($attrs as $key => $value) {
+ $out .= " $key=\"$value\"";
+ }
+ $out .= '></picture>';
+
+ return $out;
+}
diff --git a/src/web/helpers/lang.php b/src/web/helpers/lang.php
new file mode 100644
index 0000000..e8fa29e
--- /dev/null
+++ b/src/web/helpers/lang.php
@@ -0,0 +1,79 @@
+<?php /* Copyright (c) 2024 Freya Murphy */
+$lang = array();
+
+function lang($key, $default = NULL, $sub = NULL) {
+ $lang = $GLOBALS['lang'];
+ if(array_key_exists($key, $lang)) {
+ if ($sub) {
+ return sprintf($lang[$key], ...$sub);
+ } else {
+ return $lang[$key];
+ }
+ } else if ($default !== NULL) {
+ return $default;
+ } else {
+ trigger_error('Undefined lang string: ' . $key, E_USER_WARNING);
+ return $key;
+ }
+}
+
+function ilang($key,
+ $class = NULL,
+ $id = NULL,
+ $href = NULL,
+ $click = NULL,
+ $attrs = array(),
+ $sub = NULL,
+ $button = FALSE,
+ $container = 'span'
+) {
+ $text = ucfirst(lang($key . "_text", FALSE, sub: $sub));
+ $tip = lang($key . "_tip", FALSE, sub: $sub);
+ $icon = lang($key . "_icon", FALSE);
+ $content = lang($key . "_content", FALSE);
+
+ if ($click || $button) {
+ echo '<button ';
+ } else {
+ echo '<a ';
+ }
+ if ($tip) {
+ echo 'title="' . $tip . '" ';
+ echo 'aria-label="' . $tip . '" ';
+ }
+ if ($class) {
+ echo 'class="' . $class . '" ';
+ }
+ if ($id) {
+ echo 'id="' . $id . '" ';
+ }
+ if ($click) {
+ echo 'onclick="' . $click . '" ';
+ }
+ if ($href) {
+ echo 'href="' . $href . '" ';
+ }
+ foreach ($attrs as $key => $attr) {
+ echo $key . '="' . $attr . '" ';
+ }
+ echo '> ';
+ if ($icon) {
+ echo '<i class="' . $icon . '">';
+ if ($content) {
+ echo $content;
+ }
+ echo '</i>';
+ }
+ if ($text) {
+ echo '<' . $container;
+ if ($icon) {
+ echo ' class="ml-sm"';
+ }
+ echo '>' . $text . '</' . $container . '>';
+ }
+ if ($click || $button) {
+ echo '</button>';
+ } else {
+ echo '</a>';
+ }
+}
diff --git a/src/web/helpers/markdown.php b/src/web/helpers/markdown.php
new file mode 100644
index 0000000..39b430c
--- /dev/null
+++ b/src/web/helpers/markdown.php
@@ -0,0 +1,33 @@
+<?php /* Copyright (c) 2024 Freya Murphy */
+
+class MarkdownParser {
+
+ private $parsedown;
+
+ function __construct() {
+ $this->parsedown = new ParsedownExtra();
+ }
+
+ function parse($path) {
+ $content = file_get_contents($path);
+ $data = array(
+ 'meta' => array(),
+ 'content' => $content
+ );
+ if (str_starts_with($content, '---')) {
+ $parts = explode('---', $content);
+ $data['content'] = trim(implode('---', array_slice($parts, 2)));
+ $meta = array_filter(explode("\n", $parts[1]), fn($x) => $x != '');
+ foreach ($meta as $set) {
+ $parts = explode(": ", $set);
+ $key = trim($parts[0]);
+ $value = trim($parts[1]);
+ $data['meta'][$key] = $value;
+ }
+
+ }
+ $data['content'] = $this->parsedown->text($data['content']);
+ return $data;
+ }
+
+}
diff --git a/src/web/helpers/sanitize.php b/src/web/helpers/sanitize.php
new file mode 100644
index 0000000..5d37852
--- /dev/null
+++ b/src/web/helpers/sanitize.php
@@ -0,0 +1,8 @@
+<?php /* Copyright (c) 2024 Freya Murphy */
+
+function esc($data) {
+ $data = str_replace('&', '&amp;', $data);
+ $data = str_replace('<', '&lt;', $data);
+ $data = str_replace('>', '&gt;', $data);
+ return $data;
+}