Skip to content
This repository was archived by the owner on May 26, 2023. It is now read-only.

Commit 01e4c81

Browse files
authored
Merge pull request #200 from ExpDev07/dev
New features and bugfixes
2 parents 7b3f415 + a06766d commit 01e4c81

File tree

8 files changed

+311
-45
lines changed

8 files changed

+311
-45
lines changed

app/Helpers/StatisticsHelper.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use App\Ban;
66
use App\Character;
77
use App\Warning;
8+
use Illuminate\Database\Eloquent\Model;
89
use Illuminate\Support\Facades\Cache;
910
use Illuminate\Support\Facades\DB;
1011

@@ -94,6 +95,34 @@ public static function getCharacterCreationStats(): array
9495
return $data;
9596
}
9697

98+
/**
99+
* Returns Lucky Wheel statistics
100+
*
101+
* @return array
102+
*/
103+
public static function getLuckyWheelStats(): array
104+
{
105+
$key = 'lucky_wheel_spins_statistics';
106+
if (Cache::has($key)) {
107+
return Cache::get($key, []);
108+
}
109+
110+
$stats = DB::table('lucky_wheel_spins')->fromSub(function ($query) {
111+
$query->from('lucky_wheel_spins')->select([
112+
DB::raw('FROM_UNIXTIME(`timestamp`, \'%Y-%m-%d\') AS `date`'),
113+
])->orderByDesc('timestamp');
114+
}, 'spins')->select([
115+
DB::raw('COUNT(`date`) as `count`'),
116+
'date',
117+
])->groupBy('date')->get()->toArray();
118+
119+
$data = self::parseHistoricData($stats);
120+
121+
Cache::put($key, $data, 6 * 60 * 60);
122+
123+
return $data;
124+
}
125+
97126
/**
98127
* Returns Character creation statistics
99128
*
@@ -126,6 +155,7 @@ private static function parseHistoricData(array $stats): array
126155
{
127156
$map = [];
128157
foreach ($stats as $row) {
158+
$row = (array)$row;
129159
$map[$row['date']] = $row['count'];
130160
}
131161

app/Http/Controllers/PlayerWarningController.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,27 @@ public function store(Player $player, WarningStoreRequest $request): RedirectRes
2525
return back()->with('success', 'The player has successfully been warned.');
2626
}
2727

28+
/**
29+
* Updates the specified resource.
30+
*
31+
* @param Player $player
32+
* @param Warning $warning
33+
* @param WarningStoreRequest $request
34+
* @return RedirectResponse
35+
*/
36+
public function update(Player $player, Warning $warning, WarningStoreRequest $request): RedirectResponse
37+
{
38+
$staffIdentifier = $request->user()->player->steam_identifier;
39+
$issuer = $warning->issuer()->first();
40+
if (!$issuer || $staffIdentifier !== $issuer->steam_identifier) {
41+
return back()->with('error', 'You can only edit your own warnings!');
42+
}
43+
44+
$warning->update($request->validated());
45+
46+
return back()->with('success', 'Successfully updated warning');
47+
}
48+
2849
/**
2950
* Remove the specified resource from storage.
3051
*

app/Http/Controllers/StatisticsController.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@ class StatisticsController extends Controller
2626
public function render(Request $request): Response
2727
{
2828
return Inertia::render('Statistics/Index', [
29-
'bans' => StatisticsHelper::getBanStats(),
30-
'warnings' => StatisticsHelper::getWarningStats(),
31-
'creations' => StatisticsHelper::getCharacterCreationStats(),
32-
'deletions' => StatisticsHelper::getCharacterDeletionStats(),
29+
'bans' => StatisticsHelper::getBanStats(),
30+
'warnings' => StatisticsHelper::getWarningStats(),
31+
'creations' => StatisticsHelper::getCharacterCreationStats(),
32+
'deletions' => StatisticsHelper::getCharacterDeletionStats(),
33+
'luckyWheel' => StatisticsHelper::getLuckyWheelStats(),
3334
]);
3435
}
3536

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
use Illuminate\Support\Facades\DB;
4+
use Illuminate\Support\Facades\Schema;
5+
use Illuminate\Database\Schema\Blueprint;
6+
use Illuminate\Database\Migrations\Migration;
7+
8+
class CreateLuckyWheelSpinsTable extends Migration
9+
{
10+
/**
11+
* Run the migrations.
12+
*
13+
* @return void
14+
*/
15+
public function up()
16+
{
17+
if (!Schema::hasTable("lucky_wheel_spins")) {
18+
Schema::create('lucky_wheel_spins', function (Blueprint $table) {
19+
$table->bigInteger('id')->unsigned()->nullable(false)->autoIncrement();
20+
});
21+
}
22+
if (!Schema::hasColumn("lucky_wheel_spins", "steam_identifier")) {
23+
Schema::table("lucky_wheel_spins", function (Blueprint $table) {
24+
$table->string('steam_identifier')->nullable(false);
25+
});
26+
}
27+
if (!Schema::hasColumn("lucky_wheel_spins", "paid_spin")) {
28+
Schema::table("lucky_wheel_spins", function (Blueprint $table) {
29+
$table->tinyInteger('paid_spin')->nullable(false)->default(0);
30+
});
31+
}
32+
if (!Schema::hasColumn("lucky_wheel_spins", "timestamp")) {
33+
Schema::table("lucky_wheel_spins", function (Blueprint $table) {
34+
$table->integer('timestamp')->nullable(false);
35+
});
36+
}
37+
}
38+
39+
/**
40+
* Reverse the migrations.
41+
*
42+
* @return void
43+
*/
44+
public function down()
45+
{
46+
Schema::dropIfExists('lucky_wheel_spins');
47+
}
48+
}

