mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Reports
* move related functions to separate class * implement out of date comment handling shorthand * implement admin interface to work with reports - listing based on user group - assign to self / unassign from self - close with reason - comment functionality - reward reputation to creator based on resolution
This commit is contained in:
@@ -5,7 +5,7 @@ if (!defined('AOWOW_REVISION'))
|
||||
|
||||
class AjaxAdmin extends AjaxHandler
|
||||
{
|
||||
protected $validParams = ['screenshots', 'siteconfig', 'weight-presets', 'spawn-override', 'guide'];
|
||||
protected $validParams = ['screenshots', 'siteconfig', 'weight-presets', 'spawn-override', 'guide', 'comment'];
|
||||
protected $_get = array(
|
||||
'action' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW ],
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkIdListUnsigned'],
|
||||
@@ -89,6 +89,13 @@ class AjaxAdmin extends AjaxHandler
|
||||
|
||||
$this->handler = 'guideManage';
|
||||
}
|
||||
else if ($this->params[0] == 'comment')
|
||||
{
|
||||
if (!User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_MOD))
|
||||
return;
|
||||
|
||||
$this->handler = 'commentOutOfDate';
|
||||
}
|
||||
}
|
||||
|
||||
// get all => null (optional)
|
||||
@@ -526,6 +533,28 @@ class AjaxAdmin extends AjaxHandler
|
||||
return '-1';
|
||||
}
|
||||
|
||||
protected function commentOutOfDate() : string
|
||||
{
|
||||
$ok = false;
|
||||
switch ($this->_post['status'])
|
||||
{
|
||||
case 0: // up to date
|
||||
if ($ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` & ~?d WHERE `id` = ?d', CC_FLAG_OUTDATED, $this->_post['id']))
|
||||
if ($rep = new Report(Report::MODE_COMMENT, Report::CO_OUT_OF_DATE, $this->_post['id']))
|
||||
$rep->close(Report::STATUS_CLOSED_WONTFIX);
|
||||
break;
|
||||
case 1: // outdated, mark as deleted and clear other flags (sticky + outdated)
|
||||
if ($ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = ?d, `deleteUserId` = ?d, `deleteDate` = ?d WHERE `id` = ?d', CC_FLAG_DELETED, User::$id, time(), $this->_post['id']))
|
||||
if ($rep = new Report(Report::MODE_COMMENT, Report::CO_OUT_OF_DATE, $this->_post['id']))
|
||||
$rep->close(Report::STATUS_CLOSED_SOLVED);
|
||||
break;
|
||||
default:
|
||||
trigger_error('AjaxHandler::comentOutOfDate - called with invalid status');
|
||||
}
|
||||
|
||||
return $ok ? '1' : '0';
|
||||
}
|
||||
|
||||
|
||||
/***************************/
|
||||
/* additional input filter */
|
||||
|
||||
@@ -177,7 +177,7 @@ class AjaxComment extends AjaxHandler
|
||||
}
|
||||
|
||||
// in theory, there is a username passed alongside... lets just use the current user (see user.js)
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags | ?d, deleteUserId = ?d, deleteDate = UNIX_TIMESTAMP() WHERE id IN (?a){ AND userId = ?d}',
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` | ?d, `deleteUserId` = ?d, `deleteDate` = UNIX_TIMESTAMP() WHERE `id` IN (?a){ AND `userId` = ?d}',
|
||||
CC_FLAG_DELETED,
|
||||
User::$id,
|
||||
$this->_post['id'],
|
||||
@@ -187,13 +187,14 @@ class AjaxComment extends AjaxHandler
|
||||
// deflag hasComment
|
||||
if ($ok)
|
||||
{
|
||||
$coInfo = DB::Aowow()->selectRow('SELECT IF(BIT_OR(~b.flags) & ?d, 1, 0) as hasMore, b.type, b.typeId FROM ?_comments a JOIN ?_comments b ON a.type = b.type AND a.typeId = b.typeId WHERE a.id = ?d',
|
||||
$coInfo = DB::Aowow()->select('SELECT IF(BIT_OR(~b.`flags`) & ?d, 1, 0) AS hasMore, b.`type`, b.`typeId` FROM ?_comments a JOIN ?_comments b ON a.`type` = b.`type` AND a.`typeId` = b.`typeId` WHERE a.`id` IN (?a) GROUP BY b.`type`, b.`typeId`',
|
||||
CC_FLAG_DELETED,
|
||||
$this->_post['id']
|
||||
);
|
||||
|
||||
if (!$coInfo['hasMore'] && ($tbl = Type::getClassAttrib($coInfo['type'], 'dataTable')))
|
||||
DB::Aowow()->query('UPDATE '.$tbl.' SET cuFlags = cuFlags & ~?d WHERE id = ?d', CUSTOM_HAS_COMMENT, $coInfo['typeId']);
|
||||
foreach ($coInfo as $co)
|
||||
if (!$co['hasMore'] && ($tbl = Type::getClassAttrib($co['type'], 'dataTable')))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` & ~?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_COMMENT, $co['typeId']);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxComment::handleCommentDelete - user #'.User::$id.' could not flag comment #'.$this->_post['id'].' as deleted', E_USER_ERROR);
|
||||
@@ -208,7 +209,7 @@ class AjaxComment extends AjaxHandler
|
||||
}
|
||||
|
||||
// in theory, there is a username passed alongside... lets just use the current user (see user.js)
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags & ~?d WHERE id IN (?a){ AND userId = deleteUserId AND deleteUserId = ?d}',
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET `flags` = `flags` & ~?d WHERE `id` IN (?a){ AND `userId` = `deleteUserId` AND `deleteUserId` = ?d}',
|
||||
CC_FLAG_DELETED,
|
||||
$this->_post['id'],
|
||||
User::isInGroup(U_GROUP_MODERATOR) ? DBSIMPLE_SKIP : User::$id
|
||||
@@ -217,9 +218,10 @@ class AjaxComment extends AjaxHandler
|
||||
// reflag hasComment
|
||||
if ($ok)
|
||||
{
|
||||
$coInfo = DB::Aowow()->selectRow('SELECT type, typeId FROM ?_comments WHERE id = ?d', $this->_post['id']);
|
||||
if ($tbl = Type::getClassAttrib($coInfo['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE '.$tbl.' SET cuFlags = cuFlags | ?d WHERE id = ?d', CUSTOM_HAS_COMMENT, $coInfo['typeId']);
|
||||
$coInfo = DB::Aowow()->select('SELECT `type`, `typeId` FROM ?_comments WHERE `id` IN (?a) GROUP BY `type`, `typeId`', $this->_post['id']);
|
||||
foreach ($coInfo as $co)
|
||||
if ($tbl = Type::getClassAttrib($co['type'], 'dataTable'))
|
||||
DB::Aowow()->query('UPDATE ?# SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', $tbl, CUSTOM_HAS_COMMENT, $co['typeId']);
|
||||
}
|
||||
else
|
||||
trigger_error('AjaxComment::handleCommentUndelete - user #'.User::$id.' could not unflag comment #'.$this->_post['id'].' as deleted', E_USER_ERROR);
|
||||
@@ -300,19 +302,24 @@ class AjaxComment extends AjaxHandler
|
||||
if (User::isInGroup(U_GROUP_MODERATOR)) // directly mark as outdated
|
||||
{
|
||||
if (!$this->_post['remove'])
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags | 0x4 WHERE id = ?d', $this->_post['id'][0]);
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags | ?d WHERE id = ?d', CC_FLAG_OUTDATED, $this->_post['id'][0]);
|
||||
else
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags & ~0x4 WHERE id = ?d', $this->_post['id'][0]);
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags & ~?d WHERE id = ?d', CC_FLAG_OUTDATED, $this->_post['id'][0]);
|
||||
}
|
||||
else if (DB::Aowow()->selectCell('SELECT 1 FROM ?_reports WHERE `mode` = ?d AND `reason`= ?d AND `subject` = ?d AND `userId` = ?d', 1, 17, $this->_post['id'][0], User::$id))
|
||||
return Lang::main('alreadyReport');
|
||||
else if (User::$id && !$this->_post['reason'] || mb_strlen($this->_post['reason']) < self::REPLY_LENGTH_MIN)
|
||||
return Lang::main('textTooShort');
|
||||
else if (User::$id) // only report as outdated
|
||||
$ok = Util::createReport(1, 17, $this->_post['id'][0], '[Outdated Comment] '.$this->_post['reason']);
|
||||
else // try to report as outdated
|
||||
{
|
||||
$report = new Report(Report::MODE_COMMENT, Report::CO_OUT_OF_DATE, $this->_post['id'][0]);
|
||||
if ($report->create($this->_post['reason']))
|
||||
$ok = true; // the script expects the actual characters 'ok' not some json string like "ok"
|
||||
else
|
||||
return Lang::main('intError');
|
||||
|
||||
if ($ok) // this one is very special; as in: completely retarded
|
||||
return 'ok'; // the script expects the actual characters 'ok' not some string like "ok"
|
||||
if (count($report->getSimilar()) >= 5) // 5 or more reports on the same comment: trigger flag
|
||||
$ok = DB::Aowow()->query('UPDATE ?_comments SET flags = flags | ?d WHERE id = ?d', CC_FLAG_OUTDATED, $this->_post['id'][0]);
|
||||
}
|
||||
|
||||
if ($ok)
|
||||
return 'ok';
|
||||
else
|
||||
trigger_error('AjaxComment::handleCommentOutOfDate - failed to update comment in db', E_USER_ERROR);
|
||||
|
||||
|
||||
@@ -6,15 +6,15 @@ if (!defined('AOWOW_REVISION'))
|
||||
class AjaxContactus extends AjaxHandler
|
||||
{
|
||||
protected $_post = array(
|
||||
'mode' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'reason' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'ua' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'appname' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'page' => ['filter' => FILTER_SANITIZE_URL],
|
||||
'desc' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'id' => ['filter' => FILTER_SANITIZE_NUMBER_INT],
|
||||
'relatedurl' => ['filter' => FILTER_SANITIZE_URL],
|
||||
'email' => ['filter' => FILTER_SANITIZE_EMAIL]
|
||||
'mode' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt'],
|
||||
'reason' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt'],
|
||||
'ua' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'appname' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'page' => ['filter' => FILTER_SANITIZE_URL ],
|
||||
'desc' => ['filter' => FILTER_UNSAFE_RAW, 'flags' => FILTER_FLAG_STRIP_AOWOW],
|
||||
'id' => ['filter' => FILTER_CALLBACK, 'options' => 'AjaxHandler::checkInt'],
|
||||
'relatedurl' => ['filter' => FILTER_SANITIZE_URL ],
|
||||
'email' => ['filter' => FILTER_SANITIZE_EMAIL ]
|
||||
);
|
||||
|
||||
public function __construct(array $params)
|
||||
@@ -35,58 +35,13 @@ class AjaxContactus extends AjaxHandler
|
||||
*/
|
||||
protected function handleContactUs() : string
|
||||
{
|
||||
$mode = $this->_post['mode'];
|
||||
$rsn = $this->_post['reason'];
|
||||
$ua = $this->_post['ua'];
|
||||
$app = $this->_post['appname'];
|
||||
$url = $this->_post['page'];
|
||||
$desc = $this->_post['desc'];
|
||||
$subj = $this->_post['id'];
|
||||
|
||||
$contexts = array(
|
||||
[1, 2, 3, 4, 5, 6, 7, 8],
|
||||
[15, 16, 17, 18, 19, 20],
|
||||
[30, 31, 32, 33, 34, 35, 36, 37],
|
||||
[45, 46, 47, 48],
|
||||
[60, 61],
|
||||
[45, 46, 47, 48],
|
||||
[45, 46, 48]
|
||||
);
|
||||
|
||||
if ($mode === null || $rsn === null || $ua === null || $app === null || $url === null)
|
||||
{
|
||||
trigger_error('AjaxContactus::handleContactUs - malformed contact request received', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
if (!isset($contexts[$mode]) || !in_array($rsn, $contexts[$mode]))
|
||||
{
|
||||
trigger_error('AjaxContactus::handleContactUs - report has invalid context (mode:'.$mode.' / reason:'.$rsn.')', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
if (!$desc)
|
||||
return 3;
|
||||
|
||||
if (mb_strlen($desc) > 500)
|
||||
return 2;
|
||||
|
||||
if (!User::$id && !User::$ip)
|
||||
{
|
||||
trigger_error('AjaxContactus::handleContactUs - could not determine IP for anonymous user', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
}
|
||||
|
||||
// check already reported
|
||||
$field = User::$id ? 'userId' : 'ip';
|
||||
if (DB::Aowow()->selectCell('SELECT 1 FROM ?_reports WHERE `mode` = ?d AND `reason`= ?d AND `subject` = ?d AND ?# = ?', $mode, $rsn, $subj, $field, User::$id ?: User::$ip))
|
||||
return 7;
|
||||
|
||||
if (Util::createReport($mode, $rsn, $subj, $desc, $ua, $app, $url, $this->_post['relatedurl'], $this->_post['email']))
|
||||
$report = new Report($this->_post['mode'], $this->_post['reason'], $this->_post['id']);
|
||||
if ($report->create($this->_post['desc'], $this->_post['ua'], $this->_post['appname'], $this->_post['page'], $this->_post['relatedurl'], $this->_post['email']))
|
||||
return 0;
|
||||
|
||||
trigger_error('AjaxContactus::handleContactUs - write to db failed', E_USER_ERROR);
|
||||
return Lang::main('intError');
|
||||
else if ($report->errorCode > 0)
|
||||
return $report->errorCode;
|
||||
else
|
||||
return Lang::main('intError');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ class CommunityContent
|
||||
{c.replyTo <> ?d AND}
|
||||
{c.replyTo = ?d AND}
|
||||
{ur.entry IS ?n AND}
|
||||
{(c.flags & ?d) AND}
|
||||
((c.flags & ?d) = 0 OR c.userId = ?d OR ?d)
|
||||
GROUP BY
|
||||
c.id
|
||||
@@ -143,6 +144,7 @@ class CommunityContent
|
||||
empty($params['replies']) ? DBSIMPLE_SKIP : 0, // i dont know, how to switch the sign around
|
||||
!empty($params['replies']) ? DBSIMPLE_SKIP : 0,
|
||||
empty($params['unrated']) ? DBSIMPLE_SKIP : null,
|
||||
empty($params['flags']) ? DBSIMPLE_SKIP : $params['flags'],
|
||||
CC_FLAG_DELETED,
|
||||
User::$id,
|
||||
User::isInGroup(U_GROUP_COMMENTS_MODERATOR),
|
||||
|
||||
@@ -1574,32 +1574,6 @@ abstract class Util
|
||||
);
|
||||
}
|
||||
|
||||
static function createReport($mode, $reason, $subject, $desc, $userAgent = null, $appName = null, $url = null, $relUrl = null, $email = null)
|
||||
{
|
||||
$update = array(
|
||||
'userId' => User::$id,
|
||||
'createDate' => time(),
|
||||
'mode' => $mode,
|
||||
'reason' => $reason,
|
||||
'subject' => $subject ?: 0, // not set for utility, tools and misc pages
|
||||
'ip' => User::$ip,
|
||||
'description' => $desc,
|
||||
'userAgent' => $userAgent ?: $_SERVER['HTTP_USER_AGENT'],
|
||||
'appName' => $appName ?: (get_browser(null, true)['browser'] ?: '')
|
||||
);
|
||||
|
||||
if ($url)
|
||||
$update['url'] = $url;
|
||||
|
||||
if ($relUrl)
|
||||
$update['relatedurl'] = $relUrl;
|
||||
|
||||
if ($email)
|
||||
$update['email'] = $email;
|
||||
|
||||
return DB::Aowow()->query('INSERT INTO ?_reports (?#) VALUES (?a)', array_keys($update), array_values($update));
|
||||
}
|
||||
|
||||
// orientation is 2*M_PI for a full circle, increasing counterclockwise
|
||||
static function O2Deg($o)
|
||||
{
|
||||
@@ -1871,4 +1845,271 @@ abstract class Type
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Report
|
||||
{
|
||||
public const MODE_GENERAL = 0;
|
||||
public const MODE_COMMENT = 1;
|
||||
public const MODE_FORUM_POST = 2;
|
||||
public const MODE_SCREENSHOT = 3;
|
||||
public const MODE_CHARACTER = 4;
|
||||
public const MODE_VIDEO = 5;
|
||||
public const MODE_GUIDE = 6;
|
||||
|
||||
public const GEN_FEEDBACK = 1;
|
||||
public const GEN_BUG_REPORT = 2;
|
||||
public const GEN_TYPO_TRANSLATION = 3;
|
||||
public const GEN_OP_ADVERTISING = 4;
|
||||
public const GEN_OP_PARTNERSHIP = 5;
|
||||
public const GEN_PRESS_INQUIRY = 6;
|
||||
public const GEN_MISCELLANEOUS = 7;
|
||||
public const GEN_MISINFORMATION = 8;
|
||||
public const CO_ADVERTISING = 15;
|
||||
public const CO_INACCURATE = 16;
|
||||
public const CO_OUT_OF_DATE = 17;
|
||||
public const CO_SPAM = 18;
|
||||
public const CO_INAPPROPRIATE = 19;
|
||||
public const CO_MISCELLANEOUS = 20;
|
||||
public const FO_ADVERTISING = 30;
|
||||
public const FO_AVATAR = 31;
|
||||
public const FO_INACCURATE = 32;
|
||||
public const FO_OUT_OF_DATE = 33;
|
||||
public const FO_SPAM = 34;
|
||||
public const FO_STICKY_REQUEST = 35;
|
||||
public const FO_INAPPROPRIATE = 36;
|
||||
public const FO_MISCELLANEOUS = 37;
|
||||
public const SS_INACCURATE = 45;
|
||||
public const SS_OUT_OF_DATE = 46;
|
||||
public const SS_INAPPROPRIATE = 47;
|
||||
public const SS_MISCELLANEOUS = 48;
|
||||
public const PR_INACCURATE_DATA = 60;
|
||||
public const PR_MISCELLANEOUS = 61;
|
||||
public const VI_INACCURATE = 45;
|
||||
public const VI_OUT_OF_DATE = 46;
|
||||
public const VI_INAPPROPRIATE = 47;
|
||||
public const VI_MISCELLANEOUS = 48;
|
||||
public const AR_INACCURATE = 45;
|
||||
public const AR_OUT_OF_DATE = 46;
|
||||
public const AR_MISCELLANEOUS = 48;
|
||||
|
||||
private /* array */ $context = array(
|
||||
self::MODE_GENERAL => array(
|
||||
self::GEN_FEEDBACK => true,
|
||||
self::GEN_BUG_REPORT => true,
|
||||
self::GEN_TYPO_TRANSLATION => true,
|
||||
self::GEN_OP_ADVERTISING => true,
|
||||
self::GEN_OP_PARTNERSHIP => true,
|
||||
self::GEN_PRESS_INQUIRY => true,
|
||||
self::GEN_MISCELLANEOUS => true,
|
||||
self::GEN_MISINFORMATION => true
|
||||
),
|
||||
self::MODE_COMMENT => array(
|
||||
self::CO_ADVERTISING => U_GROUP_MODERATOR,
|
||||
self::CO_INACCURATE => true,
|
||||
self::CO_OUT_OF_DATE => true,
|
||||
self::CO_SPAM => U_GROUP_MODERATOR,
|
||||
self::CO_INAPPROPRIATE => U_GROUP_MODERATOR,
|
||||
self::CO_MISCELLANEOUS => U_GROUP_MODERATOR
|
||||
),
|
||||
self::MODE_FORUM_POST => array(
|
||||
self::FO_ADVERTISING => U_GROUP_MODERATOR,
|
||||
self::FO_AVATAR => true,
|
||||
self::FO_INACCURATE => true,
|
||||
self::FO_OUT_OF_DATE => U_GROUP_MODERATOR,
|
||||
self::FO_SPAM => U_GROUP_MODERATOR,
|
||||
self::FO_STICKY_REQUEST => U_GROUP_MODERATOR,
|
||||
self::FO_INAPPROPRIATE => U_GROUP_MODERATOR
|
||||
),
|
||||
self::MODE_SCREENSHOT => array(
|
||||
self::SS_INACCURATE => true,
|
||||
self::SS_OUT_OF_DATE => true,
|
||||
self::SS_INAPPROPRIATE => U_GROUP_MODERATOR,
|
||||
self::SS_MISCELLANEOUS => U_GROUP_MODERATOR
|
||||
),
|
||||
self::MODE_CHARACTER => array(
|
||||
self::PR_INACCURATE_DATA => true,
|
||||
self::PR_MISCELLANEOUS => true
|
||||
),
|
||||
self::MODE_VIDEO => array(
|
||||
self::VI_INACCURATE => true,
|
||||
self::VI_OUT_OF_DATE => true,
|
||||
self::VI_INAPPROPRIATE => U_GROUP_MODERATOR,
|
||||
self::VI_MISCELLANEOUS => U_GROUP_MODERATOR
|
||||
),
|
||||
self::MODE_GUIDE => array(
|
||||
self::AR_INACCURATE => true,
|
||||
self::AR_OUT_OF_DATE => true,
|
||||
self::AR_MISCELLANEOUS => true
|
||||
)
|
||||
);
|
||||
|
||||
private const ERR_NONE = 0; // aka: success
|
||||
private const ERR_INVALID_CAPTCHA = 1; // captcha not in use
|
||||
private const ERR_DESC_TOO_LONG = 2;
|
||||
private const ERR_NO_DESC = 3;
|
||||
private const ERR_ALREADY_REPORTED = 7;
|
||||
private const ERR_MISCELLANEOUS = -1;
|
||||
|
||||
public const STATUS_OPEN = 0;
|
||||
public const STATUS_ASSIGNED = 1;
|
||||
public const STATUS_CLOSED_WONTFIX = 2;
|
||||
public const STATUS_CLOSED_SOLVED = 3;
|
||||
|
||||
private /* int */ $mode = 0;
|
||||
private /* int */ $reason = 0;
|
||||
private /* int */ $subject = 0;
|
||||
|
||||
public /* readonly int */ $errorCode;
|
||||
|
||||
|
||||
public function __construct(int $mode, int $reason, int $subject = 0)
|
||||
{
|
||||
if ($mode < 0 || $reason <= 0 || !$subject)
|
||||
{
|
||||
trigger_error('AjaxContactus::handleContactUs - malformed contact request received', E_USER_ERROR);
|
||||
$this->errorCode = self::ERR_MISCELLANEOUS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($this->context[$mode][$reason]))
|
||||
{
|
||||
trigger_error('AjaxContactus::handleContactUs - report has invalid context (mode:'.$mode.' / reason:'.$reason.')', E_USER_ERROR);
|
||||
$this->errorCode = self::ERR_MISCELLANEOUS;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!User::$id && !User::$ip)
|
||||
{
|
||||
trigger_error('AjaxContactus::handleContactUs - could not determine IP for anonymous user', E_USER_ERROR);
|
||||
$this->errorCode = self::ERR_MISCELLANEOUS;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->mode = $mode;
|
||||
$this->reason = $reason;
|
||||
$this->subject = $subject; // 0 for utility, tools and misc pages?
|
||||
}
|
||||
|
||||
private function checkTargetContext() : int
|
||||
{
|
||||
// check already reported
|
||||
$field = User::$id ? 'userId' : 'ip';
|
||||
if (DB::Aowow()->selectCell('SELECT 1 FROM ?_reports WHERE `mode` = ?d AND `reason`= ?d AND `subject` = ?d AND ?# = ?', $this->mode, $this->reason, $this->subject, $field, User::$id ?: User::$ip))
|
||||
return self::ERR_ALREADY_REPORTED;
|
||||
|
||||
// check targeted post/postOwner staff status
|
||||
$ctxCheck = $this->context[$this->mode][$this->reason];
|
||||
if (is_int($ctxCheck))
|
||||
{
|
||||
$roles = User::$groups;
|
||||
if ($this->mode == self::MODE_COMMENT)
|
||||
$roles = DB::Aowow()->selectCell('SELECT `roles` FROM ?_comments WHERE `id` = ?d', $this->subject);
|
||||
// else if if ($this->mode == self::MODE_FORUM_POST)
|
||||
// $roles = DB::Aowow()->selectCell('SELECT `roles` FROM ?_forum_posts WHERE `id` = ?d', $this->subject);
|
||||
|
||||
return $roles & $ctxCheck ? self::ERR_NONE : self::ERR_MISCELLANEOUS;
|
||||
}
|
||||
else
|
||||
return $ctxCheck ? self::ERR_NONE : self::ERR_MISCELLANEOUS;
|
||||
|
||||
// Forum not in use, else:
|
||||
// check post owner
|
||||
// User::$id == post.op && !post.sticky;
|
||||
// check user custom avatar
|
||||
// g_users[post.user].avatar == 2 && (post.roles & U_GROUP_MODERATOR) == 0
|
||||
}
|
||||
|
||||
public function create(string $desc, ?string $userAgent = null, ?string $appName = null, ?string $pageUrl = null, ?string $relUrl = null, ?string $email = null) : bool
|
||||
{
|
||||
if ($this->errorCode)
|
||||
return false;
|
||||
|
||||
if (!$desc)
|
||||
{
|
||||
$this->errorCode = self::ERR_NO_DESC;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mb_strlen($desc) > 500)
|
||||
{
|
||||
$this->errorCode = self::ERR_DESC_TOO_LONG;
|
||||
return false;
|
||||
}
|
||||
|
||||
if($err = $this->checkTargetContext())
|
||||
{
|
||||
$this->errorCode = $err;
|
||||
return false;
|
||||
}
|
||||
|
||||
$update = array(
|
||||
'userId' => User::$id,
|
||||
'createDate' => time(),
|
||||
'mode' => $this->mode,
|
||||
'reason' => $this->reason,
|
||||
'subject' => $this->subject,
|
||||
'ip' => User::$ip,
|
||||
'description' => $desc,
|
||||
'userAgent' => $userAgent ?: $_SERVER['HTTP_USER_AGENT'],
|
||||
'appName' => $appName ?: (get_browser(null, true)['browser'] ?: '')
|
||||
);
|
||||
|
||||
if ($pageUrl)
|
||||
$update['url'] = $pageUrl;
|
||||
|
||||
if ($relUrl)
|
||||
$update['relatedurl'] = $relUrl;
|
||||
|
||||
if ($email)
|
||||
$update['email'] = $email;
|
||||
|
||||
return DB::Aowow()->query('INSERT INTO ?_reports (?#) VALUES (?a)', array_keys($update), array_values($update));
|
||||
}
|
||||
|
||||
public function getSimilar(int ...$status) : array
|
||||
{
|
||||
if ($this->errorCode)
|
||||
return [];
|
||||
|
||||
foreach ($status as &$s)
|
||||
if ($s < self::STATUS_OPEN || $s > self::STATUS_CLOSED_SOLVED)
|
||||
unset($s);
|
||||
|
||||
return DB::Aowow()->select('SELECT `id` AS ARRAY_KEY, r.* FROM ?_reports r WHERE {`status` IN (?a) AND }`mode` = ?d AND `reason` = ?d AND `subject` = ?d',
|
||||
$status ?: DBSIMPLE_SKIP, $this->mode, $this->reason, $this->subject);
|
||||
}
|
||||
|
||||
public function close(int $closeStatus, bool $inclAssigned = false) : bool
|
||||
{
|
||||
if ($closeStatus != self::STATUS_CLOSED_SOLVED && $closeStatus != self::STATUS_CLOSED_WONTFIX)
|
||||
return false;
|
||||
|
||||
if (!User::isInGroup(U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_MOD))
|
||||
return false;
|
||||
|
||||
$fromStatus = [self::STATUS_OPEN];
|
||||
if ($inclAssigned)
|
||||
$fromStatus[] = self::STATUS_ASSIGNED;
|
||||
|
||||
if ($reports = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, `userId` FROM ?_reports WHERE `status` IN (?a) AND `mode` = ?d AND `reason` = ?d AND `subject` = ?d',
|
||||
$fromStatus, $this->mode, $this->reason, $this->subject))
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_reports SET `status` = ?d, `assigned` = 0 WHERE `id` IN (?a)', $closeStatus, array_keys($reports));
|
||||
|
||||
foreach ($reports as $rId => $uId)
|
||||
Util::gainSiteReputation($uId, $closeStatus == self::STATUS_CLOSED_SOLVED ? SITEREP_ACTION_GOOD_REPORT : SITEREP_ACTION_BAD_REPORT, ['id' => $rId]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function reopen(int $assignedTo = 0) : bool
|
||||
{
|
||||
// assignedTo = 0 ? status = STATUS_OPEN : status = STATUS_ASSIGNED, userId = assignedTo
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -65,6 +65,22 @@ class AdminPage extends GenericPage
|
||||
array_push($this->path, 1, 25);
|
||||
$this->name = 'Pending Guides';
|
||||
break;
|
||||
case 'out-of-date':
|
||||
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_MOD;
|
||||
$this->generator = 'handleOutOfDate';
|
||||
$this->tpl = 'list-page-generic';
|
||||
|
||||
array_push($this->path, 1, 23);
|
||||
$this->name = 'Out of Date Comments';
|
||||
break;
|
||||
case 'reports':
|
||||
$this->reqUGroup = U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_EDITOR | U_GROUP_MOD | U_GROUP_LOCALIZER | U_GROUP_SCREENSHOT | U_GROUP_VIDEO;
|
||||
$this->generator = 'handleReports';
|
||||
$this->tpl = 'admin/reports';
|
||||
|
||||
array_push($this->path, 5);
|
||||
$this->name = 'Reports';
|
||||
break;
|
||||
default: // error out through unset template
|
||||
}
|
||||
|
||||
@@ -280,6 +296,22 @@ class AdminPage extends GenericPage
|
||||
), 'guideAdminCol'];
|
||||
}
|
||||
|
||||
private function handleOutOfDate() : void
|
||||
{
|
||||
$data = CommunityContent::getCommentPreviews(['flags' => CC_FLAG_OUTDATED]);
|
||||
|
||||
$this->lvTabs[] = ['commentpreview', array(
|
||||
'data' => $data,
|
||||
'extraCols' => '$_'
|
||||
), 'commentAdminCol'];
|
||||
}
|
||||
|
||||
private function handleReports() : void
|
||||
{
|
||||
// todo: handle reports listing
|
||||
//
|
||||
}
|
||||
|
||||
private function configAddRow($r)
|
||||
{
|
||||
$buff = '<tr>';
|
||||
|
||||
@@ -21213,52 +21213,28 @@ var ContactTool = new function() {
|
||||
[7, true] // Other
|
||||
],
|
||||
1: [ // comment
|
||||
[15, function(post) {
|
||||
return ((post.roles & U_GROUP_MODERATOR) == 0);
|
||||
}], // Advertising
|
||||
[16, true], // Inaccurate
|
||||
[17, true], // Out of date
|
||||
[18, function(post) {
|
||||
return ((post.roles & U_GROUP_MODERATOR) == 0);
|
||||
}], // Spam
|
||||
[19, function(post) {
|
||||
return ((post.roles & U_GROUP_MODERATOR) == 0);
|
||||
}], // Vulgar/inappropriate
|
||||
[20, function(post) {
|
||||
return ((post.roles & U_GROUP_MODERATOR) == 0);
|
||||
}] // Other
|
||||
[15, function(post) { return ((post.roles & U_GROUP_MODERATOR) == 0); }], // Advertising
|
||||
[16, true], // Inaccurate
|
||||
[17, true], // Out of date
|
||||
[18, function(post) { return ((post.roles & U_GROUP_MODERATOR) == 0); }], // Spam
|
||||
[19, function(post) { return ((post.roles & U_GROUP_MODERATOR) == 0); }], // Vulgar/inappropriate
|
||||
[20, function(post) { return ((post.roles & U_GROUP_MODERATOR) == 0); }] // Other
|
||||
],
|
||||
2: [ // forum post
|
||||
[30, function(post) {
|
||||
return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0);
|
||||
}], // Advertising
|
||||
[37, function(post) {
|
||||
return ((post.roles & U_GROUP_MODERATOR) == 0 && g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0 && g_users[post.user].avatar == 2);
|
||||
}], // Avatar
|
||||
[31, true], // Inaccurate
|
||||
[32, true], // Out of date
|
||||
[33, function(post) {
|
||||
return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0);
|
||||
}], // Spam
|
||||
[34, function(post) {
|
||||
return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0 && post.op && !post.sticky);
|
||||
}], // Sticky request
|
||||
[35, function(post) {
|
||||
return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0);
|
||||
}], // Vulgar/inappropriate
|
||||
[36, function(post) {
|
||||
return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0);
|
||||
}] // Other
|
||||
[30, function(post) { return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0); }], // Advertising
|
||||
[37, function(post) { return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0 && (post.roles & U_GROUP_MODERATOR) == 0 && g_users[post.user].avatar == 2); }], // Avatar
|
||||
[31, true], // Inaccurate
|
||||
[32, true], // Out of date
|
||||
[33, function(post) { return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0); }], // Spam
|
||||
[34, function(post) { return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0 && post.op && !post.sticky); }], // Sticky request
|
||||
[35, function(post) { return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0); }], // Vulgar/inappropriate
|
||||
[36, function(post) { return (g_users && g_users[post.user] && (g_users[post.user].roles & U_GROUP_MODERATOR) == 0);}] // Other
|
||||
],
|
||||
3: [ // screenshot
|
||||
[45, true], // Inaccurate,
|
||||
[46, true], // Out of date,
|
||||
[47, function(screen) {
|
||||
return (g_users && g_users[screen.user] && (g_users[screen.user].roles & U_GROUP_MODERATOR) == 0);
|
||||
}], // Vulgar/inappropriate
|
||||
[48, function(screen) {
|
||||
return (g_users && g_users[screen.user] && (g_users[screen.user].roles & U_GROUP_MODERATOR) == 0);
|
||||
}] // Other
|
||||
[47, function(screen) { return (g_users && g_users[screen.user] && (g_users[screen.user].roles & U_GROUP_MODERATOR) == 0); }], // Vulgar/inappropriate
|
||||
[48, function(screen) { return (g_users && g_users[screen.user] && (g_users[screen.user].roles & U_GROUP_MODERATOR) == 0); }] // Other
|
||||
],
|
||||
4: [ // character
|
||||
[60, true], // Inaccurate completion data
|
||||
@@ -21267,14 +21243,10 @@ var ContactTool = new function() {
|
||||
5: [ // video
|
||||
[45, true], // Inaccurate,
|
||||
[46, true], // Out of date,
|
||||
[47, function(video) {
|
||||
return (g_users && g_users[video.user] && (g_users[video.user].roles & U_GROUP_MODERATOR) == 0);
|
||||
}], // Vulgar/inappropriate
|
||||
[48, function(video) {
|
||||
return (g_users && g_users[video.user] && (g_users[video.user].roles & U_GROUP_MODERATOR) == 0);
|
||||
}] // Other
|
||||
[47, function(video) { return (g_users && g_users[video.user] && (g_users[video.user].roles & U_GROUP_MODERATOR) == 0); }], // Vulgar/inappropriate
|
||||
[48, function(video) { return (g_users && g_users[video.user] && (g_users[video.user].roles & U_GROUP_MODERATOR) == 0); }] // Other
|
||||
],
|
||||
6: [ // Guide
|
||||
6: [ // guide
|
||||
[45, true], // Inaccurate,
|
||||
[46, true], // Out of date,
|
||||
[48, true] // Other
|
||||
@@ -21323,12 +21295,12 @@ var ContactTool = new function() {
|
||||
|
||||
var params = [
|
||||
'contact=1',
|
||||
'mode=' + $WH.urlencode(data.mode),
|
||||
'reason=' + $WH.urlencode(data.reason),
|
||||
'desc=' + $WH.urlencode(data.description),
|
||||
'ua=' + $WH.urlencode(navigator.userAgent),
|
||||
'mode=' + $WH.urlencode(data.mode),
|
||||
'reason=' + $WH.urlencode(data.reason),
|
||||
'desc=' + $WH.urlencode(data.description),
|
||||
'ua=' + $WH.urlencode(navigator.userAgent),
|
||||
'appname=' + $WH.urlencode(navigator.appName),
|
||||
'page=' + $WH.urlencode(data.currenturl)
|
||||
'page=' + $WH.urlencode(data.currenturl)
|
||||
];
|
||||
|
||||
if (data.mode == 0) { // contact us
|
||||
@@ -21366,30 +21338,27 @@ var ContactTool = new function() {
|
||||
onSuccess: function(xhr, opt) {
|
||||
var resp = xhr.responseText;
|
||||
if (resp == 0) {
|
||||
if (g_user.name) {
|
||||
if (g_user.name)
|
||||
alert($WH.sprintf(LANG.ct_dialog_thanks_user, g_user.name));
|
||||
}
|
||||
else {
|
||||
else
|
||||
alert(LANG.ct_dialog_thanks);
|
||||
}
|
||||
|
||||
Lightbox.hide();
|
||||
}
|
||||
else {
|
||||
if (errors[resp]) {
|
||||
if (errors[resp])
|
||||
alert(errors[resp]);
|
||||
}
|
||||
else {
|
||||
else
|
||||
alert('Error: ' + resp);
|
||||
}
|
||||
}
|
||||
},
|
||||
onFailure: function(xhr, opt) {
|
||||
alert('Failure submitting contact request: ' + xhr.statusText);
|
||||
},
|
||||
onComplete: function(xhr, opt) {
|
||||
for (var i = 0; i < form.elements.length; ++i) {
|
||||
for (var i = 0; i < form.elements.length; ++i)
|
||||
form.elements[i].disabled = false;
|
||||
}
|
||||
|
||||
data.submitting = false;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -106,7 +106,7 @@ var mn_staff = [
|
||||
// [3, 'Localization', null, mn_localization],
|
||||
// [7, 'Statistics', null, mn_statistics, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_DEV}],
|
||||
// [4, 'Users', null, mn_users],
|
||||
// [5, 'View Reports', '?admin=reports', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_EDITOR | U_GROUP_MOD | U_GROUP_LOCALIZER | U_GROUP_SCREENSHOT | U_GROUP_VIDEO} ],
|
||||
[5, 'View Reports', '?admin=reports', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_EDITOR | U_GROUP_MOD | U_GROUP_LOCALIZER | U_GROUP_SCREENSHOT | U_GROUP_VIDEO} ],
|
||||
|
||||
[, 'Page'],
|
||||
[102, 'Validate', 'http://validator.w3.org/check/referer', null, {requiredAccess: U_GROUP_ADMIN | U_GROUP_BUREAU | U_GROUP_DEV | U_GROUP_TESTER}]];
|
||||
|
||||
50
template/listviews/commentAdminCol.tpl.php
Normal file
50
template/listviews/commentAdminCol.tpl.php
Normal file
@@ -0,0 +1,50 @@
|
||||
var _ = [
|
||||
{
|
||||
id: 'manage',
|
||||
name: 'Manage',
|
||||
type: 'text',
|
||||
align: 'center',
|
||||
value: 'subject',
|
||||
sortable: false,
|
||||
compute: function(comment, td, tr) {
|
||||
let wrapper = $WH.ce('div');
|
||||
|
||||
let send = function (el, id, status)
|
||||
{
|
||||
$.ajax({cache: false, url: '?admin=comment', type: 'POST',
|
||||
error: function() {
|
||||
alert('Operation failed.');
|
||||
},
|
||||
success: function(json) {
|
||||
if (json != 1)
|
||||
alert('Operation failed.');
|
||||
else
|
||||
$WH.de(el.parentNode);
|
||||
},
|
||||
data: { id: id, status: status }
|
||||
})
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
let a = $WH.ce('a');
|
||||
a.style.fontFamily = 'Verdana, sans-serif';
|
||||
a.style.marginLeft = '10px';
|
||||
a.href = '#';
|
||||
|
||||
_ = a.cloneNode();
|
||||
_.className = 'icon-tick';
|
||||
_.onclick = send.bind(this, td, comment.id, 0);
|
||||
g_addTooltip(_, LANG.lvcomment_uptodate);
|
||||
$WH.ae(wrapper, _);
|
||||
|
||||
_ = a.cloneNode();
|
||||
_.className = 'icon-delete';
|
||||
_.onclick = send.bind(this, td, comment.id, 1);
|
||||
g_addTooltip(_, LANG.delete);
|
||||
$WH.ae(wrapper, _);
|
||||
|
||||
$WH.ae(td, wrapper);
|
||||
}
|
||||
}
|
||||
];
|
||||
53
template/pages/admin/reports.tpl.php
Normal file
53
template/pages/admin/reports.tpl.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php $this->brick('header'); ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
<div class="main" id="main">
|
||||
<div class="main-precontents" id="main-precontents"></div>
|
||||
<div class="main-contents" id="main-contents">
|
||||
|
||||
<?php
|
||||
$this->brick('announcement');
|
||||
|
||||
$this->brick('pageTemplate');
|
||||
?>
|
||||
<div class="text">
|
||||
<h1><?=$this->name;?></h1>
|
||||
|
||||
<?php
|
||||
$this->brick('article');
|
||||
|
||||
if (isset($this->extraText)):
|
||||
?>
|
||||
<div id="text-generic" class="left"></div>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
Markup.printHtml("<?=Util::jsEscape($this->extraText);?>", "text-generic", {
|
||||
allow: Markup.CLASS_ADMIN,
|
||||
dbpage: true
|
||||
});
|
||||
//]]></script>
|
||||
|
||||
<div class="pad2"></div>
|
||||
<?php
|
||||
endif;
|
||||
|
||||
if (isset($this->extraHTML)):
|
||||
echo $this->extraHTML;
|
||||
endif;
|
||||
?>
|
||||
<h2>Edit<span id="wt-name"></span><span id="status-ic" style="float:right;"></span></h2>
|
||||
<div class="wt-edit">
|
||||
<div style="display:inline-block; vertical-align:top;"><div class="pad2" style="color: white; font-size: 15px; font-weight: bold;">Icon</div><input type="text" id="wt-icon" size="30" /></div>
|
||||
<div id="ic-container" style="display: inline-block; clear: left;"></div>
|
||||
</div>
|
||||
<div class="wt-edit">
|
||||
<div class="pad2" style="color: white; font-size: 15px; font-weight: bold;">Scale</div>
|
||||
<div id="su-container"></div>
|
||||
</div>
|
||||
<div id="su-controls" class="wt-edit" style="width:auto;"></div>
|
||||
</div>
|
||||
</div><!-- main-contents -->
|
||||
</div><!-- main -->
|
||||
|
||||
<?php $this->brick('footer'); ?>
|
||||
Reference in New Issue
Block a user