refactor
This commit is contained in:
parent
944b6b0526
commit
1f04b83be3
50 changed files with 965 additions and 491 deletions
|
@ -5,7 +5,8 @@ CREATE VIEW api.post AS
|
|||
p.content,
|
||||
p.date
|
||||
FROM
|
||||
admin.post p;
|
||||
admin.post p
|
||||
ORDER BY id DESC;
|
||||
|
||||
GRANT SELECT ON TABLE api.post
|
||||
TO rest_anon, rest_user;
|
||||
|
|
|
@ -32,6 +32,8 @@ GRANT INSERT ON TABLE api.post
|
|||
TO rest_user;
|
||||
GRANT INSERT ON TABLE admin.post
|
||||
TO rest_user;
|
||||
GRANT UPDATE ON TABLE sys.post_id_seq
|
||||
TO rest_user;
|
||||
|
||||
CREATE TRIGGER api_post_insert_trgr
|
||||
INSTEAD OF INSERT
|
||||
|
|
|
@ -29,7 +29,7 @@ BEGIN
|
|||
|
||||
IF _min IS NOT NULL AND _length < _min THEN
|
||||
PERFORM _api.raise(
|
||||
_msg => 'api_text_min',
|
||||
_msg => 'api_min_value',
|
||||
_detail => _column,
|
||||
_hint => _min || ''
|
||||
);
|
||||
|
@ -37,7 +37,7 @@ BEGIN
|
|||
|
||||
IF _max IS NOT NULL AND _length > _max THEN
|
||||
PERFORM _api.raise(
|
||||
_msg => 'api_text_max',
|
||||
_msg => 'api_max_value',
|
||||
_detail => _column,
|
||||
_hint => _max || ''
|
||||
);
|
||||
|
|
23
web/_controller/_index.php
Normal file
23
web/_controller/_index.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class _index_controller extends Controller {
|
||||
|
||||
// the home model
|
||||
private $home_model;
|
||||
|
||||
// the request model
|
||||
private $request_model;
|
||||
|
||||
// the caceh model
|
||||
private $cache_model;
|
||||
|
||||
public function index(): void {
|
||||
if ($this->main->session) {
|
||||
$this->redirect('/home');
|
||||
} else {
|
||||
$this->redirect('/login');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
20
web/_controller/apps/error.php
Normal file
20
web/_controller/apps/error.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class Error_controller extends Controller {
|
||||
|
||||
private $error_model;
|
||||
|
||||
function __construct($load) {
|
||||
parent::__construct($load);
|
||||
$this->error_model = $this->load->model('apps/error');
|
||||
}
|
||||
|
||||
public function index() {
|
||||
parent::index();
|
||||
$data = $this->error_model->get_data();
|
||||
$this->view('header', $data);
|
||||
$this->view('apps/error/main', $data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,22 +1,31 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class HomeController extends Controller {
|
||||
class Home_controller extends Controller {
|
||||
|
||||
private $model;
|
||||
// the home model
|
||||
private $home_model;
|
||||
|
||||
function __construct($model) {
|
||||
parent::__construct();
|
||||
$this->model = $model;
|
||||
// the request model
|
||||
private $request_model;
|
||||
|
||||
// the caceh model
|
||||
private $cache_model;
|
||||
|
||||
function __construct($load) {
|
||||
parent::__construct($load);
|
||||
$this->home_model = $this->load->model('apps/home');
|
||||
$this->request_model = $this->load->model('request');
|
||||
$this->cache_model = $this->load->model('cache');
|
||||
}
|
||||
|
||||
public function index() {
|
||||
public function index(): void {
|
||||
parent::index();
|
||||
$data = $this->model->get_data();
|
||||
$data = $this->home_model->get_data();
|
||||
$this->view('header', $data);
|
||||
$this->app_view('main', $data);
|
||||
$this->view('apps/home/main', $data);
|
||||
}
|
||||
|
||||
public function posts() {
|
||||
$page = $this->main->get_num('page', 0);
|
||||
public function posts(): void {
|
||||
$page = $this->request_model->get_int('page', 0);
|
||||
$page_size = 20;
|
||||
$offset = $page * $page_size;
|
||||
|
||||
|
@ -30,7 +39,7 @@ class HomeController extends Controller {
|
|||
$query = $query->select('p.*, FALSE as liked');
|
||||
}
|
||||
|
||||
$query = $query->from('admin.post p');
|
||||
$query = $query->from('api.post p');
|
||||
|
||||
if ($user) {
|
||||
$query = $query->join('admin.like l', 'p.id = l.post_id')
|
||||
|
@ -42,7 +51,7 @@ class HomeController extends Controller {
|
|||
->offset($offset)
|
||||
->rows();
|
||||
|
||||
$users = $this->main->get_users($posts);
|
||||
$users = $this->cache_model->get_users($posts);
|
||||
|
||||
foreach ($posts as $post) {
|
||||
$data = array();
|
||||
|
@ -52,9 +61,9 @@ class HomeController extends Controller {
|
|||
}
|
||||
}
|
||||
|
||||
public function comments() {
|
||||
$page = $this->main->get_num('page', 0);
|
||||
$id = $this->main->get_num('id');
|
||||
public function comments(): void {
|
||||
$page = $this->request_model->get_int('page', 0);
|
||||
$id = $this->request_model->get_int('id');
|
||||
$page_size = 20;
|
||||
$offset = $page * $page_size;
|
||||
|
||||
|
@ -65,7 +74,7 @@ class HomeController extends Controller {
|
|||
->offset($offset)
|
||||
->rows();
|
||||
|
||||
$users = $this->main->get_users($comments);
|
||||
$users = $this->cache_model->get_users($comments);
|
||||
|
||||
foreach ($comments as $comment) {
|
||||
$data = array();
|
||||
|
@ -75,10 +84,6 @@ class HomeController extends Controller {
|
|||
}
|
||||
}
|
||||
|
||||
public function new_post_modal() {
|
||||
$this->modal(lang('new_post_modal_title'), 'new-post');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
26
web/_controller/modal.php
Normal file
26
web/_controller/modal.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class Modal_controller extends Controller {
|
||||
|
||||
|
||||
function __construct($load) {
|
||||
parent::__construct($load);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $data
|
||||
*/
|
||||
private function modal($name, $data = array()): void {
|
||||
$title = lang($name . '_modal_title');
|
||||
$data['title'] = $title;
|
||||
$data['content'] = $name;
|
||||
$this->view('template/modal', $data);
|
||||
}
|
||||
|
||||
public function new_post(): void {
|
||||
$this->modal('new_post');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
22
web/_controller/template.php
Normal file
22
web/_controller/template.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class Template_controller extends Controller {
|
||||
|
||||
// the request model
|
||||
private $request_model;
|
||||
|
||||
function __construct($load) {
|
||||
parent::__construct($load);
|
||||
$this->request_model = $this->load->model('request');
|
||||
}
|
||||
|
||||
public function toast(): void {
|
||||
$data = array(
|
||||
'msg' => $this->request_model->get_str('msg', FALSE),
|
||||
'detail' => $this->request_model->get_str('detail', FALSE),
|
||||
'hint' => $this->request_model->get_str('hint', FALSE)
|
||||
);
|
||||
$this->view('template/toast', $data);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class ErrorModel extends Model {
|
||||
class Error_model extends Model {
|
||||
|
||||
function __construct($load) {
|
||||
parent::__construct($load);
|
||||
}
|
||||
|
||||
private function get_msg(&$data) {
|
||||
if (!array_key_exists('code', $_GET)) {
|
||||
|
@ -22,7 +26,7 @@ class ErrorModel extends Model {
|
|||
}
|
||||
}
|
||||
|
||||
public function get_data() {
|
||||
public function get_data(): array {
|
||||
$data = parent::get_data();
|
||||
$this->get_msg($data);
|
||||
return $data;
|
|
@ -1,7 +1,11 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class HomeModel extends Model {
|
||||
class Home_model extends Model {
|
||||
|
||||
private function get_posts() {
|
||||
function __construct($load) {
|
||||
parent::__construct($load);
|
||||
}
|
||||
|
||||
private function get_posts(): array {
|
||||
return $this->db
|
||||
->select('*')
|
||||
->from('admin.post')
|
||||
|
@ -9,11 +13,10 @@ class HomeModel extends Model {
|
|||
->rows();
|
||||
}
|
||||
|
||||
public function get_data() {
|
||||
public function get_data(): array {
|
||||
$data = parent::get_data();
|
||||
$data['title'] = lang('title');
|
||||
$data['posts'] = $this->get_posts();
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
?>
|
37
web/_model/cache.php
Normal file
37
web/_model/cache.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class Cache_model extends Model {
|
||||
|
||||
// the user cache
|
||||
private $users;
|
||||
|
||||
function __construct($load) {
|
||||
parent::__construct($load);
|
||||
$this->users = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a array of users
|
||||
*/
|
||||
public function get_users($objs) {
|
||||
$ids = array();
|
||||
foreach ($objs as $obj) {
|
||||
$id = $obj['user_id'];
|
||||
if (!array_key_exists($id, $this->users)) {
|
||||
array_push($ids, intval($id));
|
||||
}
|
||||
}
|
||||
if (!empty($ids)) {
|
||||
$result = $this->main->db
|
||||
->select('*')
|
||||
->from('api.user')
|
||||
->where_in('id', $ids)
|
||||
->rows();
|
||||
foreach ($result as $user) {
|
||||
$id = $user['id'];
|
||||
$this->users[$id] = $user;
|
||||
}
|
||||
}
|
||||
return $this->users;
|
||||
}
|
||||
|
||||
}
|
45
web/_model/format.php
Normal file
45
web/_model/format.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class Format_model extends Modal {
|
||||
|
||||
function __construct($load) {
|
||||
parent::__construct($load);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a users's name
|
||||
* @param array $user - the $user
|
||||
* @returns the user's formatted display name
|
||||
*/
|
||||
public function name($user) {
|
||||
$name = '';
|
||||
if ($user['first_name']) {
|
||||
$name .= $user['first_name'];
|
||||
}
|
||||
if ($user['middle_name']) {
|
||||
if ($name != '') {
|
||||
$name .= ' ';
|
||||
}
|
||||
$name .= $user['middle_name'];
|
||||
}
|
||||
if ($user['last_name']) {
|
||||
if ($name != '') {
|
||||
$name .= ' ';
|
||||
}
|
||||
$name .= $user['last_name'];
|
||||
}
|
||||
if ($name == '') {
|
||||
$name = '@' . $user['username'];
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date
|
||||
* @param string $date - the data in RFC3999 format
|
||||
* @returns the formatted date
|
||||
*/
|
||||
public function date($date) {
|
||||
return $date;
|
||||
}
|
||||
|
||||
}
|
84
web/_model/main.php
Normal file
84
web/_model/main.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class Main_model {
|
||||
|
||||
// the website database
|
||||
public $db;
|
||||
|
||||
// the current user session (can be NULL)
|
||||
public $session;
|
||||
|
||||
// current loaded users
|
||||
private $users;
|
||||
|
||||
// stores the current request info
|
||||
public $info;
|
||||
|
||||
/**
|
||||
* Loads the main model
|
||||
* @param Loader $load - the main loader object
|
||||
*/
|
||||
function __construct($load) {
|
||||
/// load the database helper
|
||||
$this->db = new DatabaseHelper();
|
||||
/// load the current session
|
||||
if (array_key_exists('jwt', $_SESSION)) {
|
||||
$this->get_session($_SESSION['jwt']);
|
||||
} else {
|
||||
$this->session = NULL;
|
||||
};
|
||||
/// init other vars
|
||||
$this->users = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads current session
|
||||
* @param string $jwt - the user provided JWT
|
||||
*/
|
||||
private function get_session($jwt) {
|
||||
$query = $this->db
|
||||
->select("_api.verify_jwt('" . $jwt . "') AS user_id;");
|
||||
$result = $query->row();
|
||||
$user_id = $result['user_id'];
|
||||
if ($user_id) {
|
||||
$this->session = array(
|
||||
'id' => $user_id,
|
||||
'jwt' => $jwt
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a css html link
|
||||
* @param string $path - the path to the css file
|
||||
*/
|
||||
public function link_css($path) {
|
||||
return '<link rel="stylesheet" href="/public/' . $path . '">';
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a js html link
|
||||
* @param string $path - the path to the js file
|
||||
*/
|
||||
public function link_js($path) {
|
||||
return '<script src="/public/'. $path . '"></script>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current user
|
||||
*/
|
||||
public function user() {
|
||||
if ($this->session) {
|
||||
return $this->db
|
||||
->select('*')
|
||||
->from('api.user')
|
||||
->where('id')
|
||||
->eq($this->session['id'])
|
||||
->row();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
40
web/_model/request.php
Normal file
40
web/_model/request.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class Request_model extends Model {
|
||||
|
||||
function __construct($load) {
|
||||
parent::__construct($load);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a string from the GET request
|
||||
* @param string $key - the name for the query param
|
||||
* @param string $default - the default value if not exists
|
||||
*/
|
||||
public function get_str($key, $default = NULL): string | NULL {
|
||||
if (!array_key_exists($key, $_GET)) {
|
||||
return $default;
|
||||
} else {
|
||||
return $_GET[$key];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a number from the GET request
|
||||
* @param string $key - the name for the query param
|
||||
* @param int $default - the default value if not exists
|
||||
*/
|
||||
public function get_int($key, $default = NULL): int | NULL {
|
||||
if (!array_key_exists($key, $_GET)) {
|
||||
return $default;
|
||||
} else {
|
||||
$val = $_GET[$key];
|
||||
$val = intval($val);
|
||||
if ($val < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,7 @@ class Aesthetic {
|
|||
'js' => [
|
||||
'js/jquery-3.7.1.min.js',
|
||||
'js/lib.js',
|
||||
'js/modal.js',
|
||||
'js/shared/modal.js',
|
||||
],
|
||||
'css' => [
|
||||
'css/common.css'
|
||||
|
@ -22,7 +22,8 @@ class Aesthetic {
|
|||
),
|
||||
'home' => array(
|
||||
'js' => [
|
||||
'js/post.js',
|
||||
'js/shared/post.js',
|
||||
'js/routes/home.js',
|
||||
],
|
||||
'css' => [
|
||||
'css/home.css',
|
7
web/config/routes.php
Normal file
7
web/config/routes.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
|
||||
$routes = array();
|
||||
$routes['home'] = 'apps/home';
|
||||
$routes['error'] = 'apps/error';
|
||||
|
||||
$routes[''] = '_index';
|
49
web/core/_controller.php
Normal file
49
web/core/_controller.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
abstract class Controller {
|
||||
|
||||
// the main model
|
||||
public $main;
|
||||
|
||||
// the loader
|
||||
public $load;
|
||||
|
||||
// the database
|
||||
public $db;
|
||||
|
||||
/**
|
||||
* Creates a constructor
|
||||
* @param Loader $load - the website loaded object
|
||||
*/
|
||||
function __construct($load) {
|
||||
$this->load = $load;
|
||||
$this->main = $this->load->model('main');
|
||||
$this->db = $this->main->db;
|
||||
|
||||
$info = $this->main->info;
|
||||
$lang = $info['lang'];
|
||||
$this->load->lang($lang);
|
||||
$app = $info['app'];
|
||||
if ($app) {
|
||||
$this->load->app_lang($lang, $app);
|
||||
}
|
||||
}
|
||||
|
||||
public function index() {}
|
||||
|
||||
public function redirect($link) {
|
||||
header('Location: '. $link, true, 301);
|
||||
die();
|
||||
}
|
||||
|
||||
protected function view($__name, $data = array()) {
|
||||
$__root = $GLOBALS['webroot'];
|
||||
$__path = $__root . '/views/' . $__name . '.php';
|
||||
if (is_file($__path)) {
|
||||
extract($data);
|
||||
require($__path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
44
web/core/_model.php
Normal file
44
web/core/_model.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
abstract class Model {
|
||||
// the main model
|
||||
// shared by all controllers and models
|
||||
public $main;
|
||||
public $load;
|
||||
|
||||
// the database
|
||||
public $db;
|
||||
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* Creates a model
|
||||
* @param Loader $load - the main loader object
|
||||
*/
|
||||
function __construct($load) {
|
||||
$this->load = $load;
|
||||
$this->main = $this->load->model('main');
|
||||
$this->db = $this->main->db;
|
||||
$this->config = new Aesthetic();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns the base model data
|
||||
*/
|
||||
public function get_data(): array {
|
||||
$data = array();
|
||||
$data['self'] = $this->main->user();
|
||||
|
||||
$info = $this->main->info;
|
||||
$app = $info['app'];
|
||||
|
||||
if ($app) {
|
||||
$files = $this->config->get_files($app);
|
||||
$data = array_merge($data, $files);
|
||||
} else {
|
||||
$files = $this->config->get_files();
|
||||
$data = array_merge($data, $files);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
abstract class Controller {
|
||||
|
||||
// the main model
|
||||
public $main;
|
||||
|
||||
// the loader
|
||||
public $load;
|
||||
|
||||
// the database
|
||||
public $db;
|
||||
|
||||
function __construct() {
|
||||
$this->main = $GLOBALS['__vars']['main'];
|
||||
$this->load = $GLOBALS['__vars']['load'];
|
||||
$this->db = $this->main->db;
|
||||
|
||||
$info = $this->main->info;
|
||||
$lang_code = $info['lang'];
|
||||
$route_name = $info['route'];
|
||||
$this->load->lang($lang_code);
|
||||
$this->load->route_lang($lang_code, $route_name);
|
||||
}
|
||||
|
||||
public function index() {}
|
||||
|
||||
protected function view($__name, $data = array()) {
|
||||
$__root = $GLOBALS['webroot'];
|
||||
$__path = $__root . '/views/' . $__name . '.php';
|
||||
if (is_file($__path)) {
|
||||
extract($data);
|
||||
require($__path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected function app_view($__name, $data = array()) {
|
||||
$__root = $GLOBALS['webroot'];
|
||||
$__route = $this->main->info['route'];
|
||||
$__path = $__root . '/routes/' . $__route . '/views/' . $__name . '.php';
|
||||
if (is_file($__path)) {
|
||||
extract($data);
|
||||
require($__path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected function modal($title, $content, $data = array()) {
|
||||
$data['title'] = $title;
|
||||
$data['content'] = $content;
|
||||
$this->view('template/modal', $data);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
|
@ -170,4 +170,3 @@ class DatabaseHelper {
|
|||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -1,16 +1,79 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class Loader {
|
||||
|
||||
// keep track of what has been loaded
|
||||
private $loaded;
|
||||
|
||||
function __construct() {
|
||||
$this->loaded = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a $type of object from a $dir with a given $name
|
||||
* @param string $name - the name of the object to load
|
||||
* @param string $dir - the directory theese objects are stored in
|
||||
* @param string $type - the type of the object
|
||||
*/
|
||||
private function load_type($name, $dir, $type): object|NULL {
|
||||
$path = $dir . '/' . $name . '.php';
|
||||
if (array_key_exists($path, $this->loaded)) {
|
||||
return $this->loaded[$path];
|
||||
}
|
||||
|
||||
if (!file_exists($path)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$parts = explode('/', $name);
|
||||
$part = end($parts);
|
||||
$class = ucfirst($part) . '_' . $type;
|
||||
require($path);
|
||||
|
||||
$ref = NULL;
|
||||
try {
|
||||
$ref = new ReflectionClass($class);
|
||||
} catch (Exception $_e) {}
|
||||
|
||||
if ($ref === NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
$obj = $ref->newInstance($this);
|
||||
$this->loaded[$path] = $obj;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a model
|
||||
* @param string $name - the name of the model to load
|
||||
*/
|
||||
public function model($name): object|NULL {
|
||||
$root = $GLOBALS['webroot'];
|
||||
$dir = $root . '/_model';
|
||||
return $this->load_type($name, $dir, 'model');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a controller
|
||||
* @param string $name - the name of the controller to load
|
||||
*/
|
||||
public function controller($name): Controller|NULL {
|
||||
$root = $GLOBALS['webroot'];
|
||||
$dir = $root . '/_controller';
|
||||
return $this->load_type($name, $dir, 'controller');
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the given common lang
|
||||
* @param lang_code - the language code
|
||||
* @param string $lang_code 0 the language code
|
||||
*/
|
||||
public function lang($lang_code) {
|
||||
public function lang($lang_code): void {
|
||||
$dir = $GLOBALS['webroot'] . '/lang/' . $lang_code . '/';
|
||||
$lang = $GLOBALS['lang'];
|
||||
if ($handle = opendir($dir)) {
|
||||
while (false !== ($entry = readdir($handle))) {
|
||||
if ($entry === '.' || $entry === '..' || $entry === 'routes') {
|
||||
if ($entry === '.' || $entry === '..' || $entry === 'apps') {
|
||||
continue;
|
||||
}
|
||||
$path = $dir . $entry;
|
||||
|
@ -21,12 +84,12 @@ class Loader {
|
|||
}
|
||||
|
||||
/**
|
||||
* Loads a given route specific lang
|
||||
* @param lang_coed - the language code
|
||||
* #param name - the name of the route
|
||||
* Loads a given app specific lang
|
||||
* @param string $lang_code - the language code
|
||||
* @param string $name - the name of the app
|
||||
*/
|
||||
public function route_lang($lang_code, $name) {
|
||||
$dir = $GLOBALS['webroot'] . '/lang/' . $lang_code . '/routes/';
|
||||
public function app_lang($lang_code, $name): void {
|
||||
$dir = $GLOBALS['webroot'] . '/lang/' . $lang_code . '/apps/';
|
||||
$file = $dir . $name . '.php';
|
||||
if (file_exists($file)) {
|
||||
$lang = $GLOBALS['lang'];
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class MainModel {
|
||||
|
||||
// loaded route infomation
|
||||
public $info;
|
||||
public $db;
|
||||
public $user_id;
|
||||
|
||||
private $users;
|
||||
|
||||
function __construct() {
|
||||
$this->info = NULL;
|
||||
$this->db = new DatabaseHelper();
|
||||
$this->users = array();
|
||||
$_SESSION['jwt'] = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoicmVzdF91c2VyIiwidXNlcl9pZCI6MSwiZXhwIjoxNzExODUxMDUzfQ.FUcFO44SWV--YtVOy7NftTF8OeeOYGZDaDHigygQxsY';
|
||||
if (array_key_exists('jwt', $_SESSION)) {
|
||||
$this->get_session($_SESSION['jwt']);
|
||||
} else {
|
||||
$this->user_id = NULL;
|
||||
};
|
||||
}
|
||||
|
||||
private function get_session($jwt) {
|
||||
$query = $this->db
|
||||
->select("_api.verify_jwt('" . $jwt . "') AS user_id;");
|
||||
$result = $query->row();
|
||||
$user_id = $result['user_id'];
|
||||
if ($user_id) {
|
||||
$this->user_id = $user_id;
|
||||
}
|
||||
}
|
||||
|
||||
public function link_css($path) {
|
||||
return '<link rel="stylesheet" href="/public/' . $path . '">';
|
||||
}
|
||||
|
||||
public function link_js($path) {
|
||||
return '<script src="/public/'. $path . '"></script>';
|
||||
}
|
||||
|
||||
public function user() {
|
||||
if ($this->user_id) {
|
||||
return $this->db
|
||||
->select('*')
|
||||
->from('api.user')
|
||||
->where('id')
|
||||
->eq($this->user_id)
|
||||
->row();
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
public function get_num($key, $default = NULL) {
|
||||
if (!array_key_exists($key, $_GET)) {
|
||||
if ($default !== NULL) {
|
||||
return $default;
|
||||
} else {
|
||||
error_page(400, lang('error_400'));
|
||||
}
|
||||
} else {
|
||||
$val = $_GET[$key];
|
||||
$val = intval($val);
|
||||
if ($val < 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function get_users($objs) {
|
||||
$ids = array();
|
||||
foreach ($objs as $obj) {
|
||||
$id = $obj['user_id'];
|
||||
if (!array_key_exists($id, $this->users)) {
|
||||
array_push($ids, intval($id));
|
||||
}
|
||||
}
|
||||
if (!empty($ids)) {
|
||||
$result = $this->db
|
||||
->select('*')
|
||||
->from('api.user')
|
||||
->where_in('id', $ids)
|
||||
->rows();
|
||||
foreach ($result as $user) {
|
||||
$id = $user['id'];
|
||||
$this->users[$id] = $user;
|
||||
}
|
||||
}
|
||||
return $this->users;
|
||||
}
|
||||
|
||||
public function display_name($user) {
|
||||
$name = '';
|
||||
if ($user['first_name']) {
|
||||
$name .= $user['first_name'];
|
||||
}
|
||||
if ($user['middle_name']) {
|
||||
if ($name != '') {
|
||||
$name .= ' ';
|
||||
}
|
||||
$name .= $user['middle_name'];
|
||||
}
|
||||
if ($user['last_name']) {
|
||||
if ($name != '') {
|
||||
$name .= ' ';
|
||||
}
|
||||
$name .= $user['last_name'];
|
||||
}
|
||||
if ($name == '') {
|
||||
$name = '@' . $user['username'];
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
|
||||
public function display_date($date) {
|
||||
return $date;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,29 +0,0 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
abstract class Model {
|
||||
// the main model
|
||||
// shared by all controllers and models
|
||||
public $main;
|
||||
public $load;
|
||||
|
||||
// the database
|
||||
public $db;
|
||||
|
||||
private $config;
|
||||
|
||||
function __construct() {
|
||||
$this->main = $GLOBALS['__vars']['main'];
|
||||
$this->load = $GLOBALS['__vars']['load'];
|
||||
$this->db = $this->main->db;
|
||||
$this->config = new Aesthetic();
|
||||
}
|
||||
|
||||
public function get_data() {
|
||||
$data = array();
|
||||
$route = $this->main->info['route'];
|
||||
$files = $this->config->get_files($route);
|
||||
$data = array_merge($data, $files);
|
||||
$data['self'] = $this->main->user();
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -1,127 +1,147 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class Router {
|
||||
|
||||
private $main;
|
||||
// the loader
|
||||
private $load;
|
||||
private $routes;
|
||||
|
||||
function load_route($route) {
|
||||
$name = $route['name'];
|
||||
$controller_cls = $route['controller'];
|
||||
$model_cls = $route['model'];
|
||||
// the main model
|
||||
private $main;
|
||||
|
||||
$root = $GLOBALS['webroot'];
|
||||
$dir = $root . '/routes/' . $name;
|
||||
require($dir . '/model.php');
|
||||
require($dir . '/controller.php');
|
||||
|
||||
$model_ref = new ReflectionClass($model_cls);
|
||||
$model = $model_ref->newInstance();
|
||||
|
||||
$controller_ref = new ReflectionClass($controller_cls);
|
||||
$controller = $controller_ref->newInstance($model);
|
||||
|
||||
return $controller;
|
||||
}
|
||||
|
||||
function __construct($main, $load) {
|
||||
|
||||
$routes = array(
|
||||
'home' => array(
|
||||
'slugs' => ['', 'home'],
|
||||
'model' => 'HomeModel',
|
||||
'controller' => 'HomeController',
|
||||
),
|
||||
);
|
||||
|
||||
$this->routes = array();
|
||||
foreach ($routes as $name => $route) {
|
||||
foreach ($route['slugs'] as $slug) {
|
||||
$this->routes[$slug] = $route;
|
||||
$this->routes[$slug]['name'] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->main = $main;
|
||||
/**
|
||||
* Creates a router
|
||||
* @param Loader $load - the main laoder object
|
||||
*/
|
||||
function __construct($load) {
|
||||
$this->load = $load;
|
||||
$this->main = $this->load->model('main');
|
||||
}
|
||||
|
||||
function get_info() {
|
||||
$uri = parse_url($_SERVER['REQUEST_URI']);
|
||||
/**
|
||||
* @param string $path - the current request path
|
||||
* Gets the current route
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
private function get_req_route($path): array {
|
||||
// trim the path
|
||||
$path = trim($path);
|
||||
// remove first '/'
|
||||
$path = substr($path, 1);
|
||||
// get path parts
|
||||
$parts = explode('/', $path);
|
||||
|
||||
$len = count($parts);
|
||||
|
||||
// get route info
|
||||
$route = array();
|
||||
// e.g. /
|
||||
if ($path === '') {
|
||||
$route = array(
|
||||
'route' => '',
|
||||
'slug' => 'index',
|
||||
);
|
||||
// e.g. /home /login
|
||||
} else if ($len === 1) {
|
||||
$route = array(
|
||||
'route' => $parts[0],
|
||||
'slug' => 'index',
|
||||
);
|
||||
// e.g. /home/posts
|
||||
} else {
|
||||
$route = array (
|
||||
'route' => implode('/', array_slice($parts, 0, -1)),
|
||||
'slug' => end($parts)
|
||||
);
|
||||
};
|
||||
|
||||
$route['app'] = $route['route'];
|
||||
$routes = $GLOBALS['routes'];
|
||||
if (array_key_exists($route['route'], $routes)) {
|
||||
$route['route'] = $routes[$route['route']];
|
||||
}
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the curret request info
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
private function get_req(): array {
|
||||
$method = $_SERVER['REQUEST_METHOD'];
|
||||
$parts = explode('/', $uri['path']);
|
||||
|
||||
$slug = sizeof($parts) > 1 ? $parts[1] : '';
|
||||
$path = sizeof($parts) > 2 ? $parts[2] : 'index';
|
||||
$uri = parse_url($_SERVER['REQUEST_URI']);
|
||||
$path = $uri['path'];
|
||||
|
||||
if (sizeof($parts) > 3) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return array(
|
||||
'method' => $method,
|
||||
'uri' => $uri,
|
||||
|
||||
'slug' => $slug,
|
||||
'path' => $path
|
||||
return array_merge(
|
||||
array(
|
||||
'uri' => $uri,
|
||||
'method' => $method,
|
||||
'lang' => $this->get_lang(),
|
||||
),
|
||||
$this->get_req_route($path),
|
||||
);
|
||||
}
|
||||
|
||||
function handle_error($code) {
|
||||
$route = array(
|
||||
'name' => 'error',
|
||||
'model' => 'ErrorModel',
|
||||
'controller' => 'ErrorController'
|
||||
);
|
||||
$this->main->info = array(
|
||||
'slug' => 'error',
|
||||
'lang' => 'en_US',
|
||||
'route' => 'error'
|
||||
);
|
||||
$controller = $this->load_route($route);
|
||||
/**
|
||||
* Gets the current language
|
||||
* @return string
|
||||
*/
|
||||
private function get_lang(): string {
|
||||
return 'en_US';
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a router error code
|
||||
* @param int $code - the http error code
|
||||
* @param bool $recursed
|
||||
*/
|
||||
private function handle_error($code, $recursed): void {
|
||||
if ($recursed) {
|
||||
die($code . ' (recursed)');
|
||||
}
|
||||
|
||||
$this->main->info['slug'] = 'index';
|
||||
$this->main->info['app'] = 'error';
|
||||
$this->main->info['route'] = 'apps/error';
|
||||
$req = $this->main->info;
|
||||
$_GET['code'] = $code;
|
||||
http_response_code($code);
|
||||
$controller->index();
|
||||
|
||||
$this->handle_req($req, TRUE);
|
||||
}
|
||||
|
||||
public function handle_request() {
|
||||
$request = $this->get_info();
|
||||
/**
|
||||
* @param array $req
|
||||
* @param bool $recursed
|
||||
*/
|
||||
private function handle_req($req, $recursed = FALSE): void {
|
||||
$controller = $this->load->controller($req['route']);
|
||||
|
||||
if ($request === NULL) {
|
||||
$this->handle_error(404);
|
||||
if ($controller === NULL) {
|
||||
$this->handle_error(404, $recursed);
|
||||
return;
|
||||
}
|
||||
|
||||
$slug = $request['slug'];
|
||||
if (!array_key_exists($slug, $this->routes)) {
|
||||
$this->handle_error(404);
|
||||
return;
|
||||
}
|
||||
|
||||
$route = $this->routes[$slug];
|
||||
$this->main->info = array(
|
||||
'lang' => 'en_US',
|
||||
'slug' => $slug,
|
||||
'route' => $route['name'],
|
||||
);
|
||||
|
||||
$controller = $this->load_route($route);
|
||||
|
||||
$path = $request['path'];
|
||||
$ref = NULL;
|
||||
|
||||
try {
|
||||
$ref = new ReflectionMethod($controller, $path);
|
||||
$ref = new ReflectionMethod($controller, $req['slug']);
|
||||
} catch (Exception $_e) {}
|
||||
|
||||
if ($ref === NULL || !$ref->isPublic()) {
|
||||
$this->handle_error(404);
|
||||
$this->handle_error(404, $recursed);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
$ref->invoke($controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handels the incomming reuqest
|
||||
*/
|
||||
public function handle_request(): void {
|
||||
$req = $this->get_req();
|
||||
$this->main->info = $req;
|
||||
$this->handle_req($req);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
9
web/helper/error.php
Normal file
9
web/helper/error.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
|
||||
function error_page($code, $msg) {
|
||||
$root = $GLOBALS['webroot'];
|
||||
error_reporting(E_ERROR | E_PARSE);
|
||||
http_response_code($code);
|
||||
require($root . '/views/template/error.php');
|
||||
die();
|
||||
}
|
77
web/helper/lang.php
Normal file
77
web/helper/lang.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?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 {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
function ilang($key,
|
||||
$class = NULL,
|
||||
$id = NULL,
|
||||
$href = NULL,
|
||||
$click = NULL,
|
||||
$attrs = array(),
|
||||
$sub = NULL,
|
||||
$button = FALSE,
|
||||
) {
|
||||
$text = lang($key . "_text", FALSE, sub: $sub);
|
||||
$tip = lang($key . "_tip", FALSE);
|
||||
$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 '<span';
|
||||
if ($icon) {
|
||||
echo ' class="ml-sm"';
|
||||
}
|
||||
echo '>' . $text . '</span>';
|
||||
}
|
||||
if ($click) {
|
||||
echo '</button>';
|
||||
} else {
|
||||
echo '</a>';
|
||||
}
|
||||
}
|
116
web/index.php
116
web/index.php
|
@ -2,114 +2,26 @@
|
|||
|
||||
session_start();
|
||||
|
||||
$lang = array();
|
||||
$__vars = array();
|
||||
$webroot = dirname(__FILE__);
|
||||
|
||||
function error_page($code, $msg) {
|
||||
$root = $GLOBALS['webroot'];
|
||||
error_reporting(E_ERROR | E_PARSE);
|
||||
http_response_code($code);
|
||||
require($root . '/core/error.php');
|
||||
die();
|
||||
}
|
||||
// load all the helper files
|
||||
require($webroot . '/helper/error.php');
|
||||
require($webroot . '/helper/lang.php');
|
||||
|
||||
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 {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
// load all the config files
|
||||
require($webroot . '/config/aesthetic.php');
|
||||
require($webroot . '/config/routes.php');
|
||||
|
||||
function ilang($key,
|
||||
$class = NULL,
|
||||
$id = NULL,
|
||||
$href = NULL,
|
||||
$click = NULL,
|
||||
$attrs = array(),
|
||||
$sub = NULL,
|
||||
$button = FALSE,
|
||||
) {
|
||||
$text = lang($key . "_text", FALSE, sub: $sub);
|
||||
$tip = lang($key . "_tip", FALSE);
|
||||
$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 '<span';
|
||||
if ($icon) {
|
||||
echo ' class="ml-sm"';
|
||||
}
|
||||
echo '>' . $text . '</span>';
|
||||
}
|
||||
if ($click) {
|
||||
echo '</button>';
|
||||
} else {
|
||||
echo '</a>';
|
||||
}
|
||||
}
|
||||
// load all core files
|
||||
require($webroot . '/core/_controller.php');
|
||||
require($webroot . '/core/_model.php');
|
||||
require($webroot . '/core/database.php');
|
||||
require($webroot . '/core/loader.php');
|
||||
require($webroot . '/core/router.php');
|
||||
|
||||
function __init() {
|
||||
|
||||
$root = $GLOBALS['webroot'];
|
||||
|
||||
// load all core files
|
||||
require($root . '/core/database.php');
|
||||
require($root . '/core/aesthetic.php');
|
||||
require($root . '/core/controller.php');
|
||||
require($root . '/core/model.php');
|
||||
require($root . '/core/loader.php');
|
||||
require($root . '/core/main.php');
|
||||
require($root . '/core/router.php');
|
||||
|
||||
$main = new MainModel();
|
||||
$load = new Loader();
|
||||
$router = new Router($main, $load);
|
||||
|
||||
$GLOBALS['__vars']['main'] = $main;
|
||||
$GLOBALS['__vars']['load'] = $load;
|
||||
$GLOBALS['__vars']['router'] = $router;
|
||||
|
||||
$router = new Router($load);
|
||||
$router->handle_request();
|
||||
};
|
||||
|
||||
|
@ -118,5 +30,3 @@ if (!file_exists('/status/ready')) {
|
|||
}
|
||||
|
||||
__init();
|
||||
|
||||
?>
|
||||
|
|
26
web/lang/en_US/api_lang.php
Normal file
26
web/lang/en_US/api_lang.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
|
||||
// user column
|
||||
$lang['api_column_username'] = 'username';
|
||||
$lang['api_column_first_name'] = 'first name';
|
||||
$lang['api_column_last_name'] = 'last name';
|
||||
$lang['api_column_middle_name'] = 'middle name';
|
||||
$lang['api_column_email'] = 'email';
|
||||
$lang['api_column_gender'] = 'gender';
|
||||
$lang['api_column_join_date'] = 'join date';
|
||||
$lang['api_column_birth_date'] = 'birth date';
|
||||
$lang['api_column_profile_avatar'] = 'avatar image';
|
||||
$lang['api_column_profile_banner'] = 'banner image';
|
||||
$lang['api_column_profile_bio'] = 'profile bio';
|
||||
|
||||
// post column
|
||||
$lang['api_column_content'] = 'post content';
|
||||
|
||||
// error messages
|
||||
$lang['api_denied'] = 'Action was denied';
|
||||
$lang['api_null_value'] = '%s cannot be empty';
|
||||
$lang['api_unique_value'] = '%s is not available (not unique)';
|
||||
$lang['api_min_value'] = '%s length cannot be less than %s';
|
||||
$lang['api_max_value'] = '%s length cannot exceed %s';
|
||||
|
||||
?>
|
9
web/lang/en_US/apps/home.php
Normal file
9
web/lang/en_US/apps/home.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
$lang['title'] = 'Home';
|
||||
|
||||
// actions
|
||||
$lang['action_load_posts_text'] = 'Load more posts';
|
||||
$lang['action_load_posts_tip'] = 'Load more posts';
|
||||
|
||||
?>
|
|
@ -1,4 +1,4 @@
|
|||
<?php
|
||||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
|
||||
// Navigation Bar Lang
|
||||
$lang['action_home_text'] = 'Home';
|
||||
|
@ -29,6 +29,10 @@ $lang['action_load_comments_tip'] = 'Load more comments';
|
|||
// General
|
||||
$lang['action_submit_text'] = 'Submit';
|
||||
$lang['action_submit_tip'] = 'Submit';
|
||||
$lang['action_close_text'] = '';
|
||||
$lang['action_close_tip'] = 'Close';
|
||||
$lang['action_close_icon'] = 'mi mi-sm';
|
||||
$lang['action_close_content'] = 'close';
|
||||
|
||||
// Modals
|
||||
$lang['action_modal_close_text'] = '';
|
||||
|
@ -36,6 +40,10 @@ $lang['action_modal_close_tip'] = 'Close modal.';
|
|||
$lang['action_modal_close_icon'] = 'mi mi-sm';
|
||||
$lang['action_modal_close_content'] = 'close';
|
||||
|
||||
$lang['new_post_modal_title'] = 'Author New Post';
|
||||
$lang['action_new_post_text'] = 'What\'s on your mind, %s';
|
||||
$lang['action_new_post_tip'] = 'Author a new post.';
|
||||
|
||||
// Words
|
||||
$lang['now'] = 'Now';
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?php
|
||||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
|
||||
$lang['error_400'] = 'Bad request';
|
||||
$lang['error_404'] = 'Resource not found';
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
<?php
|
||||
|
||||
$lang['title'] = 'Home';
|
||||
|
||||
// actions
|
||||
$lang['action_new_post_text'] = 'What\'s on your mind, %s';
|
||||
$lang['action_new_post_tip'] = 'Author a new post.';
|
||||
$lang['action_load_posts_text'] = 'Load more posts';
|
||||
$lang['action_load_posts_tip'] = 'Load more posts';
|
||||
|
||||
// modals
|
||||
$lang['new_post_modal_title'] = 'Author New Post';
|
||||
|
||||
?>
|
|
@ -52,6 +52,8 @@ body {
|
|||
}
|
||||
|
||||
header {
|
||||
top: 0;
|
||||
position: sticky;
|
||||
height: 3.5rem;
|
||||
background-color: var(--primary);
|
||||
display: flex;
|
||||
|
@ -145,6 +147,10 @@ input:focus {
|
|||
align-items: center;
|
||||
}
|
||||
|
||||
.nav {
|
||||
position: sticky;
|
||||
}
|
||||
|
||||
.nav-right {
|
||||
flex: 1;
|
||||
justify-content: flex-end;
|
||||
|
@ -333,6 +339,30 @@ input:focus {
|
|||
border-radius: .5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
animation: fadeIn .1s, slideInModal .1s linear;
|
||||
}
|
||||
|
||||
@keyframes slideInModal {
|
||||
0% {
|
||||
animation-timing-function: ease-in;
|
||||
transform: translate(-50%, -60%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
0% {
|
||||
animation-timing-function: ease-out;
|
||||
transform: translate(0, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal>form {
|
||||
|
@ -402,3 +432,30 @@ button[type="submit"]:hover {
|
|||
background-color: var(--logo);
|
||||
}
|
||||
|
||||
#toast-container {
|
||||
position: fixed;
|
||||
top: 4rem;
|
||||
left: 100%;
|
||||
transform: translateX(-110%);
|
||||
margin-top: 1rem;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.toast {
|
||||
padding: .75rem;
|
||||
margin: .5rem;
|
||||
border-radius: .5rem;
|
||||
min-width: 15rem;
|
||||
font-family: sfpro;
|
||||
animation: fadeIn .1s, slideIn .25s linear;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.toast.error {
|
||||
background-color: var(--error);
|
||||
}
|
||||
|
||||
.toast.success {
|
||||
background-color: var(--success);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
|
||||
///
|
||||
/// document ready functions
|
||||
///
|
||||
|
||||
let ready = false;
|
||||
|
||||
$(function() {
|
||||
|
@ -15,9 +19,14 @@ var r$ = function(callback) {
|
|||
}
|
||||
}
|
||||
|
||||
function observe(containerSelector, elementSelector, callback) {
|
||||
r$(() => {
|
||||
///
|
||||
/// dom observer
|
||||
/// checks for elements on the DOM now and added later
|
||||
///
|
||||
|
||||
function observe(containerSelector, elementSelector, callback) {
|
||||
|
||||
r$(() => {
|
||||
$(containerSelector + ' ' + elementSelector).each(function (_, e) {
|
||||
let me = $(e);
|
||||
callback(me);
|
||||
|
@ -37,9 +46,64 @@ function observe(containerSelector, elementSelector, callback) {
|
|||
};
|
||||
|
||||
var target = $(containerSelector)[0];
|
||||
|
||||
if (!target) {
|
||||
console.warn('[observe] didnt find container: ', containerSelector);
|
||||
return;
|
||||
}
|
||||
|
||||
var config = { childList: true, subtree: true };
|
||||
var MutationObserver = window.MutationObserver;
|
||||
var observer = new MutationObserver(onMutationsObserved);
|
||||
observer.observe(target, config);
|
||||
});
|
||||
}
|
||||
|
||||
///
|
||||
/// ajax setup
|
||||
///
|
||||
|
||||
let ajaxHeaders = {};
|
||||
ajaxHeaders['Content-Type'] = 'application/json';
|
||||
if (jwtStr) {
|
||||
ajaxHeaders['Authorization'] = 'Bearer ' + jwtStr
|
||||
}
|
||||
|
||||
$.ajaxSetup({
|
||||
headers: ajaxHeaders
|
||||
})
|
||||
|
||||
///
|
||||
/// ajax error handle
|
||||
///
|
||||
|
||||
var errorToast = (xhr) => {
|
||||
let data = xhr.responseJSON;
|
||||
let msg = data.message;
|
||||
let detail = data.details;
|
||||
let hint = data.hint;
|
||||
|
||||
let query = '?msg=' + msg;
|
||||
if (detail) {
|
||||
query += '&detail=' + detail;
|
||||
}
|
||||
if (hint) {
|
||||
query += '&hint=' + hint;
|
||||
}
|
||||
let url = '/template/toast' + query;
|
||||
$.get(url, function (data) {
|
||||
$('#toast-container').prepend(data);
|
||||
})
|
||||
}
|
||||
|
||||
observe('#toast-container', '.action-close-toast', function(el) {
|
||||
el.on('click', function() {
|
||||
el.parent().remove();
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
el.parent().remove();
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
observe('.post', '.action-load-comments', function(me) {
|
||||
observe('#main-content', '.action-load-comments', function(me) {
|
||||
me.on('click', function() {
|
||||
let page = me.attr('page');
|
||||
if (!page) {
|
|
@ -1,20 +0,0 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */
|
||||
class ErrorController extends Controller {
|
||||
|
||||
private $model;
|
||||
|
||||
function __construct($model) {
|
||||
parent::__construct();
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
public function index() {
|
||||
parent::index();
|
||||
$data = $this->model->get_data();
|
||||
$this->view('header', $data);
|
||||
$this->app_view('error', $data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,4 +0,0 @@
|
|||
<div id="error">
|
||||
<h1><?=$title?></h1>
|
||||
<span><?=$msg?></span>
|
||||
</div>
|
6
web/views/apps/error/main.php
Normal file
6
web/views/apps/error/main.php
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */ ?>
|
||||
<?php /* vi: syntax=php */ ?>
|
||||
<div id="error">
|
||||
<h1><?=$title?></h1>
|
||||
<span><?=$msg?></span>
|
||||
</div>
|
|
@ -1,4 +1,5 @@
|
|||
<?php // vi: syntax=php ?>
|
||||
<?php /* Copyright (c) 2024 Freya Murphy */ ?>
|
||||
<?php /* vi: syntax=php */ ?>
|
||||
<div id="main-content">
|
||||
<?php if ($self): ?>
|
||||
<div id="new-post" class="card">
|
||||
|
@ -15,7 +16,7 @@
|
|||
</div>
|
||||
<script>
|
||||
$('#action-new-post').on('click', function() {
|
||||
$.get( "/home/new_post_modal", function (data) {
|
||||
$.get( "/modal/new_post", function (data) {
|
||||
$(document.body).append(data);
|
||||
});
|
||||
})
|
|
@ -1,2 +1,4 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */ ?>
|
||||
<?php /* vi: syntax=php */ ?>
|
||||
<body>
|
||||
</html>
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
<?php // vi: syntax=php ?>
|
||||
<?php /* Copyright (c) 2024 Freya Murphy */ ?>
|
||||
<?php /* vi: syntax=php */ ?>
|
||||
<?php
|
||||
$self = $this->main->user();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
<?php if ($this->main->session): ?>
|
||||
var jwtStr = <?=json_encode($this->main->session['jwt'])?>;
|
||||
<?php else: ?>
|
||||
var jwtStr = null;
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
<?php
|
||||
foreach ($js_files as $js) {
|
||||
echo $this->main->link_js($js);
|
||||
|
@ -71,4 +79,6 @@
|
|||
menu.toggleClass('visible');
|
||||
});
|
||||
</script>
|
||||
</header>
|
||||
</header>
|
||||
<div id="toast-container">
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */ ?>
|
||||
<?php /* vi: syntax=php */ ?>
|
||||
<?php
|
||||
$user = $this->main->user();
|
||||
?>
|
||||
<form>
|
||||
<form id="new-post-form">
|
||||
<div class="modal-content new-post-modal">
|
||||
<div class="row">
|
||||
<?php $this->view('template/pfp', array('user' => $user))?>
|
||||
|
@ -12,8 +14,8 @@
|
|||
</div>
|
||||
<textarea
|
||||
type="text"
|
||||
name="text"
|
||||
id="text"
|
||||
name="content"
|
||||
id="new-post-content"
|
||||
placeholder="<?=lang('action_new_post_text', sub: [$user['first_name']])?>"
|
||||
></textarea>
|
||||
</div>
|
||||
|
@ -26,3 +28,19 @@
|
|||
)?>
|
||||
</div>
|
||||
</form>
|
||||
<script>
|
||||
$('#new-post-form').submit(function(e) {
|
||||
e.preventDefault();
|
||||
let content = $('#new-post-content').val();
|
||||
|
||||
$.ajax({
|
||||
url: '/api/post',
|
||||
method: 'POST',
|
||||
data: JSON.stringify({ content }),
|
||||
success: function(data) {
|
||||
window.location.reload();
|
||||
},
|
||||
error: errorToast
|
||||
});
|
||||
});
|
||||
</script>
|
|
@ -1,3 +1,5 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */ ?>
|
||||
<?php /* vi: syntax=php */ ?>
|
||||
<div class="comment row mt">
|
||||
<?php $this->view('template/pfp', array('user' => $user))?>
|
||||
<div class="ml col sub-card">
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */ ?>
|
||||
<?php /* vi: syntax=php */ ?>
|
||||
<div class="modal-container">
|
||||
<div class="modal">
|
||||
<div class="modal-header row">
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */ ?>
|
||||
<?php /* vi: syntax=php */ ?>
|
||||
<?php
|
||||
$class = isset($class) ? $class : '';
|
||||
?>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */ ?>
|
||||
<?php /* vi: syntax=php */ ?>
|
||||
<div class="post card">
|
||||
<div class="row">
|
||||
<?php $this->view('template/pfp', array('user' => $user))?>
|
||||
|
|
19
web/views/template/toast.php
Normal file
19
web/views/template/toast.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?php /* Copyright (c) 2024 Freya Murphy */ ?>
|
||||
<?php /* vi: syntax=php */ ?>
|
||||
<?php
|
||||
$params = array();
|
||||
|
||||
if ($detail) {
|
||||
array_push($params, lang('api_column_' . $detail));
|
||||
}
|
||||
|
||||
if ($hint) {
|
||||
array_push($params, $hint);
|
||||
}
|
||||
|
||||
$msg = lang($msg, sub: $params);
|
||||
?>
|
||||
<div class="toast error">
|
||||
<?=ucfirst($msg)?>
|
||||
<?=ilang('action_close', class: 'action-close-toast')?>
|
||||
</div>
|
Loading…
Reference in a new issue