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
|
||||
namespace Misuzu;
|
||||
|
||||
use RuntimeException;
|
||||
use Misuzu\Users\User;
|
||||
|
||||
require_once '../../../misuzu.php';
|
||||
|
@ -10,43 +11,106 @@ if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent(
|
|||
return;
|
||||
}
|
||||
|
||||
$emoteId = !empty($_GET['e']) && is_string($_GET['e']) ? (int)$_GET['e'] : 0;
|
||||
$isNew = $emoteId <= 0;
|
||||
$emoteInfo = !$isNew ? Emoticon::byId($emoteId) : new Emoticon;
|
||||
$emotes = $msz->getEmotes();
|
||||
$emoteId = (string)filter_input(INPUT_GET, 'e', FILTER_SANITIZE_NUMBER_INT);
|
||||
$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'])) {
|
||||
$emoteInfo->setUrl($_POST['emote_url'])
|
||||
->setRank($_POST['emote_hierarchy'])
|
||||
->setOrder($_POST['emote_order'])
|
||||
->save();
|
||||
if(empty($emoteId))
|
||||
$isNew = true;
|
||||
else
|
||||
try {
|
||||
$isNew = false;
|
||||
$emoteInfo = $loadEmoteInfo();
|
||||
} catch(RuntimeException $ex) {
|
||||
echo render_error(404);
|
||||
return;
|
||||
}
|
||||
|
||||
if($isNew && !$emoteInfo->hasId())
|
||||
throw new \Exception("SOMETHING HAPPENED");
|
||||
// make errors not echos lol
|
||||
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');
|
||||
$applyStrings = explode(' ', mb_strtolower($_POST['emote_strings']));
|
||||
$removeStrings = [];
|
||||
|
||||
foreach($setStrings as $string) {
|
||||
if(!in_array($string, $applyStrings)) {
|
||||
$removeStrings[] = $string;
|
||||
if($isNew || $url !== $emoteInfo->getUrl()) {
|
||||
$checkUrl = $emotes->checkEmoteUrl($url);
|
||||
if($checkUrl !== '') {
|
||||
echo match($checkUrl) {
|
||||
'empty' => 'URL may not be empty.',
|
||||
'spaces' => 'URL may not end or start with spaces.',
|
||||
'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) {
|
||||
if(!in_array($string, $setStrings)) {
|
||||
$setStrings[] = $string;
|
||||
$reload = false;
|
||||
if($isNew) {
|
||||
$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)
|
||||
$emoteInfo->removeString($string);
|
||||
foreach($setStrings as $string)
|
||||
$emoteInfo->addString($string);
|
||||
$sCurrent = $emoteInfo->getStringsRaw();
|
||||
$sApply = $strings;
|
||||
$sRemove = [];
|
||||
|
||||
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', [
|
||||
'emote_info' => $emoteInfo,
|
||||
'emote_new' => $isNew,
|
||||
'emote_info' => $emoteInfo ?? null,
|
||||
]);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace Misuzu;
|
||||
|
||||
use RuntimeException;
|
||||
use Misuzu\Users\User;
|
||||
|
||||
require_once '../../../misuzu.php';
|
||||
|
@ -10,22 +11,32 @@ if(!User::hasCurrent() || !perms_check_user(MSZ_PERMS_GENERAL, User::getCurrent(
|
|||
return;
|
||||
}
|
||||
|
||||
if(CSRF::validateRequest() && !empty($_GET['emote']) && is_string($_GET['emote'])) {
|
||||
$emoteId = (int)$_GET['emote'];
|
||||
$emoteInfo = Emoticon::byId($emoteId);
|
||||
$emotes = $msz->getEmotes();
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!empty($_GET['order']) && is_string($_GET['order'])) {
|
||||
$emoteInfo->changeOrder($_GET['order'] === 'i' ? 1 : -1);
|
||||
} elseif(!empty($_GET['alias']) && is_string($_GET['alias']) && ctype_alnum($_GET['alias'])) {
|
||||
$emoteInfo->addString(mb_strtolower($_GET['alias']));
|
||||
return;
|
||||
} elseif(!empty($_GET['delete'])) {
|
||||
$emoteInfo->delete();
|
||||
if(!empty($_GET['delete'])) {
|
||||
$emotes->deleteEmote($emoteInfo);
|
||||
} else {
|
||||
if(isset($_GET['order'])) {
|
||||
$order = filter_input(INPUT_GET, 'order');
|
||||
$offset = $order === 'i' ? 1 : ($order === 'd' ? -1 : 0);
|
||||
$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');
|
||||
|
@ -33,5 +44,5 @@ if(CSRF::validateRequest() && !empty($_GET['emote']) && is_string($_GET['emote']
|
|||
}
|
||||
|
||||
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\Config\IConfig;
|
||||
use Misuzu\Emoticons\Emotes;
|
||||
use Misuzu\SharpChat\SharpChatRoutes;
|
||||
use Misuzu\Users\Users;
|
||||
use Index\Data\IDbConnection;
|
||||
|
@ -21,11 +22,13 @@ class MisuzuContext {
|
|||
private IConfig $config;
|
||||
private Users $users;
|
||||
private HttpFx $router;
|
||||
private Emotes $emotes;
|
||||
|
||||
public function __construct(IDbConnection $dbConn, IConfig $config) {
|
||||
$this->dbConn = $dbConn;
|
||||
$this->config = $config;
|
||||
$this->users = new Users($this->dbConn);
|
||||
$this->emotes = new Emotes($this->dbConn);
|
||||
}
|
||||
|
||||
public function getDbConn(): IDbConnection {
|
||||
|
@ -57,6 +60,10 @@ class MisuzuContext {
|
|||
return $this->users;
|
||||
}*/
|
||||
|
||||
public function getEmotes(): Emotes {
|
||||
return $this->emotes;
|
||||
}
|
||||
|
||||
public function setUpHttp(bool $legacy = false): void {
|
||||
$this->router = new HttpFx;
|
||||
$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->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 {
|
||||
|
|
|
@ -3,11 +3,11 @@ namespace Misuzu\SharpChat;
|
|||
|
||||
use Index\Colour\Colour;
|
||||
use Index\Routing\IRouter;
|
||||
use Misuzu\AuthToken;
|
||||
use Misuzu\Config\IConfig;
|
||||
use Misuzu\Emoticons\Emotes;
|
||||
|
||||
// Replace
|
||||
use Misuzu\AuthToken;
|
||||
use Misuzu\Emoticon;
|
||||
use Misuzu\Users\User;
|
||||
use Misuzu\Users\UserSession;
|
||||
use Misuzu\Users\UserWarning;
|
||||
|
@ -17,10 +17,12 @@ use Misuzu\Users\UserSessionNotFoundException;
|
|||
|
||||
final class SharpChatRoutes {
|
||||
private IConfig $config;
|
||||
private Emotes $emotes;
|
||||
private string $hashKey = 'woomy';
|
||||
|
||||
public function __construct(IRouter $router, IConfig $config) {
|
||||
public function __construct(IRouter $router, IConfig $config, Emotes $emotes) {
|
||||
$this->config = $config;
|
||||
$this->emotes = $emotes;
|
||||
|
||||
$hashKey = $this->config->getValue('hashKey', IConfig::T_STR, '');
|
||||
|
||||
|
@ -68,23 +70,23 @@ final class SharpChatRoutes {
|
|||
$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-Methods', 'GET');
|
||||
|
||||
$raw = Emoticon::all();
|
||||
$emotes = $this->emotes->getAllEmotes(withStrings: true);
|
||||
$out = [];
|
||||
|
||||
foreach($raw as $emote) {
|
||||
foreach($emotes as $emoteInfo) {
|
||||
$strings = [];
|
||||
|
||||
foreach($emote->getStrings() as $string)
|
||||
$strings[] = sprintf(':%s:', $string->emote_string);
|
||||
foreach($emoteInfo->getStrings() as $stringInfo)
|
||||
$strings[] = sprintf(':%s:', $stringInfo->getString());
|
||||
|
||||
$out[] = [
|
||||
'Text' => $strings,
|
||||
'Image' => $emote->getUrl(),
|
||||
'Hierarchy' => $emote->getRank(),
|
||||
'Image' => $emoteInfo->getUrl(),
|
||||
'Hierarchy' => $emoteInfo->getMinRank(),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{% from 'macros.twig' import container_title %}
|
||||
{% 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 %}
|
||||
<div class="container manage__emotes">
|
||||
|
@ -13,22 +13,22 @@
|
|||
|
||||
<label class="manage__emote__field">
|
||||
<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 class="manage__emote__field">
|
||||
<div class="manage__emote__field__name">Hierarchy</div>
|
||||
{{ input_text('emote_hierarchy', 'manage__emote__field__value', emote_info.rank|default(0), 'number') }}
|
||||
<div class="manage__emote__field__name">Minimum Rank</div>
|
||||
{{ input_text('em_minrank', 'manage__emote__field__value', emote_info.minRank|default(0), 'number') }}
|
||||
</label>
|
||||
|
||||
<label class="manage__emote__field">
|
||||
<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 class="manage__emote__field">
|
||||
<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>
|
||||
|
||||
<div class="manage__emote__actions">
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
{{ emote.order }}
|
||||
</div>
|
||||
<div class="manage__emotes__entry__hierarchy">
|
||||
{{ emote.rank }}
|
||||
{{ emote.minRank }}
|
||||
</div>
|
||||
<div class="manage__emotes__entry__image">
|
||||
<img src="{{ emote.url }}" alt="{{ emote.url }}" class="emoticon manage__emotes__emoticon">
|
||||
|
|
Loading…
Reference in a new issue