Skip to content

Commit

Permalink
Merge pull request #123 from Team-VoW/development
Browse files Browse the repository at this point in the history
New API feature, content updates, bugfixes
  • Loading branch information
ShadyMedic authored Feb 14, 2024
2 parents ec622da + 302e75e commit 85ab5a4
Show file tree
Hide file tree
Showing 26 changed files with 430 additions and 157 deletions.
5 changes: 3 additions & 2 deletions Controllers/Api/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ abstract class ApiController extends Controller

/* All API keys go here */
//Line reporting keys
const REPORTING_API_KEY = 'testing';
const COLLECTING_API_KEY = 'testing';
const UPDATING_API_KEY = 'testing';
//Usage analysis api keys
const AGGREGATE_API_KEY = 'testing';
//Discord Integration Key
//Discord integration key
const DISCORD_INTEGRATION_API_KEY = 'testing';
//Premium authenticator key
const PREMIUM_AUTHENTICATOR_API_KEY = 'testing';

/**
* Controller constructor enabling output buffering and setting the Content-Type header
Expand Down
5 changes: 1 addition & 4 deletions Controllers/Api/LineReporting/LineReporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public function process(array $args): int
{
parse_str(file_get_contents("php://input"),$_PUT);

if (!isset($_REQUEST['apiKey']) && !isset($_PUT['apiKey'])) {
if (!isset($_REQUEST['apiKey']) && !isset($_PUT['apiKey']) && $args[0] !== 'newUnvoicedLineReport') {
return 401;
}

Expand Down Expand Up @@ -45,9 +45,6 @@ private function newReport(): int
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
return 405;
}
if ($_REQUEST['apiKey'] !== self::REPORTING_API_KEY) {
return 401;
}
$reportAdder = new ReportAdder();
return $reportAdder->createReport($_POST['full'], $_POST['npc'], $_POST['player'], $_POST['x'], $_POST['y'], $_POST['z']);
}
Expand Down
118 changes: 118 additions & 0 deletions Controllers/Api/PremiumAuthenticator/Authenticator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

namespace VoicesOfWynn\Controllers\Api\PremiumAuthenticator;

use VoicesOfWynn\Controllers\Api\ApiController;
use VoicesOfWynn\Models\Api\PremiumAuthenticator\PremiumCodeManager;

class Authenticator extends ApiController
{
const STREAM_SERVER_IP = '127.0.0.1';

public function process(array $args): int
{
parse_str(file_get_contents("php://input"),$_INPUT);
$_INPUT = array_merge($_REQUEST, $_INPUT);

$apiKey = $_INPUT['apiKey'] ?? null;
$discordUserId = $_INPUT['discord'] ?? null;

if (!in_array($args[0], ['check-code'])) {
if ($apiKey !== self::PREMIUM_AUTHENTICATOR_API_KEY) {
return 401;
}

if (is_null($discordUserId)) {
return 400;
}
}

switch ($args[0]) {
case 'check-code':
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
return 405;
}

$valid = $this->checkCode();
$result = ['valid' => ($valid === 200) ? 'true' : 'false'];
if ($valid === 200) {
$result['ip'] = self::STREAM_SERVER_IP;
} else {
$result['reason'] = ($valid === 402) ? 'expired' : 'invalid';
}
echo json_encode($result);
return 200;
case 'get-code':
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
return 405;
}

$result = $this->getCodeForUser($discordUserId);
$status = $result['status'];
$code = $result['code'] ?? null;
if ($status === 404) {
$code = $this->generateCodeForUser($discordUserId);
$status = 201;
}
echo json_encode(["code" => $code]);
return $status;
case 'deactivate-user':
if ($_SERVER['REQUEST_METHOD'] !== 'PUT') {
return 405;
}

return ($this->deactivateCodeForUser($discordUserId)) ? 204 : 500;
case 'reactivate-user':
if ($_SERVER['REQUEST_METHOD'] !== 'PUT') {
return 405;
}

return ($this->activateCodeForUser($discordUserId)) ? 204 : 500;
default:
return 400;
}
}

private function getCodeForUser(string $discordUserId): array
{
$manager = new PremiumCodeManager();
$codeInfo = $manager->getCode($discordUserId);
if (is_null($codeInfo)) {
return ['status' => 404];
} else if (!$codeInfo['active']) {
return ['status' => 402, 'code' => $codeInfo['code']];
} else {
return ['status' => 200, 'code' => $codeInfo['code']];
}
}

private function generateCodeForUser(string $discordUserId): string
{
$manager = new PremiumCodeManager();
return $manager->createNew($discordUserId);
}

private function checkCode(): int
{
$code = $_REQUEST['code'] ?? null;
if (is_null($code) || strlen($code) !== 16) {
return 400;
}

$manager = new PremiumCodeManager();
return $manager->verify($code);
}

private function deactivateCodeForUser(string $discordUserId): bool
{
$manager = new PremiumCodeManager();
return $manager->deactivate($discordUserId);
}

private function activateCodeForUser(string $discordUserId): bool
{
$manager = new PremiumCodeManager();
return $manager->activate($discordUserId);
}
}

2 changes: 1 addition & 1 deletion Controllers/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ abstract class Controller
/**
* Public method processing passed data, specific for each controller
* @param array $args Arguments to process
* @return int 1 (or TRUE), if everything worked as expected, HTTP error code otherwise
* @return int 1 (or TRUE) or HTTP success status code (2xx) if everything worked as expected, HTTP error code otherwise
*/
public abstract function process(array $args): int;
}
Expand Down
22 changes: 22 additions & 0 deletions Controllers/Errors/Error402.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace VoicesOfWynn\Controllers\Errors;

