-
+
Website / Server Info
@@ -106,7 +121,8 @@ pageBuilder::buildHeader();
=$usage->Disk->SystemUsage?> / =$usage->Disk->Total?> Used
- =SITE_CONFIG["site"]["name"]?> is using =$usage->Disk->PolygonUsage?>
+ =SITE_CONFIG["site"]["name"]?> is using =$usage->Disk->PolygonUsage?>
+ Thumbnail CDN is using =$usage->Disk->ThumbnailUsage?>
Client setup (2009-2012) is using =$usage->Disk->SetupUsage?> total
@@ -131,7 +147,6 @@ pageBuilder::buildHeader();
dead much?
-
diff --git a/api/account/character/get-assets.php b/api/account/character/get-assets.php
index 5536461..f87f56d 100644
--- a/api/account/character/get-assets.php
+++ b/api/account/character/get-assets.php
@@ -1,5 +1,7 @@
- "POST", "logged" => true, "secure" => true]);
$wearing = isset($_POST["wearing"]) && $_POST["wearing"] == "true";
@@ -14,8 +16,8 @@ if($wearing)
}
else
{
- $type_str = catalog::getTypeByNum($type);
- if(!catalog::getTypeByNum($type)) api::respond(400, false, "Invalid asset type");
+ $type_str = Catalog::GetTypeByNum($type);
+ if(!Catalog::GetTypeByNum($type)) api::respond(400, false, "Invalid asset type");
$query = $pdo->prepare("SELECT COUNT(*) FROM ownedAssets INNER JOIN assets ON assets.id = assetId WHERE userId = :uid AND assets.type = :type AND wearing = 0");
$query->bindParam(":type", $type, PDO::PARAM_INT);
}
@@ -23,6 +25,8 @@ $query->bindParam(":uid", $userId, PDO::PARAM_INT);
$query->execute();
$pages = ceil($query->fetchColumn()/8);
+if($page > $pages) $page = $pages;
+if(!is_numeric($page) || $page < 1) $page = 1;
$offset = ($page - 1)*8;
if(!$pages) api::respond(200, true, $wearing ? 'You are not currently wearing anything' : 'You don\'t have any unequipped '.($type_str.(!str_ends_with($type_str, 's') ? 's' : '').' to wear'));
diff --git a/api/account/character/paint-body.php b/api/account/character/paint-body.php
index 9517a9f..bd17a12 100644
--- a/api/account/character/paint-body.php
+++ b/api/account/character/paint-body.php
@@ -8,7 +8,7 @@ $bodyPart = $_POST["BodyPart"] ?? false;
$color = $_POST["Color"] ?? false;
if(!$color || !in_array($bodyPart, ["Head", "Torso", "Left Arm", "Right Arm", "Left Leg", "Right Leg"])) api::respond(400, false, "Bad Request");
-$brickcolor = users::hex2bc(rgbtohex($color));
+$brickcolor = Users::hex2bc(rgbtohex($color));
if(!$brickcolor) api::respond(200, false, "Invalid body color #".rgbtohex($color));
$bodyColors->{$bodyPart} = $brickcolor;
$bodyColors = json_encode($bodyColors);
diff --git a/api/account/character/request-render.php b/api/account/character/request-render.php
index 8f444ca..487e7ac 100644
--- a/api/account/character/request-render.php
+++ b/api/account/character/request-render.php
@@ -2,6 +2,6 @@
require $_SERVER['DOCUMENT_ROOT'].'/api/private/core.php';
api::initialize(["method" => "POST", "logged_in" => true, "secure" => true]);
-polygon::requestRender("Avatar", SESSION["userId"]);
+Polygon::RequestRender("Avatar", SESSION["userId"]);
api::respond(200, true, "OK");
\ No newline at end of file
diff --git a/api/account/get-feed.php b/api/account/get-feed.php
new file mode 100644
index 0000000..37bea5e
--- /dev/null
+++ b/api/account/get-feed.php
@@ -0,0 +1,107 @@
+ "POST", "logged_in" => true]);
+
+$FeedResults = db::run(
+ "SELECT feed.*, users.username FROM feed
+ INNER JOIN users ON users.id = feed.userId WHERE userId = :uid
+ OR groupId IS NULL AND userId IN
+ (
+ SELECT (CASE WHEN requesterId = :uid THEN receiverId ELSE requesterId END) FROM friends
+ WHERE requesterId = :uid OR receiverId = :uid AND status = 1
+ )
+ OR groupId IN
+ (
+ SELECT groups_members.GroupID FROM groups_members
+ INNER JOIN groups_ranks ON groups_ranks.GroupID = groups_members.GroupID AND groups_ranks.Rank = groups_members.Rank
+ WHERE groups_members.UserID = :uid AND groups_ranks.permissions LIKE '%\"CanViewGroupStatus\":true%'
+ )
+ ORDER BY feed.id DESC LIMIT 15",
+ [":uid" => SESSION["userId"]]
+);
+
+$feed = [];
+$news = [];
+
+/*$news[] =
+[
+ "header" => '
lol
',
+ "message" => 'fucked your mom'
+];*/
+
+/*$news[] =
+[
+ "header" => '
this isn\'t dead!!!! (probably)
',
+ "message" => "ive been more inclined to work on polygon now after like 4 months, so i guess development has resumed
2fa has been implemented, and next on the roadmap is the catalog system. so yeah, stay tuned for that"
+];*/
+
+/* $news[] =
+[
+ "header" => "",
+ "img" => "https://media.discordapp.net/attachments/745025397749448814/835635922590629888/HDKolobok-256px-3.gif",
+ // "message" => "What you know about KOLONBOK. ™ "
+ "message" => "KOLONBOK. ™ Has fix 2009"
+]; */
+
+/* $news[] =
+[
+ "header" => "Groups have been released!",
+ "img" => "/img/ProjectPolygon.png",
+ "message" => "Groups have now been fully released, with more functionality than you could ever imagine. Groups don't cost anything to make, and you can join up to 20 of them.
If you haven't yet, come join the
official group!"
+]; */
+
+while($row = $FeedResults->fetch(PDO::FETCH_OBJ))
+{
+ $timestamp = timeSince($row->timestamp);
+
+ if($row->groupId == NULL)
+ {
+ $feed[] =
+ [
+ "userName" => $row->username,
+ "img" => Thumbnails::GetAvatar($row->userId, 100, 100),
+ "header" => "
userId}\">{$row->username} - {$timestamp}
",
+ "message" => Polygon::FilterText($row->text)
+ ];
+ }
+ else
+ {
+ $GroupInfo = Groups::GetGroupInfo($row->groupId, true, true);
+
+ $feed[] =
+ [
+ "userName" => $GroupInfo->name,
+ "img" => Thumbnails::GetAssetFromID($GroupInfo->emblem, 420, 420),
+ "header" => "
id}\">{$GroupInfo->name} - posted by userId}\">{$row->username} - {$timestamp}
",
+ "message" => Polygon::FilterText($row->text)
+ ];
+ }
+}
+
+$FeedCount = $FeedResults->rowCount();
+
+if($FeedCount < 15)
+{
+ $feed[] =
+ [
+ "userName" => "Your feed is currently empty!",
+ "img" => "/img/feed/friends.png",
+ "header" => "
Looks like your feed's empty
",
+ "message" => "If you haven't made any friends yet,
go make some!
If you already have some, why don't you kick off the discussion?"
+ ];
+
+ if($FeedCount < 14)
+ {
+ $feed[] =
+ [
+ "userName" => "Customize your character",
+ "img" => "/img/feed/cart.png",
+ "header" => "
Customize your character
",
+ "message" => "Log in every day and earn 10 pizzas. Pizzas can be used to buy clothing in our
catalog. You can also create your own clothing on the
Build page."
+ ];
+ }
+}
+
+api::respond_custom(["status" => 200, "success" => true, "message" => "OK", "feed" => $feed, "news" => $news]);
\ No newline at end of file
diff --git a/api/account/getRecentlyPlayed.php b/api/account/get-recentlyplayed.php
similarity index 76%
rename from api/account/getRecentlyPlayed.php
rename to api/account/get-recentlyplayed.php
index 484487e..9e2128a 100644
--- a/api/account/getRecentlyPlayed.php
+++ b/api/account/get-recentlyplayed.php
@@ -1,5 +1,8 @@
"POST", "logged_in" => true]);
$userid = SESSION["userId"];
@@ -16,10 +19,10 @@ $query->execute();
while($game = $query->fetch(PDO::FETCH_OBJ))
$items[] =
[
- "game_name" => polygon::filterText($game->name),
+ "game_name" => Polygon::FilterText($game->name),
"game_id" => $game->id,
"game_thumbnail" => Thumbnails::GetAvatar($game->hoster, 250, 250),
- "playing" => games::getPlayersInServer($game->id)->rowCount()
+ "playing" => Games::GetPlayersInServer($game->id)->rowCount()
];
api::respond_custom(["status" => 200, "success" => true, "message" => "OK", "items" => $items]);
\ No newline at end of file
diff --git a/api/account/transactions.php b/api/account/get-transactions.php
similarity index 91%
rename from api/account/transactions.php
rename to api/account/get-transactions.php
index 4970bec..524b40c 100644
--- a/api/account/transactions.php
+++ b/api/account/get-transactions.php
@@ -1,5 +1,6 @@
- "POST", "logged_in" => true, "secure" => true]);
$userid = SESSION["userId"];
@@ -31,7 +32,7 @@ while($transaction = $query->fetch(PDO::FETCH_OBJ))
$transactions[] =
[
"type" => $type == "Sales" ? "Sold" : "Purchased",
- "date" => date('n/j/y', $transaction->timestamp),
+ "date" => date('j/n/y', $transaction->timestamp),
"member_name" => $transaction->username,
"member_id" => $memberID,
"member_avatar" => Thumbnails::GetAvatar($memberID, 48, 48),
diff --git a/api/account/getFeed.php b/api/account/getFeed.php
deleted file mode 100644
index 4afc08c..0000000
--- a/api/account/getFeed.php
+++ /dev/null
@@ -1,60 +0,0 @@
- "POST", "logged_in" => true]);
-
-$userid = SESSION["userId"];
-
-$query = $pdo->prepare("
- SELECT * FROM feed
- WHERE userId = :uid
- OR userId IN (SELECT receiverId FROM friends WHERE requesterId = :uid AND status = 1)
- OR userId IN (SELECT requesterId FROM friends WHERE receiverId = :uid AND status = 1)
- ORDER BY id DESC LIMIT 15");
-$query->bindParam(":uid", $userid, PDO::PARAM_INT);
-$query->execute();
-
-$feed = [];
-$news = [];
-
-/*$news[] =
-[
- "header" => '
lol
',
- "message" => 'fucked your mom'
-];*/
-
-/*$news[] =
-[
- "header" => '
this isn\'t dead!!!! (probably)
',
- "message" => "ive been more inclined to work on polygon now after like 4 months, so i guess development has resumed
2fa has been implemented, and next on the roadmap is the catalog system. so yeah, stay tuned for that"
-];*/
-
-/* $news[] =
-[
- "header" => "",
- "img" => "https://media.discordapp.net/attachments/745025397749448814/835635922590629888/HDKolobok-256px-3.gif",
- // "message" => "What you know about KOLONBOK. ™ "
- "message" => "KOLONBOK. ™ Has fix 2009"
-]; */
-
-while($row = $query->fetch(PDO::FETCH_OBJ))
-{
- $feed[] =
- [
- "userName" => users::getUserNameFromUid($row->userId),
- "img" => Thumbnails::GetAvatar($row->userId, 100, 100),
- "header" => '
'.users::getUserNameFromUid($row->userId).' - '.timeSince('@'.$row->timestamp).'
',
- "message" => polygon::filterText($row->text)
- ];
-}
-
-if($query->rowCount() < 15)
-{
- $feed[] =
- [
- "userName" => "Your feed is currently empty!",
- "img" => "/img/feed-starter.png",
- "header" => '
Looks like your feed\'s empty
',
- "message" => "If you haven't made any friends yet,
go make some!
If you already have some, why don't you kick off the discussion?"
- ];
-}
-api::respond_custom(["status" => 200, "success" => true, "message" => "OK", "feed" => $feed, "news" => $news]);
\ No newline at end of file
diff --git a/api/account/uodate-password.php b/api/account/update-password.php
similarity index 78%
rename from api/account/uodate-password.php
rename to api/account/update-password.php
index 945f539..5ae65d7 100644
--- a/api/account/uodate-password.php
+++ b/api/account/update-password.php
@@ -1,20 +1,21 @@
- "POST", "logged_in" => true, "secure" => true]);
if(!isset($_POST['currentpwd']) || !isset($_POST['newpwd']) || !isset($_POST['confnewpwd'])) api::respond(400, false, "Bad Request");
$userid = SESSION["userId"];
$row = (object)SESSION["userInfo"];
-$currentpwd = new auth($_POST['currentpwd']);
-$newpwd = new auth($_POST['newpwd']);
+$currentpwd = new Auth($_POST['currentpwd']);
+$newpwd = new Auth($_POST['newpwd']);
if($row->lastpwdchange+1800 > time()) api::respond(429, false, "Please wait ".ceil((($row->lastpwdchange+1800)-time())/60)." minutes before attempting to change your password again");
-if(!$currentpwd->verifyPassword($row->password)) api::respond(400, false, "Your current password does not match");
+if(!$currentpwd->VerifyPassword($row->password)) api::respond(400, false, "Your current password does not match");
if($_POST['currentpwd'] == $_POST['newpwd']) api::respond(400, false, "Your new password cannot be the same as your current one");
if(strlen(preg_replace('/[0-9]/', "", $_POST['newpwd'])) < 6) api::respond(400, false, "Your new password is too weak. Make sure it contains at least six non-numeric characters");
if(strlen(preg_replace('/[^0-9]/', "", $_POST['newpwd'])) < 2) api::respond(400, false, "Your new password is too weak. Make sure it contains at least two numbers");
if($_POST['newpwd'] != $_POST['confnewpwd']) api::respond(400, false, "Confirmation password does not match");
-$newpwd->updatePassword($userid);
+$newpwd->UpdatePassword($userid);
api::respond(200, true, "OK");
\ No newline at end of file
diff --git a/api/account/ping.php b/api/account/update-ping.php
similarity index 70%
rename from api/account/ping.php
rename to api/account/update-ping.php
index 4f9abd2..a54094f 100644
--- a/api/account/ping.php
+++ b/api/account/update-ping.php
@@ -1,5 +1,4 @@
- "POST", "logged_in" => true, "secure" => true]);
-users::updatePing();
+Users::UpdatePing();
api::respond_custom(["status" => 200, "success" => true, "message" => "OK", "friendRequests" => (int)SESSION["friendRequests"]]);
\ No newline at end of file
diff --git a/api/account/update-settings.php b/api/account/update-settings.php
index 2ba030b..edea276 100644
--- a/api/account/update-settings.php
+++ b/api/account/update-settings.php
@@ -8,10 +8,11 @@ $userid = SESSION["userId"];
$filter = (int)($_POST['filter'] == 'true');
$debugging = (int)(isset($_POST['debugging']) && $_POST['debugging'] == 'true');
-if(!in_array($_POST['theme'], ["light", "dark"])) api::respond(200, false, "Invalid theme");
+if(!in_array($_POST['theme'], ["light", "dark", "hitius", "2014"])) api::respond(200, false, "Invalid theme");
-if(!strlen($_POST['blurb'])) api::respond(200, false, "Your blurb can't be empty!");
-if(strlen($_POST['blurb']) > 1000) api::respond(200, false, "Your blurb is too large!");
+if(!strlen($_POST['blurb'])) api::respond(200, false, "Your blurb can't be empty");
+if(strlen($_POST['blurb']) > 1000) api::respond(200, false, "Your blurb is too large");
+if(Polygon::IsExplicitlyFiltered($_POST["blurb"])) api::respond(200, false, "Your blurb contains inappropriate text");
db::run(
"UPDATE users SET blurb = :blurb, filter = :filter, theme = :theme, debugging = :debugging WHERE id = :uid",
diff --git a/api/account/update-status.php b/api/account/update-status.php
new file mode 100644
index 0000000..fbb1bf6
--- /dev/null
+++ b/api/account/update-status.php
@@ -0,0 +1,44 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+$userId = SESSION["userId"];
+$status = $_POST['status'] ?? false;
+
+if(!strlen($status)) api::respond(200, false, "Your status cannot be empty");
+if(strlen($status) > 140) api::respond(200, false, "Your status cannot be more than 140 characters");
+
+//ratelimit
+$query = db::run(
+ "SELECT timestamp FROM feed WHERE userId = :uid AND groupID IS NULL AND timestamp+300 > UNIX_TIMESTAMP()",
+ [":uid" => $userId]
+);
+
+if($query->rowCount())
+ api::respond(200, false, "Please wait ".GetReadableTime($query->fetchColumn(), ["RelativeTime" => "5 minutes"])." before updating your status");
+
+db::run("INSERT INTO feed (userId, timestamp, text) VALUES (:uid, UNIX_TIMESTAMP(), :status)", [":uid" => $userId, ":status" => $status]);
+
+db::run("UPDATE users SET status = :status WHERE id = :uid", [":uid" => $userId, ":status" => $status]);
+
+if(time() < strtotime("2021-09-07 00:00:00") && stripos($status, "#bezosgang") !== false && !Catalog::OwnsAsset(SESSION["userId"], 2802))
+{
+ db::run(
+ "INSERT INTO ownedAssets (assetId, userId, timestamp) VALUES (2802, :uid, UNIX_TIMESTAMP())",
+ [":uid" => SESSION["userId"]]
+ );
+}
+
+Discord::SendToWebhook(
+ [
+ "username" => SESSION["userName"],
+ "content" => $status,
+ "avatar_url" => Thumbnails::GetAvatar(SESSION["userId"], 420, 420)
+ ],
+ Discord::WEBHOOK_KUSH
+);
+
+api::respond(200, true, "OK");
\ No newline at end of file
diff --git a/api/account/updateStatus.php b/api/account/updateStatus.php
deleted file mode 100644
index 8f6a587..0000000
--- a/api/account/updateStatus.php
+++ /dev/null
@@ -1,28 +0,0 @@
- "POST", "logged_in" => true, "secure" => true]);
-
-$userId = SESSION["userId"];
-$status = $_POST['status'] ?? false;
-
-if(!$status) api::respond(405, false, "Your status cannot be empty");
-if(strlen($status) > 140) api::respond(405, false, "Your status cannot be more than 140 characters");
-
-//ratelimit
-$query = db::run("SELECT timestamp FROM feed WHERE userId = :uid AND timestamp+60 > UNIX_TIMESTAMP()", [":uid" => $userId]);
-if($query->rowCount()) api::respond(400, false, "Please wait ".(($query->fetchColumn()+60)-time())." seconds before updating your status");
-
-db::run("INSERT INTO feed (userId, timestamp, text) VALUES (:uid, UNIX_TIMESTAMP(), :status)", [":uid" => $userId, ":status" => $status]);
-
-db::run("UPDATE users SET status = :status WHERE id = :uid", [":uid" => $userId, ":status" => $status]);
-
-// $status = str_ireplace("http://", "", $status);
-// $status = str_ireplace("https://", "", $status);
-
-polygon::sendKushFeed([
- "username" => SESSION["userName"],
- "content" => $status,
- "avatar_url" => Thumbnails::GetAvatar(SESSION["userId"], 420, 420)
-]);
-
-api::respond(200, true, "OK");
\ No newline at end of file
diff --git a/api/admin/addBanner.php b/api/admin/addBanner.php
deleted file mode 100644
index c9a14b4..0000000
--- a/api/admin/addBanner.php
+++ /dev/null
@@ -1,26 +0,0 @@
- "POST", "admin" => true, "admin_ratelimit" => true, "secure" => true]);
-
-if(!isset($_POST["text"]) || !isset($_POST["bg-color"]) || !isset($_POST["text-color"])){ api::respond(400, false, "Invalid Request"); }
-if($_POST["text-color"] != "dark" && $_POST["text-color"] != "light"){ api::respond(400, false, "Invalid Request"); }
-if(!trim($_POST["text"])){ api::respond(400, false, "You haven't set the banner text"); }
-if(strlen($_POST["text"]) > 128){ api::respond(400, false, "The banner text must be less than 128 characters"); }
-if(!trim($_POST["bg-color"])){ api::respond(400, false, "You haven't set a background color"); }
-if(!ctype_xdigit(ltrim($_POST["bg-color"], "#")) || strlen($_POST["bg-color"]) != 7){ api::respond(400, false, "That doesn't appear to be a valid hex color"); }
-if($pdo->query("SELECT COUNT(*) FROM announcements WHERE activated")->fetchColumn() > 5){ api::respond(400, false, "There's too many banners currently active!"); }
-
-$userId = SESSION["userId"];
-$text = trim($_POST["text"]);
-$color = trim($_POST["bg-color"]);
-$textcolor = "text-".trim($_POST["text-color"]);
-
-$query = $pdo->prepare("INSERT INTO announcements (createdBy, text, bgcolor, textcolor) VALUES (:uid, :text, :bgc, :tc)");
-$query->bindParam(":uid", $userId, PDO::PARAM_INT);
-$query->bindParam(":text", $text, PDO::PARAM_STR);
-$query->bindParam(":bgc", $color, PDO::PARAM_STR);
-$query->bindParam(":tc", $textcolor, PDO::PARAM_STR);
-$query->execute();
-
-users::logStaffAction("[ Banners ] Created site banner with text: ".$text);
-api::respond(200, true, "Banner has been created");
\ No newline at end of file
diff --git a/api/admin/delete-post.php b/api/admin/delete-post.php
index 579fffe..60421fb 100644
--- a/api/admin/delete-post.php
+++ b/api/admin/delete-post.php
@@ -1,6 +1,7 @@
- "POST", "admin" => true, "admin_ratelimit" => true, "secure" => true]);
+ "POST", "admin" => [Users::STAFF_MODERATOR, Users::STAFF_ADMINISTRATOR], "admin_ratelimit" => true, "secure" => true]);
if(!isset($_POST['postType'])){ api::respond(400, false, "Bad Request"); }
if(!in_array($_POST['postType'], ["thread", "reply"])){ api::respond(400, false, "Bad Request"); }
@@ -9,12 +10,12 @@ if(!is_numeric($_POST['postId'])){ api::respond(400, false, "Bad Request"); }
$userid = SESSION["userId"];
$isThread = $_POST['postType'] == "thread";
-$threadInfo = $isThread ? forum::getThreadInfo($_POST['postId']) : forum::getReplyInfo($_POST['postId']);
+$threadInfo = $isThread ? Forum::GetThreadInfo($_POST['postId']) : Forum::GetReplyInfo($_POST['postId']);
if(!$threadInfo){ api::respond(400, false, "Post does not exist"); }
$query = $isThread ? $pdo->prepare("UPDATE forum_threads SET deleted = 1 WHERE id = :id") : $pdo->prepare("UPDATE forum_replies SET deleted = 1 WHERE id = :id");
$query->bindParam(":id", $_POST['postId'], PDO::PARAM_INT);
-if($query->execute()){ users::logStaffAction("[ Forums ] Deleted forum ".($isThread?"thread":"reply")." ID ".$_POST['postId']); api::respond(200, true, "OK"); }
+if($query->execute()){ Users::LogStaffAction("[ Forums ] Deleted forum ".($isThread?"thread":"reply")." ID ".$_POST['postId']); api::respond(200, true, "OK"); }
else{ api::respond(500, false, "Internal Server Error"); }
\ No newline at end of file
diff --git a/api/admin/get-assets.php b/api/admin/get-assets.php
index 7719eed..1ed694b 100644
--- a/api/admin/get-assets.php
+++ b/api/admin/get-assets.php
@@ -1,12 +1,14 @@
- "POST", "admin" => true, "logged_in" => true, "secure" => true]);
+ "POST", "admin" => [Users::STAFF_CATALOG, Users::STAFF_ADMINISTRATOR], "logged_in" => true, "secure" => true]);
$type = $_POST["type"] ?? false;
$page = $_POST["page"] ?? 1;
$assets = [];
-if(!catalog::getTypeByNum($type)) api::respond(400, false, "Invalid asset type");
+if(!Catalog::GetTypeByNum($type)) api::respond(400, false, "Invalid asset type");
$query = $pdo->prepare("SELECT COUNT(*) FROM assets WHERE creator = 2 AND type = :type ORDER BY id DESC");
$query->bindParam(":type", $type, PDO::PARAM_INT);
@@ -21,7 +23,7 @@ $query->execute();
while($asset = $query->fetch(PDO::FETCH_OBJ))
{
- $info = catalog::getItemInfo($asset->id);
+ $info = Catalog::GetAssetInfo($asset->id);
$assets[] =
[
diff --git a/api/admin/getUnapprovedAssets.php b/api/admin/getUnapprovedAssets.php
index 6605a5d..3c5eca1 100644
--- a/api/admin/getUnapprovedAssets.php
+++ b/api/admin/getUnapprovedAssets.php
@@ -1,17 +1,24 @@
- "POST", "admin" => true, "secure" => true]);
+ "POST", "admin" => Users::STAFF, "secure" => true]);
$page = $_POST["page"] ?? 1;
$assets = [];
-$query = $pdo->query("SELECT COUNT(*) FROM assets WHERE NOT approved AND type != 1");
+$query = $pdo->query("SELECT COUNT(*) FROM assets WHERE NOT approved AND (type != 1 || (SELECT COUNT(*) FROM polygon.groups WHERE emblem = assets.id))");
$pages = ceil($query->fetchColumn()/18);
$offset = ($page - 1)*18;
if(!$pages) api::respond(200, true, "There are no assets to approve");
-$query = $pdo->prepare("SELECT assets.*, users.username FROM assets INNER JOIN users ON creator = users.id WHERE NOT approved AND type != 1 LIMIT 18 OFFSET :offset");
+$query = $pdo->prepare(
+ "SELECT assets.*, users.username FROM assets
+ INNER JOIN users ON creator = users.id
+ WHERE NOT approved AND (type != 1 || (SELECT COUNT(*) FROM polygon.groups WHERE emblem = assets.id))
+ LIMIT 18 OFFSET :offset"
+);
$query->bindParam(":offset", $offset, PDO::PARAM_INT);
$query->execute();
@@ -26,7 +33,7 @@ while($asset = $query->fetch(PDO::FETCH_OBJ))
"texture_id" => $asset->imageID,
"creator_id" => $asset->creator,
"creator_name" => $asset->username,
- "type" => catalog::getTypeByNum($asset->type),
+ "type" => Catalog::GetTypeByNum($asset->type),
"created" => date("j/n/y G:i A", $asset->created),
"price" => $asset->sale ? $asset->price ? '
'.$asset->price : "Free" : "Off-Sale"
];
diff --git a/api/admin/git-pull.php b/api/admin/git-pull.php
index 437e7eb..42a49cb 100644
--- a/api/admin/git-pull.php
+++ b/api/admin/git-pull.php
@@ -26,13 +26,13 @@ $output_array = [];
if($emergency)
{
- $webhook .= sprintf("[%s] Git Pull intiated by %s\n", date('d/m/Y h:i:s A'), "[[[EMERGENCY]]]");
+ $webhook .= sprintf("[%s] Git Pull intiated by %s on %s\n", date('d/m/Y h:i:s A'), "[[[OVERRIDE]]]", $_SERVER["HTTP_HOST"]);
}
else
{
require $_SERVER["DOCUMENT_ROOT"]."/api/private/core.php";
- if(!SESSION || !SESSION["adminLevel"]) die(http_response_code(404));
- $webhook .= sprintf("[%s] Git Pull executed by %s\n", date('d/m/Y h:i:s A'), SESSION["userName"]);
+ if(!Users::IsAdmin(Users::STAFF_ADMINISTRATOR)) die(http_response_code(404));
+ $webhook .= sprintf("[%s] Git Pull executed by %s on %s\n", date('d/m/Y h:i:s A'), SESSION["userName"], $_SERVER["HTTP_HOST"]);
}
exec("git pull 2>&1", $output_array, $exitcode);
@@ -46,4 +46,5 @@ $webhook .= "```yaml\n";
$webhook .= $output;
$webhook .= "```";
-// sendSystemWebhook($webhook);
+require $_SERVER["DOCUMENT_ROOT"]."/api/private/components/Discord.php";
+Discord::SendToWebhook(["content" => $webhook], Discord::WEBHOOK_POLYGON, false);
diff --git a/api/admin/giveCurrency.php b/api/admin/giveCurrency.php
index 00f9e9b..c867253 100644
--- a/api/admin/giveCurrency.php
+++ b/api/admin/giveCurrency.php
@@ -1,6 +1,6 @@
"POST", "admin" => true, "admin_ratelimit" => true, "secure" => true]);
+api::initialize(["method" => "POST", "admin" => Users::STAFF_ADMINISTRATOR, "admin_ratelimit" => true, "secure" => true]);
if(SESSION["userId"] != 1){ api::respond(400, false, "Insufficient admin level"); }
if(!isset($_POST["username"]) || !isset($_POST["amount"]) || !isset($_POST["reason"])){ api::respond(400, false, "Invalid Request"); }
@@ -13,7 +13,7 @@ if($_POST["amount"] > 500 || $_POST["amount"] < -500){ api::respond(400, false,
if(!trim($_POST["reason"])){ api::respond(400, false, "You must set a reason"); }
$amount = $_POST["amount"];
-$userInfo = users::getUserInfoFromUserName($_POST["username"]);
+$userInfo = Users::GetInfoFromName($_POST["username"]);
if(!$userInfo){ api::respond(400, false, "That user doesn't exist"); }
if(($userInfo->currency + $_POST["amount"]) < 0){ api::respond(400, false, "That'll make the user go bankrupt!"); }
@@ -22,5 +22,5 @@ $query->bindParam(":amount", $amount, PDO::PARAM_INT);
$query->bindParam(":uid", $userInfo->id, PDO::PARAM_INT);
$query->execute();
-users::logStaffAction("[ Currency ] Gave ".$_POST["amount"]." ".SITE_CONFIG["site"]["currency"]." to ".$userInfo->username." ( user ID ".$userInfo->id." ) ( Reason: ".$_POST["reason"]." )");
+Users::LogStaffAction("[ Currency ] Gave ".$_POST["amount"]." ".SITE_CONFIG["site"]["currency"]." to ".$userInfo->username." ( user ID ".$userInfo->id." ) ( Reason: ".$_POST["reason"]." )");
api::respond(200, true, "Gave ".$_POST["amount"]." ".SITE_CONFIG["site"]["currency"]." to ".$userInfo->username);
\ No newline at end of file
diff --git a/api/admin/moderateAsset.php b/api/admin/moderateAsset.php
index 537d9b6..db69548 100644
--- a/api/admin/moderateAsset.php
+++ b/api/admin/moderateAsset.php
@@ -1,12 +1,13 @@
- "POST", "admin" => true, "secure" => true]);
+ "POST", "admin" => Users::STAFF, "secure" => true]);
$assetId = $_POST['assetID'] ?? false;
$action = $_POST['action'] ?? false;
$action_sql = $action == "approve" ?: 2;
$reason = $_POST['reason'] ?? false;
-$asset = catalog::getItemInfo($assetId);
+$asset = Catalog::GetAssetInfo($assetId);
if(!in_array($action, ["approve", "decline"])) api::respond(400, false, "Invalid request");
if(!$asset) api::respond(400, false, "Asset does not exist");
@@ -17,5 +18,5 @@ $query->bindParam(":id", $asset->id, PDO::PARAM_INT);
$query->bindParam(":image", $asset->imageID, PDO::PARAM_INT);
$query->execute();
-users::logStaffAction('[ Asset Moderation ] '.ucfirst($action).'d "'.$asset->name.'" [ID '.$asset->id.']'.($reason ? ' with reason: '.$reason : ''));
+Users::LogStaffAction('[ Asset Moderation ] '.ucfirst($action).'d "'.$asset->name.'" [ID '.$asset->id.']'.($reason ? ' with reason: '.$reason : ''));
api::respond(200, true, '"'.htmlspecialchars($asset->name).'" has been '.$action.'d');
\ No newline at end of file
diff --git a/api/admin/moderateUser.php b/api/admin/moderateUser.php
index b87abcf..6e86d07 100644
--- a/api/admin/moderateUser.php
+++ b/api/admin/moderateUser.php
@@ -1,6 +1,6 @@
"POST", "admin" => true, "admin_ratelimit" => true, "secure" => true]);
+api::initialize(["method" => "POST", "admin" => [Users::STAFF_MODERATOR, Users::STAFF_ADMINISTRATOR], "admin_ratelimit" => true, "secure" => true]);
if(!isset($_POST["username"]) || !isset($_POST["banType"]) || !isset($_POST["moderationNote"]) || !isset($_POST["until"])){ api::respond(400, false, "Bad Request"); }
if($_POST["banType"] < 1 || $_POST["banType"] > 4){ api::respond(400, false, "Bad Request"); }
@@ -11,7 +11,7 @@ if($_POST["banType"] == 2 && empty($_POST["until"])){ api::respond(200, false, "
$banType = $_POST["banType"];
$staffNote = isset($_POST["staffNote"]) && $_POST["staffNote"] ? $_POST["staffNote"] : "";
$userId = SESSION["userId"];
-$bannerInfo = users::getUserInfoFromUserName($_POST["username"]);
+$bannerInfo = Users::GetInfoFromName($_POST["username"]);
$reason = $_POST["moderationNote"];
$bannedUntil = $_POST["banType"] == 2 ? strtotime($_POST["until"]." ".date('G:i:s')) : 0;
@@ -19,14 +19,14 @@ if(!$bannerInfo){ api::respond(200, false, "User does not exist"); }
if($banType == 4)
{
- if(!users::getUserModeration($bannerInfo->id)){ api::respond(200, false, "That user isn't banned!"); }
- users::undoUserModeration($bannerInfo->id, true);
+ if(!Users::GetUserModeration($bannerInfo->id)){ api::respond(200, false, "That user isn't banned!"); }
+ Users::UndoUserModeration($bannerInfo->id, true);
}
else
{
// if($bannerInfo->id == $userId){ api::respond(200, false, "You cannot moderate yourself!"); }
// if($bannerInfo->adminlevel){ api::respond(200, false, "You cannot moderate a staff member"); }
- if(users::getUserModeration($bannerInfo->id)){ api::respond(200, false, "That user is already banned!"); }
+ if(Users::GetUserModeration($bannerInfo->id)){ api::respond(200, false, "That user is already banned!"); }
if($banType == 2 && $bannedUntil < strtotime('tomorrow')){ api::respond(200, false, "Ban time must be at least 1 day long"); }
$query = $pdo->prepare("INSERT INTO bans (userId, bannerId, timeStarted, timeEnds, reason, banType, note) VALUES (:bid, :uid, UNIX_TIMESTAMP(), :ends, :reason, :type, :note)");
@@ -55,5 +55,5 @@ $staff =
4 => "Unbanned ".$bannerInfo->username
];
-users::logStaffAction("[ User Moderation ] ".$staff[$banType]." ( user ID ".$bannerInfo->id." )");
+Users::LogStaffAction("[ User Moderation ] ".$staff[$banType]." ( user ID ".$bannerInfo->id." )");
api::respond(200, true, $bannerInfo->username." has been ".$text[$banType]);
\ No newline at end of file
diff --git a/api/admin/previewModeration.php b/api/admin/previewModeration.php
index 677a734..9a93a72 100644
--- a/api/admin/previewModeration.php
+++ b/api/admin/previewModeration.php
@@ -1,6 +1,6 @@
"POST", "admin" => true, "secure" => true]);
+api::initialize(["method" => "POST", "admin" => [Users::STAFF_MODERATOR, Users::STAFF_ADMINISTRATOR], "secure" => true]);
if(!isset($_POST["banType"]) || !isset($_POST["moderationNote"]) || !isset($_POST["until"])){ api::respond(400, false, "Invalid Request"); }
if($_POST["banType"] < 1 || $_POST["banType"] > 3){ api::respond(400, false, "Invalid Request"); }
diff --git a/api/admin/request-render.php b/api/admin/request-render.php
index d7b46d0..082a250 100644
--- a/api/admin/request-render.php
+++ b/api/admin/request-render.php
@@ -1,6 +1,7 @@
- "POST", "admin" => true, "secure" => true]);
+ "POST", "admin" => Users::STAFF, "secure" => true]);
$renderType = $_POST['renderType'] ?? false;
$assetID = $_POST['assetID'] ?? false;
@@ -11,24 +12,24 @@ if(!$assetID || !is_numeric($assetID)) api::respond(400, false, "Bad Request");
if($renderType == "Asset")
{
- $asset = catalog::getItemInfo($assetID);
+ $asset = Catalog::GetAssetInfo($assetID);
if(!$asset) api::respond(200, false, "The asset you requested does not exist");
switch($asset->type)
{
- case 4: polygon::requestRender("Mesh", $assetID); break; // mesh
- case 8: case 19: polygon::requestRender("Model", $assetID); break; // hat/gear
- case 11: case 12: polygon::requestRender("Clothing", $assetID); break; // shirt/pants
- case 17: polygon::requestRender("Head", $assetID); break; // head
- case 10: polygon::requestRender("UserModel", $assetID); break; // user generated model
+ case 4: Polygon::RequestRender("Mesh", $assetID); break; // mesh
+ case 8: case 19: Polygon::RequestRender("Model", $assetID); break; // hat/gear
+ case 11: case 12: Polygon::RequestRender("Clothing", $assetID); break; // shirt/pants
+ case 17: Polygon::RequestRender("Head", $assetID); break; // head
+ case 10: Polygon::RequestRender("UserModel", $assetID); break; // user generated model
default: api::respond(200, false, "This asset cannot be re-rendered");
}
}
else if($renderType == "Avatar")
{
- $user = users::getUserInfoFromUid($assetID);
+ $user = Users::GetInfoFromID($assetID);
if(!$user) api::respond(200, false, "The user you requested does not exist");
- polygon::requestRender("Avatar", $assetID);
+ Polygon::RequestRender("Avatar", $assetID);
}
-users::logStaffAction("[ Render ] Re-rendered $renderType ID $assetID");
+Users::LogStaffAction("[ Render ] Re-rendered $renderType ID $assetID");
api::respond(200, true, "Render request has been successfully submitted! See render status
here");
\ No newline at end of file
diff --git a/api/admin/upload.php b/api/admin/upload.php
index 8410208..b2ed8e5 100644
--- a/api/admin/upload.php
+++ b/api/admin/upload.php
@@ -1,18 +1,21 @@
- "POST", "admin" => true, "secure" => true]);
+ "POST", "admin" => [Users::STAFF_CATALOG, Users::STAFF_ADMINISTRATOR], "secure" => true]);
$file = $_FILES["file"] ?? false;
$name = $_POST["name"] ?? false;
$type = $_POST["type"] ?? false;
$uploadas = $_POST["creator"] ?? "Polygon";
-$creator = users::getUidFromUserName($uploadas);
+$creator = Users::GetIDFromName($uploadas);
if(!$file) api::respond(200, false, "You must select a file");
if(!$name) api::respond(200, false, "You must specify a name");
if(strlen($name) > 50) api::respond(200, false, "Name cannot be longer than 50 characters");
if(!$creator) api::respond(400, false, "The user you're trying to create as does not exist");
-if(polygon::filterText($name, false, false, true) != $name) api::respond(400, false, "The name contains inappropriate text");
+if(Polygon::FilterText($name, false, false, true) != $name) api::respond(400, false, "The name contains inappropriate text");
//$lastCreation = $pdo->query("SELECT created FROM assets WHERE creator = 2 ORDER BY id DESC")->fetchColumn();
//if($lastCreation+60 > time()) api::respond(400, false, "Please wait ".(60-(time()-$lastCreation))." seconds before creating a new asset");
@@ -21,72 +24,72 @@ if($type == 1) //image - this is for textures and stuff
{
if(!in_array($file["type"], ["image/png", "image/jpg", "image/jpeg"])) api::respond(400, false, "Must be a .png or .jpg file");
- polygon::importLibrary("class.upload");
+ Polygon::ImportLibrary("class.upload");
$image = new Upload($file);
if(!$image->uploaded) api::respond(500, false, "Failed to process image - please contact an admin");
$image->allowed = ['image/png', 'image/jpg', 'image/jpeg'];
$image->image_convert = 'png';
- $imageId = catalog::createAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
- image::process($image, ["name" => "$imageId", "resize" => false, "dir" => "/asset/files/"]);
+ $imageId = Catalog::CreateAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
+ Image::Process($image, ["name" => "$imageId", "resize" => false, "dir" => "/asset/files/"]);
Thumbnails::UploadAsset($image, $imageId, 60, 62, ["keepRatio" => true, "align" => "C"]);
Thumbnails::UploadAsset($image, $imageId, 420, 420, ["keepRatio" => true, "align" => "C"]);
}
elseif($type == 3) // audio
{
- if(!in_array($file["type"], ["audio/mpeg", "audio/ogg", "audio/mid", "audio/wav", "video/ogg"])) api::respond(400, false, "Must be an mpeg, wav, ogg or midi audio. - ".$file["type"]);
- $assetId = catalog::createAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "audioType" => $file["type"], "approved" => 1]);
+ if(!in_array($file["type"], ["audio/mpeg", "audio/ogg", "audio/mid", "audio/wav"])) api::respond(400, false, "Must be an mpeg, wav, ogg or midi audio. - ".$file["type"]);
+ $assetId = Catalog::CreateAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "audioType" => $file["type"], "approved" => 1]);
copy($file["tmp_name"], $_SERVER['DOCUMENT_ROOT']."/asset/files/".$assetId);
- image::renderfromimg("audio", $assetId);
+ Image::RenderFromStaticImage("audio", $assetId);
}
elseif($type == 4) //mesh
{
if(!str_ends_with($file["name"], ".mesh")) api::respond(400, false, "Must be a .mesh file");
- $assetId = catalog::createAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
+ $assetId = Catalog::CreateAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
copy($file["tmp_name"], $_SERVER['DOCUMENT_ROOT']."/asset/files/".$assetId);
- polygon::requestRender("Mesh", $assetId);
+ Polygon::RequestRender("Mesh", $assetId);
}
elseif($type == 5) //lua
{
if(!str_ends_with($file["name"], ".lua")) api::respond(400, false, "Must be a .lua file");
- $assetId = catalog::createAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
+ $assetId = Catalog::CreateAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
copy($file["tmp_name"], $_SERVER['DOCUMENT_ROOT']."/asset/files/".$assetId);
- image::renderfromimg("Script", $assetId);
+ Image::RenderFromStaticImage("Script", $assetId);
}
elseif($type == 8) //hat
{
if(!str_ends_with($file["name"], ".xml") && !str_ends_with($file["name"], ".rbxm")) api::respond(400, false, "Must be a .rbxm or .xml file");
- $assetId = catalog::createAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
+ $assetId = Catalog::CreateAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
copy($file["tmp_name"], $_SERVER['DOCUMENT_ROOT']."/asset/files/".$assetId);
- polygon::requestRender("Model", $assetId);
+ Polygon::RequestRender("Model", $assetId);
}
elseif($type == 17) //head
{
if(!str_ends_with($file["name"], ".xml") && !str_ends_with($file["name"], ".rbxm")) api::respond(400, false, "Must be a .rbxm or .xml file");
- $assetId = catalog::createAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
+ $assetId = Catalog::CreateAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
copy($file["tmp_name"], $_SERVER['DOCUMENT_ROOT']."/asset/files/".$assetId);
- polygon::requestRender("Head", $assetId);
+ Polygon::RequestRender("Head", $assetId);
}
elseif($type == 18) //faces are literally just decals lmao (with a minor alteration to the xml)
{
if(!in_array($file["type"], ["image/png", "image/jpg", "image/jpeg"])) api::respond(400, false, "Must be a .png or .jpg file");
- polygon::importLibrary("class.upload");
+ Polygon::ImportLibrary("class.upload");
$image = new Upload($file);
if(!$image->uploaded) api::respond(500, false, "Failed to process image - please contact an admin");
$image->allowed = ['image/png', 'image/jpg', 'image/jpeg'];
$image->image_convert = 'png';
- $imageId = catalog::createAsset(["type" => 1, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
- image::process($image, ["name" => "$imageId", "resize" => false, "dir" => "/asset/files/"]);
+ $imageId = Catalog::CreateAsset(["type" => 1, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1]);
+ Image::Process($image, ["name" => "$imageId", "resize" => false, "dir" => "/asset/files/"]);
Thumbnails::UploadAsset($image, $imageId, 60, 62, ["keepRatio" => true, "align" => "C"]);
Thumbnails::UploadAsset($image, $imageId, 420, 420, ["keepRatio" => true, "align" => "C"]);
- $itemId = catalog::createAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "imageID" => $imageId, "approved" => 1]);
+ $itemId = Catalog::CreateAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "imageID" => $imageId, "approved" => 1]);
- file_put_contents(SITE_CONFIG['paths']['assets'].$itemId, catalog::generateGraphicXML("Face", $imageId));
+ file_put_contents(SITE_CONFIG['paths']['assets'].$itemId, Catalog::GenerateGraphicXML("Face", $imageId));
Thumbnails::UploadAsset($image, $itemId, 420, 230);
Thumbnails::UploadAsset($image, $itemId, 420, 420);
@@ -101,10 +104,10 @@ elseif($type == 19) //gear
{
if(!str_ends_with($file["name"], ".xml") && !str_ends_with($file["name"], ".rbxm")) api::respond(400, false, "Must be a .rbxm or .xml file");
- $assetId = catalog::createAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1, "gear_attributes" => '{"melee":false,"powerup":false,"ranged":false,"navigation":false,"explosive":false,"musical":false,"social":false,"transport":false,"building":false}']);
+ $assetId = Catalog::CreateAsset(["type" => $type, "creator" => $creator, "name" => $name, "description" => "", "approved" => 1, "gear_attributes" => '{"melee":false,"powerup":false,"ranged":false,"navigation":false,"explosive":false,"musical":false,"social":false,"transport":false,"building":false}']);
copy($file["tmp_name"], $_SERVER['DOCUMENT_ROOT']."/asset/files/".$assetId);
- polygon::requestRender("Model", $assetId);
+ Polygon::RequestRender("Model", $assetId);
}
-users::logStaffAction("[ Asset creation ] Created \"$name\" [ID ".($itemId ?? $assetId ?? $imageId)."]");
-api::respond_custom(["status" => 200, "success" => true, "message" => "
".catalog::getTypeByNum($type)." successfully created!"]);
\ No newline at end of file
+Users::LogStaffAction("[ Asset creation ] Created \"$name\" [ID ".($itemId ?? $assetId ?? $imageId)."]");
+api::respond_custom(["status" => 200, "success" => true, "message" => "
".Catalog::GetTypeByNum($type)." successfully created!"]);
\ No newline at end of file
diff --git a/api/catalog/get-comments.php b/api/catalog/get-comments.php
index 34ea1bc..f3cf815 100644
--- a/api/catalog/get-comments.php
+++ b/api/catalog/get-comments.php
@@ -1,5 +1,6 @@
-fetch(PDO::FETCH_OBJ))
"commenter_name" => $row->username,
"commenter_id" => $row->author,
"commenter_avatar" => Thumbnails::GetAvatar($row->author, 110, 110),
- "content" => nl2br(polygon::filterText($row->content))
+ "content" => nl2br(Polygon::FilterText($row->content))
];
}
diff --git a/api/catalog/post-comment.php b/api/catalog/post-comment.php
index 1909892..10fd74a 100644
--- a/api/catalog/post-comment.php
+++ b/api/catalog/post-comment.php
@@ -1,5 +1,6 @@
- "POST", "logged_in" => true, "secure" => true]);
if(!isset($_POST['assetID']) || !isset($_POST['content']));
@@ -8,7 +9,7 @@ $uid = SESSION["userId"];
$id = $_POST['assetID'];
$content = $_POST['content'];
-$item = catalog::getItemInfo($id);
+$item = Catalog::GetAssetInfo($id);
if(!$item) api::respond(400, false, "Asset does not exist");
if(!$item->comments) api::respond(400, false, "Comments are unavailable for this asset");
if(!strlen($content)) api::respond(400, false, "Comment cannot be empty");
@@ -17,8 +18,7 @@ if(strlen($content) > 100) api::respond(400, false, "Comment cannot be longer th
$query = $pdo->prepare("SELECT time FROM asset_comments WHERE time+60 > UNIX_TIMESTAMP() AND author = :uid");
$query->bindParam(":uid", $uid, PDO::PARAM_INT);
$query->execute();
-$lastComment = $query->fetchColumn();
-if($lastComment) api::respond(400, false, "Please wait ".(60-(time()-$lastComment))." seconds before posting a new comment");
+if($query->rowCount()) api::respond(400, false, "Please wait ".GetReadableTime($query->fetchColumn(), ["RelativeTime" => "1 minute"])." before posting a new comment");
$query = $pdo->prepare("INSERT INTO asset_comments (author, content, assetID, time) VALUES (:uid, :content, :aid, UNIX_TIMESTAMP())");
$query->bindParam(":uid", $uid, PDO::PARAM_INT);
diff --git a/api/catalog/purchase.php b/api/catalog/purchase.php
index 9a05cbd..4993465 100644
--- a/api/catalog/purchase.php
+++ b/api/catalog/purchase.php
@@ -1,5 +1,7 @@
- "POST", "logged_in" => true, "secure" => true]);
function getPrice($price)
@@ -11,12 +13,14 @@ $uid = SESSION["userId"];
$id = $_POST['id'] ?? false;
$price = $_POST['price'] ?? 0;
-$item = catalog::getItemInfo($id);
+$item = Catalog::GetAssetInfo($id);
if(!$item) api::respond(400, false, "Asset does not exist");
-if(catalog::ownsAsset($uid, $id)) api::respond(400, false, "User already owns asset");
+if(Catalog::OwnsAsset($uid, $id)) api::respond(400, false, "User already owns asset");
if(!$item->sale) api::respond(400, false, "Asset is off-sale");
if(SESSION["currency"] - $item->price < 0) api::respond(400, false, "User cannot afford asset");
+
if($item->price != $price)
+{
die(json_encode(
[
"status" => 200,
@@ -28,12 +32,23 @@ if($item->price != $price)
"footer" => 'Your balance after this transaction will be
'.(SESSION["currency"] - $item->price),
"newprice" => $item->price
]));
+}
-$query = $pdo->prepare("UPDATE users SET currency = currency - :price WHERE id = :uid; UPDATE users SET currency = currency + :price WHERE id = :seller");
-$query->bindParam(":price", $item->price, PDO::PARAM_INT);
-$query->bindParam(":uid", $uid, PDO::PARAM_INT);
-$query->bindParam(":seller", $item->creator, PDO::PARAM_INT);
-$query->execute();
+$IsAlt = false;
+
+foreach(Users::GetAlternateAccounts($item->creator) as $alt)
+{
+ if($alt["userid"] == $uid) $IsAlt = true;
+}
+
+if(!$IsAlt)
+{
+ $query = $pdo->prepare("UPDATE users SET currency = currency - :price WHERE id = :uid; UPDATE users SET currency = currency + :price WHERE id = :seller");
+ $query->bindParam(":price", $item->price, PDO::PARAM_INT);
+ $query->bindParam(":uid", $uid, PDO::PARAM_INT);
+ $query->bindParam(":seller", $item->creator, PDO::PARAM_INT);
+ $query->execute();
+}
$query = $pdo->prepare("INSERT INTO ownedAssets (assetId, userId, timestamp) VALUES (:aid, :uid, UNIX_TIMESTAMP())");
$query->bindParam(":aid", $id, PDO::PARAM_INT);
@@ -47,6 +62,14 @@ $query->bindParam(":aid", $id, PDO::PARAM_INT);
$query->bindParam(":price", $item->price, PDO::PARAM_INT);
$query->execute();
+if(time() < strtotime("2021-09-07 00:00:00") && $id == 2692 && !Catalog::OwnsAsset(SESSION["userId"], 2800))
+{
+ db::run(
+ "INSERT INTO ownedAssets (assetId, userId, timestamp) VALUES (2800, :uid, UNIX_TIMESTAMP())",
+ [":uid" => SESSION["userId"]]
+ );
+}
+
die(json_encode(
[
"status" => 200,
@@ -54,6 +77,6 @@ die(json_encode(
"message" => "OK",
"header" => "Purchase Complete!",
"image" => Thumbnails::GetAsset($item, 110, 110),
- "text" => "You have successfully purchased the ".htmlspecialchars($item->name)." ".catalog::getTypeByNum($item->type)." from ".$item->username." for ".getPrice($item->price),
+ "text" => "You have successfully purchased the ".htmlspecialchars($item->name)." ".Catalog::GetTypeByNum($item->type)." from ".$item->username." for ".getPrice($item->price),
"buttons" => [['class' => 'btn btn-primary continue-shopping', 'dismiss' => true, 'text' => 'Continue Shopping']],
]));
\ No newline at end of file
diff --git a/api/develop/getCreations.php b/api/develop/getCreations.php
index 42a70d4..02b99b7 100644
--- a/api/develop/getCreations.php
+++ b/api/develop/getCreations.php
@@ -1,5 +1,7 @@
- "POST", "logged_in" => true, "secure" => true]);
$userid = SESSION["userId"];
@@ -7,7 +9,7 @@ $type = $_POST["type"] ?? false;
$page = $_POST["page"] ?? 1;
$assets = [];
-if(!catalog::getTypeByNum($type)) api::respond(400, false, "Invalid asset type");
+if(!Catalog::GetTypeByNum($type)) api::respond(400, false, "Invalid asset type");
$query = $pdo->prepare("SELECT * FROM assets WHERE creator = :uid AND type = :type ORDER BY id DESC");
$query->bindParam(":uid", $userid, PDO::PARAM_INT);
@@ -16,7 +18,7 @@ $query->execute();
while($asset = $query->fetch(PDO::FETCH_OBJ))
{
- $info = catalog::getItemInfo($asset->id);
+ $info = Catalog::GetAssetInfo($asset->id);
$assets[] =
[
diff --git a/api/develop/upload.php b/api/develop/upload.php
index 283d7a9..76c6cf2 100644
--- a/api/develop/upload.php
+++ b/api/develop/upload.php
@@ -1,5 +1,8 @@
- "POST", "logged_in" => true, "secure" => true]);
$userid = SESSION["userId"];
@@ -7,17 +10,17 @@ $file = $_FILES["file"] ?? false;
$name = $_POST["name"] ?? false;
$type = $_POST["type"] ?? false;
-if(!$file) api::respond(400, false, "You must select a file");
-if(!in_array($file["type"], ["image/png", "image/jpg", "image/jpeg"])) api::respond(400, false, "Must be a .png or .jpg file");
-if(!$name) api::respond(400, false, "You must specify a name");
-if(polygon::filterText($name, false, false, true) != $name) api::respond(400, false, "The name contains inappropriate text");
-if(!in_array($type, [2, 11, 12, 13])) api::respond(400, false, "You can't upload that type of content!");
+if(!$file) api::respond(200, false, "You must select a file");
+if(!in_array($file["type"], ["image/png", "image/jpg", "image/jpeg"])) api::respond(200, false, "Must be a .png or .jpg file");
+if(!$name) api::respond(200, false, "You must specify a name");
+if(Polygon::IsExplicitlyFiltered($name)) api::respond(200, false, "The name contains inappropriate text");
+if(!in_array($type, [2, 11, 12, 13])) api::respond(200, false, "You can't upload that type of content!");
$query = $pdo->prepare("SELECT created FROM assets WHERE creator = :uid ORDER BY id DESC");
$query->bindParam(":uid", $userid, PDO::PARAM_INT);
$query->execute();
$lastCreation = $query->fetchColumn();
-if($lastCreation+30 > time()) api::respond(400, false, "Please wait ".(30-(time()-$lastCreation))." seconds before creating a new asset");
+if($lastCreation+30 > time()) api::respond(200, false, "Please wait ".(30-(time()-$lastCreation))." seconds before creating a new asset");
// tshirts are a bit messy but straightforward:
// the image asset itself must be 128x128 with the texture resized to preserve aspect ratio
@@ -57,35 +60,35 @@ if($lastCreation+30 > time()) api::respond(400, false, "Please wait ".(30-(time(
// Decal/Face |yes (s)| |yes (s)| yes (s) | yes (s) | | yes (s) | yes (s) | yes (s) | yes (s) |
// +-------+-------+-------+---------+---------+---------+---------+---------+---------+---------+
-polygon::importLibrary("class.upload");
+Polygon::ImportLibrary("class.upload");
$image = new Upload($file);
if(!$image->uploaded) api::respond(200, false, "Failed to process image - please contact an admin");
$image->allowed = ['image/png', 'image/jpg', 'image/jpeg'];
$image->image_convert = 'png';
-$imageId = catalog::createAsset(["type" => 1, "creator" => SESSION["userId"], "name" => $name, "description" => catalog::getTypeByNum($type)." Image"]);
+$imageId = Catalog::CreateAsset(["type" => 1, "creator" => SESSION["userId"], "name" => $name, "description" => Catalog::GetTypeByNum($type)." Image"]);
if($type == 2) //tshirt
{
- image::process($image, ["name" => "$imageId", "keepRatio" => true, "align" => "T", "x" => 128, "y" => 128, "dir" => "/asset/files/"]);
+ Image::Process($image, ["name" => "$imageId", "keepRatio" => true, "align" => "T", "x" => 128, "y" => 128, "dir" => "/asset/files/"]);
Thumbnails::UploadAsset($image, $imageId, 60, 62, ["keepRatio" => true, "align" => "T"]);
Thumbnails::UploadAsset($image, $imageId, 420, 420, ["keepRatio" => true, "align" => "T"]);
- $itemId = catalog::createAsset(["type" => 2, "creator" => SESSION["userId"], "name" => $name, "description" => "T-Shirt", "imageID" => $imageId]);
+ $itemId = Catalog::CreateAsset(["type" => 2, "creator" => SESSION["userId"], "name" => $name, "description" => "T-Shirt", "imageID" => $imageId]);
- file_put_contents(SITE_CONFIG['paths']['assets'].$itemId, catalog::generateGraphicXML("T-Shirt", $imageId));
+ file_put_contents(SITE_CONFIG['paths']['assets'].$itemId, Catalog::GenerateGraphicXML("T-Shirt", $imageId));
//process initial tshirt thumbnail
$template = imagecreatefrompng($_SERVER['DOCUMENT_ROOT']."/img/tshirt-template.png");
- $shirtdecal = image::resize(SITE_CONFIG['paths']['thumbs_assets']."/$imageId-420x420.png", 250, 250);
+ $shirtdecal = Image::Resize(SITE_CONFIG['paths']['thumbs_assets']."/$imageId-420x420.png", 250, 250);
imagesavealpha($template, true);
imagesavealpha($shirtdecal, true);
- image::merge($template, $shirtdecal, 85, 85, 0, 0, 250, 250, 100);
+ Image::MergeLayers($template, $shirtdecal, 85, 85, 0, 0, 250, 250, 100);
imagepng($template, SITE_CONFIG['paths']['thumbs_assets']."/$itemId-420x420.png");
- image::resize(SITE_CONFIG['paths']['thumbs_assets']."/$itemId-420x420.png", 100, 100, SITE_CONFIG['paths']['thumbs_assets']."/$itemId-100x100.png");
- image::resize(SITE_CONFIG['paths']['thumbs_assets']."/$itemId-420x420.png", 110, 110, SITE_CONFIG['paths']['thumbs_assets']."/$itemId-110x110.png");
+ Image::Resize(SITE_CONFIG['paths']['thumbs_assets']."/$itemId-420x420.png", 100, 100, SITE_CONFIG['paths']['thumbs_assets']."/$itemId-100x100.png");
+ Image::Resize(SITE_CONFIG['paths']['thumbs_assets']."/$itemId-420x420.png", 110, 110, SITE_CONFIG['paths']['thumbs_assets']."/$itemId-110x110.png");
Thumbnails::UploadToCDN(SITE_CONFIG['paths']['thumbs_assets']."/$itemId-100x100.png");
Thumbnails::UploadToCDN(SITE_CONFIG['paths']['thumbs_assets']."/$itemId-110x110.png");
@@ -93,31 +96,31 @@ if($type == 2) //tshirt
}
elseif($type == 11 || $type == 12) //shirt / pants
{
- image::process($image, ["name" => "$imageId", "x" => 585, "y" => 559, "dir" => "/asset/files/"]);
+ Image::Process($image, ["name" => "$imageId", "x" => 585, "y" => 559, "dir" => "/asset/files/"]);
Thumbnails::UploadAsset($image, $imageId, 60, 62, ["keepRatio" => true, "align" => "C"]);
Thumbnails::UploadAsset($image, $imageId, 420, 420, ["keepRatio" => true, "align" => "C"]);
- $itemId = catalog::createAsset(["type" => $type, "creator" => SESSION["userId"], "name" => $name, "description" => catalog::getTypeByNum($type), "imageID" => $imageId]);
- file_put_contents(SITE_CONFIG['paths']['assets'].$itemId, catalog::generateGraphicXML(catalog::getTypeByNum($type), $imageId));
- polygon::requestRender("Clothing", $itemId);
+ $itemId = Catalog::CreateAsset(["type" => $type, "creator" => SESSION["userId"], "name" => $name, "description" => Catalog::GetTypeByNum($type), "imageID" => $imageId]);
+ file_put_contents(SITE_CONFIG['paths']['assets'].$itemId, Catalog::GenerateGraphicXML(Catalog::GetTypeByNum($type), $imageId));
+ Polygon::RequestRender("Clothing", $itemId);
}
elseif($type == 13) //decal
{
- image::process($image, ["name" => "$imageId", "x" => 256, "scaleY" => true, "dir" => "/asset/files/"]);
+ Image::Process($image, ["name" => "$imageId", "x" => 256, "scaleY" => true, "dir" => "/asset/files/"]);
Thumbnails::UploadAsset($image, $imageId, 60, 62, ["keepRatio" => true, "align" => "C"]);
Thumbnails::UploadAsset($image, $imageId, 420, 420, ["keepRatio" => true, "align" => "C"]);
- $itemId = catalog::createAsset(["type" => 13, "creator" => SESSION["userId"], "name" => $name, "description" => "Decal", "imageID" => $imageId]);
+ $itemId = Catalog::CreateAsset(["type" => 13, "creator" => SESSION["userId"], "name" => $name, "description" => "Decal", "imageID" => $imageId]);
- file_put_contents(SITE_CONFIG['paths']['assets'].$itemId, catalog::generateGraphicXML("Decal", $imageId));
- image::process($image, ["name" => "$itemId-48x48.png", "x" => 48, "y" => 48, "dir" => "/thumbs/assets/"]);
- image::process($image, ["name" => "$itemId-75x75.png", "x" => 75, "y" => 75, "dir" => "/thumbs/assets/"]);
- image::process($image, ["name" => "$itemId-100x100.png", "x" => 100, "y" => 100, "dir" => "/thumbs/assets/"]);
- image::process($image, ["name" => "$itemId-110x110.png", "x" => 110, "y" => 110, "dir" => "/thumbs/assets/"]);
- image::process($image, ["name" => "$itemId-250x250.png", "x" => 250, "y" => 250, "dir" => "/thumbs/assets/"]);
- image::process($image, ["name" => "$itemId-352x352.png", "x" => 352, "y" => 352, "dir" => "/thumbs/assets/"]);
- image::process($image, ["name" => "$itemId-420x230.png", "x" => 420, "y" => 230, "dir" => "/thumbs/assets/"]);
- image::process($image, ["name" => "$itemId-420x420.png", "x" => 420, "y" => 420, "dir" => "/thumbs/assets/"]);
+ file_put_contents(SITE_CONFIG['paths']['assets'].$itemId, Catalog::GenerateGraphicXML("Decal", $imageId));
+ Thumbnails::UploadAsset($image, $itemId, 48, 48);
+ Thumbnails::UploadAsset($image, $itemId, 75, 75);
+ Thumbnails::UploadAsset($image, $itemId, 100, 100);
+ Thumbnails::UploadAsset($image, $itemId, 110, 110);
+ Thumbnails::UploadAsset($image, $itemId, 250, 250);
+ Thumbnails::UploadAsset($image, $itemId, 352, 352);
+ Thumbnails::UploadAsset($image, $itemId, 420, 230);
+ Thumbnails::UploadAsset($image, $itemId, 420, 420);
}
-api::respond_custom(["status" => 200, "success" => true, "message" => catalog::getTypeByNum($type)." successfully created!"]);
\ No newline at end of file
+api::respond_custom(["status" => 200, "success" => true, "message" => Catalog::GetTypeByNum($type)." successfully created!"]);
\ No newline at end of file
diff --git a/api/discord/check-verification.php b/api/discord/check-verification.php
new file mode 100644
index 0000000..dee9537
--- /dev/null
+++ b/api/discord/check-verification.php
@@ -0,0 +1,25 @@
+ "GET", "api" => "DiscordBot"]);
+
+if (isset($_GET["Token"]) && isset($_GET["DiscordID"]))
+{
+ $userInfo = db::run("SELECT * FROM users WHERE discordKey = :key", [":key" => $_GET["Token"]])->fetch(PDO::FETCH_OBJ);
+ if (!$userInfo) api::respond(200, false, "InvalidKey"); // check if verification key is valid
+ if ($userInfo->discordID != NULL) api::respond(200, false, "AlreadyVerified"); // check if mercury account is already verified
+
+ db::run(
+ "UPDATE users SET discordID = :id, discordVerifiedTime = UNIX_TIMESTAMP() WHERE discordKey = :key",
+ [":id" => $_GET["DiscordID"], ":key" => $_GET["Token"]]
+ );
+
+ api::respond(200, true, $userInfo->username);
+}
+else if (isset($_GET["DiscordID"]))
+{
+ $username = db::run("SELECT username FROM users WHERE discordID = :id", [":id" => $_GET["DiscordID"]]);
+ if (!$username->rowCount()) api::respond(200, false, "NotVerified"); // check if discord account is already verified
+ api::respond(200, true, $username->fetchColumn());
+}
+
+api::respond(400, false, "Bad Request");
\ No newline at end of file
diff --git a/api/discord/whois.php b/api/discord/whois.php
new file mode 100644
index 0000000..182f205
--- /dev/null
+++ b/api/discord/whois.php
@@ -0,0 +1,28 @@
+ "GET", "api" => "DiscordBot"]);
+
+if (isset($_GET["UserName"]))
+{
+ $userInfo = db::run(
+ "SELECT id, username, blurb, adminlevel, jointime, lastonline, discordID FROM users WHERE username = :name",
+ [":name" => $_GET["UserName"]]
+ )->fetch(PDO::FETCH_OBJ);
+ if (!$userInfo) api::respond(200, false, "DoesntExist");
+}
+else if (isset($_GET["DiscordID"]))
+{
+ $userInfo = db::run(
+ "SELECT id, username, blurb, adminlevel, jointime, lastonline, discordID FROM users WHERE discordID = :id",
+ [":id" => $_GET["DiscordID"]]
+ )->fetch(PDO::FETCH_OBJ);
+ if (!$userInfo) api::respond(200, false, "NotVerified");
+}
+else
+{
+ api::respond(400, false, "Bad Request");
+}
+
+$userInfo->blurb = str_ireplace(["@everyone", "@here"], ["[everyone]", "[here]"], $userInfo->blurb);
+$userInfo->blurb = preg_replace("/<(@[0-9]+)>/i", "[$1]", $userInfo->blurb);
+api::respond(200, true, $userInfo);
\ No newline at end of file
diff --git a/api/friends/getFriendRequests.php b/api/friends/getFriendRequests.php
index 1fbc6f0..4ed29b6 100644
--- a/api/friends/getFriendRequests.php
+++ b/api/friends/getFriendRequests.php
@@ -1,5 +1,6 @@
- "POST", "logged_in" => true, "secure" => true]);
$userid = SESSION["userId"];
@@ -25,7 +26,7 @@ while($row = $query->fetch(PDO::FETCH_OBJ))
{
$friends[] =
[
- "username" => users::getUserNameFromUid($row->requesterId),
+ "username" => Users::GetNameFromID($row->requesterId),
"userid" => $row->requesterId,
"avatar" => Thumbnails::GetAvatar($row->requesterId, 250, 250),
"friendid" => $row->id
diff --git a/api/friends/getFriends.php b/api/friends/getFriends.php
index 9311d6b..730f855 100644
--- a/api/friends/getFriends.php
+++ b/api/friends/getFriends.php
@@ -1,5 +1,6 @@
- "POST"]);
$url = $_SERVER['HTTP_REFERER'] ?? false;
@@ -9,7 +10,7 @@ $order = strpos($url, "/home") ? "lastonline DESC" : "id";
$limit = strpos($url, "/friends") ? 18 : 6;
$self = str_ends_with($url, "/user") || str_ends_with($url, "/friends") || strpos($url, "/home");
-if(!users::getUserInfoFromUid($userId)) api::respond(400, false, "User does not exist");
+if(!Users::GetInfoFromID($userId)) api::respond(400, false, "User does not exist");
$query = $pdo->prepare("SELECT COUNT(*) FROM friends WHERE :uid IN (requesterId, receiverId) AND status = 1");
$query->bindParam(":uid", $userId, PDO::PARAM_INT);
@@ -18,7 +19,7 @@ $query->execute();
$pages = ceil($query->fetchColumn()/$limit);
$offset = ($page - 1)*$limit;
-if(!$pages) api::respond(200, true, ($self ? "You do" : users::getUserNameFromUid($userId)." does")."n't have any friends");
+if(!$pages) api::respond(200, true, ($self ? "You do" : Users::GetNameFromID($userId)." does")."n't have any friends");
$query = $pdo->prepare("
SELECT friends.*, users.username, users.id AS userId, users.status, users.lastonline FROM friends
@@ -40,7 +41,7 @@ while($row = $query->fetch(PDO::FETCH_OBJ))
"userid" => $row->userId,
"avatar" => Thumbnails::GetAvatar($row->userId, 250, 250),
"friendid" => $row->id,
- "status" => polygon::filterText($row->status)
+ "status" => Polygon::FilterText($row->status)
];
}
diff --git a/api/games/getServers.php b/api/games/getServers.php
index e49f698..79d19fa 100644
--- a/api/games/getServers.php
+++ b/api/games/getServers.php
@@ -1,6 +1,8 @@
- "POST"]);
+ "POST", "logged_in" => true]);
$client = $_POST["client"] ?? "false";
$creator = $_POST["creator"] ?? false;
@@ -40,13 +42,14 @@ while($server = $servers->fetch(PDO::FETCH_OBJ))
{
$gears = [];
foreach(json_decode($server->allowed_gears, true) as $gear_attr => $gear_val)
- if($gear_val) $gears[] = ["name" => catalog::$gear_attr_display[$gear_attr]["text_sel"], "icon" => catalog::$gear_attr_display[$gear_attr]["icon"]];
+ if($gear_val) $gears[] = ["name" => Catalog::$GearAttributesDisplay[$gear_attr]["text_sel"], "icon" => Catalog::$GearAttributesDisplay[$gear_attr]["icon"]];
$items[] =
[
- "server_name" => polygon::filterText($server->name),
+ "server_name" => Polygon::FilterText($server->name),
+ "server_description" => strlen($server->description) ? Polygon::FilterText($server->description) : "No description available.",
"server_id" => $server->id,
"server_thumbnail" => Thumbnails::GetAvatar($server->hoster, 420, 420),
- "hoster_name" => users::getUserNameFromUid($server->hoster),
+ "hoster_name" => Users::GetNameFromID($server->hoster),
"hoster_id" => $server->hoster,
"date" => date('n/d/Y g:i:s A', $server->created),
"version" => $server->version,
diff --git a/api/games/serverlauncher.php b/api/games/serverlauncher.php
index ce9b378..7fb85fd 100644
--- a/api/games/serverlauncher.php
+++ b/api/games/serverlauncher.php
@@ -49,14 +49,17 @@ $query->bindParam(":sid", $serverID, PDO::PARAM_INT);
$query->bindParam(":teleport", $isTeleport, PDO::PARAM_INT);
$query->execute();
+$Protocol = "https";
+if($serverInfo->version == 2009) $Protocol = "http";
+
api::respond_custom([
"status" => 200,
"success" => true,
"message" => "OK",
"version" => $serverInfo->version,
- "joinScriptUrl" => "http://chef.pizzaboxer.xyz/game/join?ticket=".$ticket,
+ "joinScriptUrl" => "{$Protocol}://{$_SERVER['HTTP_HOST']}/game/join?ticket={$ticket}",
// these last few params are for teleportservice and lack any function - just ignore
- "authenticationUrl" => "http://chef.pizzaboxer.xyz/Login/Negotiate.ashx",
- "authenticationTicket" => "unusedplzignore",
+ "authenticationUrl" => "{$Protocol}://{$_SERVER['HTTP_HOST']}/Login/Negotiate.ashx",
+ "authenticationTicket" => "0",
"status" => 2
]);
\ No newline at end of file
diff --git a/api/groups/admin/get-members.php b/api/groups/admin/get-members.php
new file mode 100644
index 0000000..0a086b5
--- /dev/null
+++ b/api/groups/admin/get-members.php
@@ -0,0 +1,52 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(isset($_POST["Page"]) && !is_numeric($_POST["Page"])) api::respond(400, false, "Page is not a number");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$Page = $_POST["Page"] ?? 1;
+$Members = [];
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+$Rank = Groups::GetUserRank(SESSION["userId"], $GroupID);
+
+if($Rank->Level == 0) api::respond(200, false, "You are not a member of this group");
+if(!$Rank->Permissions->CanManageGroupAdmin) api::respond(200, false, "You are not allowed to perform this action");
+
+$MemberCount = db::run(
+ "SELECT COUNT(*) FROM groups_members
+ WHERE GroupID = :GroupID AND Rank < :RankLevel AND NOT Pending",
+ [":GroupID" => $GroupID, ":RankLevel" => $Rank->Level]
+)->fetchColumn();
+
+$Pages = ceil($MemberCount/12);
+$Offset = ($Page - 1)*12;
+
+if(!$Pages) api::respond(200, true, "This group does not have any members.");
+
+$MembersQuery = db::run(
+ "SELECT users.username, users.id, Rank FROM groups_members
+ INNER JOIN users ON users.id = groups_members.UserID
+ WHERE GroupID = :GroupID AND Rank < :RankLevel AND NOT Pending
+ ORDER BY Joined DESC LIMIT 12 OFFSET $Offset",
+ [":GroupID" => $GroupID, ":RankLevel" => $Rank->Level]
+);
+
+while($Member = $MembersQuery->fetch(PDO::FETCH_OBJ))
+{
+ $Members[] =
+ [
+ "UserName" => $Member->username,
+ "UserID" => $Member->id,
+ "RoleLevel" => $Member->Rank,
+ "Avatar" => Thumbnails::GetAvatar($Member->id, 250, 250)
+ ];
+}
+
+die(json_encode(["status" => 200, "success" => true, "message" => "OK", "pages" => $Pages, "count" => $MemberCount, "items" => $Members]));
\ No newline at end of file
diff --git a/api/groups/admin/get-roles.php b/api/groups/admin/get-roles.php
new file mode 100644
index 0000000..b611d77
--- /dev/null
+++ b/api/groups/admin/get-roles.php
@@ -0,0 +1,44 @@
+ "POST"]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$Roles = [];
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+$Rank = Groups::GetUserRank(SESSION["userId"], $GroupID);
+
+if($Rank->Level == 0) api::respond(200, false, "You are not a member of this group");
+if(!$Rank->Permissions->CanManageGroupAdmin) api::respond(200, false, "You are not allowed to perform this action");
+
+if($Rank->Level == 255)
+{
+ $RolesQuery = db::run(
+ "SELECT * FROM groups_ranks WHERE GroupID = :GroupID ORDER BY Rank ASC",
+ [":GroupID" => $GroupID]
+ );
+}
+else
+{
+ $RolesQuery = db::run(
+ "SELECT * FROM groups_ranks WHERE GroupID = :GroupID AND Rank < :MyRank ORDER BY Rank ASC",
+ [":GroupID" => $GroupID, ":MyRank" => $Rank->Level]
+ );
+}
+
+while($Role = $RolesQuery->fetch(PDO::FETCH_OBJ))
+{
+ $Roles[] =
+ [
+ "Name" => htmlspecialchars($Role->Name),
+ "Description" => htmlspecialchars($Role->Description),
+ "Rank" => $Role->Rank,
+ "Permissions" => json_decode($Role->Permissions)
+ ];
+}
+
+die(json_encode(["status" => 200, "success" => true, "message" => "OK", "items" => $Roles]));
\ No newline at end of file
diff --git a/api/groups/admin/request-relationship.php b/api/groups/admin/request-relationship.php
new file mode 100644
index 0000000..83b05e6
--- /dev/null
+++ b/api/groups/admin/request-relationship.php
@@ -0,0 +1,110 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(!isset($_POST["Recipient"])) api::respond(400, false, "Recipient is not set");
+
+if(!isset($_POST["Type"])) api::respond(400, false, "Type is not set");
+if(!in_array($_POST["Type"], ["ally", "enemy"])) api::respond(400, false, "Type is not valid");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$RecipientName = $_POST["Recipient"] ?? false;
+$Type = $_POST["Type"] ?? false;
+$Groups = [];
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+
+$Recipient = db::run("SELECT * FROM groups WHERE name = :GroupName", [":GroupName" => $RecipientName]);
+$RecipientInfo = $Recipient->fetch(PDO::FETCH_OBJ);
+
+if(!$Recipient->rowCount()) api::respond(200, false, "No group with that name exists");
+
+$MyRank = Groups::GetUserRank(SESSION["userId"], $GroupID);
+if(!$MyRank->Permissions->CanManageRelationships) api::respond(200, false, "You are not allowed to manage this group's relationships");
+
+if($RecipientInfo->id == $GroupID)
+{
+ if($Type == "ally") api::respond(200, false, "You cannot send an ally request to your own group");
+ else if($Type == "enemy") api::respond(200, false, "You cannot declare your own group as an enemy");
+}
+
+$Relationship = db::run(
+ "SELECT * FROM groups_relationships WHERE :GroupID IN (Declarer, Recipient) AND :Recipient IN (Declarer, Recipient) AND Status != 2",
+ [":GroupID" => $GroupID, ":Recipient" => $RecipientInfo->id]
+);
+$RelationshipInfo = $Relationship->fetch(PDO::FETCH_OBJ);
+
+if($Relationship->rowCount())
+{
+ if($RelationshipInfo->Type == "Allies")
+ {
+ if($RelationshipInfo->Status == 0)
+ {
+ if($RelationshipInfo->Declarer == $GroupID)
+ {
+ api::respond(200, false, "You already have an outgoing ally request to this group");
+ }
+ else
+ {
+ api::respond(200, false, "You already have an incoming ally request from this group");
+ }
+ }
+ else if($RelationshipInfo->Status == 1)
+ {
+ api::respond(200, false, "You are already allies with this group!");
+ }
+ }
+ else if($RelationshipInfo->Type == "Enemies")
+ {
+ api::respond(200, false, "You are already enemies with this group!");
+ }
+}
+
+if($Type == "ally")
+{
+ $LastRequest = db::run("SELECT Declared FROM groups_relationships WHERE Declarer = :GroupID AND Declared+3600 > UNIX_TIMESTAMP()", [":GroupID" => $GroupID]);
+ if($LastRequest->rowCount())
+ api::respond(429, false, "Please wait ".GetReadableTime($LastRequest->fetchColumn(), ["RelativeTime" => "1 hour"])." before sending a new ally request");
+
+ db::run(
+ "INSERT INTO groups_relationships (Type, Declarer, Recipient, Status, Declared)
+ VALUES (\"Allies\", :GroupID, :Recipient, 0, UNIX_TIMESTAMP())",
+ [":GroupID" => $GroupID, ":Recipient" => $RecipientInfo->id]
+ );
+
+ Groups::LogAction(
+ $GroupID, "Send Ally Request",
+ sprintf(
+ "
%s sent an ally request to
%s",
+ SESSION["userId"], SESSION["userName"], $RecipientInfo->id, htmlspecialchars($RecipientInfo->name)
+ )
+ );
+ api::respond(200, true, "Ally request has been sent to ".Polygon::FilterText($RecipientInfo->name));
+}
+else if($Type == "enemy")
+{
+ $LastRequest = db::run("SELECT Declared FROM groups_relationships WHERE Declarer = :GroupID AND Declared+3600 > UNIX_TIMESTAMP()", [":GroupID" => $GroupID]);
+ if($LastRequest->rowCount())
+ api::respond(429, false, "Please wait ".GetReadableTime($LastRequest->fetchColumn(), ["RelativeTime" => "1 hour"])." before sending a new ally request");
+
+ db::run(
+ "INSERT INTO groups_relationships (Type, Declarer, Recipient, Status, Declared, Established)
+ VALUES (\"Enemies\", :GroupID, :Recipient, 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())",
+ [":GroupID" => $GroupID, ":Recipient" => $RecipientInfo->id]
+ );
+
+ Groups::LogAction(
+ $GroupID, "Create Enemy",
+ sprintf(
+ "
%s declared
%s as an enemy",
+ SESSION["userId"], SESSION["userName"], $RecipientInfo->id, htmlspecialchars($RecipientInfo->name)
+ )
+ );
+ api::respond(200, true, Polygon::FilterText($RecipientInfo->name)." is now your enemy!");
+}
+
+api::respond(200, false, "An unexpected error occurred");
\ No newline at end of file
diff --git a/api/groups/admin/update-member.php b/api/groups/admin/update-member.php
new file mode 100644
index 0000000..70c30d8
--- /dev/null
+++ b/api/groups/admin/update-member.php
@@ -0,0 +1,57 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(!isset($_POST["UserID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["UserID"])) api::respond(400, false, "GroupID is not a number");
+
+if(isset($_POST["RoleLevel"]) && !is_numeric($_POST["RoleLevel"])) api::respond(400, false, "RoleLevel is not a number");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$UserID = $_POST["UserID"] ?? false;
+
+$RoleLevel = $_POST["RoleLevel"] ?? false;
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+
+$MyRole = Groups::GetUserRank(SESSION["userId"], $GroupID);
+$UserRole = Groups::GetUserRank($UserID, $GroupID);
+
+if($MyRole->Level == 0) api::respond(200, false, "You are not a member of this group");
+if(!$MyRole->Permissions->CanManageGroupAdmin) api::respond(200, false, "You are not allowed to perform this action");
+if($UserRole->Level == 0) api::respond(200, false, "That user is not a member of this group");
+
+if($RoleLevel !== false)
+{
+ if(!Groups::GetRankInfo($GroupID, $RoleLevel)) api::respond(200, false, "That role does not exist");
+ if($RoleLevel == 0 || $RoleLevel == 255) api::respond(200, false, "That role cannot be manually assigned to a member");
+
+ if($UserRole->Level == $RoleLevel) api::respond(200, false, "The role you tried to assign is the user's current role");
+ if($MyRole->Level <= $RoleLevel) api::respond(200, false, "You can only assign roles lower than yours");
+ if($MyRole->Level <= $UserRole->Level) api::respond(200, false, "You can only modify the role of a user who is a role lower than yours");
+
+ db::run(
+ "UPDATE groups_members SET Rank = :RoleLevel WHERE GroupID = :GroupID AND UserID = :UserID",
+ [":GroupID" => $GroupID, ":UserID" => $UserID, ":RoleLevel" => $RoleLevel]
+ );
+
+ $UserName = Users::GetNameFromID($UserID);
+ $RoleName = Groups::GetRankInfo($GroupID, $RoleLevel)->Name;
+ $Action = $RoleLevel > $UserRole->Level ? "promoted" : "demoted";
+
+ Groups::LogAction(
+ $GroupID, "Change Rank",
+ sprintf(
+ "
%s %s
%s from %s to %s",
+ SESSION["userId"], SESSION["userName"], $Action, $UserID, $UserName, htmlspecialchars($UserRole->Name), htmlspecialchars($RoleName)
+ )
+ );
+
+ api::respond(200, true, "$UserName has been $Action to " . htmlspecialchars($RoleName));
+}
+
+api::respond(200, true, "OK");
\ No newline at end of file
diff --git a/api/groups/admin/update-relationship.php b/api/groups/admin/update-relationship.php
new file mode 100644
index 0000000..9f043c5
--- /dev/null
+++ b/api/groups/admin/update-relationship.php
@@ -0,0 +1,104 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(!isset($_POST["Recipient"])) api::respond(400, false, "Recipient is not set");
+if(!is_numeric($_POST["Recipient"])) api::respond(400, false, "Recipient is not a number");
+
+if(!isset($_POST["Action"])) api::respond(400, false, "Action is not set");
+if(!in_array($_POST["Action"], ["accept", "decline"])) api::respond(400, false, "Action is not valid");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$Recipient = $_POST["Recipient"] ?? false;
+$Action = $_POST["Action"] ?? false;
+$Groups = [];
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+if(!Groups::GetGroupInfo($Recipient)) api::respond(200, false, "Recipient group does not exist");
+
+$MyRank = Groups::GetUserRank(SESSION["userId"], $GroupID);
+if(!$MyRank->Permissions->CanManageRelationships) api::respond(200, false, "You are not allowed to manage this group's relationships");
+
+$Relationship = db::run(
+ "SELECT groups_relationships.*, groups.name FROM groups_relationships
+ INNER JOIN groups ON groups.id = (CASE WHEN Declarer = :GroupID THEN Recipient ELSE Declarer END)
+ WHERE :GroupID IN (Declarer, Recipient) AND :Recipient IN (Declarer, Recipient) AND Status != 2",
+ [":GroupID" => $GroupID, ":Recipient" => $Recipient]
+);
+$RelationshipInfo = $Relationship->fetch(PDO::FETCH_OBJ);
+
+if(!$Relationship->rowCount()) api::respond(200, false, "You are not in a relationship with this group");
+
+if($Action == "accept")
+{
+ if($RelationshipInfo->Type == "Enemies") api::respond(200, false, "You cannot accept an enemy relationship");
+ if($RelationshipInfo->Status != 0) api::respond(200, false, "You are already in a relationship with this group");
+
+ db::run(
+ "UPDATE groups_relationships SET Status = 1, Established = UNIX_TIMESTAMP() WHERE ID = :RelationshipID",
+ [":RelationshipID" => $RelationshipInfo->ID]
+ );
+
+ Groups::LogAction(
+ $GroupID, "Accept Ally Request",
+ sprintf(
+ "
%s accepted an ally request from
%s",
+ SESSION["userId"], SESSION["userName"], $Recipient, htmlspecialchars($RelationshipInfo->name)
+ )
+ );
+
+ api::respond(200, true, "You have accepted {$RelationshipInfo->name}'s ally request");
+}
+else if($Action == "decline")
+{
+ db::run(
+ "UPDATE groups_relationships SET Status = 2, Broken = UNIX_TIMESTAMP() WHERE ID = :RelationshipID",
+ [":RelationshipID" => $RelationshipInfo->ID]
+ );
+
+ if($RelationshipInfo->Type == "Allies")
+ {
+ if($RelationshipInfo->Status == 0)
+ {
+ Groups::LogAction(
+ $GroupID, "Decline Ally Request",
+ sprintf(
+ "
%s declined an ally request from
%s",
+ SESSION["userId"], SESSION["userName"], $Recipient, htmlspecialchars($RelationshipInfo->name)
+ )
+ );
+
+ api::respond(200, true, "You have declined ".Polygon::FilterText($RelationshipInfo->name)."'s ally request");
+ }
+ else if($RelationshipInfo->Status == 1)
+ {
+ Groups::LogAction(
+ $GroupID, "Delete Ally",
+ sprintf(
+ "
%s removed
%s as an ally",
+ SESSION["userId"], SESSION["userName"], $Recipient, htmlspecialchars($RelationshipInfo->name)
+ )
+ );
+
+ api::respond(200, true, "You are no longer allies with ".Polygon::FilterText($RelationshipInfo->name));
+ }
+ }
+ else if($RelationshipInfo->Type == "Enemies")
+ {
+ Groups::LogAction(
+ $GroupID, "Delete Enemy",
+ sprintf(
+ "
%s removed
%s as an enemy",
+ SESSION["userId"], SESSION["userName"], $Recipient, htmlspecialchars($RelationshipInfo->name)
+ )
+ );
+
+ api::respond(200, true, "You are no longer enemies with ".Polygon::FilterText($RelationshipInfo->name));
+ }
+}
+
+api::respond(200, false, "An unexpected error occurred");
\ No newline at end of file
diff --git a/api/groups/admin/update-roles.php b/api/groups/admin/update-roles.php
new file mode 100644
index 0000000..98a3998
--- /dev/null
+++ b/api/groups/admin/update-roles.php
@@ -0,0 +1,167 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(!isset($_POST["Roles"])) api::respond(400, false, "Roles is not set");
+
+$GroupID = $_POST["GroupID"];
+$Roles = json_decode($_POST["Roles"]);
+
+if(!$Roles) api::respond(400, false, "Roles is not valid JSON");
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+
+$MyRole = Groups::GetUserRank(SESSION["userId"], $GroupID);
+
+if($MyRole->Level == 0) api::respond(200, false, "You are not a member of this group");
+if($MyRole->Level != 255) api::respond(200, false, "You are not allowed to perform this action");
+
+function FindRolesWithRank($Rank)
+{
+ global $Roles;
+ $Count = 0;
+
+ foreach ($Roles as $Role)
+ {
+ if (!isset($Role->Rank)) continue;
+ if ($Role->Rank == $Rank) $Count += 1;
+ }
+
+ return $Count;
+}
+
+function FindRoleWithRank($Rank)
+{
+ global $Roles;
+
+ foreach ($Roles as $Role)
+ {
+ if (!isset($Role->Rank)) continue;
+ if ($Role->Rank == $Rank) return $Role;
+ }
+
+ return false;
+}
+
+$Permissions =
+[
+ "CanViewGroupWall",
+ "CanViewGroupStatus",
+ "CanPostOnGroupWall",
+ "CanPostGroupStatus",
+ "CanDeleteGroupWallPosts",
+ "CanAcceptJoinRequests",
+ "CanKickLowerRankedMembers",
+ "CanRoleLowerRankedMembers",
+ "CanManageRelationships",
+ "CanCreateAssets",
+ "CanConfigureAssets",
+ "CanSpendFunds",
+ "CanManageGames",
+ "CanManageGroupAdmin",
+ "CanViewAuditLog"
+];
+
+if(FindRolesWithRank(0) == 0) api::respond(200, false, "You can not remove the Guest role");
+if(FindRolesWithRank(255) == 0) api::respond(200, false, "You can not remove the Owner role");
+if(count($Roles) < 3) api::respond(200, false, "There must be at least three roles");
+if(count($Roles) > 10) api::respond(200, false, "There must be no more than ten roles");
+
+foreach($Roles as $Role)
+{
+ if(!isset($Role->Name) || !isset($Role->Description) || !isset($Role->Rank) || !isset($Role->Permissions))
+ api::respond(200, false, "Roles are missing parameters");
+
+ if($Role->Rank < 0 || $Role->Rank > 255) api::respond(200, false, "Each role must have a rank number between 0 and 255");
+ if(FindRolesWithRank($Role->Rank) > 1) api::respond(200, false, "Each role must have a unique rank number");
+
+ $CurrentRole = Groups::GetRankInfo($GroupID, $Role->Rank);
+
+ if($CurrentRole === false) $Role->Action = "Create";
+ else $Role->Action = "Update";
+
+ if($Role->Rank == 0)
+ {
+ if($Role->Name != $CurrentRole->Name || $Role->Description != $CurrentRole->Description)
+ api::respond(200, false, "You can not modify the Guest role");
+ }
+
+ if($Role->Rank == 255 && $Role->Permissions != $CurrentRole->Permissions)
+ api::respond(200, false, "You can not modify the permissions of the Owner role");
+
+ if(strlen($Role->Name) < 3) api::respond(200, false, "Role names must be at least 3 characters long");
+ if(strlen($Role->Name) > 15) api::respond(200, false, "Role names must be no longer than 15 characters");
+
+ if(strlen($Role->Description) < 3) api::respond(200, false, "Role description must at least 3 characters long");
+ if(strlen($Role->Description) > 64) api::respond(200, false, "Role description must be no longer than 64 characters");
+
+ foreach ($Permissions as $Permission)
+ {
+ if(!isset($Role->Permissions->$Permission)) api::respond(200, false, "Role is missing a permission");
+ if(!is_bool($Role->Permissions->$Permission)) api::respond(200, false, "Role permission property must have a boolean value");
+ }
+
+ if(count((array)$Role->Permissions) != count($Permissions)) api::respond(200, false, "Role permissions contains an incorrect number of permissions");
+}
+
+foreach($Roles as $Role)
+{
+ if($Role->Action == "Create")
+ {
+ // if(SESSION["userId"] == 1) echo "Creating Role {$Role->Rank}\r\n";
+
+ db::run(
+ "INSERT INTO groups_ranks (GroupID, Name, Description, Rank, Permissions, Created)
+ VALUES (:GroupID, :Name, :Description, :Rank, :Permissions, UNIX_TIMESTAMP())",
+ [":GroupID" => $GroupID, ":Name" => $Role->Name, ":Description" => $Role->Description, ":Rank" => $Role->Rank, ":Permissions" => json_encode($Role->Permissions)]
+ );
+ }
+}
+
+$GroupRoles = Groups::GetGroupRanks($GroupID, true);
+while($ExistingRole = $GroupRoles->fetch(PDO::FETCH_OBJ))
+{
+ $Role = FindRoleWithRank($ExistingRole->Rank);
+
+ if($Role == false)
+ {
+ // if(SESSION["userId"] == 1) echo "Deleting Role {$ExistingRole->Rank}\r\n";
+
+ // for this one we gotta move the members with a role thats being deleted to the lowest rank
+ // slight issue with this is for a brief period, members assigned the role thats being deleted
+ // will have no role - if the timing is just right this could mess up the view of the group page
+
+ // delete the rank by the oldest id - so that we dont accidentally delete the new one
+ db::run(
+ "DELETE FROM groups_ranks WHERE GroupID = :GroupID AND Rank = :Rank ORDER BY id ASC LIMIT 1",
+ [":GroupID" => $GroupID, ":Rank" => $ExistingRole->Rank]
+ );
+
+ $NewRank = db::run(
+ "SELECT Rank FROM polygon.groups_ranks WHERE GroupID = :GroupID AND Rank != 0 ORDER BY Rank ASC LIMIT 1",
+ [":GroupID" => $GroupID]
+ )->fetchColumn();
+
+ // if(SESSION["userId"] == 1) echo "Updating existing members to {$NewRank}\r\n";
+
+ db::run(
+ "UPDATE groups_members SET Rank = :NewRank WHERE GroupID = :GroupID AND Rank = :Rank",
+ [":GroupID" => $GroupID, ":Rank" => $ExistingRole->Rank, ":NewRank" => $NewRank]
+ );
+ }
+ else if(isset($Role->Action) && $Role->Action == "Update")
+ {
+ // if(SESSION["userId"] == 1) echo "Updating Role {$Role->Rank}\r\n";
+
+ db::run(
+ "UPDATE groups_ranks SET Name = :Name, Description = :Description, Permissions = :Permissions
+ WHERE GroupID = :GroupID AND Rank = :Rank",
+ [":GroupID" => $GroupID, ":Name" => $Role->Name, ":Description" => $Role->Description, ":Rank" => $Role->Rank, ":Permissions" => json_encode($Role->Permissions)]
+ );
+ }
+}
+
+die(json_encode(["status" => 200, "success" => true, "message" => "Group roles have successfully been updated"]));
\ No newline at end of file
diff --git a/api/groups/delete-wall-post.php b/api/groups/delete-wall-post.php
new file mode 100644
index 0000000..506eb12
--- /dev/null
+++ b/api/groups/delete-wall-post.php
@@ -0,0 +1,40 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(!isset($_POST["PostID"])) api::respond(400, false, "PostID is not set");
+if(!is_numeric($_POST["PostID"])) api::respond(400, false, "PostID is not a number");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$PostID = $_POST["PostID"] ?? false;
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+
+$Rank = Groups::GetUserRank(SESSION["userId"], $GroupID);
+if(!$Rank->Permissions->CanDeleteGroupWallPosts) api::respond(200, false, "You are not allowed to delete wall posts on this group");
+
+$PostInfo = db::run(
+ "SELECT * FROM groups_wall WHERE id = :PostID AND :GroupID = :GroupID",
+ [":PostID" => $PostID, ":GroupID" => $GroupID]
+)->fetch(PDO::FETCH_OBJ);
+
+if(!$PostInfo) api::respond(200, false, "Wall post does not exist");
+
+Groups::LogAction(
+ $GroupID, "Delete Post",
+ sprintf(
+ "
%s deleted post \"%s\" by
%s",
+ SESSION["userId"], SESSION["userName"], htmlspecialchars($PostInfo->Content), $PostInfo->PosterID, Users::GetNameFromID($PostInfo->PosterID)
+ )
+);
+
+db::run(
+ "DELETE FROM groups_wall WHERE id = :PostID AND :GroupID = :GroupID",
+ [":PostID" => $PostID, ":GroupID" => $GroupID]
+);
+
+api::respond(200, true, "OK");
\ No newline at end of file
diff --git a/api/groups/get-audit.php b/api/groups/get-audit.php
new file mode 100644
index 0000000..060e586
--- /dev/null
+++ b/api/groups/get-audit.php
@@ -0,0 +1,75 @@
+ "POST"]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(isset($_POST["Page"]) && !is_numeric($_POST["Page"])) api::respond(400, false, "Page is not a number");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$Filter = $_POST["Filter"] ?? "All Actions";
+$Page = $_POST["Page"] ?? 1;
+$Logs = [];
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+$MyRank = Groups::GetUserRank(SESSION["userId"] ?? 0, $GroupID);
+if(!$MyRank->Permissions->CanViewAuditLog) api::respond(200, false, "You cannot audit this group");
+
+if($Filter == "All Actions")
+{
+ $LogCount = db::run(
+ "SELECT COUNT(*) FROM groups_audit WHERE GroupID = :GroupID",
+ [":GroupID" => $GroupID]
+ )->fetchColumn();
+}
+else
+{
+ $LogCount = db::run(
+ "SELECT COUNT(*) FROM groups_audit WHERE GroupID = :GroupID AND Category = :Action",
+ [":GroupID" => $GroupID, ":Action" => $Filter]
+ )->fetchColumn();
+}
+
+$Pages = ceil($LogCount/20);
+$Offset = ($Page - 1)*20;
+
+if(!$Pages) api::respond(200, true, "This group does not have any logs for this action.");
+
+if($Filter == "All Actions")
+{
+ $LogsQuery = db::run(
+ "SELECT groups_audit.*, users.username FROM groups_audit
+ INNER JOIN users ON users.id = UserId
+ WHERE GroupID = :GroupID
+ ORDER BY Time DESC LIMIT 20 OFFSET $Offset",
+ [":GroupID" => $GroupID]
+ );
+}
+else
+{
+ $LogsQuery = db::run(
+ "SELECT groups_audit.*, users.username FROM groups_audit
+ INNER JOIN users ON users.id = UserId
+ WHERE GroupID = :GroupID AND Category = :Action
+ ORDER BY Time DESC LIMIT 20 OFFSET $Offset",
+ [":GroupID" => $GroupID, ":Action" => $Filter]
+ );
+}
+
+while($Log = $LogsQuery->fetch(PDO::FETCH_OBJ))
+{
+ $Logs[] =
+ [
+ "Date" => date('j/n/y G:i', $Log->Time),
+ "UserName" => $Log->username,
+ "UserID" => $Log->UserID,
+ "UserAvatar" => Thumbnails::GetAvatar($Log->UserID, 250, 250),
+ "Rank" => Polygon::FilterText($Log->Rank),
+ "Description" => Polygon::FilterText($Log->Description, false)
+ ];
+}
+
+die(json_encode(["status" => 200, "success" => true, "message" => "OK", "pages" => $Pages, "items" => $Logs]));
\ No newline at end of file
diff --git a/api/groups/get-members.php b/api/groups/get-members.php
new file mode 100644
index 0000000..b5107ea
--- /dev/null
+++ b/api/groups/get-members.php
@@ -0,0 +1,52 @@
+ "POST"]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(!isset($_POST["RankLevel"])) api::respond(400, false, "RankLevel is not set");
+if(!is_numeric($_POST["RankLevel"])) api::respond(400, false, "RankLevel is not a number");
+
+if(isset($_POST["Page"]) && !is_numeric($_POST["Page"])) api::respond(400, false, "Page is not a number");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$RankID = $_POST["RankLevel"] ?? false;
+$Page = $_POST["Page"] ?? 1;
+$Members = [];
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+if(!Groups::GetRankInfo($GroupID, $RankID)) api::respond(200, false, "Group rank does not exist");
+
+$MemberCount = db::run(
+ "SELECT COUNT(*) FROM groups_members WHERE GroupID = :GroupID AND Rank = :RankID AND NOT Pending",
+ [":GroupID" => $GroupID, ":RankID" => $RankID]
+)->fetchColumn();
+
+$Pages = ceil($MemberCount/12);
+$Offset = ($Page - 1)*12;
+
+if(!$Pages) api::respond(200, true, "This group does not have any members of this rank.");
+
+$MembersQuery = db::run(
+ "SELECT users.username, users.id, Rank FROM groups_members
+ INNER JOIN users ON users.id = groups_members.UserID
+ WHERE GroupID = :GroupID AND Rank = :RankID AND NOT Pending
+ ORDER BY Joined DESC LIMIT 12 OFFSET $Offset",
+ [":GroupID" => $GroupID, ":RankID" => $RankID]
+);
+
+while($Member = $MembersQuery->fetch(PDO::FETCH_OBJ))
+{
+ $Members[] =
+ [
+ "UserName" => $Member->username,
+ "UserID" => $Member->id,
+ "RoleLevel" => $Member->Rank,
+ "Avatar" => Thumbnails::GetAvatar($Member->id, 250, 250)
+ ];
+}
+
+die(json_encode(["status" => 200, "success" => true, "message" => "OK", "pages" => $Pages, "count" => $MemberCount, "items" => $Members]));
\ No newline at end of file
diff --git a/api/groups/get-related.php b/api/groups/get-related.php
new file mode 100644
index 0000000..6cffe24
--- /dev/null
+++ b/api/groups/get-related.php
@@ -0,0 +1,82 @@
+ "POST"]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(!isset($_POST["Type"])) api::respond(400, false, "Type is not set");
+if(!in_array($_POST["Type"], ["Pending Allies", "Allies", "Enemies"])) api::respond(400, false, "Type is not valid");
+
+if(isset($_POST["Page"]) && !is_numeric($_POST["Page"])) api::respond(400, false, "Page is not a number");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$Type = $_POST["Type"] ?? false;
+$Page = $_POST["Page"] ?? 1;
+$Groups = [];
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+
+if($Type == "Pending Allies")
+{
+ if(!SESSION) api::respond(200, false, "You are not allowed to get this group's pending allies");
+ $MyRank = Groups::GetUserRank(SESSION["userId"], $GroupID);
+ if(!$MyRank->Permissions->CanManageRelationships) api::respond(200, false, "You are not allowed to get this group's pending allies");
+
+ $GroupsCount = db::run(
+ "SELECT COUNT(*) FROM groups_relationships WHERE Recipient = :GroupID AND Type = \"Allies\" AND Status = 0",
+ [":GroupID" => $GroupID]
+ )->fetchColumn();
+}
+else
+{
+ $GroupsCount = db::run(
+ "SELECT COUNT(*) FROM groups_relationships WHERE :GroupID IN (Declarer, Recipient) AND Type = :Type AND Status = 1",
+ [":GroupID" => $GroupID, ":Type" => $Type]
+ )->fetchColumn();
+}
+
+$Pages = ceil($GroupsCount/12);
+$Offset = ($Page - 1)*12;
+
+if(!$Pages) api::respond(200, true, "This group does not have any $Type");
+
+if($Type == "Pending Allies")
+{
+ $GroupsQuery = db::run(
+ "SELECT groups.name, groups.id, groups.emblem,
+ (SELECT COUNT(*) FROM groups_members WHERE GroupID = groups.id AND NOT Pending) AS MemberCount
+ FROM groups_relationships
+ INNER JOIN groups ON groups.id = (CASE WHEN Declarer = :GroupID THEN Recipient ELSE Declarer END)
+ WHERE Recipient = :GroupID AND Type = \"Allies\" AND Status = 0
+ ORDER BY Declared DESC LIMIT 12 OFFSET $Offset",
+ [":GroupID" => $GroupID]
+ );
+}
+else
+{
+ $GroupsQuery = db::run(
+ "SELECT groups.name, groups.id, groups.emblem,
+ (SELECT COUNT(*) FROM groups_members WHERE GroupID = groups.id AND NOT Pending) AS MemberCount
+ FROM groups_relationships
+ INNER JOIN groups ON groups.id = (CASE WHEN Declarer = :GroupID THEN Recipient ELSE Declarer END)
+ WHERE :GroupID IN (Declarer, Recipient) AND Type = :Type AND Status = 1
+ ORDER BY Established DESC LIMIT 12 OFFSET $Offset",
+ [":GroupID" => $GroupID, ":Type" => $Type]
+ );
+}
+
+while($Group = $GroupsQuery->fetch(PDO::FETCH_OBJ))
+{
+ $Groups[] =
+ [
+ "Name" => Polygon::FilterText($Group->name),
+ "ID" => $Group->id,
+ "MemberCount" => $Group->MemberCount,
+ "Emblem" => Thumbnails::GetAssetFromID($Group->emblem, 420, 420)
+ ];
+}
+
+die(json_encode(["status" => 200, "success" => true, "message" => "OK", "pages" => $Pages, "items" => $Groups]));
\ No newline at end of file
diff --git a/api/groups/get-wall.php b/api/groups/get-wall.php
new file mode 100644
index 0000000..591d673
--- /dev/null
+++ b/api/groups/get-wall.php
@@ -0,0 +1,53 @@
+ "POST"]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(isset($_POST["Page"]) && !is_numeric($_POST["Page"])) api::respond(400, false, "Page is not a number");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$Page = $_POST["Page"] ?? 1;
+$Wall = [];
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+
+if(SESSION) $Rank = Groups::GetUserRank(SESSION["userId"], $GroupID);
+else $Rank = Groups::GetRankInfo($GroupID, 0);
+
+if(!$Rank->Permissions->CanViewGroupWall) api::respond(200, false, "You are not allowed to view this group wall");
+
+$PostCount = db::run(
+ "SELECT COUNT(*) FROM groups_wall WHERE GroupID = :GroupID AND NOT Deleted",
+ [":GroupID" => $GroupID]
+)->fetchColumn();
+
+$Pages = ceil($PostCount/15);
+$Offset = ($Page - 1)*15;
+
+if(!$Pages) api::respond(200, true, "This group does not have any wall posts.");
+
+$PostQuery = db::run(
+ "SELECT groups_wall.id, users.username AS PosterName, PosterID, Content, TimePosted FROM groups_wall
+ INNER JOIN users ON users.id = PosterID WHERE GroupID = :GroupID AND NOT Deleted
+ ORDER BY TimePosted DESC LIMIT 15 OFFSET $Offset",
+ [":GroupID" => $GroupID]
+);
+
+while($Post = $PostQuery->fetch(PDO::FETCH_OBJ))
+{
+ $Wall[] =
+ [
+ "id" => $Post->id,
+ "username" => $Post->PosterName,
+ "userid" => $Post->PosterID,
+ "content" => nl2br(Polygon::FilterText($Post->Content)),
+ "time" => date('j/n/Y g:i:s A', $Post->TimePosted),
+ "avatar" => Thumbnails::GetAvatar($Post->PosterID, 420, 420)
+ ];
+}
+
+die(json_encode(["status" => 200, "success" => true, "message" => "OK", "pages" => $Pages, "count" => $PostCount, "items" => $Wall]));
\ No newline at end of file
diff --git a/api/groups/join-group.php b/api/groups/join-group.php
new file mode 100644
index 0000000..d2d5708
--- /dev/null
+++ b/api/groups/join-group.php
@@ -0,0 +1,30 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+$GroupID = $_POST["GroupID"] ?? false;
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+if(Groups::CheckIfUserInGroup(SESSION["userId"], $GroupID)) api::respond(200, false, "You are already in this group");
+
+if(Groups::GetUserGroups(SESSION["userId"])->rowCount() >= 20) api::respond(200, false, "You have reached the maximum number of groups");
+
+$RateLimit = db::run("SELECT Joined FROM groups_members WHERE UserID = :UserID AND Joined+300 > UNIX_TIMESTAMP()", [":UserID" => SESSION["userId"]]);
+if($RateLimit->rowCount())
+ api::respond(200, false, "Please wait ".GetReadableTime($RateLimit->fetchColumn(), ["RelativeTime" => "5 minutes"])." before joining a new group");
+
+$RankLevel = db::run(
+ "SELECT Rank FROM groups_ranks WHERE GroupID = :GroupID AND Rank != 0 ORDER BY Rank ASC LIMIT 1",
+ [":GroupID" => $GroupID]
+)->fetchColumn();
+
+db::run(
+ "INSERT INTO groups_members (GroupID, UserID, Rank, Joined) VALUES (:GroupID, :UserID, :RankLevel, UNIX_TIMESTAMP())",
+ [":GroupID" => $GroupID, ":UserID" => SESSION["userId"], ":RankLevel" => $RankLevel]
+);
+
+api::respond(200, true, "OK");
\ No newline at end of file
diff --git a/api/groups/leave-group.php b/api/groups/leave-group.php
new file mode 100644
index 0000000..b758a78
--- /dev/null
+++ b/api/groups/leave-group.php
@@ -0,0 +1,21 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$GroupInfo = Groups::GetGroupInfo($GroupID);
+
+if(!$GroupInfo) api::respond(200, false, "Group does not exist");
+if($GroupInfo->creator == SESSION["userId"]) api::respond(200, false, "You are the creator of this group");
+if(!Groups::CheckIfUserInGroup(SESSION["userId"], $GroupID)) api::respond(200, false, "You are not in this group");
+
+db::run(
+ "DELETE FROM groups_members WHERE GroupID = :GroupID AND UserID = :UserID",
+ [":GroupID" => $GroupID, ":UserID" => SESSION["userId"]]
+);
+
+api::respond(200, true, "OK");
\ No newline at end of file
diff --git a/api/groups/post-shout.php b/api/groups/post-shout.php
new file mode 100644
index 0000000..ef13bbe
--- /dev/null
+++ b/api/groups/post-shout.php
@@ -0,0 +1,56 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(!isset($_POST["Content"])) api::respond(400, false, "Content is not set");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$Content = $_POST["Content"] ?? false;
+$GroupInfo = Groups::GetGroupInfo($GroupID);
+
+if(!$GroupInfo) api::respond(200, false, "Group does not exist");
+
+$Rank = Groups::GetUserRank(SESSION["userId"], $GroupID);
+
+if(!$Rank->Permissions->CanPostGroupStatus) api::respond(200, false, "You are not allowed to post on this group wall");
+
+if(strlen($Content) < 3) api::respond(200, false, "Group shout must be at least 3 characters long");
+if(strlen($Content) > 255) api::respond(200, false, "Group shout can not be longer than 64 characters");
+
+$LastPost = db::run(
+ "SELECT timestamp FROM feed WHERE groupId = :GroupID AND userId = :UserID AND timestamp+300 > UNIX_TIMESTAMP()",
+ [":GroupID" => $GroupID, ":UserID" => SESSION["userId"]]
+);
+
+if($LastPost->rowCount())
+ api::respond(200, false, "Please wait ".GetReadableTime($LastPost->fetchColumn(), ["RelativeTime" => "5 minutes"])." before posting a group shout");
+
+Groups::LogAction(
+ $GroupID, "Post Shout",
+ sprintf(
+ "
%s changed the group status to: %s",
+ SESSION["userId"], SESSION["userName"], htmlspecialchars($Content)
+ )
+);
+
+db::run(
+ "INSERT INTO feed (groupId, userId, text, timestamp) VALUES (:GroupID, :UserID, :Content, UNIX_TIMESTAMP())",
+ [":GroupID" => $GroupID, ":UserID" => SESSION["userId"], ":Content" => $Content]
+);
+
+Discord::SendToWebhook(
+ [
+ "username" => $GroupInfo->name,
+ "content" => $Content."\n(Posted by ".SESSION["userName"].")",
+ "avatar_url" => Thumbnails::GetAssetFromID($GroupInfo->emblem, 420, 420)
+ ],
+ Discord::WEBHOOK_KUSH
+);
+
+api::respond(200, true, "OK");
\ No newline at end of file
diff --git a/api/groups/post-wall.php b/api/groups/post-wall.php
new file mode 100644
index 0000000..a75822b
--- /dev/null
+++ b/api/groups/post-wall.php
@@ -0,0 +1,38 @@
+ "POST", "logged_in" => true, "secure" => true]);
+
+if(!isset($_POST["GroupID"])) api::respond(400, false, "GroupID is not set");
+if(!is_numeric($_POST["GroupID"])) api::respond(400, false, "GroupID is not a number");
+
+if(!isset($_POST["Content"])) api::respond(400, false, "Content is not set");
+
+$GroupID = $_POST["GroupID"] ?? false;
+$Content = $_POST["Content"] ?? false;
+
+if(!Groups::GetGroupInfo($GroupID)) api::respond(200, false, "Group does not exist");
+
+$Rank = Groups::GetUserRank(SESSION["userId"], $GroupID);
+
+if(!$Rank->Permissions->CanPostOnGroupWall) api::respond(200, false, "You are not allowed to post on this group wall");
+
+if(strlen($Content) < 3) api::respond(200, false, "Wall post must be at least 3 characters long");
+if(strlen($Content) > 255) api::respond(200, false, "Wall post can not be longer than 255 characters");
+
+$LastPost = db::run(
+ "SELECT TimePosted FROM groups_wall
+ WHERE GroupID = :GroupID AND PosterID = :UserID AND TimePosted+60 > UNIX_TIMESTAMP()
+ ORDER BY TimePosted DESC LIMIT 1",
+ [":GroupID" => $GroupID, ":UserID" => SESSION["userId"]]
+);
+
+if(SESSION["userId"] != 1 && $LastPost->rowCount())
+ api::respond(200, false, "Please wait ".(60-(time()-$LastPost->fetchColumn()))." seconds before posting a new wall post");
+
+db::run(
+ "INSERT INTO groups_wall (GroupID, PosterID, Content, TimePosted) VALUES (:GroupID, :UserID, :Content, UNIX_TIMESTAMP())",
+ [":GroupID" => $GroupID, ":UserID" => SESSION["userId"], ":Content" => $Content]
+);
+
+api::respond(200, true, "OK");
\ No newline at end of file
diff --git a/api/ide/toolbox.php b/api/ide/toolbox.php
index 56b6f49..a26dcb5 100644
--- a/api/ide/toolbox.php
+++ b/api/ide/toolbox.php
@@ -1,5 +1,6 @@
-"Bricks",
@@ -92,7 +93,7 @@ $query->execute();