mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Template/Update (Part 38)
* split Screenshot upload & management into separate endpoints * move shared functions to manager classes * cleanup javascript * move test for config screenshot min size to cfg class
This commit is contained in:
68
endpoints/admin/screenshots.php
Normal file
68
endpoints/admin/screenshots.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsResponse extends TemplateResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected string $template = 'admin/screenshots';
|
||||
protected string $pageName = 'screenshots';
|
||||
protected ?int $activeTab = parent::TAB_STAFF;
|
||||
protected array $breadcrumb = [4, 1, 5]; // Staff > Content > Screenshots
|
||||
|
||||
protected array $scripts = array(
|
||||
[SC_JS_FILE, 'js/screenshot.js'],
|
||||
[SC_CSS_STRING, '.layout {margin: 0px 25px; max-width: inherit; min-width: 1200px; }'],
|
||||
[SC_CSS_STRING, '#highlightedRow { background-color: #322C1C; }']
|
||||
);
|
||||
protected array $expectedGET = array(
|
||||
'action' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']],
|
||||
'all' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']],
|
||||
'type' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'typeid' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'urldecode' ]
|
||||
);
|
||||
|
||||
public ?bool $getAll = null;
|
||||
public array $ssPages = [];
|
||||
public array $ssData = [];
|
||||
public int $ssNFound = 0;
|
||||
public array $pageTypes = [];
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = 'Screenshot Manager';
|
||||
|
||||
// types that can have screenshots
|
||||
foreach (Type::getClassesFor(0, 'contribute', CONTRIBUTE_SS) as $type => $obj)
|
||||
$this->pageTypes[$type] = Util::ucWords(Lang::game(Type::getFileString($type)));
|
||||
|
||||
$ssGetAll = $this->_get['all'];
|
||||
$ssPages = [];
|
||||
$ssData = [];
|
||||
$nMatches = 0;
|
||||
|
||||
if ($this->_get['type'] && $this->_get['typeid'])
|
||||
$ssData = ScreenshotMgr::getScreenshots($this->_get['type'], $this->_get['typeid'], nFound: $nMatches);
|
||||
else if ($this->_get['user'])
|
||||
{
|
||||
if (mb_strlen($this->_get['user']) >= 3)
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']))
|
||||
$ssData = ScreenshotMgr::getScreenshots(userId: $uId, nFound: $nMatches);
|
||||
}
|
||||
else
|
||||
$ssPages = ScreenshotMgr::getPages($ssGetAll, $nMatches);
|
||||
|
||||
$this->getAll = $ssGetAll;
|
||||
$this->ssPages = $ssPages;
|
||||
$this->ssData = $ssData;
|
||||
$this->ssNFound = $nMatches; // ssm_numPagesFound
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
62
endpoints/admin/screenshots_approve.php
Normal file
62
endpoints/admin/screenshots_approve.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
use GdImage;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionApproveResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('AdminScreenshotsActionApproveResponse - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenshotMgr::init();
|
||||
|
||||
// create resized and thumb version of screenshot
|
||||
$ssEntries = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `userIdOwner`, `date`, `type`, `typeId` FROM ?_screenshots WHERE (`status` & ?d) = 0 AND `id` IN (?a)', CC_FLAG_APPROVED, $this->_get['id']);
|
||||
foreach ($ssEntries as $id => $ssData)
|
||||
{
|
||||
if (!ScreenshotMgr::loadFile(ScreenshotMgr::PATH_PENDING, $id))
|
||||
continue;
|
||||
|
||||
if (!ScreenshotMgr::createResized($id))
|
||||
continue;
|
||||
|
||||
if (!ScreenshotMgr::createThumbnail($id))
|
||||
continue;
|
||||
|
||||
// move pending > normal
|
||||
if (!rename(sprintf(ScreenshotMgr::PATH_PENDING, $id), sprintf(ScreenshotMgr::PATH_NORMAL, $id)))
|
||||
continue;
|
||||
|
||||
// set as approved in DB
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = ?d, `userIdApprove` = ?d WHERE `id` = ?d', CC_FLAG_APPROVED, User::$id, $id);
|
||||
|
||||
// gain siterep
|
||||
Util::gainSiteReputation($ssData['userIdOwner'], SITEREP_ACTION_SUBMIT_SCREENSHOT, ['id' => $id, 'what' => 1, 'date' => $ssData['date']]);
|
||||
|
||||
// flag DB entry as having screenshots
|
||||
if ($tbl = Type::getClassAttrib($ssData['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_SCREENSHOT, $ssData['typeId']);
|
||||
|
||||
unset($ssEntries[$id]);
|
||||
}
|
||||
|
||||
if (!$ssEntries)
|
||||
trigger_error('AdminScreenshotsActionApproveResponse - screenshot(s) # '.implode(', ', array_keys($ssEntries)).' not in db or already approved', E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
62
endpoints/admin/screenshots_delete.php
Normal file
62
endpoints/admin/screenshots_delete.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionDeleteResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']]
|
||||
);
|
||||
|
||||
// 2 steps: 1) remove from sight, 2) remove from disk
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('AdminScreenshotsActionDeleteResponse - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->_get['id'] as $id)
|
||||
{
|
||||
// irrevocably purge files already flagged as deleted (should only exist as pending)
|
||||
if (User::isInGroup(U_GROUP_ADMIN) && DB::Aowow()->selectCell('SELECT 1 FROM ?_screenshots WHERE `status` & ?d AND `id` = ?d', CC_FLAG_DELETED, $id))
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_screenshots WHERE `id` = ?d', $id);
|
||||
if (file_exists(sprintf(ScreenshotMgr::PATH_PENDING, $id)))
|
||||
unlink(sprintf(ScreenshotMgr::PATH_PENDING, $id));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// move normal to pending and remove resized and thumb
|
||||
if (file_exists(sprintf(ScreenshotMgr::PATH_NORMAL, $id)))
|
||||
rename(sprintf(ScreenshotMgr::PATH_NORMAL, $id), sprintf(ScreenshotMgr::PATH_PENDING, $id));
|
||||
|
||||
if (file_exists(sprintf(ScreenshotMgr::PATH_THUMB, $id)))
|
||||
unlink(sprintf(ScreenshotMgr::PATH_THUMB, $id));
|
||||
|
||||
if (file_exists(sprintf(ScreenshotMgr::PATH_RESIZED, $id)))
|
||||
unlink(sprintf(ScreenshotMgr::PATH_RESIZED, $id));
|
||||
}
|
||||
|
||||
// flag as deleted if not aready
|
||||
$oldEntries = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, GROUP_CONCAT(`typeId`) FROM ?_screenshots WHERE `id` IN (?a) GROUP BY `type`', $this->_get['id']);
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = ?d, `userIdDelete` = ?d WHERE `id` IN (?a)', CC_FLAG_DELETED, User::$id, $this->_get['id']);
|
||||
|
||||
// deflag db entry as having screenshots
|
||||
foreach ($oldEntries as $type => $typeIds)
|
||||
{
|
||||
$typeIds = explode(',', $typeIds);
|
||||
$toUnflag = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, IF(BIT_OR(`status`) & ?d, 1, 0) AS "hasMore" FROM ?_screenshots WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `typeId` HAVING `hasMore` = 0', CC_FLAG_APPROVED, $type, $typeIds);
|
||||
if ($toUnflag && ($tbl = Type::getClassAttrib($type, 'dataTable')))
|
||||
DB::Aowow()->query('UPDATE ?# SET cuFlags = cuFlags & ~?d WHERE id IN (?a)', $tbl, CUSTOM_HAS_SCREENSHOT, array_keys($toUnflag));
|
||||
}
|
||||
}
|
||||
}
|
||||
32
endpoints/admin/screenshots_editalt.php
Normal file
32
endpoints/admin/screenshots_editalt.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionEditaltResponse extends TextResponse
|
||||
{
|
||||
use TrCommunityHelper;
|
||||
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT]
|
||||
);
|
||||
protected array $expectedPOST = array(
|
||||
'alt' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
return;
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `caption` = ? WHERE `id` = ?d',
|
||||
$this->handleCaption($this->_post['alt']),
|
||||
$this->_get['id']
|
||||
);
|
||||
}
|
||||
}
|
||||
23
endpoints/admin/screenshots_list.php
Normal file
23
endpoints/admin/screenshots_list.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionListResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'all' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkEmptySet']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$pages = ScreenshotMgr::getPages($this->_get['all'], $nPages);
|
||||
$this->result = 'ssm_screenshotPages = '.Util::toJSON($pages).";\n";
|
||||
$this->result .= 'ssm_numPagesFound = '.$nPages.';';
|
||||
}
|
||||
}
|
||||
31
endpoints/admin/screenshots_manage.php
Normal file
31
endpoints/admin/screenshots_manage.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionManageResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'type' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'typeid' => ['filter' => FILTER_VALIDATE_INT ],
|
||||
'user' => ['filter' => FILTER_CALLBACK, 'options' => 'urldecode']
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$res = [];
|
||||
|
||||
if ($this->_get['type'] && $this->_get['typeid'])
|
||||
$res = ScreenshotMgr::getScreenshots($this->_get['type'], $this->_get['typeid']);
|
||||
else if ($this->_get['user'])
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']))
|
||||
$res = ScreenshotMgr::getScreenshots(userId: $uId);
|
||||
|
||||
$this->result = 'ssm_screenshotData = '.Util::toJSON($res);
|
||||
}
|
||||
}
|
||||
48
endpoints/admin/screenshots_relocate.php
Normal file
48
endpoints/admin/screenshots_relocate.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionRelocateResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_VALIDATE_INT],
|
||||
'typeid' => ['filter' => FILTER_VALIDATE_INT]
|
||||
// (but not type..?)
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id', 'typeid'))
|
||||
{
|
||||
trigger_error('AdminScreenshotsActionRelocateResponse - screenshotId or typeId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
[$type, $oldTypeId] = array_values(DB::Aowow()->selectRow('SELECT `type`, `typeId` FROM ?_screenshots WHERE `id` = ?d', $this->_get['id']));
|
||||
$typeId = $this->_get['typeid'];
|
||||
|
||||
if (Type::validateIds($type, $typeId))
|
||||
{
|
||||
$tbl = Type::getClassAttrib($type, 'dataTable');
|
||||
|
||||
// move screenshot
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `typeId` = ?d WHERE `id` = ?d', $typeId, $this->_get['id']);
|
||||
|
||||
// flag target as having screenshot
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_SCREENSHOT, $typeId);
|
||||
|
||||
// deflag source for having had screenshots (maybe)
|
||||
$ssInfo = DB::Aowow()->selectRow('SELECT IF(BIT_OR(~`status`) & ?d, 1, 0) AS "hasMore" FROM ?_screenshots WHERE `status`& ?d AND `type` = ?d AND `typeId` = ?d', CC_FLAG_DELETED, CC_FLAG_APPROVED, $type, $oldTypeId);
|
||||
if ($ssInfo || !$ssInfo['hasMore'])
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` & ~?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_SCREENSHOT, $oldTypeId);
|
||||
}
|
||||
else
|
||||
trigger_error('AdminScreenshotsActionRelocateResponse - invalid typeId #'.$typeId.' for type #'.$type, E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
72
endpoints/admin/screenshots_sticky.php
Normal file
72
endpoints/admin/screenshots_sticky.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class AdminScreenshotsActionStickyResponse extends TextResponse
|
||||
{
|
||||
protected int $requiredUserGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
|
||||
protected array $expectedGET = array(
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkIdListUnsigned']]
|
||||
);
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if (!$this->assertGET('id'))
|
||||
{
|
||||
trigger_error('AdminScreenshotsActionStickyResponse - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// this one is a bit strange: as far as i've seen, the only thing a 'sticky' screenshot does is show up in the infobox
|
||||
// this also means, that only one screenshot per page should be sticky
|
||||
// so, handle it one by one and the last one affecting one particular type/typId-key gets the cake
|
||||
$ssEntries = DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, `userIdOwner`, `date`, `type`, `typeId`, `status` FROM ?_screenshots WHERE (`status` & ?d) = 0 AND `id` IN (?a)', CC_FLAG_DELETED, $this->_get['id']);
|
||||
foreach ($ssEntries as $id => $ssData)
|
||||
{
|
||||
// approve yet unapproved screenshots
|
||||
if (!($ssData['status'] & CC_FLAG_APPROVED))
|
||||
{
|
||||
ScreenshotMgr::init();
|
||||
|
||||
if (!ScreenshotMgr::loadFile(ScreenshotMgr::PATH_PENDING, $id))
|
||||
continue;
|
||||
|
||||
if (!ScreenshotMgr::createResized($id))
|
||||
continue;
|
||||
|
||||
if (!ScreenshotMgr::createThumbnail($id))
|
||||
continue;
|
||||
|
||||
// move pending > normal
|
||||
if (!rename(sprintf(ScreenshotMgr::PATH_PENDING, $id), sprintf(ScreenshotMgr::PATH_NORMAL, $id)))
|
||||
continue;
|
||||
|
||||
// set as approved in DB
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = ?d, `userIdApprove` = ?d WHERE `id` = ?d', CC_FLAG_APPROVED, User::$id, $id);
|
||||
|
||||
// gain siterep
|
||||
Util::gainSiteReputation($ssData['userIdOwner'], SITEREP_ACTION_SUBMIT_SCREENSHOT, ['id' => $id, 'what' => 1, 'date' => $ssData['date']]);
|
||||
|
||||
// flag DB entry as having screenshots
|
||||
if ($tbl = Type::getClassAttrib($ssData['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_SCREENSHOT, $ssData['typeId']);
|
||||
}
|
||||
|
||||
// reset all others
|
||||
DB::Aowow()->query('UPDATE ?_screenshots a, ?_screenshots b SET a.`status` = a.`status` & ~?d WHERE a.`type` = b.`type` AND a.`typeId` = b.`typeId` AND a.`id` <> b.`id` AND b.`id` = ?d', CC_FLAG_STICKY, $id);
|
||||
|
||||
// toggle sticky status
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = IF(`status` & ?d, `status` & ~?d, `status` | ?d) WHERE `id` = ?d AND `status` & ?d', CC_FLAG_STICKY, CC_FLAG_STICKY, CC_FLAG_STICKY, $id, CC_FLAG_APPROVED);
|
||||
|
||||
unset($ssEntries[$id]);
|
||||
}
|
||||
|
||||
if ($ssEntries)
|
||||
trigger_error('AdminScreenshotsActionStickyResponse - screenshot(s) # '.implode(', ', array_keys($ssEntries)).' not in db or flagged as deleted', E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
98
endpoints/screenshot/add.php
Normal file
98
endpoints/screenshot/add.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
-> 1. =add: receives user upload
|
||||
1.1. checks and processing on the upload
|
||||
1.2. forward to =crop or blank response
|
||||
2. =crop: user edites upload
|
||||
3. =complete: store edited screenshot file and data
|
||||
4. =thankyou
|
||||
*/
|
||||
|
||||
// filename: Username-type-typeId-<hash>[_original].jpg
|
||||
|
||||
class ScreenshotAddResponse extends TextResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
private string $imgHash = '';
|
||||
private int $destType = 0;
|
||||
private int $destTypeId = 0;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
// get screenshot destination
|
||||
// target delivered as screenshot=<command>&<type>.<typeId>.<hash:16> (hash is optional)
|
||||
if (!preg_match('/^screenshot=\w+&(-?\d+)\.(-?\d+)(\.(\w{16}))?$/i', $_SERVER['QUERY_STRING'] ?? '', $m, PREG_UNMATCHED_AS_NULL))
|
||||
$this->generate404();
|
||||
|
||||
[, $this->destType, $this->destTypeId, , $imgHash] = $m;
|
||||
|
||||
// no such type or this type cannot receive screenshots
|
||||
if (!Type::checkClassAttrib($this->destType, 'contribute', CONTRIBUTE_SS))
|
||||
$this->generate404();
|
||||
|
||||
// no such typeId
|
||||
if (!Type::validateIds($this->destType, $this->destTypeId))
|
||||
$this->generate404();
|
||||
|
||||
// only accept/expect hash for crop & complete
|
||||
if ($imgHash)
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if ($this->handleAdd())
|
||||
$this->redirectTo = '?screenshot=crop&'.$this->destType.'.'.$this->destTypeId.'.'.$this->imgHash;
|
||||
else if ($this->destType && $this->destTypeId)
|
||||
$this->redirectTo = '?'.Type::getFileString($this->destType).'='.$this->destTypeId.'#submit-a-screenshot';
|
||||
else
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
private function handleAdd() : bool
|
||||
{
|
||||
if (!User::canUploadScreenshot())
|
||||
{
|
||||
$_SESSION['error']['ss'] = Lang::screenshot('error', 'notAllowed');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ScreenshotMgr::init())
|
||||
{
|
||||
$_SESSION['error']['ss'] = Lang::main('intError');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ScreenshotMgr::validateUpload())
|
||||
{
|
||||
$_SESSION['error']['ss'] = ScreenshotMgr::$error;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ScreenshotMgr::loadUpload())
|
||||
{
|
||||
$_SESSION['error']['ss'] = Lang::main('intError');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ScreenshotMgr::tempSaveUpload([$this->destType, $this->destTypeId], $this->imgHash))
|
||||
{
|
||||
$_SESSION['error']['ss'] = Lang::main('intError');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
106
endpoints/screenshot/complete.php
Normal file
106
endpoints/screenshot/complete.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
1. =add: receives user upload
|
||||
2. =crop: user edites upload
|
||||
-> 3. =complete: store edited screenshot file and data
|
||||
4. =thankyou
|
||||
*/
|
||||
|
||||
// filename: Username-type-typeId-<hash>[_original].jpg
|
||||
|
||||
class ScreenshotCompleteResponse extends TextResponse
|
||||
{
|
||||
use TrCommunityHelper;
|
||||
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected array $expectedPOST = array(
|
||||
'coords' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkCoords'] ],
|
||||
'screenshotalt' => ['filter' => FILTER_CALLBACK, 'options' => [self::class, 'checkTextLine']]
|
||||
);
|
||||
|
||||
private int $destType = 0;
|
||||
private int $destTypeId = 0;
|
||||
private string $imgHash = '';
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
// get screenshot destination
|
||||
// target delivered as screenshot=<command>&<type>.<typeId>.<hash:16> (hash is optional)
|
||||
if (!preg_match('/^screenshot=\w+&(-?\d+)\.(-?\d+)(\.(\w{16}))?$/i', $_SERVER['QUERY_STRING'] ?? '', $m, PREG_UNMATCHED_AS_NULL))
|
||||
$this->generate404();
|
||||
|
||||
[, $this->destType, $this->destTypeId, , $this->imgHash] = $m;
|
||||
|
||||
// no such type or this type cannot receive screenshots
|
||||
if (!Type::checkClassAttrib($this->destType, 'contribute', CONTRIBUTE_SS))
|
||||
$this->generate404();
|
||||
|
||||
// no such typeId
|
||||
if (!Type::validateIds($this->destType, $this->destTypeId))
|
||||
$this->generate404();
|
||||
|
||||
// hash required for crop & complete
|
||||
if (!$this->imgHash)
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
if ($this->handleComplete())
|
||||
$this->forward('?screenshot=thankyou&'.$this->destType.'.'.$this->destTypeId);
|
||||
else
|
||||
$this->generate404();
|
||||
}
|
||||
|
||||
private function handleComplete() : bool
|
||||
{
|
||||
if (!$this->assertPOST('coords'))
|
||||
return false;
|
||||
|
||||
ScreenshotMgr::init();
|
||||
|
||||
if (!ScreenshotMgr::loadFile(ScreenshotMgr::PATH_TEMP, User::$username.'-'.$this->destType.'-'.$this->destTypeId.'-'.$this->imgHash.'_original'))
|
||||
return false;
|
||||
|
||||
ScreenshotMgr::cropImg(...$this->_post['coords']);
|
||||
|
||||
['oWidth' => $w, 'oHeight' => $h] = ScreenshotMgr::calcImgDimensions();
|
||||
|
||||
// write to db
|
||||
$newId = DB::Aowow()->query(
|
||||
'INSERT INTO ?_screenshots (`type`, `typeId`, `userIdOwner`, `date`, `width`, `height`, `caption`, `status`) VALUES (?d, ?d, ?d, UNIX_TIMESTAMP(), ?d, ?d, ?, 0)',
|
||||
$this->destType, $this->destTypeId,
|
||||
User::$id,
|
||||
$w, $h,
|
||||
$this->handleCaption($this->_post['screenshotalt'])
|
||||
);
|
||||
if (!is_int($newId)) // 0 is valid, NULL or FALSE is not
|
||||
{
|
||||
trigger_error('ScreenshotCompleteResponse - screenshot query failed', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// write to file
|
||||
return ScreenshotMgr::writeImage(ScreenshotMgr::PATH_PENDING, $newId);
|
||||
}
|
||||
|
||||
protected static function checkCoords(string $val) : ?array
|
||||
{
|
||||
if (preg_match('/^[01]\.[0-9]{3}(,[01]\.[0-9]{3}){3}$/', $val))
|
||||
return explode(',', $val);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
92
endpoints/screenshot/crop.php
Normal file
92
endpoints/screenshot/crop.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
1. =add: receives user upload
|
||||
-> 2. =crop: user edites upload
|
||||
2.1. just show edit page
|
||||
2.2. user submits coords and description to =complete
|
||||
3. =complete: store edited screenshot file and data
|
||||
4. =thankyou
|
||||
*/
|
||||
|
||||
// filename: Username-type-typeId-<hash>[_original].jpg
|
||||
|
||||
class ScreenshotCropResponse extends TemplateResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected string $template = 'screenshot';
|
||||
protected string $pageName = 'screenshot';
|
||||
|
||||
protected array $scripts = [[SC_JS_FILE, 'js/Cropper.js'], [SC_CSS_FILE, 'css/Cropper.css']];
|
||||
|
||||
public ?Markup $infobox = null;
|
||||
public array $cropper = [];
|
||||
public int $destType = 0;
|
||||
public int $destTypeId = 0;
|
||||
public string $imgHash = '';
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
// get screenshot destination
|
||||
// target delivered as screenshot=<command>&<type>.<typeId>.<hash:16> (hash is optional)
|
||||
if (!preg_match('/^screenshot=\w+&(-?\d+)\.(-?\d+)(\.(\w{16}))?$/i', $_SERVER['QUERY_STRING'] ?? '', $m, PREG_UNMATCHED_AS_NULL))
|
||||
$this->generateError();
|
||||
|
||||
[, $this->destType, $this->destTypeId, , $this->imgHash] = $m;
|
||||
|
||||
// no such type or this type cannot receive screenshots
|
||||
if (!Type::checkClassAttrib($this->destType, 'contribute', CONTRIBUTE_SS))
|
||||
$this->generateError();
|
||||
|
||||
// no such typeId
|
||||
if (!Type::validateIds($this->destType, $this->destTypeId))
|
||||
$this->generateError();
|
||||
|
||||
// hash required for crop & complete
|
||||
if (!$this->imgHash)
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Lang::screenshot('submission');
|
||||
$fileBase = User::$username.'-'.$this->destType.'-'.$this->destTypeId.'-'.$this->imgHash;
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
|
||||
ScreenshotMgr::init();
|
||||
|
||||
if (!ScreenshotMgr::loadFile(ScreenshotMgr::PATH_TEMP, $fileBase.'_original'))
|
||||
{
|
||||
$_SESSION['error']['ss'] = Lang::main('intError');
|
||||
$this->forward('?'.Type::getFileString($this->destType).'='.$this->destTypeId.'#submit-a-screenshot');
|
||||
}
|
||||
|
||||
$dims = ScreenshotMgr::calcImgDimensions();
|
||||
|
||||
$this->cropper = $dims + array(
|
||||
'url' => Cfg::get('STATIC_URL').'/uploads/screenshots/temp/'.$fileBase.'.jpg',
|
||||
'parent' => 'ss-container',
|
||||
'minCrop' => ScreenshotMgr::$MIN_SIZE, // optional; defaults to 150 - min selection size (a square)
|
||||
'type' => $this->destType, // only used to check against NPC: 15384 [OLDWorld Trigger (DO NOT DELETE)] for U_GROUP_MODERATOR | U_GROUP_EDITOR. If successful drops minCrop constraint
|
||||
'typeId' => $this->destTypeId // i guess this was used to upload arbitrary imagery for articles, blog posts, etc
|
||||
);
|
||||
|
||||
// target
|
||||
$this->infobox = new Markup(Lang::screenshot('displayOn', [Lang::typeName($this->destType), Type::getFileString($this->destType), $this->destTypeId]), ['allow' => Markup::CLASS_STAFF, 'dbpage' => true], 'infobox-contents0');
|
||||
$this->extendGlobalIds($this->destType, $this->destTypeId);
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
66
endpoints/screenshot/thankyou.php
Normal file
66
endpoints/screenshot/thankyou.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
/*
|
||||
1. =add: receives user upload
|
||||
2. =crop: user edites upload
|
||||
3. =complete: store edited screenshot file and data
|
||||
-> 4. =thankyou
|
||||
*/
|
||||
|
||||
// filename: Username-type-typeId-<hash>[_original].jpg
|
||||
|
||||
class ScreenshotThankyouResponse extends TemplateResponse
|
||||
{
|
||||
protected bool $requiresLogin = true;
|
||||
|
||||
protected string $template = 'text-page-generic';
|
||||
protected string $pageName = 'screenshot';
|
||||
|
||||
private int $destType = 0;
|
||||
private int $destTypeId = 0;
|
||||
|
||||
public function __construct(string $pageParam)
|
||||
{
|
||||
parent::__construct($pageParam);
|
||||
|
||||
// get screenshot destination
|
||||
// target delivered as screenshot=<command>&<type>.<typeId>.<hash:16> (hash is optional)
|
||||
if (!preg_match('/^screenshot=\w+&(-?\d+)\.(-?\d+)(\.(\w{16}))?$/i', $_SERVER['QUERY_STRING'] ?? '', $m, PREG_UNMATCHED_AS_NULL))
|
||||
$this->generateError();
|
||||
|
||||
[, $this->destType, $this->destTypeId, , $imgHash] = $m;
|
||||
|
||||
// no such type or this type cannot receive screenshots
|
||||
if (!Type::checkClassAttrib($this->destType, 'contribute', CONTRIBUTE_SS))
|
||||
$this->generateError();
|
||||
|
||||
// no such typeId
|
||||
if (!Type::validateIds($this->destType, $this->destTypeId))
|
||||
$this->generateError();
|
||||
|
||||
// only accept/expect hash for crop & complete
|
||||
if ($imgHash)
|
||||
$this->generateError();
|
||||
}
|
||||
|
||||
protected function generate() : void
|
||||
{
|
||||
$this->h1 = Lang::screenshot('submission');
|
||||
|
||||
array_unshift($this->title, $this->h1);
|
||||
|
||||
$this->extraHTML = Lang::screenshot('thanks', 'contrib').'<br /><br />';
|
||||
$this->extraHTML .= Lang::screenshot('thanks', 'goBack', [Type::getFileString($this->destType), $this->destTypeId])."<br /><br />\n";
|
||||
$this->extraHTML .= '<i>'.Lang::screenshot('thanks', 'note').'</i>';
|
||||
|
||||
parent::generate();
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -56,7 +56,7 @@ class TopusersBaseResponse extends TemplateResponse
|
||||
GROUP BY a.`id`
|
||||
ORDER BY reputation DESC
|
||||
LIMIT ?d',
|
||||
SITEREP_ACTION_COMMENT, SITEREP_ACTION_UPLOAD, SITEREP_ACTION_GOOD_REPORT,
|
||||
SITEREP_ACTION_COMMENT, SITEREP_ACTION_SUBMIT_SCREENSHOT, SITEREP_ACTION_GOOD_REPORT,
|
||||
$time ?: DBSIMPLE_SKIP, Cfg::get('SQL_LIMIT_SEARCH')
|
||||
);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class AjaxAdmin extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['screenshots', 'siteconfig', 'weight-presets', 'spawn-override', 'guide', 'comment'];
|
||||
protected $validParams = ['siteconfig', 'weight-presets', 'spawn-override', 'guide', 'comment'];
|
||||
protected $_get = array(
|
||||
'action' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkTextLine' ],
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\AjaxHandler::checkIdListUnsigned'],
|
||||
@@ -37,27 +37,7 @@ class AjaxAdmin extends AjaxHandler
|
||||
if (!$this->params)
|
||||
return;
|
||||
|
||||
if ($this->params[0] == 'screenshots' && $this->_get['action'])
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT))
|
||||
return;
|
||||
|
||||
if ($this->_get['action'] == 'list')
|
||||
$this->handler = 'ssList';
|
||||
else if ($this->_get['action'] == 'manage')
|
||||
$this->handler = 'ssManage';
|
||||
else if ($this->_get['action'] == 'editalt')
|
||||
$this->handler = 'ssEditAlt';
|
||||
else if ($this->_get['action'] == 'approve')
|
||||
$this->handler = 'ssApprove';
|
||||
else if ($this->_get['action'] == 'sticky')
|
||||
$this->handler = 'ssSticky';
|
||||
else if ($this->_get['action'] == 'delete')
|
||||
$this->handler = 'ssDelete';
|
||||
else if ($this->_get['action'] == 'relocate')
|
||||
$this->handler = 'ssRelocate';
|
||||
}
|
||||
else if ($this->params[0] == 'siteconfig' && $this->_get['action'])
|
||||
if ($this->params[0] == 'siteconfig' && $this->_get['action'])
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_DEV | U_GROUP_ADMIN))
|
||||
return;
|
||||
@@ -100,227 +80,6 @@ class AjaxAdmin extends AjaxHandler
|
||||
}
|
||||
}
|
||||
|
||||
// get all => null (optional)
|
||||
// evaled response .. UNK
|
||||
protected function ssList() : string
|
||||
{
|
||||
// ssm_screenshotPages
|
||||
// ssm_numPagesFound
|
||||
|
||||
$pages = CommunityContent::getScreenshotPagesForManager($this->_get['all'], $nPages);
|
||||
$buff = 'ssm_screenshotPages = '.Util::toJSON($pages).";\n";
|
||||
$buff .= 'ssm_numPagesFound = '.$nPages.';';
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
// get: [type => type, typeId => typeId] || [user => username]
|
||||
// evaled response .. UNK
|
||||
protected function ssManage() : string
|
||||
{
|
||||
$res = [];
|
||||
|
||||
if ($this->_get['type'] && $this->_get['type'] && $this->_get['typeid'] && $this->_get['typeid'])
|
||||
$res = CommunityContent::getScreenshotsForManager($this->_get['type'], $this->_get['typeid']);
|
||||
else if ($this->_get['user'])
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']))
|
||||
$res = CommunityContent::getScreenshotsForManager(0, 0, $uId);
|
||||
|
||||
return 'ssm_screenshotData = '.Util::toJSON($res);
|
||||
}
|
||||
|
||||
// get: id => SSid
|
||||
// resp: ''
|
||||
protected function ssEditAlt() : void
|
||||
{
|
||||
// doesn't need to be htmlEscaped, ths javascript does that
|
||||
if ($this->_get['id'] && $this->_post['alt'] !== null)
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET caption = ? WHERE id = ?d', trim($this->_post['alt']), $this->_get['id'][0]);
|
||||
}
|
||||
|
||||
// get: id => comma-separated SSids
|
||||
// resp: ''
|
||||
protected function ssApprove() : void
|
||||
{
|
||||
if (!$this->reqGET('id'))
|
||||
{
|
||||
trigger_error('AjaxAdmin::ssApprove - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// create resized and thumb version of screenshot
|
||||
$resized = [772, 618];
|
||||
$thumb = [150, 150];
|
||||
$path = 'static/uploads/screenshots/%s/%d.jpg';
|
||||
|
||||
foreach ($this->_get['id'] as $id)
|
||||
{
|
||||
// must not be already approved
|
||||
if ($ssEntry = DB::Aowow()->selectRow('SELECT userIdOwner, date, type, typeId FROM ?_screenshots WHERE (status & ?d) = 0 AND id = ?d', CC_FLAG_APPROVED, $id))
|
||||
{
|
||||
// should also error-log
|
||||
if (!file_exists(sprintf($path, 'pending', $id)))
|
||||
{
|
||||
trigger_error('AjaxAdmin::ssApprove - screenshot #'.$id.' exists in db but not as file', E_USER_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
$srcImg = imagecreatefromjpeg(sprintf($path, 'pending', $id));
|
||||
$srcW = imagesx($srcImg);
|
||||
$srcH = imagesy($srcImg);
|
||||
|
||||
// write thumb
|
||||
$scale = min(1.0, min($thumb[0] / $srcW, $thumb[1] / $srcH));
|
||||
$destW = $srcW * $scale;
|
||||
$destH = $srcH * $scale;
|
||||
$destImg = imagecreatetruecolor($destW, $destH);
|
||||
|
||||
imagefill($destImg, 0, 0, imagecolorallocate($destImg, 255, 255, 255));
|
||||
imagecopyresampled($destImg, $srcImg, 0, 0, 0, 0, $destW, $destH, $srcW, $srcH);
|
||||
|
||||
imagejpeg($destImg, sprintf($path, 'thumb', $id), 100);
|
||||
|
||||
// write resized (only if required)
|
||||
if ($srcW > $resized[0] || $srcH > $resized[1])
|
||||
{
|
||||
$scale = min(1.0, min($resized[0] / $srcW, $resized[1] / $srcH));
|
||||
$destW = $srcW * $scale;
|
||||
$destH = $srcH * $scale;
|
||||
$destImg = imagecreatetruecolor($destW, $destH);
|
||||
|
||||
imagefill($destImg, 0, 0, imagecolorallocate($destImg, 255, 255, 255));
|
||||
imagecopyresampled($destImg, $srcImg, 0, 0, 0, 0, $destW, $destH, $srcW, $srcH);
|
||||
|
||||
imagejpeg($destImg, sprintf($path, 'resized', $id), 100);
|
||||
}
|
||||
|
||||
imagedestroy($srcImg);
|
||||
|
||||
// move screenshot from pending to normal
|
||||
rename(sprintf($path, 'pending', $id), sprintf($path, 'normal', $id));
|
||||
|
||||
// set as approved in DB and gain rep (once!)
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET status = ?d, userIdApprove = ?d WHERE id = ?d', CC_FLAG_APPROVED, User::$id, $id);
|
||||
Util::gainSiteReputation($ssEntry['userIdOwner'], SITEREP_ACTION_UPLOAD, ['id' => $id, 'what' => 1, 'date' => $ssEntry['date']]);
|
||||
// flag DB entry as having screenshots
|
||||
if ($tbl = Type::getClassAttrib($ssEntry['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE '.$tbl.' SET cuFlags = cuFlags | ?d WHERE id = ?d', CUSTOM_HAS_SCREENSHOT, $ssEntry['typeId']);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxAdmin::ssApprove - screenshot #'.$id.' not in db or already approved', E_USER_ERROR);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// get: id => comma-separated SSids
|
||||
// resp: ''
|
||||
protected function ssSticky() : void
|
||||
{
|
||||
if (!$this->reqGET('id'))
|
||||
{
|
||||
trigger_error('AjaxAdmin::ssSticky - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// approve soon to be sticky screenshots
|
||||
$this->ssApprove();
|
||||
|
||||
// this one is a bit strange: as far as i've seen, the only thing a 'sticky' screenshot does is show up in the infobox
|
||||
// this also means, that only one screenshot per page should be sticky
|
||||
// so, handle it one by one and the last one affecting one particular type/typId-key gets the cake
|
||||
foreach ($this->_get['id'] as $id)
|
||||
{
|
||||
// reset all others
|
||||
DB::Aowow()->query('UPDATE ?_screenshots a, ?_screenshots b SET a.status = a.status & ~?d WHERE a.type = b.type AND a.typeId = b.typeId AND a.id <> b.id AND b.id = ?d', CC_FLAG_STICKY, $id);
|
||||
|
||||
// toggle sticky status
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET `status` = IF(`status` & ?d, `status` & ~?d, `status` | ?d) WHERE id = ?d AND `status` & ?d', CC_FLAG_STICKY, CC_FLAG_STICKY, CC_FLAG_STICKY, $id, CC_FLAG_APPROVED);
|
||||
}
|
||||
}
|
||||
|
||||
// get: id => comma-separated SSids
|
||||
// resp: ''
|
||||
// 2 steps: 1) remove from sight, 2) remove from disk
|
||||
protected function ssDelete() : void
|
||||
{
|
||||
if (!$this->reqGET('id'))
|
||||
{
|
||||
trigger_error('AjaxAdmin::ssDelete - screenshotId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$path = 'static/uploads/screenshots/%s/%d.jpg';
|
||||
|
||||
foreach ($this->_get['id'] as $id)
|
||||
{
|
||||
// irrevocably remove already deleted files
|
||||
if (User::isInGroup(U_GROUP_ADMIN) && DB::Aowow()->selectCell('SELECT 1 FROM ?_screenshots WHERE status & ?d AND id = ?d', CC_FLAG_DELETED, $id))
|
||||
{
|
||||
DB::Aowow()->query('DELETE FROM ?_screenshots WHERE id = ?d', $id);
|
||||
if (file_exists(sprintf($path, 'pending', $id)))
|
||||
unlink(sprintf($path, 'pending', $id));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// move pending or normal to pending
|
||||
if (file_exists(sprintf($path, 'normal', $id)))
|
||||
rename(sprintf($path, 'normal', $id), sprintf($path, 'pending', $id));
|
||||
|
||||
// remove resized and thumb
|
||||
if (file_exists(sprintf($path, 'thumb', $id)))
|
||||
unlink(sprintf($path, 'thumb', $id));
|
||||
|
||||
if (file_exists(sprintf($path, 'resized', $id)))
|
||||
unlink(sprintf($path, 'resized', $id));
|
||||
}
|
||||
|
||||
// flag as deleted if not aready
|
||||
$oldEntries = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, GROUP_CONCAT(typeId) FROM ?_screenshots WHERE id IN (?a) GROUP BY `type`', $this->_get['id']);
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET status = ?d, userIdDelete = ?d WHERE id IN (?a)', CC_FLAG_DELETED, User::$id, $this->_get['id']);
|
||||
// deflag db entry as having screenshots
|
||||
foreach ($oldEntries as $type => $typeIds)
|
||||
{
|
||||
$typeIds = explode(',', $typeIds);
|
||||
$toUnflag = DB::Aowow()->selectCol('SELECT typeId AS ARRAY_KEY, IF(BIT_OR(`status`) & ?d, 1, 0) AS hasMore FROM ?_screenshots WHERE `type` = ?d AND typeId IN (?a) GROUP BY typeId HAVING hasMore = 0', CC_FLAG_APPROVED, $type, $typeIds);
|
||||
if ($toUnflag && ($tbl = Type::getClassAttrib($type, 'dataTable')))
|
||||
DB::Aowow()->query('UPDATE '.$tbl.' SET cuFlags = cuFlags & ~?d WHERE id IN (?a)', CUSTOM_HAS_SCREENSHOT, array_keys($toUnflag));
|
||||
}
|
||||
}
|
||||
|
||||
// get: id => ssId, typeid => typeId (but not type..?)
|
||||
// resp: ''
|
||||
protected function ssRelocate() : void
|
||||
{
|
||||
if (!$this->reqGET('id', 'typeid'))
|
||||
{
|
||||
trigger_error('AjaxAdmin::ssRelocate - screenshotId or typeId empty', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$id = $this->_get['id'][0];
|
||||
[$type, $oldTypeId] = array_values(DB::Aowow()->selectRow('SELECT type, typeId FROM ?_screenshots WHERE id = ?d', $id));
|
||||
$typeId = (int)$this->_get['typeid'];
|
||||
|
||||
$tc = Type::newList($type, [['id', $typeId]]);
|
||||
if ($tc && !$tc->error)
|
||||
{
|
||||
// move screenshot
|
||||
DB::Aowow()->query('UPDATE ?_screenshots SET typeId = ?d WHERE id = ?d', $typeId, $id);
|
||||
|
||||
// flag target as having screenshot
|
||||
DB::Aowow()->query('UPDATE '.$tc::$dataTable.' SET cuFlags = cuFlags | ?d WHERE id = ?d', CUSTOM_HAS_SCREENSHOT, $typeId);
|
||||
|
||||
// deflag source for having had screenshots (maybe)
|
||||
$ssInfo = DB::Aowow()->selectRow('SELECT IF(BIT_OR(~status) & ?d, 1, 0) AS hasMore FROM ?_screenshots WHERE `status`& ?d AND `type` = ?d AND typeId = ?d', CC_FLAG_DELETED, CC_FLAG_APPROVED, $type, $oldTypeId);
|
||||
if($ssInfo || !$ssInfo['hasMore'])
|
||||
DB::Aowow()->query('UPDATE '.$tc::$dataTable.' SET cuFlags = cuFlags & ~?d WHERE id = ?d', CUSTOM_HAS_SCREENSHOT, $oldTypeId);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxAdmin::ssRelocate - invalid typeId #'.$typeId.' for type #'.$type, E_USER_ERROR);
|
||||
}
|
||||
|
||||
protected function confAdd() : string
|
||||
{
|
||||
$key = trim($this->_get['key']);
|
||||
|
||||
@@ -206,7 +206,6 @@ class Cfg
|
||||
return 'empty value given for required config';
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_config SET `value` = ? WHERE `key` = ?', $value, $key);
|
||||
|
||||
self::$store[$key][self::IDX_VALUE] = $value;
|
||||
|
||||
// validate change
|
||||
@@ -251,6 +250,7 @@ class Cfg
|
||||
return 'configuration option not found';
|
||||
|
||||
[$oldValue, $flags, , $default, ] = self::$store[$key];
|
||||
|
||||
if ($flags & self::FLAG_INTERNAL)
|
||||
return 'can\'t set an internal option directly';
|
||||
|
||||
@@ -446,6 +446,17 @@ class Cfg
|
||||
{
|
||||
return (($_SERVER['HTTPS'] ?? 'off') != 'off') || (self::$store['force_ssl'][self::IDX_VALUE] ?? 0);
|
||||
}
|
||||
|
||||
private static function screenshot_min_size(int|string $value, ?string &$msg = '') : bool
|
||||
{
|
||||
if ($value < 200)
|
||||
{
|
||||
$msg .= 'Value must be at least 200 (px).';
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -236,129 +236,6 @@ class CommunityContent
|
||||
return $replies;
|
||||
}
|
||||
|
||||
public static function getScreenshotsForManager($type, $typeId, $userId = 0)
|
||||
{
|
||||
$screenshots = DB::Aowow()->select(
|
||||
'SELECT s.`id`, a.`username` AS "user", s.`date`, s.`width`, s.`height`, s.`type`, s.`typeId`, s.`caption`, s.`status`, s.`status` AS "flags"
|
||||
FROM ?_screenshots s
|
||||
LEFT JOIN ?_account a ON s.`userIdOwner` = a.`id`
|
||||
WHERE
|
||||
{ s.`type` = ?d}
|
||||
{ AND s.`typeId` = ?d}
|
||||
{ s.`userIdOwner` = ?d}
|
||||
LIMIT 100',
|
||||
$userId ? DBSIMPLE_SKIP : $type,
|
||||
$userId ? DBSIMPLE_SKIP : $typeId,
|
||||
$userId ? $userId : DBSIMPLE_SKIP
|
||||
);
|
||||
|
||||
$num = [];
|
||||
foreach ($screenshots as $s)
|
||||
{
|
||||
if (empty($num[$s['type']][$s['typeId']]))
|
||||
$num[$s['type']][$s['typeId']] = 1;
|
||||
else
|
||||
$num[$s['type']][$s['typeId']]++;
|
||||
}
|
||||
|
||||
// format data to meet requirements of the js
|
||||
foreach ($screenshots as $idx => &$s)
|
||||
{
|
||||
$s['date'] = date(Util::$dateFormatInternal, $s['date']);
|
||||
|
||||
$s['name'] = "Screenshot #".$s['id']; // what should we REALLY name it?
|
||||
|
||||
if (isset($screenshots[$idx - 1]))
|
||||
$s['prev'] = $idx - 1;
|
||||
|
||||
if (isset($screenshots[$idx + 1]))
|
||||
$s['next'] = $idx + 1;
|
||||
|
||||
// order gives priority for 'status'
|
||||
if (!($s['flags'] & CC_FLAG_APPROVED))
|
||||
{
|
||||
$s['pending'] = 1;
|
||||
$s['status'] = 0;
|
||||
}
|
||||
else
|
||||
$s['status'] = 100;
|
||||
|
||||
if ($s['flags'] & CC_FLAG_STICKY)
|
||||
{
|
||||
$s['sticky'] = 1;
|
||||
$s['status'] = 105;
|
||||
}
|
||||
|
||||
if ($s['flags'] & CC_FLAG_DELETED)
|
||||
{
|
||||
$s['deleted'] = 1;
|
||||
$s['status'] = 999;
|
||||
}
|
||||
|
||||
// something todo with massSelect .. am i doing this right?
|
||||
if ($num[$s['type']][$s['typeId']] == 1)
|
||||
$s['unique'] = 1;
|
||||
|
||||
if (!$s['user'])
|
||||
unset($s['user']);
|
||||
}
|
||||
|
||||
return $screenshots;
|
||||
}
|
||||
|
||||
public static function getScreenshotPagesForManager($all, &$nFound)
|
||||
{
|
||||
// i GUESS .. ss_getALL ? everything : pending
|
||||
$nFound = 0;
|
||||
$pages = DB::Aowow()->select(
|
||||
'SELECT s.`type`, s.`typeId`, COUNT(1) AS "count", MIN(s.`date`) AS "date"
|
||||
FROM ?_screenshots s
|
||||
{ WHERE (s.`status` & ?d) = 0 }
|
||||
GROUP BY s.`type`, s.`typeId`',
|
||||
$all ? DBSIMPLE_SKIP : CC_FLAG_APPROVED | CC_FLAG_DELETED
|
||||
);
|
||||
|
||||
if ($pages)
|
||||
{
|
||||
// limit to one actually existing type each
|
||||
foreach (array_unique(array_column($pages, 'type')) as $t)
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($pages as $row)
|
||||
if ($row['type'] == $t)
|
||||
$ids[] = $row['typeId'];
|
||||
|
||||
if (!$ids)
|
||||
continue;
|
||||
|
||||
$obj = Type::newList($t, [Cfg::get('SQL_LIMIT_NONE'), ['id', $ids]]);
|
||||
if (!$obj || $obj->error)
|
||||
continue;
|
||||
|
||||
foreach ($pages as &$p)
|
||||
if ($p['type'] == $t)
|
||||
if ($obj->getEntry($p['typeId']))
|
||||
$p['name'] = $obj->getField('name', true);
|
||||
}
|
||||
|
||||
foreach ($pages as &$p)
|
||||
{
|
||||
if (empty($p['name']))
|
||||
{
|
||||
trigger_error('Screenshot linked to nonexistent type/typeId combination: '.$p['type'].'/'.$p['typeId'], E_USER_NOTICE);
|
||||
unset($p);
|
||||
}
|
||||
else
|
||||
{
|
||||
$nFound += $p['count'];
|
||||
$p['date'] = date(Util::$dateFormatInternal, $p['date']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
public static function getComments(int $type, int $typeId) : array
|
||||
{
|
||||
|
||||
|
||||
306
includes/components/imageupload.class.php
Normal file
306
includes/components/imageupload.class.php
Normal file
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
abstract class ImageUpload
|
||||
{
|
||||
public const /* int */ MIME_UNK = 0;
|
||||
public const /* int */ MIME_JPG = 1;
|
||||
public const /* int */ MIME_PNG = 2;
|
||||
public const /* int */ MIME_WEBP = 3;
|
||||
|
||||
// scale img down if larger than crop screen
|
||||
private const /* int */ CROP_W = 488;
|
||||
private const /* int */ CROP_H = 325;
|
||||
|
||||
protected const /* int */ JPEG_QUALITY = 85;
|
||||
|
||||
protected static int $mimeType = self::MIME_UNK;
|
||||
protected static ?\GdImage $img = null;
|
||||
protected static string $fileName = '';
|
||||
protected static string $uploadFormField;
|
||||
protected static string $tmpPath;
|
||||
|
||||
public static bool $hasUpload = false;
|
||||
public static string $error = '';
|
||||
|
||||
public static function init() : bool
|
||||
{
|
||||
// active screenshot upload
|
||||
self::$hasUpload = $_FILES && !empty($_FILES[static::$uploadFormField]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function validateUpload() : bool
|
||||
{
|
||||
if (!self::$hasUpload)
|
||||
return false;
|
||||
|
||||
switch ($_FILES[static::$uploadFormField]['error']) // 0 is fine
|
||||
{
|
||||
case UPLOAD_ERR_INI_SIZE: // 1
|
||||
case UPLOAD_ERR_FORM_SIZE: // 2
|
||||
trigger_error('ImageUpload::validateUpload - the file exceeds the maximum size of '.ini_get('upload_max_filesize'), E_USER_WARNING);
|
||||
self::$error = Lang::main('intError');
|
||||
return false;
|
||||
case UPLOAD_ERR_PARTIAL: // 3
|
||||
trigger_error('ImageUpload::validateUpload - upload was interrupted', E_USER_WARNING);
|
||||
self::$error = Lang::screenshot('error', 'selectSS');
|
||||
return false;
|
||||
case UPLOAD_ERR_NO_FILE: // 4
|
||||
trigger_error('ImageUpload::validateUpload - no file was received', E_USER_WARNING);
|
||||
self::$error = Lang::screenshot('error', 'selectSS');
|
||||
return false;
|
||||
case UPLOAD_ERR_NO_TMP_DIR: // 6
|
||||
trigger_error('ImageUpload::validateUpload - temporary upload directory is not set', E_USER_ERROR);
|
||||
self::$error = Lang::main('intError');
|
||||
return false;
|
||||
case UPLOAD_ERR_CANT_WRITE: // 7
|
||||
trigger_error('ImageUpload::validateUpload - could not write temporary file to disk', E_USER_ERROR);
|
||||
self::$error = Lang::main('intError');
|
||||
return false;
|
||||
case UPLOAD_ERR_EXTENSION: // 8
|
||||
trigger_error('ImageUpload::validateUpload - a php extension stopped the file upload.', E_USER_ERROR);
|
||||
self::$error = Lang::main('intError');
|
||||
return false;
|
||||
}
|
||||
|
||||
self::$fileName = $_FILES[static::$uploadFormField]['tmp_name'];
|
||||
|
||||
// points to invalid file
|
||||
if (!is_uploaded_file(self::$fileName))
|
||||
{
|
||||
trigger_error('ImageUpload::validateUpload - uploaded file not in upload directory', E_USER_ERROR);
|
||||
self::$error = Lang::main('intError');
|
||||
self::$fileName = '';
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if file is an image
|
||||
if (!self::setMimeType())
|
||||
{
|
||||
self::$error = Lang::screenshot('error', 'unkFormat');
|
||||
self::$fileName = '';
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!self::$error)
|
||||
return true;
|
||||
|
||||
self::$fileName = '';
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function loadUpload() : bool
|
||||
{
|
||||
if (!self::$hasUpload)
|
||||
return false;
|
||||
|
||||
return match (self::$mimeType)
|
||||
{
|
||||
self::MIME_JPG => self::loadFromJPG(),
|
||||
self::MIME_PNG => self::loadFromPNG(),
|
||||
self::MIME_WEBP => self::loadFromWEBP(),
|
||||
default => false
|
||||
};
|
||||
}
|
||||
|
||||
public static function loadFile(string $path, string $nameBase) : bool
|
||||
{
|
||||
self::$fileName = sprintf($path, $nameBase);
|
||||
|
||||
if (!file_exists(self::$fileName))
|
||||
{
|
||||
trigger_error('ImageUpload::loadFile - image ('.self::$fileName.') not found', E_USER_ERROR);
|
||||
self::$fileName = '';
|
||||
return false;
|
||||
}
|
||||
|
||||
// we are using only jpg internally
|
||||
return self::loadFromJPG();
|
||||
}
|
||||
|
||||
public static function calcImgDimensions() : array
|
||||
{
|
||||
if (!self::$img)
|
||||
return [];
|
||||
|
||||
$oSize = $rSize = [imagesx(self::$img), imagesy(self::$img)];
|
||||
$rel = $oSize[0] / $oSize[1];
|
||||
|
||||
// check for oversize and refit to crop-screen
|
||||
if ($rel >= 1.5 && $oSize[0] > self::CROP_W)
|
||||
$rSize = [self::CROP_W, self::CROP_W / $rel];
|
||||
else if ($rel < 1.5 && $oSize[1] > self::CROP_H)
|
||||
$rSize = [self::CROP_H * $rel, self::CROP_H];
|
||||
|
||||
// r: resized; o: original
|
||||
// r: x <= 488 && y <= 325 while x proportional to y
|
||||
return array(
|
||||
'oWidth' => $oSize[0],
|
||||
'rWidth' => $rSize[0],
|
||||
'oHeight' => $oSize[1],
|
||||
'rHeight' => $rSize[1]
|
||||
);
|
||||
}
|
||||
|
||||
public static function tempSaveUpload(array $tmpNameParts, ?string &$uid) : bool
|
||||
{
|
||||
if (!self::$img || !$tmpNameParts)
|
||||
return false;
|
||||
|
||||
$uid = Util::createHash(16);
|
||||
|
||||
$nameBase = User::$username.'-'.implode('-', $tmpNameParts).'-'.$uid;
|
||||
|
||||
// use this image for work
|
||||
if (!self::writeImage(static::$tmpPath, $nameBase.'_original'))
|
||||
return false;
|
||||
|
||||
['oWidth' => $oW, 'rWidth' => $rW, 'oHeight' => $oH, 'rHeight' => $rH] = self::calcImgDimensions();
|
||||
|
||||
// use this image to display in cropper
|
||||
$res = imagecreatetruecolor($rW, $rH);
|
||||
if (!$res)
|
||||
{
|
||||
trigger_error('ImageUpload::tempSaveUpload - imagecreate failed', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!imagecopyresampled($res, self::$img, 0, 0, 0, 0, $rW, $rH, $oW, $oH))
|
||||
{
|
||||
trigger_error('ImageUpload::tempSaveUpload - imagecopy failed', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
self::$img = $res;
|
||||
unset($res);
|
||||
|
||||
return self::writeImage(static::$tmpPath, $nameBase);
|
||||
}
|
||||
|
||||
public static function cropImg(float $scaleX, float $scaleY, float $scaleW, float $scaleH) : bool
|
||||
{
|
||||
if (!self::$img)
|
||||
return false;
|
||||
|
||||
$x = (int)(imagesx(self::$img) * $scaleX);
|
||||
$y = (int)(imagesy(self::$img) * $scaleY);
|
||||
$w = (int)(imagesx(self::$img) * $scaleW);
|
||||
$h = (int)(imagesy(self::$img) * $scaleH);
|
||||
|
||||
$destImg = imagecreatetruecolor($w, $h);
|
||||
if (!$destImg)
|
||||
return false;
|
||||
|
||||
// imagefill($destImg, 0, 0, imagecolorallocate($destImg, 255, 255, 255));
|
||||
imagecopy($destImg, self::$img, 0, 0, $x, $y, $w, $h);
|
||||
|
||||
self::$img = $destImg;
|
||||
imagedestroy($destImg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function writeImage(string $path, string $file) : bool
|
||||
{
|
||||
if (!self::$img)
|
||||
return false;
|
||||
|
||||
if (imagejpeg(self::$img, sprintf($path, $file), self::JPEG_QUALITY))
|
||||
return true;
|
||||
|
||||
trigger_error('ImageUpload::writeImage - write failed', E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function setMimeType() : bool
|
||||
{
|
||||
if (!self::$hasUpload)
|
||||
return false;
|
||||
|
||||
$mime = (new \finfo(FILEINFO_MIME))?->file(self::$fileName);
|
||||
|
||||
if ($mime && stripos($mime, 'image/png') === 0)
|
||||
self::$mimeType = self::MIME_PNG;
|
||||
else if ($mime && stripos($mime, 'image/webp') === 0)
|
||||
self::$mimeType = self::MIME_WEBP;
|
||||
else if ($mime && preg_match('/^image\/jpe?g/i', $mime))
|
||||
self::$mimeType = self::MIME_JPG;
|
||||
else
|
||||
trigger_error('ImageUpload::setMimeType - uploaded file is of type: '.$mime, E_USER_WARNING);
|
||||
|
||||
return self::$mimeType != self::MIME_UNK;
|
||||
}
|
||||
|
||||
private static function loadFromPNG() : bool
|
||||
{
|
||||
// straight self::$img = imagecreatefrompng(self::$fileName); causes issues when transforming the alpha channel
|
||||
// this roundabout way through imagealphablending() avoids that
|
||||
$image = imagecreatefrompng(self::$fileName);
|
||||
if (!$image)
|
||||
return false;
|
||||
|
||||
self::$img = imagecreatetruecolor(imagesx($image), imagesy($image)) ?: null;
|
||||
if (!self::$img)
|
||||
return false;
|
||||
|
||||
imagealphablending(self::$img, true);
|
||||
imagecopy(self::$img, $image, 0, 0, 0, 0, imagesx($image), imagesy($image));
|
||||
imagedestroy($image);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function loadFromJPG() : bool
|
||||
{
|
||||
self::$img = imagecreatefromjpeg(self::$fileName) ?: null;
|
||||
|
||||
return !is_null(self::$img);
|
||||
}
|
||||
|
||||
private static function loadFromWEBP() : bool
|
||||
{
|
||||
$image = imagecreatefromwebp(self::$fileName);
|
||||
if (!$image)
|
||||
return false;
|
||||
|
||||
self::$img = imagecreatetruecolor(imagesx($image), imagesy($image)) ?: null;
|
||||
if (!self::$img)
|
||||
return false;
|
||||
|
||||
imagealphablending(self::$img, true);
|
||||
imagecopy(self::$img, $image, 0, 0, 0, 0, imagesx($image), imagesy($image));
|
||||
imagedestroy($image);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static function resizeAndWrite(int $limitW, int $limitH, string $path, string $file) : bool
|
||||
{
|
||||
$srcW = imagesx(self::$img);
|
||||
$srcH = imagesy(self::$img);
|
||||
|
||||
// already small enough
|
||||
if ($srcW < $limitW && $srcH < $limitH)
|
||||
return true;
|
||||
|
||||
$scale = min(1.0, $limitW / $srcW, $limitH / $srcH);
|
||||
$destW = $srcW * $scale;
|
||||
$destH = $srcH * $scale;
|
||||
|
||||
$destImg = imagecreatetruecolor($destW, $destH);
|
||||
|
||||
// imagefill($destImg, 0, 0, imagecolorallocate($destImg, 255, 255, 255));
|
||||
imagecopyresampled($destImg, self::$img, 0, 0, 0, 0, $destW, $destH, $srcW, $srcH);
|
||||
|
||||
return imagejpeg($destImg, sprintf($path, $file), self::JPEG_QUALITY);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -86,10 +86,7 @@ trait TrCommunityHelper
|
||||
$caption = trim(preg_replace('/\s{2,}/', ' ', $caption));
|
||||
|
||||
// shorten to fit db
|
||||
$caption = substr($caption, 0, 200);
|
||||
|
||||
// jsEscape just in case
|
||||
return Util::jsEscape($caption);
|
||||
return substr($caption, 0, 200);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
230
includes/components/screenshotmgr.class.php
Normal file
230
includes/components/screenshotmgr.class.php
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
class ScreenshotMgr extends ImageUpload
|
||||
{
|
||||
// config value
|
||||
public static int $MIN_SIZE; // 200
|
||||
// 4k resolution
|
||||
private const /* int */ MAX_W = 4096;
|
||||
private const /* int */ MAX_H = 2160;
|
||||
|
||||
// as expected by js - this also makes the CC-flags functionally exclusive with each other
|
||||
private const /* int */ STATUS_PENDING = 0;
|
||||
private const /* int */ STATUS_DELETED = 999;
|
||||
private const /* int */ STATUS_APPROVED = 100;
|
||||
private const /* int */ STATUS_STICKY = 105;
|
||||
|
||||
private const /* array */ DIMS_RESIZED = [772, 618];
|
||||
private const /* array */ DIMS_THUMB = [150, 150];
|
||||
|
||||
protected static string $uploadFormField = 'screenshotfile';
|
||||
protected static string $tmpPath = self::PATH_TEMP;
|
||||
|
||||
public const /* string */ PATH_TEMP = 'static/uploads/screenshots/temp/%s.jpg';
|
||||
public const /* string */ PATH_PENDING = 'static/uploads/screenshots/pending/%d.jpg';
|
||||
public const /* string */ PATH_THUMB = 'static/uploads/screenshots/thumb/%d.jpg';
|
||||
public const /* string */ PATH_RESIZED = 'static/uploads/screenshots/resized/%d.jpg';
|
||||
public const /* string */ PATH_NORMAL = 'static/uploads/screenshots/normal/%d.jpg';
|
||||
|
||||
public static function init() : bool
|
||||
{
|
||||
self::$MIN_SIZE = Cfg::get('SCREENSHOT_MIN_SIZE');
|
||||
|
||||
$dirErr = false;
|
||||
foreach (['TEMP', 'PENDING', 'THUMB', 'RESIZED', 'NORMAL'] as $p)
|
||||
{
|
||||
$path = constant('self::PATH_' . $p);
|
||||
if (!is_writable(substr($path, 0, strrpos($path, '/'))))
|
||||
{
|
||||
trigger_error('ScreenshotMgr::init - directory '.substr($path, 0, strrpos($path, '/')).' not writable', E_USER_ERROR);
|
||||
$dirErr = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($dirErr)
|
||||
return false;
|
||||
|
||||
return parent::init();
|
||||
}
|
||||
|
||||
public static function validateUpload() : bool
|
||||
{
|
||||
if (!parent::validateUpload())
|
||||
return false;
|
||||
|
||||
// invalid file
|
||||
if ($is = getimagesize(self::$fileName))
|
||||
{
|
||||
// image size out of bounds
|
||||
if ($is[0] < self::$MIN_SIZE || $is[1] < self::$MIN_SIZE)
|
||||
self::$error = Lang::screenshot('error', 'tooSmall');
|
||||
else if ($is[0] > self::MAX_W || $is[1] > self::MAX_H)
|
||||
self::$error = Lang::screenshot('error', 'selectSS');
|
||||
}
|
||||
else
|
||||
self::$error = Lang::screenshot('error', 'selectSS');
|
||||
|
||||
if (!self::$error)
|
||||
return true;
|
||||
|
||||
self::$fileName = '';
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function createThumbnail(string $fileName) : bool
|
||||
{
|
||||
if (!self::$img)
|
||||
return false;
|
||||
|
||||
return static::resizeAndWrite(self::DIMS_THUMB[0], self::DIMS_THUMB[1], self::PATH_THUMB, $fileName);
|
||||
}
|
||||
|
||||
public static function createResized(string $fileName) : bool
|
||||
{
|
||||
if (!self::$img)
|
||||
return false;
|
||||
|
||||
return self::resizeAndWrite(self::DIMS_RESIZED[0], self::DIMS_RESIZED[1], self::PATH_RESIZED, $fileName);
|
||||
}
|
||||
|
||||
|
||||
/*************/
|
||||
/* Admin Mgr */
|
||||
/*************/
|
||||
|
||||
public static function getScreenshots(int $type = 0, int $typeId = 0, $userId = 0, ?int &$nFound = 0) : array
|
||||
{
|
||||
$screenshots = DB::Aowow()->select(
|
||||
'SELECT s.`id`, a.`username` AS "user", s.`date`, s.`width`, s.`height`, s.`type`, s.`typeId`, s.`caption`, s.`status`, s.`status` AS "flags"
|
||||
FROM ?_screenshots s
|
||||
LEFT JOIN ?_account a ON s.`userIdOwner` = a.`id`
|
||||
WHERE
|
||||
{ s.`type` = ?d }
|
||||
{ AND s.`typeId` = ?d }
|
||||
{ s.`userIdOwner` = ?d }
|
||||
{ LIMIT ?d }',
|
||||
$userId ? DBSIMPLE_SKIP : $type,
|
||||
$userId ? DBSIMPLE_SKIP : $typeId,
|
||||
$userId ? $userId : DBSIMPLE_SKIP,
|
||||
$userId || $type ? DBSIMPLE_SKIP : 100
|
||||
);
|
||||
|
||||
$num = [];
|
||||
foreach ($screenshots as $s)
|
||||
{
|
||||
if (empty($num[$s['type']][$s['typeId']]))
|
||||
$num[$s['type']][$s['typeId']] = 1;
|
||||
else
|
||||
$num[$s['type']][$s['typeId']]++;
|
||||
}
|
||||
|
||||
$nFound = 0;
|
||||
|
||||
// format data to meet requirements of the js
|
||||
foreach ($screenshots as $i => &$s)
|
||||
{
|
||||
$nFound++;
|
||||
|
||||
$s['date'] = date(Util::$dateFormatInternal, $s['date']);
|
||||
|
||||
$s['name'] = "Screenshot #".$s['id']; // what should we REALLY name it?
|
||||
|
||||
if ($i > 0)
|
||||
$s['prev'] = $i - 1;
|
||||
|
||||
if (($i + 1) < count($screenshots))
|
||||
$s['next'] = $i + 1;
|
||||
|
||||
// order gives priority for 'status'
|
||||
if (!($s['flags'] & CC_FLAG_APPROVED))
|
||||
{
|
||||
$s['pending'] = 1;
|
||||
$s['status'] = self::STATUS_PENDING;
|
||||
}
|
||||
else
|
||||
$s['status'] = self::STATUS_APPROVED;
|
||||
|
||||
if ($s['flags'] & CC_FLAG_STICKY)
|
||||
{
|
||||
$s['sticky'] = 1;
|
||||
$s['status'] = self::STATUS_STICKY;
|
||||
}
|
||||
|
||||
if ($s['flags'] & CC_FLAG_DELETED)
|
||||
{
|
||||
$s['deleted'] = 1;
|
||||
$s['status'] = self::STATUS_DELETED;
|
||||
}
|
||||
|
||||
// something todo with massSelect .. am i doing this right?
|
||||
if ($num[$s['type']][$s['typeId']] == 1)
|
||||
$s['unique'] = 1;
|
||||
|
||||
if (!$s['user'])
|
||||
unset($s['user']);
|
||||
}
|
||||
|
||||
return $screenshots;
|
||||
}
|
||||
|
||||
public static function getPages(?bool $all, ?int &$nFound) : array
|
||||
{
|
||||
// i GUESS .. ss_getALL ? everything : pending
|
||||
$nFound = 0;
|
||||
$pages = DB::Aowow()->select(
|
||||
'SELECT s.`type`, s.`typeId`, COUNT(1) AS "count", MIN(s.`date`) AS "date"
|
||||
FROM ?_screenshots s
|
||||
{ WHERE (s.`status` & ?d) = 0 }
|
||||
GROUP BY s.`type`, s.`typeId`',
|
||||
$all ? DBSIMPLE_SKIP : CC_FLAG_APPROVED | CC_FLAG_DELETED
|
||||
);
|
||||
|
||||
if ($pages)
|
||||
{
|
||||
// limit to one actually existing type each
|
||||
foreach (array_unique(array_column($pages, 'type')) as $t)
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($pages as $row)
|
||||
if ($row['type'] == $t)
|
||||
$ids[] = $row['typeId'];
|
||||
|
||||
if (!$ids)
|
||||
continue;
|
||||
|
||||
$obj = Type::newList($t, [Cfg::get('SQL_LIMIT_NONE'), ['id', $ids]]);
|
||||
if (!$obj || $obj->error)
|
||||
continue;
|
||||
|
||||
foreach ($pages as &$p)
|
||||
if ($p['type'] == $t)
|
||||
if ($obj->getEntry($p['typeId']))
|
||||
$p['name'] = $obj->getField('name', true);
|
||||
}
|
||||
|
||||
foreach ($pages as &$p)
|
||||
{
|
||||
if (empty($p['name']))
|
||||
{
|
||||
trigger_error('ScreenshotMgr::getPages - screenshot linked to nonexistent type/typeId combination: '.$p['type'].'/'.$p['typeId'], E_USER_NOTICE);
|
||||
unset($p);
|
||||
}
|
||||
else
|
||||
{
|
||||
$nFound += $p['count'];
|
||||
$p['date'] = date(Util::$dateFormatInternal, $p['date']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -90,7 +90,7 @@ define('SITEREP_ACTION_DAILYVISIT', 2); // Daily visit
|
||||
define('SITEREP_ACTION_COMMENT', 3); // Posted comment
|
||||
define('SITEREP_ACTION_UPVOTED', 4); // Your comment was upvoted
|
||||
define('SITEREP_ACTION_DOWNVOTED', 5); // Your comment was downvoted
|
||||
define('SITEREP_ACTION_UPLOAD', 6); // Submitted screenshot (suggested video)
|
||||
define('SITEREP_ACTION_SUBMIT_SCREENSHOT', 6); // Submitted screenshot (suggested video)
|
||||
// Cast vote
|
||||
// Uploaded data
|
||||
define('SITEREP_ACTION_GOOD_REPORT', 9); // Report accepted
|
||||
|
||||
@@ -644,7 +644,8 @@ abstract class Util
|
||||
return $success;
|
||||
}
|
||||
|
||||
public static function createHash($length = 40) // just some random numbers for unsafe identification purpose
|
||||
// just some random numbers for unsafe identification purpose
|
||||
public static function createHash(int $length = 40) : string
|
||||
{
|
||||
static $seed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
$hash = '';
|
||||
@@ -725,12 +726,12 @@ abstract class Util
|
||||
$x['sourceB'] = $miscData['voterId'];
|
||||
$x['amount'] = $action == SITEREP_ACTION_UPVOTED ? Cfg::get('REP_REWARD_UPVOTED') : Cfg::get('REP_REWARD_DOWNVOTED');
|
||||
break;
|
||||
case SITEREP_ACTION_UPLOAD:
|
||||
case SITEREP_ACTION_SUBMIT_SCREENSHOT:
|
||||
if (empty($miscData['id']) || empty($miscData['what']))
|
||||
return false;
|
||||
|
||||
$x['sourceA'] = $miscData['id']; // screenshotId or videoId
|
||||
$x['sourceB'] = $miscData['what']; // screenshot:1 or video:NYD
|
||||
$x['sourceB'] = $miscData['what']; // screenshot:1
|
||||
$x['amount'] = Cfg::get('REP_REWARD_UPLOAD');
|
||||
break;
|
||||
case SITEREP_ACTION_GOOD_REPORT: // NYI
|
||||
|
||||
@@ -35,14 +35,6 @@ class AdminPage extends GenericPage
|
||||
{
|
||||
switch ($pageParam)
|
||||
{
|
||||
case 'screenshots':
|
||||
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_SCREENSHOT;
|
||||
$this->generator = 'handleScreenshots';
|
||||
$this->tpl = 'admin/screenshots';
|
||||
|
||||
array_push($this->path, 1, 5);
|
||||
$this->name = 'Screenshot Manager';
|
||||
break;
|
||||
case 'phpinfo':
|
||||
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_DEV;
|
||||
$this->generator = 'handlePhpInfo';
|
||||
@@ -202,44 +194,6 @@ class AdminPage extends GenericPage
|
||||
}
|
||||
}
|
||||
|
||||
private function handleScreenshots() : void
|
||||
{
|
||||
$this->addScript(
|
||||
[SC_JS_FILE, 'js/screenshot.js'],
|
||||
[SC_CSS_STRING, '.layout {margin: 0px 25px; max-width: inherit; min-width: 1200px; }'],
|
||||
[SC_CSS_STRING, '#highlightedRow { background-color: #322C1C; }']
|
||||
);
|
||||
|
||||
$ssGetAll = $this->_get['all'];
|
||||
$ssPages = [];
|
||||
$ssData = [];
|
||||
$nMatches = 0;
|
||||
|
||||
if ($this->_get['type'] && $this->_get['typeid'])
|
||||
{
|
||||
$ssData = CommunityContent::getScreenshotsForManager($this->_get['type'], $this->_get['typeid']);
|
||||
$nMatches = count($ssData);
|
||||
}
|
||||
else if ($this->_get['user'])
|
||||
{
|
||||
if (mb_strlen($this->_get['user']) >= 3)
|
||||
{
|
||||
if ($uId = DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE LOWER(`username`) = LOWER(?)', $this->_get['user']))
|
||||
{
|
||||
$ssData = CommunityContent::getScreenshotsForManager(0, 0, $uId);
|
||||
$nMatches = count($ssData);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
$ssPages = CommunityContent::getScreenshotPagesForManager($ssGetAll, $nMatches);
|
||||
|
||||
$this->getAll = $ssGetAll;
|
||||
$this->ssPages = $ssPages;
|
||||
$this->ssData = $ssData;
|
||||
$this->ssNFound = $nMatches; // ssm_numPagesFound
|
||||
}
|
||||
|
||||
private function handleWeightPresets() : void
|
||||
{
|
||||
$this->addScript(
|
||||
|
||||
@@ -1,396 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Aowow;
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
|
||||
// filename: Username-type-typeId-<hash>[_original].jpg
|
||||
|
||||
class ScreenshotPage extends GenericPage
|
||||
{
|
||||
const MAX_W = 488;
|
||||
const MAX_H = 325;
|
||||
|
||||
protected $infobox = [];
|
||||
protected $cropper = [];
|
||||
protected $extraHTML = null;
|
||||
|
||||
protected $tpl = 'screenshot';
|
||||
protected $scripts = [[SC_JS_FILE, 'js/Cropper.js'], [SC_CSS_FILE, 'css/Cropper.css']];
|
||||
protected $reqAuth = true;
|
||||
protected $tabId = 0;
|
||||
|
||||
private $tmpPath = 'static/uploads/temp/';
|
||||
private $pendingPath = 'static/uploads/screenshots/pending/';
|
||||
private $destination = null;
|
||||
private $minSize = 200;
|
||||
private $command = '';
|
||||
|
||||
protected $validCats = ['add', 'crop', 'complete', 'thankyou'];
|
||||
protected $destType = 0;
|
||||
protected $destTypeId = 0;
|
||||
protected $imgHash = '';
|
||||
|
||||
protected $_post = array(
|
||||
'coords' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\ScreenshotPage::checkCoords'],
|
||||
'screenshotalt' => ['filter' => FILTER_CALLBACK, 'options' => 'Aowow\GenericPage::checkTextBlob']
|
||||
);
|
||||
|
||||
public function __construct($pageCall, $pageParam)
|
||||
{
|
||||
parent::__construct($pageCall, $pageParam);
|
||||
|
||||
$this->name = Lang::screenshot('submission');
|
||||
$this->command = $pageParam;
|
||||
|
||||
if ($ms = Cfg::get('SCREENSHOT_MIN_SIZE'))
|
||||
$this->minSize = abs($ms);
|
||||
else
|
||||
trigger_error('config error: Invalid value for minimum screenshot dimensions. Value forced to '.$this->minSize, E_USER_WARNING);
|
||||
|
||||
// get screenshot destination
|
||||
// target delivered as screenshot=<command>&<type>.<typeId>.<hash:16> (hash is optional)
|
||||
if (preg_match('/^screenshot=\w+&(-?\d+)\.(-?\d+)(\.(\w{16}))?$/i', $_SERVER['QUERY_STRING'] ?? '', $m))
|
||||
{
|
||||
// no such type or this type cannot receive screenshots
|
||||
if (!Type::checkClassAttrib($m[1], 'contribute', CONTRIBUTE_SS))
|
||||
$this->error();
|
||||
|
||||
$this->destination = Type::newList($m[1], [['id', intVal($m[2])]]);
|
||||
|
||||
// no such typeId
|
||||
if (!$this->destination || $this->destination->error)
|
||||
$this->error();
|
||||
|
||||
// only accept/expect hash for crop & complete
|
||||
if (empty($m[4]) && ($this->command == 'crop' || $this->command == 'complete'))
|
||||
$this->error();
|
||||
else if (!empty($m[4]) && ($this->command == 'add' || $this->command == 'thankyou'))
|
||||
$this->error();
|
||||
else if (!empty($m[4]))
|
||||
$this->imgHash = $m[4];
|
||||
|
||||
$this->destType = intVal($m[1]);
|
||||
$this->destTypeId = intVal($m[2]);
|
||||
}
|
||||
else
|
||||
$this->error();
|
||||
}
|
||||
|
||||
protected function generateContent() : void
|
||||
{
|
||||
switch ($this->command)
|
||||
{
|
||||
case 'add':
|
||||
if ($this->handleAdd())
|
||||
header('Location: ?screenshot=crop&'.$this->destType.'.'.$this->destTypeId.'.'.$this->imgHash, true, 302);
|
||||
else
|
||||
header('Location: ?'.Type::getFileString($this->destType).'='.$this->destTypeId.'#submit-a-screenshot', true, 302);
|
||||
die();
|
||||
case 'crop':
|
||||
if (!$this->handleCrop())
|
||||
header('Location: ?'.Type::getFileString($this->destType).'='.$this->destTypeId.'#submit-a-screenshot', true, 302);
|
||||
break;
|
||||
case 'complete':
|
||||
if ($_ = $this->handleComplete())
|
||||
$this->notFound(Lang::main('nfPageTitle'), sprintf(Lang::main('intError2'), '#'.$_));
|
||||
else
|
||||
header('Location: ?screenshot=thankyou&'.$this->destType.'.'.$this->destTypeId, true, 302);
|
||||
die();
|
||||
case 'thankyou':
|
||||
$this->tpl = 'list-page-generic';
|
||||
$this->handleThankyou();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************/
|
||||
/* command handler */
|
||||
/*******************/
|
||||
|
||||
private function handleAdd() : bool
|
||||
{
|
||||
$this->imgHash = Util::createHash(16);
|
||||
|
||||
if (!is_writable($this->tmpPath))
|
||||
{
|
||||
trigger_error('ScreenshotPage::handleAdd - temp upload directory not writable', E_USER_ERROR);
|
||||
$_SESSION['error']['ss'] = Lang::main('intError');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!User::canUploadScreenshot())
|
||||
{
|
||||
$_SESSION['error']['ss'] = Lang::screenshot('error', 'notAllowed');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($_ = $this->validateScreenshot($isPNG))
|
||||
{
|
||||
$_SESSION['error']['ss'] = $_;
|
||||
return false;
|
||||
}
|
||||
|
||||
$im = $isPNG ? $this->loadFromPNG() : $this->loadFromJPG();
|
||||
if (!$im)
|
||||
{
|
||||
$_SESSION['error']['ss'] = Lang::main('intError');
|
||||
return false;
|
||||
}
|
||||
|
||||
$oSize = $rSize = [imagesx($im), imagesy($im)];
|
||||
$rel = $oSize[0] / $oSize[1];
|
||||
|
||||
// check for oversize and refit to crop-screen
|
||||
if ($rel >= 1.5 && $oSize[0] > self::MAX_W)
|
||||
$rSize = [self::MAX_W, self::MAX_W / $rel];
|
||||
else if ($rel < 1.5 && $oSize[1] > self::MAX_H)
|
||||
$rSize = [self::MAX_H * $rel, self::MAX_H];
|
||||
|
||||
$success = true;
|
||||
|
||||
// use this image for work
|
||||
if (!$this->writeImage($im, $oSize[0], $oSize[1], $this->ssName().'_original'))
|
||||
$success = false;
|
||||
|
||||
// use this image to display
|
||||
if (!$this->writeImage($im, $rSize[0], $rSize[1], $this->ssName()))
|
||||
$success = false;
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
private function handleCrop() : bool
|
||||
{
|
||||
$tmpFile = $this->tmpPath.$this->ssName().'_original.jpg';
|
||||
|
||||
if (!file_exists($tmpFile))
|
||||
{
|
||||
trigger_error('ScreenshotPage::handleCrop - temp image ('.$tmpFile.') not found', E_USER_ERROR);
|
||||
$_SESSION['error']['ss'] = Lang::main('intError');
|
||||
return false;
|
||||
}
|
||||
|
||||
$im = imagecreatefromjpeg($tmpFile);
|
||||
if (!$im)
|
||||
{
|
||||
trigger_error('ScreenshotPage::handleCrop - imagecreate failed ('.$tmpFile.')', E_USER_ERROR);
|
||||
$_SESSION['error']['ss'] = Lang::main('intError');
|
||||
return false;
|
||||
}
|
||||
|
||||
$oSize = $rSize = [imagesx($im), imagesy($im)];
|
||||
$rel = $oSize[0] / $oSize[1];
|
||||
|
||||
// check for oversize and refit to crop-screen
|
||||
if ($rel >= 1.5 && $oSize[0] > self::MAX_W)
|
||||
$rSize = [self::MAX_W, self::MAX_W / $rel];
|
||||
else if ($rel < 1.5 && $oSize[1] > self::MAX_H)
|
||||
$rSize = [self::MAX_H * $rel, self::MAX_H];
|
||||
|
||||
// r: resized; o: original
|
||||
// r: x <= 488 && y <= 325 while x proportional to y
|
||||
// mincrop is optional and specifies the minimum resulting image size
|
||||
$this->cropper = [
|
||||
'url' => Cfg::get('STATIC_URL').'/uploads/temp/'.$this->ssName().'.jpg',
|
||||
'parent' => 'ss-container',
|
||||
'oWidth' => $oSize[0],
|
||||
'rWidth' => $rSize[0],
|
||||
'oHeight' => $oSize[1],
|
||||
'rHeight' => $rSize[1],
|
||||
'type' => $this->destType, // only used to check against NPC: 15384 [OLDWorld Trigger (DO NOT DELETE)]
|
||||
'typeId' => $this->destTypeId // i guess this was used to upload arbitrary imagery
|
||||
];
|
||||
|
||||
// minimum dimensions
|
||||
if (!User::isInGroup(U_GROUP_STAFF))
|
||||
$this->cropper['minCrop'] = $this->minSize;
|
||||
|
||||
// target
|
||||
$this->infobox = sprintf(Lang::screenshot('displayOn'), Lang::typeName($this->destType), Type::getFileString($this->destType), $this->destTypeId);
|
||||
$this->extendGlobalIds($this->destType, $this->destTypeId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function handleComplete() : int
|
||||
{
|
||||
// check tmp file
|
||||
$fullPath = $this->tmpPath.$this->ssName().'_original.jpg';
|
||||
if (!file_exists($fullPath))
|
||||
return 1;
|
||||
|
||||
// check post data
|
||||
if (!$this->_post['coords'])
|
||||
return 2;
|
||||
|
||||
$dims = $this->_post['coords'];
|
||||
if (count($dims) != 4)
|
||||
return 3;
|
||||
|
||||
Util::checkNumeric($dims, NUM_CAST_FLOAT);
|
||||
|
||||
// actually crop the image
|
||||
$srcImg = imagecreatefromjpeg($fullPath);
|
||||
|
||||
$x = (int)(imagesx($srcImg) * $dims[0]);
|
||||
$y = (int)(imagesy($srcImg) * $dims[1]);
|
||||
$w = (int)(imagesx($srcImg) * $dims[2]);
|
||||
$h = (int)(imagesy($srcImg) * $dims[3]);
|
||||
|
||||
$destImg = imagecreatetruecolor($w, $h);
|
||||
|
||||
imagefill($destImg, 0, 0, imagecolorallocate($destImg, 255, 255, 255));
|
||||
imagecopy($destImg, $srcImg, 0, 0, $x, $y, $w, $h);
|
||||
imagedestroy($srcImg);
|
||||
|
||||
// write to db
|
||||
$newId = DB::Aowow()->query(
|
||||
'INSERT INTO ?_screenshots (`type`, `typeId`, `userIdOwner`, `date`, `width`, `height`, `caption`, `status`) VALUES (?d, ?d, ?d, UNIX_TIMESTAMP(), ?d, ?d, ?, 0)',
|
||||
$this->destType, $this->destTypeId,
|
||||
User::$id,
|
||||
$w, $h,
|
||||
$this->_post['screenshotalt'] ?? ''
|
||||
);
|
||||
|
||||
// write to file
|
||||
if (is_int($newId)) // 0 is valid, NULL or FALSE is not
|
||||
imagejpeg($destImg, $this->pendingPath.$newId.'.jpg', 100);
|
||||
else
|
||||
return 6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function handleThankyou() : void
|
||||
{
|
||||
$this->extraHTML = Lang::screenshot('thanks', 'contrib').'<br><br>';
|
||||
$this->extraHTML .= sprintf(Lang::screenshot('thanks', 'goBack'), Type::getFileString($this->destType), $this->destTypeId)."<br /><br />\n";
|
||||
$this->extraHTML .= '<i>'.Lang::screenshot('thanks', 'note').'</i>';
|
||||
}
|
||||
|
||||
|
||||
/**********/
|
||||
/* helper */
|
||||
/**********/
|
||||
|
||||
private function loadFromPNG() // : resource/gd
|
||||
{
|
||||
$image = imagecreatefrompng($_FILES['screenshotfile']['tmp_name']);
|
||||
$bg = imagecreatetruecolor(imagesx($image), imagesy($image));
|
||||
|
||||
imagefill($bg, 0, 0, imagecolorallocate($bg, 255, 255, 255));
|
||||
imagealphablending($bg, true);
|
||||
imagecopy($bg, $image, 0, 0, 0, 0, imagesx($image), imagesy($image));
|
||||
imagedestroy($image);
|
||||
|
||||
return $bg;
|
||||
}
|
||||
|
||||
private function loadFromJPG() // : resource/gd
|
||||
{
|
||||
return imagecreatefromjpeg($_FILES['screenshotfile']['tmp_name']);
|
||||
}
|
||||
|
||||
private function writeImage(/*resource/gd*/ $im, int $w, int $h, string $file) : bool
|
||||
{
|
||||
if ($res = imagecreatetruecolor($w, $h))
|
||||
{
|
||||
if (imagecopyresampled($res, $im, 0, 0, 0, 0, $w, $h, imagesx($im), imagesy($im)))
|
||||
{
|
||||
if (imagejpeg($res, $this->tmpPath.$file.'.jpg', 100))
|
||||
return true;
|
||||
else
|
||||
trigger_error('ScreenshotPage::writeImage - write failed', E_USER_ERROR);
|
||||
}
|
||||
else
|
||||
trigger_error('ScreenshotPage::writeImage - imagecopy failed', E_USER_ERROR);
|
||||
}
|
||||
else
|
||||
trigger_error('ScreenshotPage::writeImage - imagecreate failed', E_USER_ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function validateScreenshot(?bool &$isPNG = false) : string
|
||||
{
|
||||
// no upload happened or some error occured
|
||||
if (!$_FILES || empty($_FILES['screenshotfile']))
|
||||
return Lang::screenshot('error', 'selectSS');
|
||||
|
||||
switch ($_FILES['screenshotfile']['error']) // 0 is fine
|
||||
{
|
||||
case UPLOAD_ERR_INI_SIZE: // 1
|
||||
case UPLOAD_ERR_FORM_SIZE: // 2
|
||||
trigger_error('validateScreenshot - the file exceeds the maximum size of '.ini_get('upload_max_filesize'), E_USER_WARNING);
|
||||
return Lang::screenshot('error', 'selectSS');
|
||||
case UPLOAD_ERR_PARTIAL: // 3
|
||||
trigger_error('validateScreenshot - upload was interrupted', E_USER_WARNING);
|
||||
return Lang::screenshot('error', 'selectSS');
|
||||
case UPLOAD_ERR_NO_FILE: // 4
|
||||
trigger_error('validateScreenshot - no file was received', E_USER_WARNING);
|
||||
return Lang::screenshot('error', 'selectSS');
|
||||
case UPLOAD_ERR_NO_TMP_DIR: // 6
|
||||
trigger_error('validateScreenshot - temporary upload directory is not set', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
case UPLOAD_ERR_CANT_WRITE: // 7
|
||||
trigger_error('validateScreenshot - could not write temporary file to disk', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
case UPLOAD_ERR_EXTENSION: // 8
|
||||
trigger_error('validateScreenshot - a php extension stopped the file upload.', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
// points to invalid file (hack attempt)
|
||||
if (!is_uploaded_file($_FILES['screenshotfile']['tmp_name']))
|
||||
{
|
||||
trigger_error('validateScreenshot - uploaded file not in upload directory', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
// check if file is an image; allow jpeg, png
|
||||
$finfo = new \finfo(FILEINFO_MIME); // fileInfo appends charset information and other nonsense
|
||||
$mime = $finfo->file($_FILES['screenshotfile']['tmp_name']);
|
||||
if (preg_match('/^image\/(png|jpe?g)/i', $mime, $m))
|
||||
$isPNG = $m[0] == 'image/png';
|
||||
else
|
||||
return Lang::screenshot('error', 'unkFormat');
|
||||
|
||||
// invalid file
|
||||
$is = getimagesize($_FILES['screenshotfile']['tmp_name']);
|
||||
if (!$is)
|
||||
return Lang::screenshot('error', 'selectSS');
|
||||
|
||||
// size-missmatch: 4k UHD upper limit; 150px lower limit
|
||||
if ($is[0] < $this->minSize || $is[1] < $this->minSize)
|
||||
return Lang::screenshot('error', 'tooSmall');
|
||||
else if ($is[0] > 3840 || $is[1] > 2160)
|
||||
return Lang::screenshot('error', 'selectSS');
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function ssName() : string
|
||||
{
|
||||
return $this->imgHash ? User::$username.'-'.$this->destType.'-'.$this->destTypeId.'-'.$this->imgHash : '';
|
||||
}
|
||||
|
||||
protected static function checkCoords(string $val) : array
|
||||
{
|
||||
if (preg_match('/^[01]\.[0-9]{3}(,[01]\.[0-9]{3}){3}$/', $val))
|
||||
return explode(',', $val);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function generatePath() : void { }
|
||||
protected function generateTitle() : void
|
||||
{
|
||||
array_unshift($this->title, Lang::screenshot('submission'));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
3
setup/updates/1758578400_05.sql
Normal file
3
setup/updates/1758578400_05.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
DELETE FROM `aowow_config` WHERE `key` = 'screenshot_min_size';
|
||||
INSERT INTO `aowow_config` (`key`, `value`, `default`, `cat`, `flags`, `comment`) VALUES
|
||||
('screenshot_min_size', 200, 200, 1, 1153, "minimum dimensions of uploaded screenshots in px (yes, it's square, no it cant go below 200)");
|
||||
2
setup/updates/1758578400_06.sql
Normal file
2
setup/updates/1758578400_06.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `aowow_screenshots`
|
||||
MODIFY COLUMN `caption` varchar(200) DEFAULT NULL;
|
||||
@@ -322,4 +322,4 @@ Cropper.mouseMove = function (ev) {
|
||||
|
||||
this.moveSelection(left, top, width - left, height - top);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -47,19 +47,16 @@ function ss_Refresh(openNext, type, typeId) {
|
||||
|
||||
ssm_UpdatePages();
|
||||
|
||||
if (openNext) {
|
||||
if (openNext)
|
||||
ss_Manage($WH.ge('pages-container').firstChild.firstChild, ssm_screenshotPages[0].type, ssm_screenshotPages[0].typeId, true);
|
||||
}
|
||||
else if (type && typeId) {
|
||||
else if (type && typeId)
|
||||
ss_Manage(null, type, typeId, true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$WH.ee($WH.ge('show-all-pages'));
|
||||
$WH.ge('pages-container').innerHTML = 'NO SCREENZSHOT NEEDS 2 BE APPRVED NOW KTHX. :)';
|
||||
if (type && typeId) {
|
||||
if (type && typeId)
|
||||
ss_Manage(null, type, typeId, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -73,11 +70,9 @@ function ss_Manage(_this, type, typeId, openNext) {
|
||||
eval(xhr.responseText);
|
||||
ssm_numPending = 0;
|
||||
|
||||
for (var i in ssm_screenshotData) {
|
||||
if (ssm_screenshotData[i].pending) {
|
||||
for (var i in ssm_screenshotData)
|
||||
if (ssm_screenshotData[i].pending)
|
||||
ssm_numPending++;
|
||||
}
|
||||
}
|
||||
|
||||
var nRows = ssm_screenshotData.length;
|
||||
$WH.ge('screenshotTotal').innerHTML = nRows + ' total' + (nRows == 100 ? ' (limit reached)' : '');
|
||||
@@ -85,15 +80,13 @@ function ss_Manage(_this, type, typeId, openNext) {
|
||||
ssm_UpdateList(openNext);
|
||||
ssm_UpdateMassLinks();
|
||||
|
||||
if (ss_managedRow != null) {
|
||||
if (ss_managedRow != null)
|
||||
ss_ColorizeRow('transparent');
|
||||
}
|
||||
|
||||
ss_managedRow = _this;
|
||||
|
||||
if (ss_managedRow != null) {
|
||||
if (ss_managedRow != null)
|
||||
ss_ColorizeRow('#282828');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -120,13 +113,15 @@ function ss_ManageUser() {
|
||||
method: 'get',
|
||||
onSuccess: function (xhr) {
|
||||
eval(xhr.responseText);
|
||||
|
||||
var nRows = ssm_screenshotData.length;
|
||||
$WH.ge('screenshotTotal').innerHTML = nRows + ' total' + (nRows == 100 ? ' (limit reached)' : '');
|
||||
|
||||
ssm_UpdateList();
|
||||
ssm_UpdateMassLinks();
|
||||
if (ss_managedRow != null) {
|
||||
|
||||
if (ss_managedRow != null)
|
||||
ss_ColorizeRow('transparent');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -134,33 +129,28 @@ function ss_ManageUser() {
|
||||
}
|
||||
|
||||
function ss_ColorizeRow(color) {
|
||||
for (var i = 0; i < ss_managedRow.childNodes.length; ++i) {
|
||||
for (var i = 0; i < ss_managedRow.childNodes.length; ++i)
|
||||
ss_managedRow.childNodes[i].style.backgroundColor = color;
|
||||
}
|
||||
}
|
||||
|
||||
function ssm_GetScreenshot(id) {
|
||||
for (var i in ssm_screenshotData) {
|
||||
if (ssm_screenshotData[i].id == id) {
|
||||
for (var i in ssm_screenshotData)
|
||||
if (ssm_screenshotData[i].id == id)
|
||||
return ssm_screenshotData[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function ssm_View(row, id) {
|
||||
if (ssm_ViewedRow != null) {
|
||||
if (ssm_ViewedRow != null)
|
||||
ssm_ColorizeRow('transparent');
|
||||
}
|
||||
|
||||
ssm_ViewedRow = row;
|
||||
ssm_ColorizeRow('#282828');
|
||||
|
||||
var screenshot = ssm_GetScreenshot(id);
|
||||
if (screenshot != null) {
|
||||
if (screenshot != null)
|
||||
ScreenshotManager.show(screenshot);
|
||||
}
|
||||
}
|
||||
|
||||
function ssm_ColorizeRow(color) {
|
||||
@@ -248,23 +238,20 @@ function ssm_UpdatePages(UNUSED) {
|
||||
}
|
||||
|
||||
function ssm_UpdateList(openNext) {
|
||||
var tsl = $WH.ge('theScreenshotsList');
|
||||
var tbl = $WH.ge('theScreenshotsList');
|
||||
var tBody = false;
|
||||
var i = 1;
|
||||
|
||||
while (tsl.childNodes.length > i) {
|
||||
if (tsl.childNodes[i].nodeName == 'TR' && tBody) {
|
||||
$WH.de(tsl.childNodes[i]);
|
||||
}
|
||||
else if (tsl.childNodes[i].nodeName == 'TR') {
|
||||
while (tbl.childNodes.length > i) {
|
||||
if (tbl.childNodes[i].nodeName == 'TR' && tBody)
|
||||
$WH.de(tbl.childNodes[i]);
|
||||
else if (tbl.childNodes[i].nodeName == 'TR')
|
||||
tBody = true;
|
||||
}
|
||||
else {
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
var now = new Date();
|
||||
var now = new Date();
|
||||
var ssId = 0;
|
||||
for (var i in ssm_screenshotData) {
|
||||
var screenshot = ssm_screenshotData[i];
|
||||
@@ -299,15 +286,13 @@ function ssm_UpdateList(openNext) {
|
||||
var a = $WH.ce('a');
|
||||
a.href = '?' + g_types[screenshot.type] + '=' + screenshot.typeId + '#screenshots:id=' + screenshot.id;
|
||||
a.target = '_blank';
|
||||
a.onclick = function (e) {
|
||||
$WH.sp(e);
|
||||
};
|
||||
a.onclick = function (e) { $WH.sp(e); };
|
||||
$WH.ae(a, $WH.ct(screenshot.id));
|
||||
$WH.ae(td, a);
|
||||
}
|
||||
else {
|
||||
else
|
||||
$WH.ae(td, $WH.ct(screenshot.id));
|
||||
}
|
||||
|
||||
$WH.ae(tr, td);
|
||||
|
||||
td = $WH.ce('td');
|
||||
@@ -336,9 +321,9 @@ function ssm_UpdateList(openNext) {
|
||||
|
||||
var a = $WH.ce('a');
|
||||
a.href = 'javascript:;';
|
||||
a.onclick = function (id, e) {
|
||||
a.onclick = function (ss, e) {
|
||||
$WH.sp(e);
|
||||
(ssm_ShowEdit.bind(this, id))()
|
||||
(ssm_ShowEdit.bind(this, ss))();
|
||||
}.bind(a, screenshot);
|
||||
$WH.ae(a, $WH.ct('Edit'));
|
||||
$WH.ae(sp, a);
|
||||
@@ -346,9 +331,9 @@ function ssm_UpdateList(openNext) {
|
||||
|
||||
a = $WH.ce('a');
|
||||
a.href = 'javascript:;';
|
||||
a.onclick = function (id, e) {
|
||||
a.onclick = function (ss, e) {
|
||||
$WH.sp(e);
|
||||
(ssm_Clear.bind(this, id))()
|
||||
(ssm_Clear.bind(this, ss))();
|
||||
}.bind(a, screenshot);
|
||||
$WH.ae(a, $WH.ct('Clear'));
|
||||
$WH.ae(sp, a);
|
||||
@@ -364,9 +349,7 @@ function ssm_UpdateList(openNext) {
|
||||
a = $WH.ce('a');
|
||||
a.href = '?user=' + screenshot.user;
|
||||
a.target = '_blank';
|
||||
a.onclick = function (e) {
|
||||
$WH.sp(e);
|
||||
};
|
||||
a.onclick = function (e) { $WH.sp(e); };
|
||||
$WH.ae(a, $WH.ct(screenshot.user));
|
||||
$WH.ae(td, a);
|
||||
$WH.ae(tr, td);
|
||||
@@ -384,6 +367,7 @@ function ssm_UpdateList(openNext) {
|
||||
(ssm_UpdateMassLinks.bind(this))();
|
||||
}.bind(cb);
|
||||
$WH.ae(td, cb);
|
||||
|
||||
$WH.ae(td, $WH.ct(' '));
|
||||
|
||||
if (screenshot.status != 999) {
|
||||
@@ -392,23 +376,21 @@ function ssm_UpdateList(openNext) {
|
||||
return false;
|
||||
}.bind(tr, screenshot.id);
|
||||
|
||||
if (screenshot.id == ssId && openNext) {
|
||||
if (screenshot.id == ssId && openNext)
|
||||
ssm_View(tr, screenshot.id);
|
||||
}
|
||||
|
||||
if (screenshot.pending) {
|
||||
a = $WH.ce('a');
|
||||
a.href = 'javascript:;';
|
||||
a.onclick = function (e) {
|
||||
$WH.sp(e);
|
||||
(ssm_Approve.bind(this, false))()
|
||||
(ssm_Approve.bind(this, false))();
|
||||
}.bind(screenshot);
|
||||
$WH.ae(a, $WH.ct('Approve'));
|
||||
$WH.ae(td, a);
|
||||
}
|
||||
else {
|
||||
else
|
||||
$WH.ae(td, $WH.ct('Approve'));
|
||||
}
|
||||
|
||||
$WH.ae(td, makePipe());
|
||||
|
||||
@@ -422,9 +404,9 @@ function ssm_UpdateList(openNext) {
|
||||
$WH.ae(a, $WH.ct('Make sticky'));
|
||||
$WH.ae(td, a);
|
||||
}
|
||||
else {
|
||||
else
|
||||
$WH.ae(td, $WH.ct('Make sticky'));
|
||||
}
|
||||
|
||||
$WH.ae(td, makePipe());
|
||||
|
||||
a = $WH.ce('a');
|
||||
@@ -435,6 +417,7 @@ function ssm_UpdateList(openNext) {
|
||||
}.bind(screenshot);
|
||||
$WH.ae(a, $WH.ct('Delete'));
|
||||
$WH.ae(td, a);
|
||||
|
||||
$WH.ae(td, makePipe());
|
||||
|
||||
a = $WH.ce('a');
|
||||
@@ -449,24 +432,24 @@ function ssm_UpdateList(openNext) {
|
||||
}
|
||||
|
||||
$WH.ae(tr, td);
|
||||
$WH.ae(tsl, tr);
|
||||
$WH.ae(tbl, tr);
|
||||
}
|
||||
}
|
||||
|
||||
function ssm_UpdateMassLinks() {
|
||||
var buff = '';
|
||||
var idBuff = '';
|
||||
var i = 0;
|
||||
var tSL = $WH.ge('theScreenshotsList');
|
||||
var inp = $WH.gE(tSL, 'input');
|
||||
|
||||
$WH.array_walk(inp, function (x) {
|
||||
if (x.checked) {
|
||||
buff += x.value + ',';
|
||||
idBuff += x.value + ',';
|
||||
++i;
|
||||
}
|
||||
});
|
||||
|
||||
buff = $WH.rtrim(buff, ',');
|
||||
idBuff = $WH.rtrim(idBuff, ',');
|
||||
|
||||
var selCnt = $WH.ge('withselected');
|
||||
if (i > 0) {
|
||||
@@ -477,23 +460,22 @@ function ssm_UpdateMassLinks() {
|
||||
var b = $WH.ge('massdelete');
|
||||
var a = $WH.ge('masssticky');
|
||||
|
||||
c.href = '?admin=screenshots&action=approve&id=' + buff;
|
||||
c.href = '?admin=screenshots&action=approve&id=' + idBuff;
|
||||
c.onclick = ssm_ConfirmMassApprove;
|
||||
|
||||
b.href = '?admin=screenshots&action=delete&id=' + buff;
|
||||
b.href = '?admin=screenshots&action=delete&id=' + idBuff;
|
||||
b.onclick = ssm_ConfirmMassDelete;
|
||||
|
||||
a.href = '?admin=screenshots&action=sticky&id=' + buff;
|
||||
a.href = '?admin=screenshots&action=sticky&id=' + idBuff;
|
||||
a.onclick = ssm_ConfirmMassSticky;
|
||||
}
|
||||
else {
|
||||
else
|
||||
selCnt.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function ssm_MassSelect(action) {
|
||||
var tSL = $WH.ge('theScreenshotsList');
|
||||
var inp = $WH.gE(tSL, 'input');
|
||||
var tbl = $WH.ge('theScreenshotsList');
|
||||
var inp = $WH.gE(tbl, 'input');
|
||||
|
||||
switch (parseInt(action)) {
|
||||
case 1:
|
||||
@@ -527,12 +509,10 @@ function ssm_MassSelect(action) {
|
||||
function ssm_ShowEdit(screenshot, isAlt) {
|
||||
var node;
|
||||
|
||||
if (isAlt) {
|
||||
node = $WH.ge('alt2-' + screenshot.id)
|
||||
}
|
||||
else {
|
||||
node = $WH.ge('alt-' + screenshot.id)
|
||||
}
|
||||
if (isAlt)
|
||||
node = $WH.ge('alt2-' + screenshot.id);
|
||||
else
|
||||
node = $WH.ge('alt-' + screenshot.id);
|
||||
|
||||
var sp = $WH.gE(node, 'span')[0];
|
||||
var div = $WH.ce('div');
|
||||
@@ -548,28 +528,27 @@ function ssm_ShowEdit(screenshot, isAlt) {
|
||||
var btn = $WH.ce('input');
|
||||
btn.type = 'button';
|
||||
btn.value = 'Update';
|
||||
btn.onclick = function (i, j, k) {
|
||||
if (!j) {
|
||||
$WH.sp(k);
|
||||
}
|
||||
btn.onclick = function (ss, isAlt, e) {
|
||||
if (!isAlt)
|
||||
$WH.sp(e);
|
||||
|
||||
(ssm_Edit.bind(this, i, j))();
|
||||
(ssm_Edit.bind(this, ss, isAlt))();
|
||||
}.bind(btn, screenshot, isAlt);
|
||||
div.appendChild(btn);
|
||||
|
||||
var c = $WH.ce('span');
|
||||
c.appendChild($WH.ct(' '));
|
||||
div.appendChild(c);
|
||||
var sp2 = $WH.ce('span');
|
||||
sp2.appendChild($WH.ct(' '));
|
||||
div.appendChild(sp2);
|
||||
|
||||
btn = $WH.ce('input');
|
||||
btn.type = 'button';
|
||||
btn.value = 'Cancel';
|
||||
btn.onclick = function (i, j, k) {
|
||||
if (!j) {
|
||||
$WH.sp(k);
|
||||
btn.onclick = function (ss, isAlt, e) {
|
||||
if (!isAlt) {
|
||||
$WH.sp(e);
|
||||
}
|
||||
|
||||
(ssm_CancelEdit.bind(this, i, j))();
|
||||
(ssm_CancelEdit.bind(this, ss, isAlt))();
|
||||
}.bind(btn, screenshot, isAlt);
|
||||
div.appendChild(btn);
|
||||
|
||||
@@ -583,12 +562,10 @@ function ssm_ShowEdit(screenshot, isAlt) {
|
||||
function ssm_CancelEdit(screenshot, isAlt) {
|
||||
var node;
|
||||
|
||||
if (isAlt) {
|
||||
if (isAlt)
|
||||
node = $WH.ge('alt2-' + screenshot.id);
|
||||
}
|
||||
else {
|
||||
else
|
||||
node = $WH.ge('alt-' + screenshot.id);
|
||||
}
|
||||
|
||||
var sp = $WH.gE(node, 'span')[1];
|
||||
sp.style.display = '';
|
||||
@@ -610,41 +587,39 @@ function ssm_Edit(screenshot, isAlt) {
|
||||
var desc = node.firstChild.childNodes;
|
||||
if (desc[0].value == screenshot.caption) {
|
||||
ssm_CancelEdit(screenshot, isAlt);
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
screenshot.caption = desc[0].value;
|
||||
|
||||
ssm_CancelEdit(screenshot, isAlt);
|
||||
|
||||
node = node.firstChild;
|
||||
while (node.childNodes.length > 0) {
|
||||
while (node.childNodes.length > 0)
|
||||
node.removeChild(node.firstChild);
|
||||
}
|
||||
|
||||
$WH.ae(node, $WH.ct(screenshot.caption));
|
||||
|
||||
new Ajax('?admin=screenshots&action=editalt&id=' + screenshot.id, {
|
||||
method: 'POST',
|
||||
params: 'alt=' + $WH.urlencode(screenshot.caption)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function ssm_Clear(screenshot, isAlt) {
|
||||
var node;
|
||||
|
||||
if (isAlt) {
|
||||
if (isAlt)
|
||||
node = $WH.ge('alt2-' + screenshot.id);
|
||||
}
|
||||
else {
|
||||
else
|
||||
node = $WH.ge('alt-' + screenshot.id);
|
||||
}
|
||||
|
||||
var sp = $WH.gE(node, 'span');
|
||||
var a = $WH.gE(sp[1], 'a');
|
||||
sp = sp[0];
|
||||
|
||||
if (screenshot.caption == '') {
|
||||
if (screenshot.caption == '')
|
||||
return;
|
||||
}
|
||||
|
||||
screenshot.caption = '';
|
||||
sp.innerHTML = '<i class="q0">NULL</i>';
|
||||
@@ -652,67 +627,64 @@ function ssm_Clear(screenshot, isAlt) {
|
||||
new Ajax('?admin=screenshots&action=editalt&id=' + screenshot.id, {
|
||||
method: 'POST',
|
||||
params: 'alt=' + $WH.urlencode('')
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function ssm_Approve(openNext) {
|
||||
var _self = this;
|
||||
new Ajax('?admin=screenshots&action=approve&id=' + _self.id, {
|
||||
var ss = this;
|
||||
new Ajax('?admin=screenshots&action=approve&id=' + ss.id, {
|
||||
method: 'get',
|
||||
onSuccess: function (x) {
|
||||
Lightbox.hide();
|
||||
if (ssm_numPending == 1 && _self.pending) {
|
||||
if (ssm_numPending == 1 && ss.pending)
|
||||
ss_Refresh(true);
|
||||
}
|
||||
else {
|
||||
ss_Refresh();
|
||||
ss_Manage(ss_managedRow, _self.type, _self.typeId, openNext, 0);
|
||||
ss_Manage(ss_managedRow, ss.type, ss.typeId, openNext, 0);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function ssm_Sticky(openNext) {
|
||||
var _self = this;
|
||||
new Ajax('?admin=screenshots&action=sticky&id=' + _self.id, {
|
||||
var ss = this;
|
||||
new Ajax('?admin=screenshots&action=sticky&id=' + ss.id, {
|
||||
method: 'get',
|
||||
onSuccess: function (x) {
|
||||
Lightbox.hide();
|
||||
if (ssm_numPending == 1 && _self.pending) {
|
||||
if (ssm_numPending == 1 && ss.pending)
|
||||
ss_Refresh(true);
|
||||
}
|
||||
else {
|
||||
ss_Refresh();
|
||||
ss_Manage(ss_managedRow, _self.type, _self.typeId, openNext, 0);
|
||||
ss_Manage(ss_managedRow, ss.type, ss.typeId, openNext, 0);
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function ssm_Delete(openNext) {
|
||||
var _self = this;
|
||||
new Ajax('?admin=screenshots&action=delete&id=' + _self.id, {
|
||||
var ss = this;
|
||||
new Ajax('?admin=screenshots&action=delete&id=' + ss.id, {
|
||||
method: 'get',
|
||||
onSuccess: function (x) {
|
||||
Lightbox.hide();
|
||||
if (ssm_numPending == 1 && _self.pending) {
|
||||
if (ssm_numPending == 1 && ss.pending)
|
||||
ss_Refresh(true);
|
||||
}
|
||||
else {
|
||||
ss_Refresh();
|
||||
ss_Manage(ss_managedRow, _self.type, _self.typeId, openNext, 0);
|
||||
ss_Manage(ss_managedRow, ss.type, ss.typeId, openNext, 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function ssm_Relocate(typeId) {
|
||||
var _self = this;
|
||||
new Ajax('?admin=screenshots&action=relocate&id=' + _self.id + '&typeid=' + typeId, {
|
||||
var ss = this;
|
||||
new Ajax('?admin=screenshots&action=relocate&id=' + ss.id + '&typeid=' + typeId, {
|
||||
method: 'get',
|
||||
onSuccess: function (x) {
|
||||
ss_Refresh();
|
||||
ss_Manage(ss_managedRow, _self.type, typeId);
|
||||
ss_Manage(ss_managedRow, ss.type, typeId);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -733,10 +705,10 @@ var ScreenshotManager = new function () {
|
||||
aCover,
|
||||
aOriginal,
|
||||
divFrom,
|
||||
spCaption,
|
||||
divCaption,
|
||||
__div,
|
||||
h2Name,
|
||||
u,
|
||||
controlsCOPY,
|
||||
aEdit,
|
||||
aClear,
|
||||
spApprove,
|
||||
@@ -753,17 +725,14 @@ var ScreenshotManager = new function () {
|
||||
desiredScale = Math.min(772 / screenshot.width, 618 / screenshot.height);
|
||||
scale = Math.min(772 / screenshot.width, availHeight / screenshot.height);
|
||||
}
|
||||
else {
|
||||
else
|
||||
desiredScale = scale = 1;
|
||||
}
|
||||
|
||||
if (desiredScale > 1) {
|
||||
if (desiredScale > 1)
|
||||
desiredScale = 1;
|
||||
}
|
||||
|
||||
if (scale > 1) {
|
||||
if (scale > 1)
|
||||
scale = 1;
|
||||
}
|
||||
|
||||
imgWidth = Math.round(scale * screenshot.width);
|
||||
imgHeight = Math.round(scale * screenshot.height);
|
||||
@@ -778,14 +747,12 @@ var ScreenshotManager = new function () {
|
||||
}
|
||||
|
||||
function render(resizing) {
|
||||
if (resizing && (scale == desiredScale) && $WH.g_getWindowSize().h > container.offsetHeight) {
|
||||
if (resizing && (scale == desiredScale) && $WH.g_getWindowSize().h > container.offsetHeight)
|
||||
return;
|
||||
}
|
||||
|
||||
container.style.visibility = 'hidden';
|
||||
|
||||
var
|
||||
resized = (screenshot.width > 772 || screenshot.height > 618);
|
||||
var resized = (screenshot.width > 772 || screenshot.height > 618);
|
||||
|
||||
computeDimensions(0);
|
||||
|
||||
@@ -798,43 +765,39 @@ var ScreenshotManager = new function () {
|
||||
|
||||
if (!resizing) {
|
||||
aOriginal.href = g_staticUrl + '/uploads/screenshots/' + (screenshot.pending ? 'pending' : 'normal') + '/' + screenshot.id + '.jpg';
|
||||
var hasFrom1 = screenshot.date && screenshot.user;
|
||||
if (hasFrom1) {
|
||||
var hasFrom = screenshot.date && screenshot.user;
|
||||
if (hasFrom) {
|
||||
var
|
||||
postedOn = new Date(screenshot.date),
|
||||
elapsed = (g_serverTime - postedOn) / 1000;
|
||||
elapsed = (g_serverTime - postedOn) / 1000;
|
||||
|
||||
var a = divFrom.firstChild.childNodes[1];
|
||||
a.href = '?user=' + screenshot.user;
|
||||
a.innerHTML = screenshot.user;
|
||||
|
||||
var s = divFrom.firstChild.childNodes[3];
|
||||
|
||||
$WH.ee(s);
|
||||
g_formatDate(s, elapsed, postedOn);
|
||||
|
||||
divFrom.firstChild.style.display = '';
|
||||
}
|
||||
else {
|
||||
else
|
||||
divFrom.firstChild.style.display = 'none';
|
||||
}
|
||||
|
||||
divFrom.style.display = (hasFrom1 ? '' : 'none');
|
||||
divFrom.style.display = (hasFrom ? '' : 'none');
|
||||
|
||||
var hasCaption = (screenshot.caption != null && screenshot.caption.length);
|
||||
if (hasCaption) {
|
||||
var html = '';
|
||||
if (hasCaption) {
|
||||
if (hasCaption)
|
||||
html += '<span class="screenshotviewer-caption"><b>' + Markup.toHtml(screenshot.caption, { mode: Markup.MODE_SIGNATURE }) + '</b></span>';
|
||||
}
|
||||
|
||||
divCaption.innerHTML = html;
|
||||
}
|
||||
else {
|
||||
divCaption.innerHTML = '<i class="q0">NULL</i>';
|
||||
spCaption.innerHTML = html;
|
||||
}
|
||||
else
|
||||
spCaption.innerHTML = '<i class="q0">NULL</i>';
|
||||
|
||||
__div.id = 'alt2-' + screenshot.id;
|
||||
divCaption.id = 'alt2-' + screenshot.id;
|
||||
|
||||
aEdit.onclick = ssm_ShowEdit.bind(aEdit, screenshot, true);
|
||||
aClear.onclick = ssm_Clear.bind(aClear, screenshot, true);
|
||||
@@ -851,24 +814,22 @@ var ScreenshotManager = new function () {
|
||||
|
||||
Lightbox.reveal();
|
||||
|
||||
if (divCaption.offsetHeight > 18) {
|
||||
computeDimensions(divCaption.offsetHeight - 18);
|
||||
}
|
||||
if (spCaption.offsetHeight > 18)
|
||||
computeDimensions(spCaption.offsetHeight - 18);
|
||||
|
||||
container.style.visibility = 'visible';
|
||||
}
|
||||
|
||||
function nextScreenshot() {
|
||||
if (screenshot.next !== undefined) {
|
||||
if (screenshot.next !== undefined)
|
||||
screenshot = ssm_screenshotData[screenshot.next];
|
||||
}
|
||||
|
||||
onRender();
|
||||
}
|
||||
|
||||
function prevScreenshot() {
|
||||
if (screenshot.prev !== undefined) {
|
||||
if (screenshot.prev !== undefined)
|
||||
screenshot = ssm_screenshotData[screenshot.prev];
|
||||
}
|
||||
|
||||
onRender();
|
||||
}
|
||||
@@ -890,7 +851,6 @@ var ScreenshotManager = new function () {
|
||||
dest.className = 'screenshotviewer';
|
||||
|
||||
screen = $WH.ce('div');
|
||||
|
||||
screen.className = 'screenshotviewer-screen';
|
||||
|
||||
aPrev = $WH.ce('a');
|
||||
@@ -914,12 +874,14 @@ var ScreenshotManager = new function () {
|
||||
aCover.className = 'screenshotviewer-cover';
|
||||
aCover.href = 'javascript:;';
|
||||
aCover.onclick = Lightbox.hide;
|
||||
|
||||
var foo = $WH.ce('span');
|
||||
$WH.ae(foo, $WH.ce('b'));
|
||||
$WH.ae(aCover, foo);
|
||||
$WH.ae(screen, aPrev);
|
||||
$WH.ae(screen, aNext);
|
||||
$WH.ae(screen, aCover);
|
||||
|
||||
var _div = $WH.ce('div');
|
||||
_div.className = 'text';
|
||||
h2Name = $WH.ce('h2');
|
||||
@@ -937,28 +899,38 @@ var ScreenshotManager = new function () {
|
||||
_div.style.paddingTop = '6px';
|
||||
_div.style.cssFloat = _div.style.styleFloat = 'right';
|
||||
_div.className = 'bigger-links';
|
||||
|
||||
aApprove = $WH.ce('a');
|
||||
aApprove.href = 'javascript:;';
|
||||
$WH.ae(aApprove, $WH.ct('Approve'));
|
||||
$WH.ae(_div, aApprove);
|
||||
|
||||
spApprove = $WH.ce('span');
|
||||
spApprove.style.display = 'none';
|
||||
$WH.ae(spApprove, $WH.ct('Approve'));
|
||||
$WH.ae(_div, spApprove);
|
||||
|
||||
$WH.ae(_div, makePipe());
|
||||
|
||||
aMakeSticky = $WH.ce('a');
|
||||
aMakeSticky.href = 'javascript:;';
|
||||
$WH.ae(aMakeSticky, $WH.ct('Make sticky'));
|
||||
$WH.ae(_div, aMakeSticky);
|
||||
|
||||
$WH.ae(_div, makePipe());
|
||||
|
||||
aDelete = $WH.ce('a');
|
||||
aDelete.href = 'javascript:;';
|
||||
$WH.ae(aDelete, $WH.ct('Delete'));
|
||||
$WH.ae(_div, aDelete);
|
||||
u = _div;
|
||||
|
||||
controlsCOPY = _div;
|
||||
|
||||
$WH.ae(dest, _div);
|
||||
|
||||
divFrom = $WH.ce('div');
|
||||
divFrom.className = 'screenshotviewer-from';
|
||||
|
||||
var sp = $WH.ce('span');
|
||||
$WH.ae(sp, $WH.ct(LANG.lvscreenshot_from));
|
||||
$WH.ae(sp, $WH.ce('a'));
|
||||
@@ -966,9 +938,11 @@ var ScreenshotManager = new function () {
|
||||
$WH.ae(sp, $WH.ce('span'));
|
||||
$WH.ae(divFrom, sp);
|
||||
$WH.ae(dest, divFrom);
|
||||
|
||||
_div = $WH.ce('div');
|
||||
_div.className = 'clear';
|
||||
$WH.ae(dest, _div);
|
||||
|
||||
var aClose = $WH.ce('a');
|
||||
aClose.className = 'screenshotviewer-close';
|
||||
aClose.href = 'javascript:;';
|
||||
@@ -983,23 +957,27 @@ var ScreenshotManager = new function () {
|
||||
$WH.ae(aOriginal, $WH.ce('span'));
|
||||
$WH.ae(dest, aOriginal);
|
||||
|
||||
__div = $WH.ce('div');
|
||||
divCaption = $WH.ce('span');
|
||||
divCaption.style.paddingRight = '8px';
|
||||
$WH.ae(__div, divCaption);
|
||||
divCaption = $WH.ce('div');
|
||||
spCaption = $WH.ce('span');
|
||||
spCaption.style.paddingRight = '8px';
|
||||
$WH.ae(divCaption, spCaption);
|
||||
|
||||
var sp = $WH.ce('span');
|
||||
sp.style.whiteSpace = 'nowrap';
|
||||
aEdit = $WH.ce('a');
|
||||
aEdit.href = 'javascript:;';
|
||||
$WH.ae(aEdit, $WH.ct('Edit'));
|
||||
$WH.ae(sp, aEdit);
|
||||
|
||||
$WH.ae(sp, makePipe());
|
||||
|
||||
aClear = $WH.ce('a');
|
||||
aClear.href = 'javascript:;';
|
||||
$WH.ae(aClear, $WH.ct('Clear'));
|
||||
$WH.ae(sp, aClear);
|
||||
$WH.ae(__div, sp);
|
||||
$WH.ae(dest, __div);
|
||||
$WH.ae(divCaption, sp);
|
||||
$WH.ae(dest, divCaption);
|
||||
|
||||
_div = $WH.ce('div');
|
||||
_div.className = 'clear';
|
||||
$WH.ae(dest, _div);
|
||||
@@ -1033,7 +1011,7 @@ var ScreenshotManager = new function () {
|
||||
}
|
||||
else {
|
||||
container.className = '';
|
||||
lightboxComponents = [];
|
||||
lightboxComponents = [];
|
||||
|
||||
while (container.firstChild) {
|
||||
lightboxComponents.push(container.firstChild);
|
||||
@@ -1056,7 +1034,7 @@ var ScreenshotManager = new function () {
|
||||
|
||||
var img = $WH.ce('img');
|
||||
img.src = g_staticUrl + '/images/ui/misc/progress-anim.gif';
|
||||
img.width = 126;
|
||||
img.width = 126;
|
||||
img.height = 22;
|
||||
|
||||
$WH.ae(div, img);
|
||||
@@ -1067,25 +1045,26 @@ var ScreenshotManager = new function () {
|
||||
}, 150);
|
||||
|
||||
loadingImage = new Image();
|
||||
loadingImage.onload = (function (screen, timer) {
|
||||
loadingImage.onload = (function (ss, timer) {
|
||||
clearTimeout(timer);
|
||||
screen.width = this.width;
|
||||
screen.height = this.height;
|
||||
loadingImage = null;
|
||||
ss.width = this.width;
|
||||
ss.height = this.height;
|
||||
loadingImage = null;
|
||||
restoreLightbox();
|
||||
render();
|
||||
}).bind(loadingImage, screenshot, lightboxTimer);
|
||||
|
||||
loadingImage.onerror = (function (timer) {
|
||||
clearTimeout(timer);
|
||||
loadingImage = null;
|
||||
Lightbox.hide();
|
||||
restoreLightbox();
|
||||
}).bind(loadingImage, lightboxTimer);
|
||||
|
||||
loadingImage.src = (screenshot.url ? screenshot.url : g_staticUrl + '/uploads/screenshots/' + (screenshot.pending ? 'pending' : 'normal') + '/' + screenshot.id + '.jpg');
|
||||
}
|
||||
else {
|
||||
else
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
function cancelImageLoading() {
|
||||
@@ -1101,15 +1080,13 @@ var ScreenshotManager = new function () {
|
||||
}
|
||||
|
||||
function restoreLightbox() {
|
||||
if (!lightboxComponents) {
|
||||
if (!lightboxComponents)
|
||||
return;
|
||||
}
|
||||
|
||||
$WH.ee(container);
|
||||
container.className = 'screenshotviewer';
|
||||
for (var i = 0; i < lightboxComponents.length; ++i) {
|
||||
for (var i = 0; i < lightboxComponents.length; ++i)
|
||||
$WH.ae(container, lightboxComponents[i]);
|
||||
}
|
||||
|
||||
lightboxComponents = null;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php namespace Aowow\Template; ?>
|
||||
|
||||
<h2><img src="<?=Cfg::get('STATIC_URL'); ?>/images/icons/bubble-big.gif" width="32" height="29" alt="" style="vertical-align:middle;margin-right:8px">Reminder</h2>
|
||||
<h2><img src="<?=$this->gStaticUrl; ?>/images/icons/bubble-big.gif" width="32" height="29" alt="" style="vertical-align:middle;margin-right:8px">Reminder</h2>
|
||||
Your screenshot will <b class="q10">not</b> be approved if it doesn't correspond to the following guidelines.
|
||||
|
||||
<ul>
|
||||
|
||||
12
template/localized/ssReminder_2.tpl.php
Normal file
12
template/localized/ssReminder_2.tpl.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace Aowow\Template; ?>
|
||||
|
||||
<h2><img src="<?=$this->gStaticUrl; ?>/images/icons/bubble-big.gif" width="32" height="29" alt="" style="vertical-align:middle;margin-right:8px">Rappel</h2>
|
||||
Votre capture d'écran <b class="q10">ne</b> sera pas approuvée si elle ne respecte pas les directives suivantes.
|
||||
|
||||
<ul>
|
||||
<li><div>Assurez-vous d'augmenter vos <u><b>paramètres graphiques</b></u> pour que la capture soit de bonne qualité !</div></li>
|
||||
<li><div>Les captures d'écran du <u><b>visualiseur de modèles</b></u> sont supprimées immédiatement (cela inclut généralement la sélection de personnage).</div></li>
|
||||
<li><div>N'incluez pas le <u><b>texte à l'écran</b></u> ni le <u><b>cercle de sélection</b></u> d'un PNJ.</div></li>
|
||||
<li><div>N'incluez aucune <u><b>interface utilisateur</b></u> dans la capture si possible.</div></li>
|
||||
<li><div>Utilisez l'<u><b>outil de recadrage</b></u> pour vous concentrer autant que possible sur l'objet et réduire l'environnement inutile, afin de mieux mettre en valeur l'objet sur la vignette qui apparaîtra sur la page de l'objet.</div></li>
|
||||
</ul>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php namespace Aowow\Template; ?>
|
||||
|
||||
<h2><img src="<?=Cfg::get('STATIC_URL'); ?>/images/icons/bubble-big.gif" width="32" height="29" alt="" style="vertical-align:middle;margin-right:8px">Hinweis</h2>
|
||||
<h2><img src="<?=$this->gStaticUrl; ?>/images/icons/bubble-big.gif" width="32" height="29" alt="" style="vertical-align:middle;margin-right:8px">Hinweis</h2>
|
||||
Euer Screenshot wird <b class="q10">nicht</b> zugelassen werden, wenn er nicht unseren Richtlinien entspricht.
|
||||
|
||||
<ul>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php namespace Aowow\Template; ?>
|
||||
|
||||
<h2><img src="<?=Cfg::get('STATIC_URL'); ?>/images/icons/bubble-big.gif" width="32" height="29" alt="" style="vertical-align:middle;margin-right:8px">提醒</h2>
|
||||
你的截图将<b class="q10">不会</b> 通过审查假设不符合下列准则。
|
||||
<h2><img src="<?=$this->gStaticUrl; ?>/images/icons/bubble-big.gif" width="32" height="29" alt="" style="vertical-align:middle;margin-right:8px">提醒</h2>
|
||||
如果您的截图不符合以下指南,将<b class="q10">不会</b>被通过审核。
|
||||
|
||||
<ul>
|
||||
<li><div>Be sure to turn up your <u><b>graphics settings</b></u> to make sure the shot looks good!</div></li>
|
||||
<li><div><u><b>Model viewer</b></u> shots are deleted on sight (this also includes character select, typically).</div></li>
|
||||
<li><div>Don't include the <u><b>onscreen text</b></u> and the <u><b>selection circle</b></u> of a NPC.</div></li>
|
||||
<li><div>Don't include any <u><b>UI</b></u> in the shot if you can help it.</div></li>
|
||||
<li><div>Use the screenshot <u><b>cropping tool</b></u> to focus on the item as much as possible and reduce any unnecessary surrounding, as to better show off the item in question when reduced to the thumbnail that will be present on the item's page.</div></li>
|
||||
<li><div>请确保将您的<u><b>图形设置</b></u>调高,以保证截图质量!</div></li>
|
||||
<li><div>使用<u><b>模型查看器</b></u>的截图会被直接删除(包括角色选择界面)。</div></li>
|
||||
<li><div>请勿包含NPC的<u><b>屏幕文字</b></u>和<u><b>选择圈</b></u>。</div></li>
|
||||
<li><div>如有可能,请勿在截图中包含任何<u><b>用户界面</b></u>元素。</div></li>
|
||||
<li><div>请使用<u><b>截图裁剪工具</b></u>尽量聚焦于物品本身,减少不必要的背景,以便在物品页面的缩略图中更好地展示该物品。</div></li>
|
||||
</ul>
|
||||
|
||||
12
template/localized/ssReminder_6.tpl.php
Normal file
12
template/localized/ssReminder_6.tpl.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace Aowow\Template; ?>
|
||||
|
||||
<h2><img src="<?=$this->gStaticUrl; ?>/images/icons/bubble-big.gif" width="32" height="29" alt="" style="vertical-align:middle;margin-right:8px">Recordatorio</h2>
|
||||
Su captura de pantalla <b class="q10">no</b> será aprobada si no cumple con las siguientes directrices.
|
||||
|
||||
<ul>
|
||||
<li><div>¡Asegúrese de subir la <u><b>configuración gráfica</b></u> para que la imagen se vea bien!</div></li>
|
||||
<li><div>Las capturas de <u><b>model viewer</b></u> se eliminan automáticamente (esto también incluye la selección de personaje, normalmente).</div></li>
|
||||
<li><div>No incluya el <u><b>texto en pantalla</b></u> ni el <u><b>círculo de selección</b></u> de un PNJ.</div></li>
|
||||
<li><div>No incluya ninguna <u><b>interfaz de usuario</b></u> en la imagen si puede evitarlo.</div></li>
|
||||
<li><div>Utilice la <u><b>herramienta de recorte de capturas</b></u> para centrarse en el objeto tanto como sea posible y reducir el entorno innecesario, para mostrar mejor el objeto en la miniatura que aparecerá en la página del objeto.</div></li>
|
||||
</ul>
|
||||
12
template/localized/ssReminder_8.tpl.php
Normal file
12
template/localized/ssReminder_8.tpl.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace Aowow\Template; ?>
|
||||
|
||||
<h2><img src="<?=$this->gStaticUrl; ?>/images/icons/bubble-big.gif" width="32" height="29" alt="" style="vertical-align:middle;margin-right:8px">Напоминание</h2>
|
||||
Ваш скриншот <b class="q10">не</b> будет одобрен, если он не соответствует следующим рекомендациям.
|
||||
|
||||
<ul>
|
||||
<li><div>Обязательно увеличьте свои <u><b>настройки графики</b></u>, чтобы скриншот выглядел хорошо!</div></li>
|
||||
<li><div>Скриншоты из <u><b>просмотрщика моделей</b></u> удаляются сразу (это также касается выбора персонажа).</div></li>
|
||||
<li><div>Не включайте <u><b>текст на экране</b></u> и <u><b>круг выделения</b></u> NPC.</div></li>
|
||||
<li><div>Не включайте никакой <u><b>интерфейс пользователя</b></u> в скриншот, если это возможно.</div></li>
|
||||
<li><div>Используйте <u><b>инструмент обрезки скриншотов</b></u>, чтобы максимально сфокусироваться на предмете и уменьшить ненужное окружение, чтобы лучше показать предмет на миниатюре, которая будет на странице предмета.</div></li>
|
||||
</ul>
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php namespace Aowow; ?>
|
||||
|
||||
<?php $this->brick('header'); ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
$this->brick('header');
|
||||
?>
|
||||
<div class="main" id="main">
|
||||
<div class="main-precontents" id="main-precontents"></div>
|
||||
<div class="main-contents" id="main-contents">
|
||||
@@ -12,7 +13,7 @@ $this->brick('announcement');
|
||||
$this->brick('pageTemplate');
|
||||
?>
|
||||
<div class="text">
|
||||
<h1><?=$this->name; ?></h1>
|
||||
<h1><?=$this->h1; ?></h1>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
@@ -24,13 +25,7 @@ $this->brick('pageTemplate');
|
||||
<td>Page: </td>
|
||||
<td>
|
||||
<select id="pagetype">
|
||||
<?php
|
||||
foreach (Type::getFileStringsFor() as $i => $str):
|
||||
if (Lang::game($str) && Type::checkClassAttrib($i, 'contribute', CONTRIBUTE_SS)):
|
||||
echo " <option value=\"".$i."\">".Util::ucFirst(Lang::game($str))."</option>\n";
|
||||
endif;
|
||||
endforeach;
|
||||
?>
|
||||
<?=$this->makeOptionsList($this->pageTypes, null, 32); ?>
|
||||
</select>
|
||||
</td>
|
||||
<td>#<input type="number" size="6" id="pagetypeid"></td>
|
||||
@@ -42,20 +37,20 @@ endforeach;
|
||||
<thead><tr><th style="width:135px;"><div>Menu</div></th><th style="width:400px;">Pages</th><th>Screenshots: <span id="screenshotTotal"></span></th></tr></thead>
|
||||
<tbody><tr>
|
||||
<td id="menu-container" style="vertical-align: top;">
|
||||
<div id="show-all-pages"><?=($this->ssNFound ? ' – <a href="?admin=screenshots&all">Show All</a> ('.$this->ssNFound.')' : null); ?></div>
|
||||
<div id="show-all-pages"><?=($this->ssNFound ? ' – <a href="?admin=screenshots&all">Show All</a> ('.$this->ssNFound.')' : ''); ?></div>
|
||||
<h4>Mass Select</h4>
|
||||
– <a href="#" onClick="ssm_MassSelect(1);">Select All</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(0);">Deselect All</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(-1);">Toggle Selection</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(2);">Select All Pending</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(5);">Select All Unique</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(3);">Select All Approved</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(4);">Select All Sticky</a><br>
|
||||
– <a href="#" onClick="ssm_MassSelect(1);">Select All</a><br />
|
||||
– <a href="#" onClick="ssm_MassSelect(0);">Deselect All</a><br />
|
||||
– <a href="#" onClick="ssm_MassSelect(-1);">Toggle Selection</a><br />
|
||||
– <a href="#" onClick="ssm_MassSelect(2);">Select All Pending</a><br />
|
||||
– <a href="#" onClick="ssm_MassSelect(5);">Select All Unique</a><br />
|
||||
– <a href="#" onClick="ssm_MassSelect(3);">Select All Approved</a><br />
|
||||
– <a href="#" onClick="ssm_MassSelect(4);">Select All Sticky</a><br />
|
||||
<div id="withselected" style="display:none;">
|
||||
<h4>Mass Action <b>(0)</b></h4>
|
||||
– <a href="#" id="massapprove">Approve All</a><br>
|
||||
– <a href="#" id="massdelete">Delete All</a><br>
|
||||
– <a href="#" id="masssticky">Sticky All</a><br>
|
||||
– <a href="#" id="massapprove">Approve All</a><br />
|
||||
– <a href="#" id="massdelete">Delete All</a><br />
|
||||
– <a href="#" id="masssticky">Sticky All</a><br />
|
||||
</div>
|
||||
</td>
|
||||
<td id="pages-container" style="vertical-align: top;"></td>
|
||||
@@ -124,10 +119,10 @@ if ($this->getAll):
|
||||
echo " var ss_getAll = true;\n";
|
||||
endif;
|
||||
if ($this->ssPages):
|
||||
echo " var ssm_screenshotPages = ".Util::toJSON($this->ssPages).";\n";
|
||||
echo " var ssm_screenshotPages = ".$this->json($this->ssPages).";\n";
|
||||
echo " ssm_UpdatePages();\n";
|
||||
elseif ($this->ssData):
|
||||
echo " var ssm_screenshotData = ".Util::toJSON($this->ssData).";\n";
|
||||
echo " var ssm_screenshotData = ".$this->json($this->ssData).";\n";
|
||||
echo " ssm_UpdateList();\n";
|
||||
endif;
|
||||
?>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<?php namespace Aowow; ?>
|
||||
<?php
|
||||
namespace Aowow\Template;
|
||||
|
||||
<?php $this->brick('header'); ?>
|
||||
use \Aowow\Lang;
|
||||
|
||||
$this->brick('header');
|
||||
?>
|
||||
<div class="main" id="main">
|
||||
<div class="main-precontents" id="main-precontents"></div>
|
||||
<div class="main-contents" id="main-contents">
|
||||
@@ -15,12 +18,12 @@ $this->brick('infobox');
|
||||
|
||||
?>
|
||||
<div class="text">
|
||||
<h1><?=$this->name; ?></h1>
|
||||
<h1><?=$this->h1; ?></h1>
|
||||
|
||||
<span><?=Lang::screenshot('cropHint'); ?></span>
|
||||
<div class="pad"></div>
|
||||
<div id="ss-container"></div><script type="text/javascript">//<![CDATA[
|
||||
var myCropper = new Cropper(<?=Util::toJSON($this->cropper); ?>);
|
||||
var myCropper = new Cropper(<?=$this->json($this->cropper); ?>);
|
||||
//]]></script>
|
||||
|
||||
<div class="pad"></div>
|
||||
|
||||
Reference in New Issue
Block a user