Rewrote backend for emoticons.
Manage actually works this time!!!
This commit is contained in:
parent
9b65ce005a
commit
3909cdf762
10 changed files with 499 additions and 235 deletions
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
|
|
||||||
require_once '../../../misuzu.php';
|
require_once '../../../misuzu.php';
|
||||||
|
@ -10,43 +11,106 @@ if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$emoteId = !empty($_GET['e']) && is_string($_GET['e']) ? (int)$_GET['e'] : 0;
|
$emotes = $msz->getEmotes();
|
||||||
$isNew = $emoteId <= 0;
|
$emoteId = (string)filter_input(INPUT_GET, 'e', FILTER_SANITIZE_NUMBER_INT);
|
||||||
$emoteInfo = !$isNew ? Emoticon::byId($emoteId) : new Emoticon;
|
$loadEmoteInfo = fn() => $emotes->getEmoteById($emoteId, true);
|
||||||
|
|
||||||
if(CSRF::validateRequest() && isset($_POST['emote_order']) && isset($_POST['emote_hierarchy']) && !empty($_POST['emote_url']) && !empty($_POST['emote_strings'])) {
|
if(empty($emoteId))
|
||||||
$emoteInfo->setUrl($_POST['emote_url'])
|
$isNew = true;
|
||||||
->setRank($_POST['emote_hierarchy'])
|
else
|
||||||
->setOrder($_POST['emote_order'])
|
try {
|
||||||
->save();
|
$isNew = false;
|
||||||
|
$emoteInfo = $loadEmoteInfo();
|
||||||
|
} catch(RuntimeException $ex) {
|
||||||
|
echo render_error(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if($isNew && !$emoteInfo->hasId())
|
// make errors not echos lol
|
||||||
throw new \Exception("SOMETHING HAPPENED");
|
while($_SERVER['REQUEST_METHOD'] === 'POST' && CSRF::validateRequest()) {
|
||||||
|
$order = (int)filter_input(INPUT_POST, 'em_order', FILTER_SANITIZE_NUMBER_INT);
|
||||||
|
$minRank = (int)filter_input(INPUT_POST, 'em_minrank', FILTER_SANITIZE_NUMBER_INT);
|
||||||
|
$url = trim((string)filter_input(INPUT_POST, 'em_url'));
|
||||||
|
$strings = explode(' ', trim((string)filter_input(INPUT_POST, 'em_strings')));
|
||||||
|
|
||||||
$setStrings = array_column($emoteInfo->getStrings(), 'emote_string');
|
if($isNew || $url !== $emoteInfo->getUrl()) {
|
||||||
$applyStrings = explode(' ', mb_strtolower($_POST['emote_strings']));
|
$checkUrl = $emotes->checkEmoteUrl($url);
|
||||||
$removeStrings = [];
|
if($checkUrl !== '') {
|
||||||
|
echo match($checkUrl) {
|
||||||
foreach($setStrings as $string) {
|
'empty' => 'URL may not be empty.',
|
||||||
if(!in_array($string, $applyStrings)) {
|
'spaces' => 'URL may not end or start with spaces.',
|
||||||
$removeStrings[] = $string;
|
'used' => 'This URL already belongs to another emoticon.',
|
||||||
|
default => 'URL cannot be accepted: ' . $checkUrl,
|
||||||
|
};
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$setStrings = array_diff($setStrings, $removeStrings);
|
if($order == 0)
|
||||||
|
$order = null;
|
||||||
|
|
||||||
foreach($applyStrings as $string) {
|
$reload = false;
|
||||||
if(!in_array($string, $setStrings)) {
|
if($isNew) {
|
||||||
$setStrings[] = $string;
|
$emoteInfo = $emotes->createEmote($url, $minRank, $order);
|
||||||
|
} else {
|
||||||
|
if($order === $emoteInfo->getOrder())
|
||||||
|
$order = null;
|
||||||
|
if($minRank === $emoteInfo->getMinRank())
|
||||||
|
$minRank = null;
|
||||||
|
if($url === $emoteInfo->getUrl())
|
||||||
|
$url = null;
|
||||||
|
|
||||||
|
if($order !== null || $minRank !== null || $url !== null) {
|
||||||
|
$reload = true;
|
||||||
|
$emotes->updateEmote($emoteInfo, $order, $minRank, $url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($removeStrings as $string)
|
$sCurrent = $emoteInfo->getStringsRaw();
|
||||||
$emoteInfo->removeString($string);
|
$sApply = $strings;
|
||||||
foreach($setStrings as $string)
|
$sRemove = [];
|
||||||
$emoteInfo->addString($string);
|
|
||||||
|
foreach($sCurrent as $string)
|
||||||
|
if(!in_array($string, $sApply)) {
|
||||||
|
$sRemove[] = $string;
|
||||||
|
$emotes->removeEmoteString($string);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sCurrent = array_diff($sCurrent, $sRemove);
|
||||||
|
|
||||||
|
if(!$reload)
|
||||||
|
$reload = !empty($sRemove) || !empty(array_diff($sApply, $sCurrent));
|
||||||
|
|
||||||
|
foreach($sApply as $string)
|
||||||
|
if(!in_array($string, $sCurrent)) {
|
||||||
|
$checkString = $emotes->checkEmoteString($string);
|
||||||
|
if($checkString === '') {
|
||||||
|
$emotes->addEmoteString($emoteInfo, $string);
|
||||||
|
} else {
|
||||||
|
echo match($checkString) {
|
||||||
|
'empty' => 'String may not be empty.',
|
||||||
|
'spaces' => 'String may not end or start with spaces.',
|
||||||
|
'case' => 'String must be lowercase.',
|
||||||
|
'format' => 'String must follow proper formatting.',
|
||||||
|
'used' => 'This string has already been used for another emoticon.',
|
||||||
|
default => 'String cannot be accepted: ' . $checkString,
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sCurrent[] = $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($reload) {
|
||||||
|
if($isNew)
|
||||||
|
url_redirect('manage-general-emoticon', ['emote' => $emoteInfo->getId()]);
|
||||||
|
else
|
||||||
|
$emoteInfo = $loadEmoteInfo();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Template::render('manage.general.emoticon', [
|
Template::render('manage.general.emoticon', [
|
||||||
'emote_info' => $emoteInfo,
|
'emote_new' => $isNew,
|
||||||
|
'emote_info' => $emoteInfo ?? null,
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
namespace Misuzu;
|
namespace Misuzu;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
|
|
||||||
require_once '../../../misuzu.php';
|
require_once '../../../misuzu.php';
|
||||||
|
@ -10,22 +11,32 @@ if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CSRF::validateRequest() && !empty($_GET['emote']) && is_string($_GET['emote'])) {
|
$emotes = $msz->getEmotes();
|
||||||
$emoteId = (int)$_GET['emote'];
|
|
||||||
$emoteInfo = Emoticon::byId($emoteId);
|
|
||||||
|
|
||||||
if(empty($emoteInfo)) {
|
if(CSRF::validateRequest() && !empty($_GET['emote'])) {
|
||||||
|
$emoteId = (string)filter_input(INPUT_GET, 'emote', FILTER_SANITIZE_NUMBER_INT);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$emoteInfo = $emotes->getEmoteById($emoteId);
|
||||||
|
} catch(RuntimeException $ex) {
|
||||||
echo render_error(404);
|
echo render_error(404);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!empty($_GET['order']) && is_string($_GET['order'])) {
|
if(!empty($_GET['delete'])) {
|
||||||
$emoteInfo->changeOrder($_GET['order'] === 'i' ? 1 : -1);
|
$emotes->deleteEmote($emoteInfo);
|
||||||
} elseif(!empty($_GET['alias']) && is_string($_GET['alias']) && ctype_alnum($_GET['alias'])) {
|
} else {
|
||||||
$emoteInfo->addString(mb_strtolower($_GET['alias']));
|
if(isset($_GET['order'])) {
|
||||||
return;
|
$order = filter_input(INPUT_GET, 'order');
|
||||||
} elseif(!empty($_GET['delete'])) {
|
$offset = $order === 'i' ? 1 : ($order === 'd' ? -1 : 0);
|
||||||
$emoteInfo->delete();
|
$emotes->updateEmoteOrderOffset($emoteInfo, $offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($_GET['alias'])) {
|
||||||
|
$alias = (string)filter_input(INPUT_GET, 'alias');
|
||||||
|
if($emotes->checkEmoteString($alias) === '')
|
||||||
|
$emotes->addEmoteString($emoteInfo, $alias);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
url_redirect('manage-general-emoticons');
|
url_redirect('manage-general-emoticons');
|
||||||
|
@ -33,5 +44,5 @@ if(CSRF::validateRequest() && !empty($_GET['emote']) && is_string($_GET['emote']
|
||||||
}
|
}
|
||||||
|
|
||||||
Template::render('manage.general.emoticons', [
|
Template::render('manage.general.emoticons', [
|
||||||
'emotes' => Emoticon::all(PHP_INT_MAX),
|
'emotes' => $emotes->getAllEmotes(),
|
||||||
]);
|
]);
|
||||||
|
|
179
src/Emoticon.php
179
src/Emoticon.php
|
@ -1,179 +0,0 @@
|
||||||
<?php
|
|
||||||
namespace Misuzu;
|
|
||||||
|
|
||||||
use InvalidArgumentException;
|
|
||||||
|
|
||||||
final class Emoticon {
|
|
||||||
private int $emote_id;
|
|
||||||
private int $emote_order;
|
|
||||||
private int $emote_hierarchy;
|
|
||||||
private string $emote_url;
|
|
||||||
|
|
||||||
public const ALL = PHP_INT_MAX;
|
|
||||||
|
|
||||||
public function __construct() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId(): int {
|
|
||||||
return $this->emote_id ?? 0;
|
|
||||||
}
|
|
||||||
public function hasId(): bool {
|
|
||||||
return isset($this->emote_id) && $this->emote_id > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOrder(): int {
|
|
||||||
return $this->emote_order ?? 0;
|
|
||||||
}
|
|
||||||
public function setOrder(int $order): self {
|
|
||||||
$this->emote_order = $order;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
public function changeOrder(int $difference): self {
|
|
||||||
if(!$this->hasId())
|
|
||||||
return $this;
|
|
||||||
|
|
||||||
DB::prepare('
|
|
||||||
UPDATE `msz_emoticons`
|
|
||||||
SET `emote_order` = `emote_order` + :diff
|
|
||||||
WHERE `emote_id` = :id
|
|
||||||
')->bind('id', $this->getId())
|
|
||||||
->bind('diff', $difference)
|
|
||||||
->execute();
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRank(): int {
|
|
||||||
return $this->emote_hierarchy ?? 0;
|
|
||||||
}
|
|
||||||
public function setRank(int $rank): self {
|
|
||||||
$this->emote_hierarchy = $rank;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUrl(): string {
|
|
||||||
return $this->emote_url ?? '';
|
|
||||||
}
|
|
||||||
public function setUrl(string $url): self {
|
|
||||||
$this->emote_url = $url;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addString(string $string, ?int $order = null): bool {
|
|
||||||
if(!$this->hasId())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if($order === null) {
|
|
||||||
$order = DB::prepare('
|
|
||||||
SELECT MAX(`emote_string_order`) + 1
|
|
||||||
FROM `msz_emoticons_strings`
|
|
||||||
WHERE `emote_id` = :id
|
|
||||||
')->bind('id', $this->getId())->fetchColumn();
|
|
||||||
}
|
|
||||||
|
|
||||||
return DB::prepare('
|
|
||||||
REPLACE INTO `msz_emoticons_strings` (`emote_id`, `emote_string_order`, `emote_string`)
|
|
||||||
VALUES (:id, :order, :string)
|
|
||||||
')->bind('id', $this->getId())
|
|
||||||
->bind('order', $order)
|
|
||||||
->bind('string', $string)
|
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
public function removeString(string $string): bool {
|
|
||||||
if(!$this->hasId())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return DB::prepare('
|
|
||||||
DELETE FROM `msz_emoticons_strings`
|
|
||||||
WHERE `emote_string` = :string
|
|
||||||
')->bind('string', $string)
|
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
public function getStrings(): array {
|
|
||||||
if(!$this->hasId())
|
|
||||||
return [];
|
|
||||||
|
|
||||||
return DB::prepare('
|
|
||||||
SELECT `emote_string_order`, `emote_string`
|
|
||||||
FROM `msz_emoticons_strings`
|
|
||||||
WHERE `emote_id` = :id
|
|
||||||
ORDER BY `emote_string_order`
|
|
||||||
')->bind('id', $this->getId())->fetchObjects();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function save(): bool {
|
|
||||||
if($this->hasId()) {
|
|
||||||
$save = DB::prepare('
|
|
||||||
UPDATE `msz_emoticons`
|
|
||||||
SET `emote_order` = :order,
|
|
||||||
`emote_hierarchy` = :hierarchy,
|
|
||||||
`emote_url` = :url
|
|
||||||
WHERE `emote_id` = :id
|
|
||||||
')->bind('id', $this->getId());
|
|
||||||
} else {
|
|
||||||
$save = DB::prepare('
|
|
||||||
INSERT INTO `msz_emoticons` (`emote_order`, `emote_hierarchy`, `emote_url`)
|
|
||||||
VALUES (:order, :hierarchy, :url)
|
|
||||||
');
|
|
||||||
}
|
|
||||||
|
|
||||||
$saved = $save->bind('order', $this->getOrder())
|
|
||||||
->bind('hierarchy', $this->getRank())
|
|
||||||
->bind('url', $this->getUrl())
|
|
||||||
->execute();
|
|
||||||
|
|
||||||
if(!$this->hasId() && $saved)
|
|
||||||
$this->emote_id = DB::lastId();
|
|
||||||
|
|
||||||
return $saved;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function delete(): void {
|
|
||||||
if(!$this->hasId())
|
|
||||||
return;
|
|
||||||
|
|
||||||
DB::prepare('DELETE FROM `msz_emoticons` WHERE `emote_id` = :id')
|
|
||||||
->bind('id', $this->getId())
|
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function byId(int $emoteId): self {
|
|
||||||
if($emoteId < 1)
|
|
||||||
throw new InvalidArgumentException('$emoteId is not a valid emoticon id.');
|
|
||||||
|
|
||||||
$getEmote = DB::prepare('
|
|
||||||
SELECT `emote_id`, `emote_order`, `emote_hierarchy`, `emote_url`
|
|
||||||
FROM `msz_emoticons`
|
|
||||||
WHERE `emote_id` = :id
|
|
||||||
');
|
|
||||||
$getEmote->bind('id', $emoteId);
|
|
||||||
return $getEmote->fetchObject(self::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function all(int $hierarchy = self::ALL, bool $unique = false, bool $order = true): array {
|
|
||||||
$getEmotes = DB::prepare('
|
|
||||||
SELECT `emote_id`, `emote_order`, `emote_hierarchy`, `emote_url`
|
|
||||||
FROM `msz_emoticons`
|
|
||||||
WHERE `emote_hierarchy` <= :hierarchy
|
|
||||||
ORDER BY IF(:order, `emote_order`, `emote_id`)
|
|
||||||
');
|
|
||||||
$getEmotes->bind('hierarchy', $hierarchy);
|
|
||||||
$getEmotes->bind('order', $order);
|
|
||||||
$emotes = $getEmotes->fetchObjects(self::class);
|
|
||||||
|
|
||||||
// Removes aliases, emote with lowest ordering is considered the main
|
|
||||||
if($unique) {
|
|
||||||
$existing = [];
|
|
||||||
|
|
||||||
for($i = 0; $i < count($emotes); $i++) {
|
|
||||||
if(in_array($emotes[$i]->emote_url, $existing)) {
|
|
||||||
unset($emotes[$i]);
|
|
||||||
} else {
|
|
||||||
$existing[] = $emotes[$i]->emote_url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $emotes;
|
|
||||||
}
|
|
||||||
}
|
|
52
src/Emoticons/EmoteInfo.php
Normal file
52
src/Emoticons/EmoteInfo.php
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Emoticons;
|
||||||
|
|
||||||
|
use Stringable;
|
||||||
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
|
class EmoteInfo implements Stringable {
|
||||||
|
private string $id;
|
||||||
|
private int $order;
|
||||||
|
private int $rank;
|
||||||
|
private string $url;
|
||||||
|
private array $strings;
|
||||||
|
|
||||||
|
public function __construct(IDbResult $result, array $strings = []) {
|
||||||
|
$this->id = (string)$result->getInteger(0);
|
||||||
|
$this->order = $result->getInteger(1);
|
||||||
|
$this->rank = $result->getInteger(2);
|
||||||
|
$this->url = $result->getString(3);
|
||||||
|
$this->strings = $strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getId(): string {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOrder(): int {
|
||||||
|
return $this->order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMinRank(): int {
|
||||||
|
return $this->rank;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUrl(): string {
|
||||||
|
return $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStrings(): array {
|
||||||
|
return $this->strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStringsRaw(): array {
|
||||||
|
$strings = [];
|
||||||
|
foreach($this->strings as $info)
|
||||||
|
$strings[] = $info->getString();
|
||||||
|
return $strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string {
|
||||||
|
return $this->url;
|
||||||
|
}
|
||||||
|
}
|
33
src/Emoticons/EmoteStringInfo.php
Normal file
33
src/Emoticons/EmoteStringInfo.php
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Emoticons;
|
||||||
|
|
||||||
|
use Stringable;
|
||||||
|
use Index\Data\IDbResult;
|
||||||
|
|
||||||
|
class EmoteStringInfo implements Stringable {
|
||||||
|
private string $emoteId;
|
||||||
|
private int $order;
|
||||||
|
private string $string;
|
||||||
|
|
||||||
|
public function __construct(IDbResult $result) {
|
||||||
|
$this->emoteId = (string)$result->getInteger(0);
|
||||||
|
$this->order = $result->getInteger(1);
|
||||||
|
$this->string = $result->getString(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmoteId(): string {
|
||||||
|
return $this->emoteId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOrder(): int {
|
||||||
|
return $this->order;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getString(): string {
|
||||||
|
return $this->string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __toString(): string {
|
||||||
|
return $this->string;
|
||||||
|
}
|
||||||
|
}
|
274
src/Emoticons/Emotes.php
Normal file
274
src/Emoticons/Emotes.php
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
<?php
|
||||||
|
namespace Misuzu\Emoticons;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
use Index\Data\IDbConnection;
|
||||||
|
use Index\Data\IDbStatement;
|
||||||
|
|
||||||
|
class Emotes {
|
||||||
|
private const EMOTE_ORDER = [
|
||||||
|
'order' => 'emote_order',
|
||||||
|
'id' => 'emote_id',
|
||||||
|
'rank' => 'emote_hierarchy',
|
||||||
|
];
|
||||||
|
|
||||||
|
private IDbConnection $dbConn;
|
||||||
|
|
||||||
|
private ?IDbStatement $getEmoteById = null;
|
||||||
|
private ?IDbStatement $checkEmoteUrl = null;
|
||||||
|
private ?IDbStatement $createEmote = null;
|
||||||
|
private ?IDbStatement $deleteEmote = null;
|
||||||
|
private ?IDbStatement $updateEmote = null;
|
||||||
|
private ?IDbStatement $updateEmoteOrderOffset = null;
|
||||||
|
private ?IDbStatement $getEmoteStrings = null;
|
||||||
|
private ?IDbStatement $checkEmoteString = null;
|
||||||
|
private ?IDbStatement $addEmoteString = null;
|
||||||
|
private ?IDbStatement $removeEmoteString = null;
|
||||||
|
|
||||||
|
public function __construct(IDbConnection $dbConn) {
|
||||||
|
$this->dbConn = $dbConn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmoteById(string $emoteId, bool $withStrings = false): EmoteInfo {
|
||||||
|
if($this->getEmoteById === null)
|
||||||
|
$this->getEmoteById = $this->dbConn->prepare(
|
||||||
|
'SELECT emote_id, emote_order, emote_hierarchy, emote_url FROM msz_emoticons WHERE emote_id = ?');
|
||||||
|
else
|
||||||
|
$this->getEmoteById->reset();
|
||||||
|
|
||||||
|
$this->getEmoteById->addParameter(1, $emoteId);
|
||||||
|
$this->getEmoteById->execute();
|
||||||
|
|
||||||
|
$result = $this->getEmoteById->getResult();
|
||||||
|
if(!$result->next())
|
||||||
|
throw new RuntimeException('No emoticon with ID exists.');
|
||||||
|
|
||||||
|
$strings = $withStrings ? $this->getEmoteStrings($emoteId) : [];
|
||||||
|
|
||||||
|
return new EmoteInfo($result, $strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function emoteOrderOptions(): array {
|
||||||
|
return array_keys(self::EMOTE_ORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: pagination
|
||||||
|
public function getAllEmotes(
|
||||||
|
int $minRank = -1,
|
||||||
|
string $orderBy = '',
|
||||||
|
bool $desc = false,
|
||||||
|
bool $withStrings = false
|
||||||
|
): array {
|
||||||
|
if($minRank < 0) $minRank = PHP_INT_MAX;
|
||||||
|
$orderBy = self::EMOTE_ORDER[$orderBy] ?? self::EMOTE_ORDER[array_key_first(self::EMOTE_ORDER)];
|
||||||
|
|
||||||
|
$getAll = $this->dbConn->prepare(sprintf(
|
||||||
|
'SELECT emote_id, emote_order, emote_hierarchy, emote_url FROM msz_emoticons WHERE emote_hierarchy <= ? ORDER BY %s %s',
|
||||||
|
$orderBy, ($desc ? 'DESC' : 'ASC')
|
||||||
|
));
|
||||||
|
$getAll->addParameter(1, $minRank);
|
||||||
|
$getAll->execute();
|
||||||
|
|
||||||
|
$emotes = [];
|
||||||
|
$result = $getAll->getResult();
|
||||||
|
|
||||||
|
if($withStrings) {
|
||||||
|
while($result->next())
|
||||||
|
$emotes[] = new EmoteInfo($result, $this->getEmoteStrings((string)$result->getInteger(0)));
|
||||||
|
} else {
|
||||||
|
while($result->next())
|
||||||
|
$emotes[] = new EmoteInfo($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $emotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function checkEmoteUrlInternal(string $url): string {
|
||||||
|
// more checks?
|
||||||
|
if(empty($url))
|
||||||
|
return 'empty';
|
||||||
|
if(trim($url) !== $url)
|
||||||
|
return 'spaces';
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkEmoteUrl(string $url): string {
|
||||||
|
$check = self::checkEmoteUrlInternal($url);
|
||||||
|
if($check !== '')
|
||||||
|
return $check;
|
||||||
|
|
||||||
|
if($this->checkEmoteUrl === null)
|
||||||
|
$this->checkEmoteUrl = $this->dbConn->prepare('SELECT COUNT(*) FROM msz_emoticons WHERE emote_url = ?');
|
||||||
|
else
|
||||||
|
$this->checkEmoteUrl->reset();
|
||||||
|
|
||||||
|
$this->checkEmoteUrl->addParameter(1, $url);
|
||||||
|
$this->checkEmoteUrl->execute();
|
||||||
|
$result = $this->checkEmoteUrl->getResult();
|
||||||
|
|
||||||
|
if($result->next() && $result->getInteger(0) > 0)
|
||||||
|
return 'used';
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createEmote(string $url, int $minRank = 0, ?int $order = null): EmoteInfo {
|
||||||
|
$check = self::checkEmoteUrlInternal($url);
|
||||||
|
if($check !== '')
|
||||||
|
throw new InvalidArgumentException('$url is not correctly formatted: ' . $check);
|
||||||
|
|
||||||
|
if($this->createEmote === null)
|
||||||
|
$this->createEmote = $this->dbConn->prepare('INSERT INTO msz_emoticons (emote_url, emote_hierarchy, emote_order) SELECT ?, ?, COALESCE(?, (SELECT FLOOR(MAX(emote_order) / 10) * 10 + 10 FROM msz_emoticons), 10)');
|
||||||
|
else
|
||||||
|
$this->createEmote->reset();
|
||||||
|
|
||||||
|
$this->createEmote->addParameter(1, $url);
|
||||||
|
$this->createEmote->addParameter(2, $minRank);
|
||||||
|
$this->createEmote->addParameter(3, $order);
|
||||||
|
$this->createEmote->execute();
|
||||||
|
|
||||||
|
return $this->getEmoteById((string)$this->dbConn->getLastInsertId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteEmote(EmoteInfo|string $infoOrId): void {
|
||||||
|
if($infoOrId instanceof EmoteInfo)
|
||||||
|
$infoOrId = $infoOrId->getId();
|
||||||
|
|
||||||
|
if($this->deleteEmote === null)
|
||||||
|
$this->deleteEmote = $this->dbConn->prepare('DELETE FROM msz_emoticons WHERE emote_id = ?');
|
||||||
|
else
|
||||||
|
$this->deleteEmote->reset();
|
||||||
|
|
||||||
|
$this->deleteEmote->addParameter(1, $infoOrId);
|
||||||
|
$this->deleteEmote->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateEmote(
|
||||||
|
EmoteInfo|string $infoOrId,
|
||||||
|
?int $order = null,
|
||||||
|
?int $minRank = null,
|
||||||
|
?string $url = null
|
||||||
|
): void {
|
||||||
|
if($url !== null) {
|
||||||
|
$check = self::checkEmoteUrlInternal($url);
|
||||||
|
if($check !== '')
|
||||||
|
throw new InvalidArgumentException('$url is not correctly formatted: ' . $check);
|
||||||
|
}
|
||||||
|
|
||||||
|
if($infoOrId instanceof EmoteInfo)
|
||||||
|
$infoOrId = $infoOrId->getId();
|
||||||
|
|
||||||
|
if($this->updateEmote === null)
|
||||||
|
$this->updateEmote = $this->dbConn->prepare(
|
||||||
|
'UPDATE msz_emoticons SET emote_order = COALESCE(?, emote_order), emote_hierarchy = COALESCE(?, emote_hierarchy), emote_url = COALESCE(?, emote_url) WHERE emote_id = ?');
|
||||||
|
else
|
||||||
|
$this->updateEmote->reset();
|
||||||
|
|
||||||
|
$this->updateEmote->addParameter(1, $order);
|
||||||
|
$this->updateEmote->addParameter(2, $minRank);
|
||||||
|
$this->updateEmote->addParameter(3, $url);
|
||||||
|
$this->updateEmote->addParameter(4, $infoOrId);
|
||||||
|
$this->updateEmote->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateEmoteOrderOffset(EmoteInfo|string $infoOrId, int $offset): void {
|
||||||
|
if($offset === 0) return;
|
||||||
|
if($infoOrId instanceof EmoteInfo)
|
||||||
|
$infoOrId = $infoOrId->getId();
|
||||||
|
|
||||||
|
if($this->updateEmoteOrderOffset === null)
|
||||||
|
$this->updateEmoteOrderOffset = $this->dbConn->prepare('UPDATE msz_emoticons SET emote_order = emote_order + ? WHERE emote_id = ?');
|
||||||
|
else
|
||||||
|
$this->updateEmoteOrderOffset->reset();
|
||||||
|
|
||||||
|
$this->updateEmoteOrderOffset->addParameter(1, $offset);
|
||||||
|
$this->updateEmoteOrderOffset->addParameter(2, $infoOrId);
|
||||||
|
$this->updateEmoteOrderOffset->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmoteStrings(EmoteInfo|string $infoOrId): array {
|
||||||
|
if($infoOrId instanceof EmoteInfo)
|
||||||
|
$infoOrId = $infoOrId->getId();
|
||||||
|
|
||||||
|
if($this->getEmoteStrings === null)
|
||||||
|
$this->getEmoteStrings = $this->dbConn->prepare('SELECT emote_id, emote_string_order, emote_string FROM msz_emoticons_strings WHERE emote_id = ? ORDER BY emote_string_order');
|
||||||
|
else
|
||||||
|
$this->getEmoteStrings->reset();
|
||||||
|
|
||||||
|
$this->getEmoteStrings->addParameter(1, $infoOrId);
|
||||||
|
$this->getEmoteStrings->execute();
|
||||||
|
|
||||||
|
$strings = [];
|
||||||
|
$result = $this->getEmoteStrings->getResult();
|
||||||
|
|
||||||
|
while($result->next())
|
||||||
|
$strings[] = new EmoteStringInfo($result);
|
||||||
|
|
||||||
|
return $strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function checkEmoteStringInternal(string $string): string {
|
||||||
|
if(empty($string))
|
||||||
|
return 'empty';
|
||||||
|
if(trim($string) !== $string)
|
||||||
|
return 'spaces';
|
||||||
|
if(strtolower($string) !== $string)
|
||||||
|
return 'case';
|
||||||
|
if(!preg_match('#^[a-z][a-z0-9_-]*[a-z0-9]$#', $string))
|
||||||
|
return 'format';
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkEmoteString(string $string): string {
|
||||||
|
$check = self::checkEmoteStringInternal($string);
|
||||||
|
if($check !== '')
|
||||||
|
return $check;
|
||||||
|
|
||||||
|
if($this->checkEmoteString === null)
|
||||||
|
$this->checkEmoteString = $this->dbConn->prepare('SELECT COUNT(*) FROM msz_emoticons_strings WHERE emote_string = ?');
|
||||||
|
else
|
||||||
|
$this->checkEmoteString->reset();
|
||||||
|
|
||||||
|
$this->checkEmoteString->addParameter(1, $string);
|
||||||
|
$this->checkEmoteString->execute();
|
||||||
|
$result = $this->checkEmoteString->getResult();
|
||||||
|
|
||||||
|
if($result->next() && $result->getInteger(0) > 0)
|
||||||
|
return 'used';
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addEmoteString(EmoteInfo|string $infoOrId, string $string, ?int $order = null): void {
|
||||||
|
$check = self::checkEmoteStringInternal($string);
|
||||||
|
if($check !== '')
|
||||||
|
throw new InvalidArgumentException('$string is not correctly formatted: ' . $check);
|
||||||
|
|
||||||
|
if($infoOrId instanceof EmoteInfo)
|
||||||
|
$infoOrId = $infoOrId->getId();
|
||||||
|
|
||||||
|
if($this->addEmoteString === null)
|
||||||
|
$this->addEmoteString = $this->dbConn->prepare('INSERT INTO msz_emoticons_strings (emote_id, emote_string, emote_string_order) SELECT ? AS target_emote_id, ?, COALESCE(?, (SELECT MAX(emote_string_order) + 1 FROM msz_emoticons_strings WHERE emote_id = target_emote_id), 1)');
|
||||||
|
else
|
||||||
|
$this->addEmoteString->reset();
|
||||||
|
|
||||||
|
$this->addEmoteString->addParameter(1, $infoOrId);
|
||||||
|
$this->addEmoteString->addParameter(2, $string);
|
||||||
|
$this->addEmoteString->addParameter(3, $order);
|
||||||
|
$this->addEmoteString->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeEmoteString(EmoteStringInfo|string $infoOrString): void {
|
||||||
|
if($infoOrString instanceof EmoteStringInfo)
|
||||||
|
$infoOrString = $infoOrString->getString();
|
||||||
|
|
||||||
|
if($this->removeEmoteString === null)
|
||||||
|
$this->removeEmoteString = $this->dbConn->prepare('DELETE FROM msz_emoticons_strings WHERE emote_string = ?');
|
||||||
|
else
|
||||||
|
$this->removeEmoteString->reset();
|
||||||
|
|
||||||
|
$this->removeEmoteString->addParameter(1, $infoOrString);
|
||||||
|
$this->removeEmoteString->execute();
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ namespace Misuzu;
|
||||||
|
|
||||||
use Misuzu\Template;
|
use Misuzu\Template;
|
||||||
use Misuzu\Config\IConfig;
|
use Misuzu\Config\IConfig;
|
||||||
|
use Misuzu\Emoticons\Emotes;
|
||||||
use Misuzu\SharpChat\SharpChatRoutes;
|
use Misuzu\SharpChat\SharpChatRoutes;
|
||||||
use Misuzu\Users\Users;
|
use Misuzu\Users\Users;
|
||||||
use Index\Data\IDbConnection;
|
use Index\Data\IDbConnection;
|
||||||
|
@ -21,11 +22,13 @@ class MisuzuContext {
|
||||||
private IConfig $config;
|
private IConfig $config;
|
||||||
private Users $users;
|
private Users $users;
|
||||||
private HttpFx $router;
|
private HttpFx $router;
|
||||||
|
private Emotes $emotes;
|
||||||
|
|
||||||
public function __construct(IDbConnection $dbConn, IConfig $config) {
|
public function __construct(IDbConnection $dbConn, IConfig $config) {
|
||||||
$this->dbConn = $dbConn;
|
$this->dbConn = $dbConn;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->users = new Users($this->dbConn);
|
$this->users = new Users($this->dbConn);
|
||||||
|
$this->emotes = new Emotes($this->dbConn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDbConn(): IDbConnection {
|
public function getDbConn(): IDbConnection {
|
||||||
|
@ -57,6 +60,10 @@ class MisuzuContext {
|
||||||
return $this->users;
|
return $this->users;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
public function getEmotes(): Emotes {
|
||||||
|
return $this->emotes;
|
||||||
|
}
|
||||||
|
|
||||||
public function setUpHttp(bool $legacy = false): void {
|
public function setUpHttp(bool $legacy = false): void {
|
||||||
$this->router = new HttpFx;
|
$this->router = new HttpFx;
|
||||||
$this->router->use('/', function($response) {
|
$this->router->use('/', function($response) {
|
||||||
|
@ -125,7 +132,7 @@ class MisuzuContext {
|
||||||
$this->router->get('/forum/mark-as-read', msz_compat_handler('Forum', 'markAsReadGET'));
|
$this->router->get('/forum/mark-as-read', msz_compat_handler('Forum', 'markAsReadGET'));
|
||||||
$this->router->post('/forum/mark-as-read', msz_compat_handler('Forum', 'markAsReadPOST'));
|
$this->router->post('/forum/mark-as-read', msz_compat_handler('Forum', 'markAsReadPOST'));
|
||||||
|
|
||||||
new SharpChatRoutes($this->router, $this->config->scopeTo('sockChat'));
|
new SharpChatRoutes($this->router, $this->config->scopeTo('sockChat'), $this->emotes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function registerLegacyRedirects(): void {
|
private function registerLegacyRedirects(): void {
|
||||||
|
|
|
@ -3,11 +3,11 @@ namespace Misuzu\SharpChat;
|
||||||
|
|
||||||
use Index\Colour\Colour;
|
use Index\Colour\Colour;
|
||||||
use Index\Routing\IRouter;
|
use Index\Routing\IRouter;
|
||||||
|
use Misuzu\AuthToken;
|
||||||
use Misuzu\Config\IConfig;
|
use Misuzu\Config\IConfig;
|
||||||
|
use Misuzu\Emoticons\Emotes;
|
||||||
|
|
||||||
// Replace
|
// Replace
|
||||||
use Misuzu\AuthToken;
|
|
||||||
use Misuzu\Emoticon;
|
|
||||||
use Misuzu\Users\User;
|
use Misuzu\Users\User;
|
||||||
use Misuzu\Users\UserSession;
|
use Misuzu\Users\UserSession;
|
||||||
use Misuzu\Users\UserWarning;
|
use Misuzu\Users\UserWarning;
|
||||||
|
@ -17,10 +17,12 @@ use Misuzu\Users\UserSessionNotFoundException;
|
||||||
|
|
||||||
final class SharpChatRoutes {
|
final class SharpChatRoutes {
|
||||||
private IConfig $config;
|
private IConfig $config;
|
||||||
|
private Emotes $emotes;
|
||||||
private string $hashKey = 'woomy';
|
private string $hashKey = 'woomy';
|
||||||
|
|
||||||
public function __construct(IRouter $router, IConfig $config) {
|
public function __construct(IRouter $router, IConfig $config, Emotes $emotes) {
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
|
$this->emotes = $emotes;
|
||||||
|
|
||||||
$hashKey = $this->config->getValue('hashKey', IConfig::T_STR, '');
|
$hashKey = $this->config->getValue('hashKey', IConfig::T_STR, '');
|
||||||
|
|
||||||
|
@ -68,23 +70,23 @@ final class SharpChatRoutes {
|
||||||
$router->delete('/_sockchat/bans/revoke', [$this, 'deleteBanRevoke']);
|
$router->delete('/_sockchat/bans/revoke', [$this, 'deleteBanRevoke']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getEmotes($response, $request): array {
|
public function getEmotes($response, $request): array {
|
||||||
$response->setHeader('Access-Control-Allow-Origin', '*');
|
$response->setHeader('Access-Control-Allow-Origin', '*');
|
||||||
$response->setHeader('Access-Control-Allow-Methods', 'GET');
|
$response->setHeader('Access-Control-Allow-Methods', 'GET');
|
||||||
|
|
||||||
$raw = Emoticon::all();
|
$emotes = $this->emotes->getAllEmotes(withStrings: true);
|
||||||
$out = [];
|
$out = [];
|
||||||
|
|
||||||
foreach($raw as $emote) {
|
foreach($emotes as $emoteInfo) {
|
||||||
$strings = [];
|
$strings = [];
|
||||||
|
|
||||||
foreach($emote->getStrings() as $string)
|
foreach($emoteInfo->getStrings() as $stringInfo)
|
||||||
$strings[] = sprintf(':%s:', $string->emote_string);
|
$strings[] = sprintf(':%s:', $stringInfo->getString());
|
||||||
|
|
||||||
$out[] = [
|
$out[] = [
|
||||||
'Text' => $strings,
|
'Text' => $strings,
|
||||||
'Image' => $emote->getUrl(),
|
'Image' => $emoteInfo->getUrl(),
|
||||||
'Hierarchy' => $emote->getRank(),
|
'Hierarchy' => $emoteInfo->getMinRank(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
{% from 'macros.twig' import container_title %}
|
{% from 'macros.twig' import container_title %}
|
||||||
{% from '_layout/input.twig' import input_csrf, input_text, input_checkbox, input_file, input_select, input_colour %}
|
{% from '_layout/input.twig' import input_csrf, input_text, input_checkbox, input_file, input_select, input_colour %}
|
||||||
|
|
||||||
{% set title = emote_info is null ? 'Adding a new emoticon' : 'Editing #' ~ emote_info.id %}
|
{% set title = emote_new ? 'Adding a new emoticon' : 'Editing #' ~ emote_info.id %}
|
||||||
|
|
||||||
{% block manage_content %}
|
{% block manage_content %}
|
||||||
<div class="container manage__emotes">
|
<div class="container manage__emotes">
|
||||||
|
@ -13,22 +13,22 @@
|
||||||
|
|
||||||
<label class="manage__emote__field">
|
<label class="manage__emote__field">
|
||||||
<div class="manage__emote__field__name">Order</div>
|
<div class="manage__emote__field__name">Order</div>
|
||||||
{{ input_text('emote_order', 'manage__emote__field__value', emote_info.order|default(0), 'number') }}
|
{{ input_text('em_order', 'manage__emote__field__value', emote_info.order|default(0), 'number') }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="manage__emote__field">
|
<label class="manage__emote__field">
|
||||||
<div class="manage__emote__field__name">Hierarchy</div>
|
<div class="manage__emote__field__name">Minimum Rank</div>
|
||||||
{{ input_text('emote_hierarchy', 'manage__emote__field__value', emote_info.rank|default(0), 'number') }}
|
{{ input_text('em_minrank', 'manage__emote__field__value', emote_info.minRank|default(0), 'number') }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="manage__emote__field">
|
<label class="manage__emote__field">
|
||||||
<div class="manage__emote__field__name">URL</div>
|
<div class="manage__emote__field__name">URL</div>
|
||||||
{{ input_text('emote_url', 'manage__emote__field__value', emote_info.url|default(), 'text', '', true) }}
|
{{ input_text('em_url', 'manage__emote__field__value', emote_info.url|default(), 'text', '', true) }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<label class="manage__emote__field">
|
<label class="manage__emote__field">
|
||||||
<div class="manage__emote__field__name">Strings</div>
|
<div class="manage__emote__field__name">Strings</div>
|
||||||
{{ input_text('emote_strings', 'manage__emote__field__value', emote_info.strings|column('emote_string')|join(' '), 'text', '', true) }}
|
{{ input_text('em_strings', 'manage__emote__field__value', emote_info.strings|default([])|join(' '), 'text', '', true) }}
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div class="manage__emote__actions">
|
<div class="manage__emote__actions">
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
{{ emote.order }}
|
{{ emote.order }}
|
||||||
</div>
|
</div>
|
||||||
<div class="manage__emotes__entry__hierarchy">
|
<div class="manage__emotes__entry__hierarchy">
|
||||||
{{ emote.rank }}
|
{{ emote.minRank }}
|
||||||
</div>
|
</div>
|
||||||
<div class="manage__emotes__entry__image">
|
<div class="manage__emotes__entry__image">
|
||||||
<img src="{{ emote.url }}" alt="{{ emote.url }}" class="emoticon manage__emotes__emoticon">
|
<img src="{{ emote.url }}" alt="{{ emote.url }}" class="emoticon manage__emotes__emoticon">
|
||||||
|
|
Loading…
Reference in a new issue