class Error402 extends ErrorController
{

protected function displayErrorWebsite()
{
self::$data['error402_title'] = 'Subscription Required';
self::$data['error402_description'] = 'Oops, you probably didn\'t want to end up here.';
self::$data['error402_keywords'] = '';

self::$view = 'error402';
}

protected function sendHttpErrorHeader()
{
header("HTTP/1.1 402 Payment Required");
}
}

6 changes: 4 additions & 2 deletions Controllers/Website/Administration/Upload.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ private function get(array $args): int
private function post(array $args): int
{
$uploader = new RecordingUploader();

$uploader->upload($_FILES['recordings']);
$questId = (empty($_POST['questId']) ? null : $_POST['questId']);
$npcId = (empty($_POST['npcId']) ? null : $_POST['npcId']);
$overwriteFiles = isset($_POST['overwrite']) && $_POST['overwrite'] === 'on';
$uploader->upload($_FILES['recordings'], $overwriteFiles, $questId, $npcId);
self::$data['upload_uploadErrors'] = $uploader->getErrors();
self::$data['upload_uploadSuccesses'] = $uploader->getSuccesses();

Expand Down
4 changes: 0 additions & 4 deletions Controllers/Website/Downloads.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ class Downloads extends WebpageController
public function process(array $args): int
{
switch (array_shift($args)) {
case 'junction':
self::$views[] = 'downloads';
self::$cssFiles[] = 'downloads';
break;
case 'forge':
$downloadsManager = new DownloadsManager();
self::$data['downloadslist_versions'] = $downloadsManager->listDownloads(DownloadsManager::FORGE_VERSIONS);
Expand Down
23 changes: 0 additions & 23 deletions Controllers/Website/Npc.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,29 +89,6 @@ private function get(array $args): int
return true;
}

/**
* Processing method for POST requests to this controller (new recordings were uploaded)
* @param array $args
* @return int|bool
*/
private function post(array $args): int
{
if ($this->disallowAdministration) {
return 403;
}

$uploader = new RecordingUploader();
$questId = $_POST['questId'];
$npcId = $_POST['npcId'];
$overwriteFiles = isset($_POST['overwrite']) && $_POST['overwrite'] === 'on';

$uploader->upload($_FILES['recordings'], $overwriteFiles, $questId, $npcId);
self::$data['npc_uploadErrors'][$questId] = $uploader->getErrors();
self::$data['npc_uploadSuccesses'][$questId] = $uploader->getSuccesses();

return $this->get($args);
}

/**
* Processing method for PUT requests to this controller (recast, archivation of NPC or archivation of recordings)
* @param array $args Voice actor id as the first element
Expand Down
1 change: 1 addition & 0 deletions Controllers/Website/WebpageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ private function sanitize($value)
$attr['id'] = $this->sanitize($value->getId());
$attr['name'] = $this->sanitize($value->getName());
$attr['archived'] = $this->sanitize($value->isArchived());
$attr['recordings_count'] = $this->sanitize($value->getRecordingsCount());
$voiceActor = $this->sanitize($value->getVoiceActor());
$npc = new Npc($attr);
if ($voiceActor !== null) {
Expand Down
4 changes: 4 additions & 0 deletions Models/Api/PremiumAuthenticator/DbInfo.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
host=localhost
database=premium-authenticator
username=root
password=
94 changes: 94 additions & 0 deletions Models/Api/PremiumAuthenticator/PremiumCodeManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

namespace VoicesOfWynn\Models\Api\PremiumAuthenticator;


use Exception;
use PDOException;
use VoicesOfWynn\Models\Db;

class PremiumCodeManager
{

/**
* Method generating new premium access code for a single Discord User
* @param string $discordUserId Discord user ID of the user to which the new code should belong (numerical
* string or BIGINT in MySQL)
* @return bool The generated access code, if the new code was generated and saved successfully, FALSE otherwise
*/
public function createNew(string $discordUserId)
{
try {
$code = strtoupper(substr(base_convert(bin2hex(random_bytes(11)), 16, 36), 0, 16));
} catch (Exception $e) {
return false;
}

try {
$db = new Db('Api/PremiumAuthenticator/DbInfo.ini');
$result = $db->executeQuery('INSERT INTO access_codes(code,discord_id) VALUES (?,?);', [$code, $discordUserId]);
} catch (PDOException $ex) {
return false;
}

return $code;
}

/**
* Method loading an premium access code for the given Discord user
* @param string $discordUserId Discord user ID of the user whose code should be loaded (numerical string or BIGINT
* in MySQL)
* @return array|null Associative array with elements "code" (the 16-character code) and "active" (boolean) or NULL,
* if no code for the user exists
*/
public function getCode(string $discordUserId): ?array
{
$db = new Db('Api/PremiumAuthenticator/DbInfo.ini');
$result = $db->fetchQuery('SELECT code,active FROM access_codes WHERE discord_id = ? LIMIT 1;', [$discordUserId]);
if ($result === false) {
return null;
}
return $result;
}

/**
* Method checking whether a premium access code is valid
* @param string $code Access code to check
* @return int An HTTP-like code indicator:
* 200 if the code is valid, 402 if the code is disabled, 404 if code does not exist
*/
public function verify(string $code): int
{
$code = strtoupper($code);
$db = new Db('Api/PremiumAuthenticator/DbInfo.ini');
$result = $db->fetchQuery('SELECT active FROM access_codes WHERE code = ? LIMIT 1;', [$code]);
if ($result === false) {
return 404;
} else {
return ($result['active']) ? 200 : 402;
}
}

/**
* Method marking a certain user's access code as disabled
* @param string $discordUserId Discord ID of the user whose access code should be deactivated
* @return bool TRUE on success, FALSE on failure
*/
public function deactivate(string $discordUserId)
{
$db = new Db('Api/PremiumAuthenticator/DbInfo.ini');
return $db->executeQuery('UPDATE access_codes SET active = 0 WHERE discord_id = ?;', [$discordUserId]);
}

/**
* Method marking a certain user's access code as enabled
* @param string $discordUserId Discord ID of the user whose access code should be activated
* @return bool TRUE on success, FALSE on failure
*/
public function activate(string $discordUserId)
{
$db = new Db('Api/PremiumAuthenticator/DbInfo.ini');
return $db->executeQuery('UPDATE access_codes SET active = 1 WHERE discord_id = ?;', [$discordUserId]);
}
}

19 changes: 10 additions & 9 deletions Models/Website/ContentManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ class ContentManager
public function getQuests(?int $questId = null): array
{
$query = '
SELECT quest.quest_id, quest.name AS "qname", npc.npc_id, npc.name AS "nname", npc.voice_actor_id, npc.archived, user.user_id, user.display_name, user.picture
FROM quest
JOIN npc_quest ON npc_quest.quest_id = quest.quest_id
JOIN npc ON npc.npc_id = npc_quest.npc_id
LEFT JOIN user ON npc.voice_actor_id = user.user_id
'.(is_null($questId) ? '' : 'WHERE quest.quest_id = ?').'
ORDER BY quest.quest_id, npc_quest.sorting_order;
SELECT quest.quest_id, quest.name AS "qname", npc.npc_id, npc.name AS "nname", npc.voice_actor_id, npc.archived, user.user_id, user.display_name, COUNT(DISTINCT recording.recording_id) AS "recordings_count"
FROM quest
JOIN npc_quest ON npc_quest.quest_id = quest.quest_id
JOIN npc ON npc.npc_id = npc_quest.npc_id
JOIN recording ON recording.npc_id = npc.npc_id AND recording.quest_id = quest.quest_id
LEFT JOIN user ON npc.voice_actor_id = user.user_id
'.(is_null($questId) ? '' : 'WHERE quest.quest_id = ?').'
GROUP BY quest.quest_id, npc.npc_id, npc_quest.sorting_order
ORDER BY quest.quest_id, npc_quest.sorting_order;
';
$result = (new Db('Website/DbInfo.ini'))->fetchQuery($query, (is_null($questId) ? array() : array($questId)), true);

Expand All @@ -29,9 +31,8 @@ public function getQuests(?int $questId = null): array
}
$currentQuest = new Quest($npc);
}

$npcObj = new Npc($npc);
if ($npc['user_id'] !== null) {
if ($npc['user_id'] !== null) {
$voiceActor = new User();
$voiceActor->setData($npc);
$npcObj->setVoiceActor($voiceActor);
Expand Down
2 changes: 1 addition & 1 deletion Models/Website/DownloadsManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class DownloadsManager
private const FILE_NAME_FORMATS = 'VoicesOfWynn-MC{mcVersion}-v{version}.jar';

public const FORGE_VERSIONS = ['1.12.2'];
public const FABRIC_VERSIONS = ['1.19.4', '1.19.3', '1.18.2'];
public const FABRIC_VERSIONS = ['1.20.2', '1.19.4', '1.19.3', '1.18.2'];


/**
Expand Down
Loading

0 comments on commit 85ab5a4

Please sign in to comment.