resources/js/Pages/Logs/Index.vue

Lines changed: 112 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,38 +61,38 @@
6161
<input class="block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
6262
id="details" :placeholder="t('logs.placeholder_details')" v-model="filters.details">
6363
</div>
64-
<!-- Before -->
65-
<div class="w-1/6 px-3 pr-1 mobile:w-full mobile:mb-3">
66-
<label class="block mb-3 mt-3" for="before-date">
67-
{{ t('logs.before-date') }} <sup class="text-muted dark:text-dark-muted">*</sup>
68-
</label>
69-
<input class="block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
70-
id="before-date" type="date" placeholder="">
71-
</div>
72-
<!-- Before -->
73-
<div class="w-1/6 px-3 pl-1 mobile:w-full mobile:mb-3">
74-
<label class="block mb-3 mt-3" for="before-time">
75-
{{ t('logs.before-time') }} <sup class="text-muted dark:text-dark-muted">*</sup>
76-
</label>
77-
<input class="block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
78-
id="before-time" type="time" placeholder="">
79-
</div>
80-
<!-- After -->
64+
<!-- After Date -->
8165
<div class="w-1/6 px-3 pr-1 mobile:w-full mobile:mb-3">
8266
<label class="block mb-3 mt-3" for="after-date">
8367
{{ t('logs.after-date') }} <sup class="text-muted dark:text-dark-muted">*</sup>
8468
</label>
8569
<input class="block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600" id="after-date"
8670
type="date" placeholder="">
8771
</div>
88-
<!-- Before -->
72+
<!-- After Time -->
8973
<div class="w-1/6 px-3 pl-1 mobile:w-full mobile:mb-3">
9074
<label class="block mb-3 mt-3" for="after-time">
9175
{{ t('logs.after-time') }} <sup class="text-muted dark:text-dark-muted">*</sup>
9276
</label>
9377
<input class="block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
9478
id="after-time" type="time" placeholder="">
9579
</div>
80+
<!-- Before Date -->
81+
<div class="w-1/6 px-3 pr-1 mobile:w-full mobile:mb-3">
82+
<label class="block mb-3 mt-3" for="before-date">
83+
{{ t('logs.before-date') }} <sup class="text-muted dark:text-dark-muted">*</sup>
84+
</label>
85+
<input class="block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
86+
id="before-date" type="date" placeholder="">
87+
</div>
88+
<!-- Before Time -->
89+
<div class="w-1/6 px-3 pl-1 mobile:w-full mobile:mb-3">
90+
<label class="block mb-3 mt-3" for="before-time">
91+
{{ t('logs.before-time') }} <sup class="text-muted dark:text-dark-muted">*</sup>
92+
</label>
93+
<input class="block w-full px-4 py-3 bg-gray-200 border rounded dark:bg-gray-600"
94+
id="before-time" type="time" placeholder="">
95+
</div>
9696
</div>
9797
<!-- Description -->
9898
<div class="w-full px-3 mt-3">
@@ -204,18 +204,42 @@
204204
</template>
205205
</v-section>
206206

207+
<modal :show.sync="showLogDetail">
208+
<template #header>
209+
<h1 class="dark:text-white">
210+
{{ t('logs.detail.title') }}
211+
</h1>
212+
<p class="dark:text-dark-muted !-mt-3 italic">
213+
{{ t('logs.detail.description', log_detail.user) }}
214+
</p>
215+
</template>
216+
217+
<template #default>
218+
<pre class="text-lg block mb-2">{{ log_detail.reason }}</pre>
219+
{{ log_detail.description }}
220+
</template>
221+
222+
<template #actions>
223+
<button type="button" class="px-5 py-2 rounded hover:bg-gray-200 dark:bg-gray-600 dark:hover:bg-gray-400" @click="showLogDetail = false">
224+
{{ t('global.close') }}
225+
</button>
226+
</template>
227+
</modal>
228+
207229
</div>
208230
</template>
209231

