return $round->toJson();
}
+ public function getSeed(Request $request, Round $round) {
+ $this->authorize('getSeed', $round);
+
+ if ($request->user()) {
+ Protocol::roundSeedGet(
+ $round->tournament,
+ $round,
+ $request->user(),
+ );
+ }
+
+ return redirect($round->seed);
+ }
+
public function uploadSeed(Request $request, Round $round) {
$this->authorize('update', $round);
ProtocolAdded::dispatch($protocol);
}
+ public static function roundSeedGet(Tournament $tournament, Round $round, User $user) {
+ $protocol = static::create([
+ 'tournament_id' => $tournament->id,
+ 'user_id' => $user->id,
+ 'type' => 'round.getseed',
+ 'details' => [
+ 'tournament' => static::tournamentMemo($tournament),
+ 'round' => static::roundMemo($round),
+ ],
+ ]);
+ ProtocolAdded::dispatch($protocol);
+ }
+
public static function roundSeedSet(Tournament $tournament, Round $round, User $user) {
$protocol = static::create([
'tournament_id' => $tournament->id,
use Illuminate\Broadcasting\Channel;
use Illuminate\Database\Eloquent\BroadcastsEvents;
+use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
}
}
+ protected function hasSeed(): Attribute {
+ return Attribute::make(
+ get: fn () => !!$this->seed,
+ );
+ }
+
public function results() {
return $this->hasMany(Result::class);
return $this->belongsTo(Tournament::class);
}
+ protected $appends = [
+ 'has_seed',
+ ];
protected $casts = [
'code' => 'array',
return !$round->locked && ($user->isRunner($round->tournament) || $user->isTournamentAdmin($round->tournament));
}
+ /**
+ * Determine whether the user can get the seed for this round.
+ *
+ * @param \App\Models\User $user
+ * @param \App\Models\Round $round
+ * @return \Illuminate\Auth\Access\Response|bool
+ */
+ public function getSeed(User $user = null, Round $round)
+ {
+ if ($round->locked) {
+ return true;
+ }
+ if (!$round->tournament->require_auth) {
+ return true;
+ }
+ return !!$user;
+ }
+
/**
* Determine whether the user can lock this round.
*
--- /dev/null
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration {
+
+ /**
+ * Run the migrations.
+ */
+ public function up(): void
+ {
+ Schema::table('tournaments', function (Blueprint $table) {
+ $table->boolean('require_auth')->default(false);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('tournaments', function (Blueprint $table) {
+ $table->dropColumn('require_auth');
+ });
+ }
+
+};
Icon.CROSSHAIRS = makePreset('CrosshairsIcon', 'crosshairs');
Icon.DELETE = makePreset('DeleteIcon', 'user-xmark');
Icon.DISCORD = makePreset('DiscordIcon', ['fab', 'discord']);
+Icon.DOWNLOAD = makePreset('DownloadIcon', 'download');
Icon.EDIT = makePreset('EditIcon', 'edit');
Icon.ERROR = makePreset('ErrorIcon', 'triangle-exclamation');
Icon.FILTER = makePreset('FilterIcon', 'filter');
case 'round.create':
case 'round.delete':
case 'round.edit':
+ case 'round.getseed':
case 'round.lock':
case 'round.seed':
case 'round.unlock':
return <Icon.ADD />;
case 'round.delete':
return <Icon.REMOVE />;
+ case 'round.getseed':
+ return <Icon.DOWNLOAD />;
case 'round.lock':
case 'tournament.close':
case 'tournament.lock':
import { useTranslation } from 'react-i18next';
import SeedDialog from './SeedDialog';
-import { maySetSeed } from '../../helpers/permissions';
+import { mayGetSeed, maySetSeed } from '../../helpers/permissions';
import { useUser } from '../../hooks/user';
const SeedButton = ({ round, tournament }) => {
const { t } = useTranslation();
const { user } = useUser();
- if (round.seed) {
+ if (round.has_seed) {
+ if (!mayGetSeed(user, tournament, round)) {
+ return t('rounds.loginForSeed');
+ }
return <>
- <Button href={round.seed} target="_blank" variant="primary">
+ <Button href={`/rounds/${round.id}/get-seed`} target="_blank" variant="primary">
{t('rounds.seed')}
</Button>
{round.spoiler ?
SeedButton.propTypes = {
round: PropTypes.shape({
+ has_seed: PropTypes.bool,
+ id: PropTypes.number,
seed: PropTypes.string,
spoiler: PropTypes.string,
}),
export const mayLockRound = (user, tournament) =>
!tournament.locked && isTournamentAdmin(user, tournament);
+export const mayGetSeed = (user, tournament, round) =>
+ round.locked || !tournament.require_auth || !!user;
+
export const maySetSeed = (user, tournament, round) =>
!round.locked &&
(isRunner(user, tournament) || isTournamentAdmin(user, tournament));
create: 'Runde #{{number}} hinzugefügt',
delete: 'Runde #{{number}} gelöscht',
edit: 'Runde #{{number}} bearbeitet',
+ getseed: 'Seed für Runde #{{number}} bezogen',
lock: 'Runde #{{number}} gesperrt',
seed: 'Seed für Runde #{{number}} eingetragen',
unlock: 'Runde #{{number}} entsperrt',
lockError: 'Fehler beim Sperren',
lockIncompleteWarning: 'Achtung: Noch nicht alle Runner haben ihr Ergebnis für diese Runde eingereicht!',
lockSuccess: 'Runde gesperrt',
+ loginForSeed: 'Seed verfügbar nach Login',
rolled_by: 'Gerollt von',
rolledBy: 'Gerollt von {{name}}',
seed: 'Seed',
create: 'Added round #{{number}}',
delete: 'Deleted round #{{number}}',
edit: 'Edited round #{{number}}',
+ getseed: 'Got seed for round #{{number}}',
lock: 'Round #{{number}} locked',
seed: 'Set seed for round #{{number}}',
unlock: 'Round #{{number}} unlocked',
lockError: 'Error locking round',
lockIncompleteWarning: 'Warning: Not all runners have submitted their results for this round yet!',
lockSuccess: 'Round locked',
+ loginForSeed: 'Seed available after login',
rolled_by: 'Rolled by',
rolledBy: 'Rolled by {{name}}',
seed: 'Seed',
return app()->call('App\Http\Controllers\TechniqueController@web', ['type' => 'mode', 'name' => $name]);
});
+Route::get('/rounds/{round}/get-seed', 'App\Http\Controllers\RoundController@getSeed');
+
Route::get('/rulesets/{name}', function ($name) {
return app()->call('App\Http\Controllers\TechniqueController@web', ['type' => 'ruleset', 'name' => $name]);
});