Skip to content

Commit

Permalink
Merge pull request #14 from DripDropz/wallet_link
Browse files Browse the repository at this point in the history
My Account and Wallet Linking functionality
  • Loading branch information
latheesan-k authored Dec 6, 2024
2 parents 429dff9 + be78204 commit 301a5d6
Show file tree
Hide file tree
Showing 14 changed files with 989 additions and 84 deletions.
3 changes: 2 additions & 1 deletion application/app/Http/Controllers/API/AuthController.php
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ public function verifyWallet(string $publicApiKey, Request $request): JsonRespon
* @urlParam publicApiKey string required The project's public api key. Example: 414f7c5c-b932-4d26-9570-1c2f954b64ed
* @queryParam reference string required Unique user/session identifier in your application that was used in the initialization step. Example: abcd1234
*
* @response status=200 scenario="OK - Authenticated" {"authenticated":true,"account":{"auth_provider":"google","auth_provider_id":"117571893339073554831","auth_wallet":"eternl","auth_name":"Latheesan","auth_email":"[email protected]","auth_avatar":"https://example.com/profile.jpg"},"session":{"reference":"your-app-identifier-123","session_id":"265dfd21-0fa2-4895-9277-87d2ed74a294","auth_country_code":"GB","authenticated_at":"2024-11-21 22:46:16"}}
* @response status=200 scenario="OK - Authenticated" {"authenticated":true,"account":{"auth_provider":"google","auth_provider_id":"117571893339073554831","auth_wallet":"eternl","auth_name":"Latheesan","auth_email":"[email protected]","auth_avatar":"https://example.com/profile.jpg", "linked_wallet_stake_address": null},"session":{"reference":"your-app-identifier-123","session_id":"265dfd21-0fa2-4895-9277-87d2ed74a294","auth_country_code":"GB","authenticated_at":"2024-11-21 22:46:16"}}
* @response status=200 scenario="OK - Unauthenticated" {"authenticated":false,"account":null,"session":null}
* @response status=429 scenario="Too Many Requests" [No Content]
* @responseFile status=400 scenario="Bad Request" resources/api-responses/400.json
Expand Down Expand Up @@ -417,6 +417,7 @@ public function check(string $publicApiKey, Request $request): JsonResponse
'auth_name' => $projectAccountSession->account->auth_name,
'auth_email' => $projectAccountSession->account->auth_email,
'auth_avatar' => $projectAccountSession->account->auth_avatar,
'linked_wallet_stake_address' => $projectAccountSession->account->linked_wallet_stake_address,
] : null,
'session' => $isAuthenticated ? [
'reference' => $projectAccountSession->reference,
Expand Down
8 changes: 4 additions & 4 deletions application/app/Http/Controllers/API/EventsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ public function store(Request $request): Response

try {

// Hotfix: Hydra doom is not sending is_qualifier flag in game_started event (so add it manually)
if ($validated['data']['type'] === 'game_started') {
$validated['data']['is_qualifier'] = true;
}
// // Hotfix: Hydra doom is not sending is_qualifier flag in game_started event (so add it manually)
// if ($validated['data']['type'] === 'game_started') {
// $validated['data']['is_qualifier'] = true;
// }

$eventData = EventData::create([
'project_id' => $request->project->id,
Expand Down
79 changes: 79 additions & 0 deletions application/app/Http/Controllers/API/StatsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
use App\Jobs\HydraDoomAccountStatsJob;
use App\Models\Project;
use App\Models\ProjectAccount;
use App\Models\ProjectAccountSession;
use App\Models\ProjectAccountStats;
use App\Traits\GEOBlockTrait;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Throwable;

/**
* @group Stats
Expand Down Expand Up @@ -149,6 +151,83 @@ public function session(string $publicApiKey, string $reference, Request $reques
->json($projectAccountStats);
}

/**
* Session Link Wallet Address
*
* @urlParam publicApiKey string required The project's public api key. Example: 414f7c5c-b932-4d26-9570-1c2f954b64ed
* @bodyParam session_id string required Previously authentication session id. Example: 069ff9f1-87ad-43b0-90a9-05493a330273
* @bodyParam wallet_address string required The wallet address you want to link to your social account. Example: stake1upafv37jqjy8pgrjdauxyxrruqme0hqhh9ryww34mm297agc0f3vc
*
* @response status=204 scenario="Successfully Linked" [No Content]
* @response status=429 scenario="Too Many Requests" [No Content]
* @responseFile status=400 scenario="Bad Request" resources/api-responses/400.json
* @responseFile status=401 scenario="Unauthorized" resources/api-responses/401.json
* @responseFile status=500 scenario="Internal Server Error" resources/api-responses/500.json
*/
public function sessionLinkWalletAddress(string $publicApiKey, Request $request): \Illuminate\Http\Response|JsonResponse
{
// Check if reference is provided in the request
if (empty($request->input('session_id')) || strlen($request->input('session_id')) > 64) {
return response()->json([
'error' => __('Bad Request'),
'reason' => __('The session_id field is empty or larger than 64 characters.'),
], 400);
}

// Check if new_reference is provided in the request
if (empty($request->input('wallet_address'))) {
return response()->json([
'error' => __('Bad Request'),
'reason' => __('The wallet_address field is empty.'),
], 400);
}

// Load project by public api key
$project = Cache::remember(sprintf('project:%s', $publicApiKey), 600, function () use ($publicApiKey) {
$project = Project::query()
->where('public_api_key', $publicApiKey)
->first();
if (!$project) {
return false;
}
return $project;
});
if (!$project) {
return response()->json([
'error' => __('Unauthorized'),
'reason' => __('Invalid project public api key'),
], 401);
}

// Check if this request should be geo-blocked
if ($this->isGEOBlocked($project, $request)) {
return response()->json([
'error' => __('Unauthorized'),
'reason' => __('Access not permitted'),
], 401);
}

// Load specific project account session
$projectAccountSession = ProjectAccountSession::query()
->where('session_id', $request->input('session_id'))
->with('account')
->first();
if (!$projectAccountSession || (int) $projectAccountSession->authenticated_at->diffInSeconds(now()) > $project->session_valid_for_seconds) {
return response()->json([
'error' => __('Unauthorized'),
'reason' => __('Invalid session id or session expired'),
], 401);
}

// Update linked wallet address
$projectAccountSession->account->update([
'linked_wallet_stake_address' => $request->input('wallet_address'),
]);

// Success
return response()->noContent();
}

/**
* Leaderboard
*
Expand Down
41 changes: 36 additions & 5 deletions application/app/Http/Controllers/LeaderboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Traits\GEOBlockTrait;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Inertia\Inertia;
use Inertia\Response;

Expand All @@ -16,11 +17,15 @@ class LeaderboardController extends Controller
public function index(string $publicApiKey, Request $request): Response|JsonResponse
{
// Load project by public api key
$project = Project::query()
->where('public_api_key', $publicApiKey)
->first();

// Check if project exists
$project = Cache::remember(sprintf('project:%s', $publicApiKey), 600, function () use ($publicApiKey) {
$project = Project::query()
->where('public_api_key', $publicApiKey)
->first();
if (!$project) {
return false;
}
return $project;
});
if (!$project) {
return response()->json([
'error' => __('Unauthorized'),
Expand All @@ -42,4 +47,30 @@ public function index(string $publicApiKey, Request $request): Response|JsonResp
'projectName' => $project->name,
]);
}

public function myAccount(string $publicApiKey, Request $request)
{
// Load project by public api key
$project = Cache::remember(sprintf('project:%s', $publicApiKey), 600, function () use ($publicApiKey) {
$project = Project::query()
->where('public_api_key', $publicApiKey)
->first();
if (!$project) {
return false;
}
return $project;
});
if (!$project) {
return response()->json([
'error' => __('Unauthorized'),
'reason' => __('Invalid project public api key'),
], 401);
}

// Render view
return Inertia::render('Leaderboard/MyAccount', [
'publicApiKey' => $publicApiKey,
'projectName' => $project->name,
]);
}
}
22 changes: 21 additions & 1 deletion application/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion application/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"moment": "^2.30.1",
"vue-chartjs": "^5.3.2",
"vue-toast-notification": "^3.1.2",
"vuetify": "^3.7.2"
"vuetify": "^3.7.2",
"vuetify-use-dialog": "^0.6.11"
}
}
2 changes: 2 additions & 0 deletions application/resources/js/Layouts/GuestLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ defineProps({
<Head :title="title"/>
<v-app-bar color="white" elevation="0" class="px-8">
{{ title }}
<v-spacer />
<slot name="right-app-bar" />
</v-app-bar>
<v-main>
<slot/>
Expand Down
5 changes: 5 additions & 0 deletions application/resources/js/Pages/Leaderboard/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ const top10PlayersByDeathsTableData = computed(() => [...leaderboardData.value[t

<template>
<GuestLayout :title="props.projectName + ': Leaderboard'">
<template v-slot:right-app-bar>
<v-btn :href="route('leaderboard.myAccount', props.publicApiKey)" variant="tonal">
My Account
</v-btn>
</template>
<v-container>

<!-- Grouped Stats -->
Expand Down
Loading

0 comments on commit 301a5d6

Please sign in to comment.