210232
<script>
211233
import Layout from './../../Layouts/App';
212234
import VSection from './../../Components/Section';
213235
import Pagination from './../../Components/Pagination';
236+
import Modal from './../../Components/Modal';
214237
215238
export default {
216239
layout: Layout,
217240
components: {
218241
Pagination,
242+
Modal,
219243
VSection,
220244
},
221245
props: {
@@ -250,7 +274,13 @@ export default {
250274
},
251275
data() {
252276
return {
253-
isLoading: false
277+
isLoading: false,
278+
showLogDetail: false,
279+
log_detail: {
280+
user: '',
281+
reason: '',
282+
description: ''
283+
}
254284
};
255285
},
256286
methods: {
@@ -293,6 +323,57 @@ export default {
293323
294324
this.isLoading = false;
295325
},
326+
parseDisconnectLog(details) {
327+
const regex = /(?<=\) has disconnected from the server .+? with reason: `)(.+?)(?=`\.)/gm;
328+
const matches = details.match(regex);
329+
const match = matches && matches.length === 1 && matches[0].trim() ? matches[0].trim() : null;
330+
331+
if (match) {
332+
const descriptions = [
333+
[/^Exiting/gmi, this.t('logs.detail.reasons.exited')],
334+
[/^Disconnected|^You have disconnected from the server/gmi, this.t('logs.detail.reasons.disconnected')],
335+
[/Game crashed: /gmi, this.t('logs.detail.reasons.crash')],
336+
[/(?<=connection|You) timed out[!.]|^Timed out after/gmi, this.t('logs.detail.reasons.timeout')],
337+
[/^You have been banned/gmi, this.t('logs.detail.reasons.banned')],
338+
[/^The server is restarting/gmi, this.t('logs.detail.reasons.restart')],
339+
[/^You have been kicked/gmi, this.t('logs.detail.reasons.kicked')],
340+
[/^Your Job Priority expired/gmi, this.t('logs.detail.reasons.job')],
341+
[/^Failed to sync doors/gmi, this.t('logs.detail.reasons.doors')],
342+
[/^You have been globally banned from all OP-FW servers/gmi, this.t('logs.detail.reasons.global')],
343+
[/^Entering Rockstar Editor/gmi, this.t('logs.detail.reasons.editor')],
344+
[/^Reliable network event overflow/gmi, this.t('logs.detail.reasons.overflow')],
345+
[/^Connecting to another server/gmi, this.t('logs.detail.reasons.another')],
346+
[/^Obtaining configuration from server failed/gmi, this.t('logs.detail.reasons.config')],
347+
];
348+
349+
let description = '';
350+
for (let x in descriptions) {
351+
const entry = descriptions[x];
352+
353+
if (entry[0].test(match)) {
354+
description = entry[1];
355+
break;
356+
}
357+
}
358+
359+
if (!description) {
360+
description = this.t('logs.detail.reasons.unknown');
361+
}
362+
363+
const html = $('<div />').append(
364+
$('<a></a>', {
365+
"data-reason" : match,
366+
"data-description" : description,
367+
"class": "text-yellow-800 dark:text-yellow-200 exit-log",
368+
"href": "#"
369+
}).text(match)
370+
).html();
371+
372+
return details.replace(match, html);
373+
}
374+
375+
return details;
376+
},
296377
parseLog(details) {
297378
const regex = /(to|from) (inventory )?((trunk|glovebox|character|property)-(\d+-)?\d+:\d+)/gmi;
298379
@@ -313,13 +394,24 @@ export default {
313394
details = details.replaceAll(inventories[x], '<a title="' + this.t('inventories.view') + '" class="text-indigo-600 dark:text-indigo-400" href="/inventory/' + inventories[x] + '">' + inventories[x] + '</a>');
314395
}
315396
316-
return details;
397+
return this.parseDisconnectLog(details);
317398
},
318399
playerName(steamIdentifier) {
319400
return steamIdentifier in this.playerMap ? this.playerMap[steamIdentifier] : steamIdentifier;
320401
}
321402
},
322403
mounted() {
404+
const _this = this;
405+
$('body').on('click', 'a.exit-log', function(e) {
406+
e.preventDefault();
407+
const parent = $(this).closest('tr');
408+
409+
_this.showLogDetail = true;
410+
_this.log_detail.user = $('td:first-child a', parent).text().trim();
411+
_this.log_detail.reason = $(this).data('reason');
412+
_this.log_detail.description = $(this).data('description');
413+
});
414+
323415
if (this.filters.before) {
324416
const d = new Date(this.filters.before * 1000);
325417

0 commit comments

Comments
 (0)