mirror of
https://github.com/chylex/Lightning-Tracker.git
synced 2025-05-24 23:34:08 +02:00
Minor fixes (code formatting, unused elements, future TODOs)
This commit is contained in:
parent
ab75ece64c
commit
ae25051aa8
db
src
Database
Pages
index.php@ -1,11 +1,11 @@
|
||||
CREATE TABLE `system_role_perms` (
|
||||
`role_id` SMALLINT NOT NULL,
|
||||
`permission` ENUM (
|
||||
'settings',
|
||||
'trackers.list',
|
||||
'trackers.list.hidden',
|
||||
'trackers.add',
|
||||
'trackers.edit',
|
||||
'settings',
|
||||
'trackers.list',
|
||||
'trackers.list.hidden',
|
||||
'trackers.add',
|
||||
'trackers.edit',
|
||||
'users.list',
|
||||
'users.list.email',
|
||||
'users.add',
|
||||
|
@ -1,9 +1,9 @@
|
||||
CREATE TABLE `trackers` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(32) NOT NULL,
|
||||
`url` VARCHAR(32) NOT NULL,
|
||||
`owner_id` INT NOT NULL,
|
||||
`hidden` BOOL NOT NULL,
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(32) NOT NULL,
|
||||
`url` VARCHAR(32) NOT NULL,
|
||||
`owner_id` INT NOT NULL,
|
||||
`hidden` BOOL NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`url`),
|
||||
FOREIGN KEY (`owner_id`)
|
||||
|
@ -6,8 +6,8 @@ CREATE TABLE `user_logins` (
|
||||
UNIQUE KEY (`token`),
|
||||
FOREIGN KEY (`id`)
|
||||
REFERENCES `users` (`id`)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE
|
||||
) ENGINE = InnoDB
|
||||
DEFAULT CHARSET = utf8mb4
|
||||
COLLATE utf8mb4_general_ci
|
||||
|
@ -1,4 +1,4 @@
|
||||
CREATE TABLE IF NOT EXISTS `users` (
|
||||
CREATE TABLE `users` (
|
||||
`id` INT NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(32) NOT NULL,
|
||||
`email` VARCHAR(255) NOT NULL,
|
||||
|
@ -15,6 +15,7 @@ abstract class AbstractTable{
|
||||
|
||||
/**
|
||||
* Fetches the next result.
|
||||
*
|
||||
* @param PDOStatement $stmt
|
||||
* @return mixed
|
||||
*/
|
||||
@ -24,6 +25,7 @@ abstract class AbstractTable{
|
||||
|
||||
/**
|
||||
* Fetches the next result.
|
||||
*
|
||||
* @param PDOStatement $stmt
|
||||
* @return mixed
|
||||
*/
|
||||
@ -33,6 +35,7 @@ abstract class AbstractTable{
|
||||
|
||||
/**
|
||||
* Fetches one result and closes the cursor.
|
||||
*
|
||||
* @param PDOStatement $stmt
|
||||
* @return mixed
|
||||
*/
|
||||
@ -44,6 +47,7 @@ abstract class AbstractTable{
|
||||
|
||||
/**
|
||||
* Fetches one result and closes the cursor.
|
||||
*
|
||||
* @param PDOStatement $stmt
|
||||
* @return mixed
|
||||
*/
|
||||
|
@ -11,7 +11,7 @@ final class DB{
|
||||
SET time_zone = "+00:00",
|
||||
sql_mode = "STRICT_ALL_TABLES,NO_ENGINE_SUBSTITUTION"
|
||||
SQL;
|
||||
|
||||
|
||||
/**
|
||||
* @return PDO
|
||||
* @throws PDOException
|
||||
|
@ -18,10 +18,6 @@ final class RoleInfo{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getTitle(): string{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getTitleSafe(): string{
|
||||
return protect($this->title);
|
||||
}
|
||||
|
@ -10,14 +10,14 @@ final class UserInfo{
|
||||
private string $name;
|
||||
private string $email;
|
||||
private ?string $role_title;
|
||||
private string $registration_date;
|
||||
private string $date_registered;
|
||||
|
||||
public function __construct(int $id, string $name, string $email, ?string $role_title, string $registration_date){
|
||||
public function __construct(int $id, string $name, string $email, ?string $role_title, string $date_registered){
|
||||
$this->id = $id;
|
||||
$this->name = $name;
|
||||
$this->email = $email;
|
||||
$this->role_title = $role_title;
|
||||
$this->registration_date = $registration_date;
|
||||
$this->date_registered = $date_registered;
|
||||
}
|
||||
|
||||
public function getId(): int{
|
||||
@ -37,7 +37,7 @@ final class UserInfo{
|
||||
}
|
||||
|
||||
public function getRegistrationDate(): string{
|
||||
return $this->registration_date;
|
||||
return $this->date_registered;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ final class UserLoginInfo{
|
||||
*/
|
||||
public static function hashPassword(string $password): string{
|
||||
$hash = password_hash($password, PASSWORD_BCRYPT);
|
||||
|
||||
|
||||
if (!$hash){
|
||||
throw new Exception('Fatal error, hashing function failed.');
|
||||
}
|
||||
|
@ -3,11 +3,10 @@ declare(strict_types = 1);
|
||||
|
||||
namespace Database\Tables;
|
||||
|
||||
use Database\Tables\Traits\PermTable;
|
||||
use Database\AbstractTable;
|
||||
use Database\DB;
|
||||
use Database\Objects\RoleInfo;
|
||||
use Database\Objects\UserProfile;
|
||||
use Database\Tables\Traits\PermTable;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
||||
|
@ -87,9 +87,9 @@ SQL;
|
||||
}
|
||||
|
||||
public function removeUserId(int $user_id){
|
||||
$stmt = $this->db->prepare('DELETE FROM tracker_members WHERE tracker_id = ? AND user_id = ?');
|
||||
$stmt->bindValue(1, $this->getTrackerId(), PDO::PARAM_INT);
|
||||
$stmt->bindValue(2, $user_id, PDO::PARAM_INT);
|
||||
$stmt = $this->db->prepare('DELETE FROM tracker_members WHERE user_id = ? AND tracker_id = ?');
|
||||
$stmt->bindValue(1, $user_id, PDO::PARAM_INT);
|
||||
$stmt->bindValue(2, $this->getTrackerId(), PDO::PARAM_INT);
|
||||
$stmt->execute();
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,11 @@ declare(strict_types = 1);
|
||||
|
||||
namespace Database\Tables;
|
||||
|
||||
use Database\Tables\Traits\PermTable;
|
||||
use Database\AbstractTrackerTable;
|
||||
use Database\Objects\RoleInfo;
|
||||
use Database\Objects\TrackerInfo;
|
||||
use Database\Objects\UserProfile;
|
||||
use Database\Tables\Traits\PermTable;
|
||||
use PDO;
|
||||
use PDOException;
|
||||
|
||||
|
@ -69,7 +69,7 @@ final class TrackerTable extends AbstractTable{
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
public function countTrackers(TrackerFilter $filter = null): ?int{
|
||||
public function countTrackers(?TrackerFilter $filter = null): ?int{
|
||||
$filter ??= TrackerFilter::empty();
|
||||
|
||||
$stmt = $this->db->prepare('SELECT COUNT(*) FROM trackers '.$filter->generateClauses(true));
|
||||
@ -84,7 +84,7 @@ final class TrackerTable extends AbstractTable{
|
||||
* @param TrackerFilter|null $filter
|
||||
* @return TrackerInfo[]
|
||||
*/
|
||||
public function listTrackers(TrackerFilter $filter = null): array{
|
||||
public function listTrackers(?TrackerFilter $filter = null): array{
|
||||
$filter ??= TrackerFilter::empty();
|
||||
|
||||
$stmt = $this->db->prepare('SELECT id, name, url, owner_id FROM trackers '.$filter->generateClauses());
|
||||
|
@ -19,11 +19,11 @@ trait PermTable{
|
||||
|
||||
$values = implode(',', array_map(fn($ignore): string => '(LAST_INSERT_ID(), ?)', $perms));
|
||||
$stmt = $this->db->prepare(str_replace('()', $values, $sql_base));
|
||||
|
||||
|
||||
for($i = 0, $count = count($perms); $i < $count; $i++){
|
||||
$stmt->bindValue($i + 1, $perms[$i]);
|
||||
}
|
||||
|
||||
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
@ -33,11 +33,11 @@ trait PermTable{
|
||||
*/
|
||||
protected final function fetchRoles(PDOStatement $stmt): array{
|
||||
$results = [];
|
||||
|
||||
|
||||
while(($res = $this->fetchNext($stmt)) !== false){
|
||||
$results[] = new RoleInfo($res['id'], $res['title']);
|
||||
}
|
||||
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
@ -47,11 +47,11 @@ trait PermTable{
|
||||
*/
|
||||
protected final function fetchPerms(PDOStatement $stmt): array{
|
||||
$results = [];
|
||||
|
||||
|
||||
while(($res = $this->fetchNextColumn($stmt)) !== false){
|
||||
$results[] = $res;
|
||||
}
|
||||
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ final class UserTable extends AbstractTable{
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
public function countUsers(UserFilter $filter = null): ?int{
|
||||
public function countUsers(?UserFilter $filter = null): ?int{
|
||||
$filter ??= UserFilter::empty();
|
||||
|
||||
$stmt = $this->db->prepare('SELECT COUNT(*) FROM users '.$filter->generateClauses(true));
|
||||
@ -56,7 +56,7 @@ final class UserTable extends AbstractTable{
|
||||
* @param UserFilter|null $filter
|
||||
* @return UserInfo[]
|
||||
*/
|
||||
public function listUsers(UserFilter $filter = null): array{
|
||||
public function listUsers(?UserFilter $filter = null): array{
|
||||
$filter ??= UserFilter::empty();
|
||||
|
||||
$sql = <<<SQL
|
||||
|
@ -75,7 +75,7 @@ HTML;
|
||||
echo '<option value="'.$option[0].'"'.$class.$selected.'>'.$option[1].'</option>';
|
||||
}
|
||||
|
||||
echo <<<HTML
|
||||
echo <<<HTML
|
||||
</select>
|
||||
HTML;
|
||||
|
||||
|
@ -136,6 +136,7 @@ HTML;
|
||||
|
||||
/**
|
||||
* Fills form fields using the provided data.
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
public function fill(array $data){
|
||||
@ -154,6 +155,7 @@ HTML;
|
||||
|
||||
/**
|
||||
* Refills form fields using the provided data, given that the form ID matches.
|
||||
*
|
||||
* @param array $data
|
||||
* @return string|bool Truthy if all fields were present, indicating that the form is ready for validation. The truthy value is the submit button value if present, or true if no button had a set value.
|
||||
*/
|
||||
@ -161,7 +163,7 @@ HTML;
|
||||
if (!isset($data[self::ACTION_KEY]) || $data[self::ACTION_KEY] !== $this->id){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$this->is_filled = true;
|
||||
$filled_fields = 0;
|
||||
|
||||
@ -180,7 +182,7 @@ HTML;
|
||||
if ($filled_fields !== count($this->fields)){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (isset($data[self::RELOADED_KEY])){
|
||||
if (isset($data[self::MESSAGES_KEY])){
|
||||
array_push($this->messages, ...$data[self::MESSAGES_KEY]);
|
||||
@ -194,6 +196,7 @@ HTML;
|
||||
|
||||
/**
|
||||
* Reloads the form, saving data and form messages in a session.
|
||||
*
|
||||
* @param array $data
|
||||
* @return ReloadFormAction
|
||||
*/
|
||||
@ -248,7 +251,7 @@ HTML;
|
||||
}
|
||||
|
||||
$element->echoBody();
|
||||
|
||||
|
||||
/** @noinspection PhpUnusedLocalVariableInspection */
|
||||
foreach($groups as $group){
|
||||
echo '</div>';
|
||||
|
@ -28,7 +28,7 @@ class RequireTracker implements IControlHandler{
|
||||
if ($url === null){
|
||||
$page_model = new BasicRootPageModel($req);
|
||||
$error_model = new ErrorModel($page_model, 'Tracker Error', 'Tracker is missing in the URL.');
|
||||
|
||||
|
||||
return view(new ErrorPage($error_model->load()));
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ class RegisterController extends AbstractHandlerController{
|
||||
if ($sess->isLoggedOn()){
|
||||
return redirect([BASE_URL_ENC, $req->getBasePath()->encoded()]);
|
||||
}
|
||||
|
||||
|
||||
$model = new RegisterModel($req, $this->tracker);
|
||||
$data = $req->getData();
|
||||
|
||||
|
@ -23,18 +23,18 @@ class SettingsController extends AbstractHandlerController{
|
||||
protected function finally(Request $req, Session $sess): IAction{
|
||||
$model = new SettingsModel($req);
|
||||
$data = $req->getData();
|
||||
|
||||
|
||||
if (!empty($data)){
|
||||
$form = $model->getForm();
|
||||
$action = $form->accept($data);
|
||||
|
||||
|
||||
if (($action === $model::ACTION_REMOVE_BACKUP && $model->removeBackupFile()) ||
|
||||
($action === $model::ACTION_UPDATE_SETTINGS && $model->updateConfig($data))
|
||||
){
|
||||
return $form->reload($data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return view(new SettingsPage($model->load()));
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use Pages\Components\Navigation\NavigationComponent;
|
||||
interface IModel{
|
||||
/**
|
||||
* Loads data into the model.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function load(): IModel;
|
||||
|
@ -30,7 +30,7 @@ class AccountModel extends BasicMixedPageModel{
|
||||
|
||||
$this->menu_links->addLink(Text::withIcon('Profile', 'user'), '/account');
|
||||
$this->menu_links->addLink(Text::withIcon('Security', 'key'), '/account/security');
|
||||
|
||||
|
||||
$this->menu_actions->addActionButton(Text::withIcon('Logout', 'switch'), self::ACTION_LOGOUT);
|
||||
|
||||
return $this;
|
||||
|
@ -43,7 +43,7 @@ class AccountSecurityModel extends AccountModel{
|
||||
|
||||
$form->addButton('submit', 'Change Password')
|
||||
->icon('pencil');
|
||||
|
||||
|
||||
$this->change_password_form = $form;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ use Validation\Validator;
|
||||
class TrackersModel extends BasicRootPageModel{
|
||||
public const ACTION_CREATE = 'Create';
|
||||
public const ACTION_DELETE = 'Delete';
|
||||
|
||||
|
||||
public const PERM_LIST = 'trackers.list';
|
||||
public const PERM_LIST_HIDDEN = 'trackers.list.hidden';
|
||||
public const PERM_ADD = 'trackers.add';
|
||||
@ -39,7 +39,7 @@ class TrackersModel extends BasicRootPageModel{
|
||||
|
||||
public function __construct(Request $req, Permissions $perms){
|
||||
parent::__construct($req);
|
||||
|
||||
|
||||
$this->perms = $perms;
|
||||
|
||||
$this->table = new TableComponent();
|
||||
@ -130,11 +130,11 @@ class TrackersModel extends BasicRootPageModel{
|
||||
$name = $data['Name'];
|
||||
$url = $data['Url'];
|
||||
$hidden = (bool)($data['Hidden'] ?? false);
|
||||
|
||||
|
||||
$validator = new Validator();
|
||||
$validator->str('Name', $name)->notEmpty();
|
||||
$validator->str('Url', $url)->notEmpty()->notContains('/')->notContains('\\');
|
||||
|
||||
|
||||
try{
|
||||
$validator->validate();
|
||||
$trackers = new TrackerTable(DB::get());
|
||||
@ -156,12 +156,12 @@ class TrackersModel extends BasicRootPageModel{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->form->onGeneralError($e);
|
||||
}catch(Exception $e){
|
||||
$this->form->onGeneralError($e);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -179,9 +179,17 @@ class UsersModel extends BasicRootPageModel{
|
||||
return false;
|
||||
}
|
||||
|
||||
$users = new UserTable(DB::get());
|
||||
$users->deleteById((int)$data['User']);
|
||||
return true;
|
||||
try{
|
||||
$users = new UserTable(DB::get());
|
||||
$users->deleteById((int)$data['User']);
|
||||
return true;
|
||||
}catch(PDOException $e){
|
||||
if ($e->getCode() === SQL::CONSTRAINT_VIOLATION){
|
||||
// TODO show message with reason which foreign key checks failed, i.e. cannot delete tracker owner
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,10 +45,10 @@ class MembersModel extends BasicTrackerPageModel{
|
||||
$this->table = new TableComponent();
|
||||
$this->table->ifEmpty('No members found.');
|
||||
|
||||
$this->table->addColumn('Username');
|
||||
$this->table->addColumn('Username')->bold();
|
||||
$this->table->addColumn('Role');
|
||||
|
||||
if ($this->perms->checkTracker($tracker, self::PERM_MANAGE)){
|
||||
if ($perms->checkTracker($tracker, self::PERM_MANAGE)){
|
||||
$this->table->addColumn('Actions')->right()->tight();
|
||||
|
||||
$roles = (new TrackerPermTable(DB::get(), $tracker))->listRoles();
|
||||
|
@ -22,7 +22,7 @@ class AccountSecurityPage extends AccountPage{
|
||||
<h3>Change Password</h3>
|
||||
<article>
|
||||
HTML;
|
||||
|
||||
|
||||
$this->model->getChangePasswordForm()->echoBody();
|
||||
|
||||
echo <<<HTML
|
||||
|
@ -67,6 +67,8 @@ foreach(['&/', 'tracker/:tracker/&/'] as $base){
|
||||
$router->add($base.'account/security', 'Mixed/AccountSecurityController');
|
||||
}
|
||||
|
||||
// TODO CSRF
|
||||
|
||||
function handle_error(int $code, string $title, string $message, ?Request $req = null): void{
|
||||
http_response_code($code);
|
||||
$page_model = new BasicRootPageModel($req ?? new Request('', '', []));
|
||||
|
Loading…
Reference in New Issue
Block a user