]> git.localhorst.tv Git - alttp.git/commitdiff
relax unique constraint on techniques
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 9 Mar 2023 13:12:42 +0000 (14:12 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Thu, 9 Mar 2023 13:35:17 +0000 (14:35 +0100)
app/Http/Controllers/TechniqueController.php
database/migrations/2023_03_09_125727_tech_unique_per_type.php [new file with mode: 0644]
resources/js/components/App.js
resources/js/components/pages/Technique.js
resources/js/components/pages/Techniques.js
resources/js/helpers/Technique.js
routes/api.php

index b27465e5da1afe0819198cc88338e7f23ce80282..7173f1edce28ad515b364e79d2eeb98a454dead1 100644 (file)
@@ -10,6 +10,19 @@ use Illuminate\Http\Request;
 class TechniqueController extends Controller
 {
 
+       public function byType(Request $request, $type) {
+               $techs = Technique::where('index', true)->where('type', '=', $type);
+               $this->applyFilter($request, $techs);
+               return $techs->get()->toJson();
+       }
+
+       public function byTypeAndName(Request $request, $type, $name) {
+               $tech = Technique::where('type', '=', $type)->where('name', '=', $name)->firstOrFail();
+               $this->authorize('view', $tech);
+               $tech->load(['chapters', 'relations']);
+               return $tech->toJson();
+       }
+
        public function forMap($map) {
                $techs = TechniqueMap::with(['technique', 'technique.relations'])->where('map', '=', $map);
 
@@ -17,6 +30,18 @@ class TechniqueController extends Controller
        }
 
        public function search(Request $request) {
+               $techs = Technique::where('index', '=', 1);
+               $this->applyFilter($request, $techs);
+               return $techs->get()->toJson();
+       }
+
+       public function single(Request $request, Technique $tech) {
+               $this->authorize('view', $tech);
+               $tech->load(['chapters', 'relations']);
+               return $tech->toJson();
+       }
+
+       protected function applyFilter(Request $request, Builder $query) {
                $validatedData = $request->validate([
                        'phrase' => 'string|nullable',
                        'ruleset' => 'array|nullable',
@@ -27,15 +52,13 @@ class TechniqueController extends Controller
                        'type' => 'string|nullable',
                ]);
 
-               $techs = Technique::where('index', '=', 1);
-
                if (!empty($validatedData['type'])) {
-                       $techs = $techs->where('type', '=', $validatedData['type']);
+                       $query->where('type', '=', $validatedData['type']);
                }
 
                if (!empty($validatedData['phrase'])) {
                        $search = $validatedData['phrase'];
-                       $techs = $techs->where(function (Builder $query) use ($search) {
+                       $query->where(function (Builder $query) use ($search) {
                                $query->where('title', 'LIKE', '%'.$search.'%')
                                ->orWhere('short', 'LIKE', '%'.$search.'%');
                        });
@@ -49,7 +72,7 @@ class TechniqueController extends Controller
                        $any = $com || $owg || $mg || $nl;
                        $all = $com && $owg && $mg && $nl;
                        if ($any && !$all) {
-                               $techs->where(function(Builder $query) use ($com, $owg, $mg, $nl) {
+                               $query->where(function(Builder $query) use ($com, $owg, $mg, $nl) {
                                        $query->whereNull('rulesets');
                                        if ($com) {
                                                $query->orWhere('rulesets->competitive', '=', true);
@@ -66,14 +89,6 @@ class TechniqueController extends Controller
                                });
                        }
                }
-
-               return $techs->get()->toJson();
-       }
-
-       public function single(Request $request, Technique $tech) {
-               $this->authorize('view', $tech);
-               $tech->load(['chapters', 'relations']);
-               return $tech->toJson();
        }
 
 }
diff --git a/database/migrations/2023_03_09_125727_tech_unique_per_type.php b/database/migrations/2023_03_09_125727_tech_unique_per_type.php
new file mode 100644 (file)
index 0000000..b3624de
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+use Illuminate\Database\Migrations\Migration;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Support\Facades\Schema;
+
+return new class extends Migration
+{
+       /**
+        * Run the migrations.
+        *
+        * @return void
+        */
+       public function up()
+       {
+               Schema::table('techniques', function(Blueprint $table) {
+                       $table->dropUnique(['name']);
+                       $table->unique(['type', 'name']);
+               });
+       }
+
+       /**
+        * Reverse the migrations.
+        *
+        * @return void
+        */
+       public function down()
+       {
+               Schema::table('techniques', function(Blueprint $table) {
+                       $table->dropUnique(['type', 'name']);
+                       $table->unique(['name']);
+               });
+       }
+};
index a26683c477b71f8a01e43b8a7558a3e4d34b2a16..3ad2494981cbec2f9f878dbdd0faad155a87338d 100644 (file)
@@ -70,7 +70,23 @@ const App = () => {
                                </Helmet>
                                <Header doLogout={doLogout} />
                                <Routes>
+                                       <Route
+                                               path="dungeons"
+                                               element={<Techniques namespace="dungeons" type="dungeon" />}
+                                       />
+                                       <Route
+                                               path="dungeons/:name"
+                                               element={<Technique namespace="dungeons" type="dungeon" />}
+                                       />
                                        <Route path="h/:hash" element={<AlttpSeed />} />
+                                       <Route
+                                               path="locations"
+                                               element={<Techniques namespace="locations" type="location" />}
+                                       />
+                                       <Route
+                                               path="locations/:name"
+                                               element={<Technique namespace="locations" type="location" />}
+                                       />
                                        <Route path="map" element={<Map />} />
                                        <Route
                                                path="modes"
index c4be0666614eb932d5c22e5ae8ccbf0ffd3dc23b..4004707895ad23dc18607e1af5a1758c2b01e3fa 100644 (file)
@@ -1,4 +1,5 @@
 import axios from 'axios';
+import PropTypes from 'prop-types';
 import React, { useEffect, useState } from 'react';
 import { Helmet } from 'react-helmet';
 import { withTranslation } from 'react-i18next';
@@ -13,7 +14,7 @@ import Detail from '../techniques/Detail';
 import { getLanguages, getMatchedLocale, getTranslation } from '../../helpers/Technique';
 import i18n from '../../i18n';
 
-const Technique = () => {
+const Technique = ({ type }) => {
        const params = useParams();
        const { name } = params;
 
@@ -25,7 +26,7 @@ const Technique = () => {
                const ctrl = new AbortController();
                setLoading(true);
                axios
-                       .get(`/api/tech/${name}`, { signal: ctrl.signal })
+                       .get(`/api/pages/${type}/${name}`, { signal: ctrl.signal })
                        .then(response => {
                                setError(null);
                                setLoading(false);
@@ -39,7 +40,7 @@ const Technique = () => {
                return () => {
                        ctrl.abort();
                };
-       }, [name]);
+       }, [name, type]);
 
        if (loading) {
                return <Loading />;
@@ -67,4 +68,8 @@ const Technique = () => {
        </ErrorBoundary>;
 };
 
+Technique.propTypes = {
+       type: PropTypes.string,
+};
+
 export default withTranslation()(Technique);
index ebeb6e5613e8f9067995bbdbde2b639f93365967..c2d7aec80627aaec51f6344d113ecbfccb55530d 100644 (file)
@@ -39,11 +39,8 @@ const Techniques = ({ namespace, type }) => {
                        setLoading(true);
                }
                axios
-                       .get(`/api/content`, {
-                               params: {
-                                       type,
-                                       ...filter,
-                               },
+                       .get(`/api/pages/${type}`, {
+                               params: filter,
                                signal: ctrl.signal
                        })
                        .then(response => {
index b289341d34833bbb4b99262885522786260da515..f3daae7d1dfd53453dd1166edaa639f27dcf167d 100644 (file)
@@ -1,6 +1,12 @@
 import i18n from '../i18n';
 
 export const getLink = tech => {
+       if (tech.type === 'dungeon') {
+               return `/dungeons/${tech.name}`;
+       }
+       if (tech.type === 'location') {
+               return `/locations/${tech.name}`;
+       }
        if (tech.type === 'mode') {
                return `/modes/${tech.name}`;
        }
index 8fdfad417e6e69ba090bdd40ae4bdfae265a51ec..c0db87cd7ec2819f69c1a43b4f07b1035fdeb0be 100644 (file)
@@ -48,6 +48,9 @@ Route::get('events/{event:name}', 'App\Http\Controllers\EventController@single')
 
 Route::get('markers/{map}', 'App\Http\Controllers\TechniqueController@forMap');
 
+Route::get('pages/{type}', 'App\Http\Controllers\TechniqueController@byType');
+Route::get('pages/{type}/{name}', 'App\Http\Controllers\TechniqueController@byTypeAndName');
+
 Route::get('protocol/{tournament}', 'App\Http\Controllers\ProtocolController@forTournament');
 
 Route::post('results', 'App\Http\Controllers\ResultController@create');