]> git.localhorst.tv Git - alttp.git/commitdiff
result modification
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 26 Nov 2025 17:58:18 +0000 (18:58 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Wed, 26 Nov 2025 17:58:18 +0000 (18:58 +0100)
17 files changed:
app/Http/Controllers/ResultController.php
app/Models/Protocol.php
app/Models/Result.php
app/Policies/ResultPolicy.php
database/migrations/2025_11_26_163943_result_disqualified.php [new file with mode: 0644]
resources/js/components/common/Icon.jsx
resources/js/components/protocol/Item.jsx
resources/js/components/results/DetailDialog.jsx
resources/js/components/results/ModifyForm.jsx [new file with mode: 0644]
resources/js/components/results/Verification.jsx
resources/js/helpers/Result.jsx
resources/js/helpers/permissions.js
resources/js/i18n/de.js
resources/js/i18n/en.js
resources/js/pages/Tournament.jsx
resources/sass/results.scss
routes/api.php

index 78a1c682f47ef67e489f7f7485475b87553b3669..cca1887bc9d78b6e97d4b2711c2d4534ea6764cb 100644 (file)
@@ -89,6 +89,31 @@ class ResultController extends Controller
                return $result->toJson();
        }
 
+       public function modify(Request $request, Result $result) {
+               $this->authorize('modify', $result);
+
+               $validatedData = $request->validate([
+                       'disqualified' => 'boolean',
+                       'forfeit' => 'boolean',
+                       'time' => 'numeric',
+               ]);
+
+               if (isset($validatedData['disqualified'])) $result->disqualified = $validatedData['disqualified'];
+               if (isset($validatedData['forfeit'])) $result->forfeit = $validatedData['forfeit'];
+               if (isset($validatedData['time'])) $result->time = $validatedData['time'];
+               $result->save();
+
+               Protocol::resultModified(
+                       $result->round->tournament,
+                       $result,
+                       $request->user(),
+               );
+
+               ResultChanged::dispatch($result);
+
+               return $result->toJson();
+       }
+
        public function unverify(Request $request, Result $result) {
                $this->authorize('unverify', $result);
 
index 07a1491b0bfd8598c003f7e30329e5d9ca753519..cfade454818b628d0c0b8f0b1b497c03820c6d49 100644 (file)
@@ -94,6 +94,21 @@ class Protocol extends Model
                ProtocolAdded::dispatch($protocol);
        }
 
+       public static function resultModified(Tournament $tournament, Result $result, User $user) {
+               $protocol = static::create([
+                       'tournament_id' => $tournament->id,
+                       'user_id' => $user->id,
+                       'type' => 'result.modify',
+                       'details' => [
+                               'tournament' => static::tournamentMemo($tournament),
+                               'result' => static::resultMemo($result),
+                               'runner' => static::userMemo($result->user),
+                               'round' => static::roundMemo($result->round),
+                       ],
+               ]);
+               ProtocolAdded::dispatch($protocol);
+       }
+
        public static function resultUnverified(Tournament $tournament, Result $result, User $user) {
                $protocol = static::create([
                        'tournament_id' => $tournament->id,
@@ -323,6 +338,7 @@ class Protocol extends Model
                return [
                        'id' => $result->id,
                        'comment' => $result->comment,
+                       'disqualified' => $result->disqualified,
                        'forfeit' => $result->forfeit,
                        'time' => $result->time,
                ];
@@ -343,9 +359,11 @@ class Protocol extends Model
                return [
                        'id' => $tournament->id,
                        'accept_applications' => $tournament->accept_applications,
+                       'group_size' => $tournament->group_size,
                        'locked' => $tournament->locked,
                        'no_record' => $tournament->no_record,
                        'title' => $tournament->title,
+                       'type' => $tournament->type,
                ];
        }
 
index a85dbc7a83f84708355b8f257b4333b4fe16b8e0..317a35405cbc8233b6d474a815da8f948dc92ca0 100644 (file)
@@ -103,6 +103,7 @@ class Result extends Model
 
 
        protected $casts = [
+               'disqualified' => 'boolean',
                'forfeit' => 'boolean',
                'got_seed_at' => 'datetime',
                'time' => 'double',
index 4c4bff50976dbc3c6ecd42b0935907d238ae025e..a8f13775c275208bd9b90fb0e5fa77b7a3e00cbb 100644 (file)
@@ -92,6 +92,20 @@ class ResultPolicy
                return false;
        }
 
+       /**
+        * Determine whether the user can modify the result administratively.
+        *
+        * @param  \App\Models\User  $user
+        * @param  \App\Models\Result  $result
+        * @return \Illuminate\Auth\Access\Response|bool
+        */
+       public function modify(User $user, Result $result)
+       {
+               return !$result->verified_at &&
+                       $user->isTournamentCrew($result->round->tournament) &&
+                       $user->id != $result->user_id;
+       }
+
        /**
         * Determine whether the user can unverify the result.
         *
@@ -101,7 +115,7 @@ class ResultPolicy
         */
        public function unverify(User $user, Result $result)
        {
-               return $user->isTournamentCrew($result->round->tournament);
+               return $user->isTournamentCrew($result->round->tournament) && $user->id != $result->user_id;
        }
 
        /**
@@ -113,7 +127,7 @@ class ResultPolicy
         */
        public function verify(User $user, Result $result)
        {
-               return $user->isTournamentCrew($result->round->tournament);
+               return $user->isTournamentCrew($result->round->tournament) && $user->id != $result->user_id;
        }
 
 }
diff --git a/database/migrations/2025_11_26_163943_result_disqualified.php b/database/migrations/2025_11_26_163943_result_disqualified.php
new file mode 100644 (file)
index 0000000..be2cf84
--- /dev/null
@@ -0,0 +1,28 @@
+<?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('results', function (Blueprint $table) {
+                       $table->boolean('disqualified')->default(false)->after('forfeit');
+               });
+       }
+
+       /**
+        * Reverse the migrations.
+        */
+       public function down(): void
+       {
+               Schema::table('results', function (Blueprint $table) {
+                       $table->dropColumn('disqualified');
+               });
+       }
+};
index c6e0cfaab353b4306ec4d33bd3a3c5228228976f..16f26b8e026073af3aab59d7b91e70f39e794c70 100644 (file)
@@ -60,6 +60,7 @@ Icon.CHART = makePreset('ChartIcon', 'chart-line');
 Icon.CROSSHAIRS = makePreset('CrosshairsIcon', 'crosshairs');
 Icon.DELETE = makePreset('DeleteIcon', 'user-xmark');
 Icon.DISCORD = makePreset('DiscordIcon', ['fab', 'discord']);
+Icon.DISQUALIFIED = makePreset('DisqualifiedIcon', 'square-xmark');
 Icon.DOWNLOAD = makePreset('DownloadIcon', 'download');
 Icon.EDIT = makePreset('EditIcon', 'edit');
 Icon.ERROR = makePreset('ErrorIcon', 'triangle-exclamation');
@@ -68,7 +69,7 @@ Icon.FILTER = makePreset('FilterIcon', 'filter');
 Icon.FINISHED = makePreset('FinishedIcon', 'square-check');
 Icon.FIRST_PLACE = makePreset('FirstPlaceIcon', 'trophy');
 Icon.FORBIDDEN = makePreset('ForbiddenIcon', 'square-xmark');
-Icon.FORFEIT = makePreset('ForfeitIcon', 'square-xmark');
+Icon.FORFEIT = makePreset('ForfeitIcon', 'square-minus');
 Icon.HASH = makePreset('HashIcon', 'hashtag');
 Icon.INFO = makePreset('Info', 'circle-info');
 Icon.INVERT = makePreset('InvertIcon', 'circle-half-stroke');
index e7134f9c4a2b4e8382d91d1a4a24a0857e169d5c..d215bb92a9c4d674e7daec07800778bfef25bf05 100644 (file)
@@ -7,6 +7,7 @@ import { Trans, useTranslation } from 'react-i18next';
 import Icon from '../common/Icon';
 import Spoiler from '../common/Spoiler';
 import { formatTime } from '../../helpers/Result';
+import { formatNumberAlways } from '../../helpers/Round';
 import { getUserName } from '../../helpers/User';
 
 const getEntryDate = entry => {
@@ -27,7 +28,7 @@ const getEntryDetailsUsername = entry => {
 };
 
 const getEntryRoundNumber = entry =>
-       (entry && entry.details && entry.details.round && entry.details.round.number) || '?';
+       (entry && entry.details && entry.details.round && formatNumberAlways(entry.details.tournament, entry.details.round)) || '?';
 
 const getEntryResultComment = entry => {
        if (!entry || !entry.details || !entry.details.result || !entry.details.result.comment) {
@@ -53,6 +54,7 @@ const getEntryResultRunner = entry => {
 const getEntryResultTime = entry => {
        if (!entry || !entry.details || !entry.details.result) return 'ERROR';
        const result = entry.details.result;
+       if (result.disqualified) return 'DQ XXX';
        if (result.forfeit) return 'DNF XX';
        return formatTime(result);
 };
@@ -94,6 +96,7 @@ const getEntryDescription = (entry, t) => {
                                <Spoiler>{{time}}</Spoiler>,
                        </Trans>;
                }
+               case 'result.modify':
                case 'result.unverify':
                case 'result.verify': {
                        const number = getEntryRoundNumber(entry);
@@ -145,6 +148,7 @@ const getEntryIcon = entry => {
                case 'result.unverify':
                case 'round.delete':
                        return <Icon.REMOVE />;
+               case 'result.modify':
                case 'round.edit':
                case 'round.seed':
                        return <Icon.EDIT />;
index 388d57d648cb803ecdc289bf8e3bbe0d2988efd5..5031caeb19239386244a9e0679176635ea42d50c 100644 (file)
@@ -4,11 +4,12 @@ import React from 'react';
 import { Button, Col, Form, Modal, Row } from 'react-bootstrap';
 import { useTranslation } from 'react-i18next';
 
+import ModifyForm from './ModifyForm';
 import Verification from './Verification';
 import Box from '../users/Box';
 import { formatTime, getTime } from '../../helpers/Result';
 import { formatNumberAlways } from '../../helpers/Round';
-import { maySeeResult, mayVerifyResult } from '../../helpers/permissions';
+import { mayModifyResult, maySeeResult, mayVerifyResult } from '../../helpers/permissions';
 import { findResult } from '../../helpers/User';
 import { useUser } from '../../hooks/user';
 
@@ -30,6 +31,10 @@ const DetailDialog = ({
                () => findResult(user, round),
                [round, user],
        );
+       const mayModify = React.useMemo(
+               () => mayModifyResult(authUser, tournament, round, result),
+               [authUser, result, round, tournament],
+       );
        const maySee = React.useMemo(
                () => maySeeResult(authUser, tournament, round, result),
                [authUser, result, round, tournament],
@@ -122,6 +127,12 @@ const DetailDialog = ({
                                <Verification actions={actions} result={result} round={round} tournament={tournament} />
                        </Modal.Body>
                ) : null}
+               {mayModify && actions.modifyResult ? (
+                       <Modal.Body className="modification">
+                               <div className="h5">{t('results.modify')}</div>
+                               <ModifyForm onSubmit={(values) => actions.modifyResult(result, values)} result={result} />
+                       </Modal.Body>
+               ) : null}
                <Modal.Footer>
                        <Button onClick={onHide} variant="secondary">
                                {t('button.close')}
@@ -132,6 +143,7 @@ const DetailDialog = ({
 
 DetailDialog.propTypes = {
        actions: PropTypes.shape({
+               modifyResult: PropTypes.func,
                verifyResult: PropTypes.func,
        }),
        onHide: PropTypes.func,
diff --git a/resources/js/components/results/ModifyForm.jsx b/resources/js/components/results/ModifyForm.jsx
new file mode 100644 (file)
index 0000000..258feaf
--- /dev/null
@@ -0,0 +1,138 @@
+import { withFormik } from 'formik';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Col, Form, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import LargeCheck from '../common/LargeCheck';
+import laravelErrorsToFormik from '../../helpers/laravelErrorsToFormik';
+import { formatTime, parseTime } from '../../helpers/Result';
+import yup from '../../schema/yup';
+
+const ModifyForm = ({
+       errors,
+       handleBlur,
+       handleChange,
+       handleSubmit,
+       touched,
+       values,
+}) => {
+       const { t } = useTranslation();
+
+       return <Form noValidate onSubmit={handleSubmit}>
+               <Row>
+                       <Form.Group as={Col} sm={8} controlId="modify.time">
+                               <Form.Label>{t('results.reportTime')}</Form.Label>
+                               <Form.Control
+                                       isInvalid={!!(touched.time && errors.time)}
+                                       name="time"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       placeholder={values.forfeit ? 'DNF' : '1:22:59'}
+                                       type="text"
+                                       value={values.time || ''}
+                               />
+                               {touched.time && errors.time ?
+                                       <Form.Control.Feedback type="invalid">
+                                               {t(errors.time)}
+                                       </Form.Control.Feedback>
+                               :
+                                       <Form.Text muted>
+                                               {parseTime(values.time) ?
+                                                       t(
+                                                               'results.reportPreview',
+                                                               { time: formatTime({ time: parseTime(values.time) })},
+                                                       )
+                                               : null}
+                                       </Form.Text>
+                               }
+                       </Form.Group>
+                       <Form.Group as={Col} sm={2} controlId="modify.forfeit">
+                               <Form.Label title={t('results.forfeit')}>
+                                       {t('results.forfeitShort')}
+                               </Form.Label>
+                               <Form.Control
+                                       as={LargeCheck}
+                                       isInvalid={!!(touched.forfeit && errors.forfeit)}
+                                       name="forfeit"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={!!values.forfeit}
+                               />
+                       </Form.Group>
+                       <Form.Group as={Col} sm={2} controlId="modify.disqualified">
+                               <Form.Label title={t('results.disqualified')}>
+                                       {t('results.disqualifiedShort')}
+                               </Form.Label>
+                               <Form.Control
+                                       as={LargeCheck}
+                                       isInvalid={!!(touched.disqualified && errors.disqualified)}
+                                       name="disqualified"
+                                       onBlur={handleBlur}
+                                       onChange={handleChange}
+                                       value={!!values.disqualified}
+                               />
+                       </Form.Group>
+               </Row>
+               <Button className="mt-3" type="submit" variant="primary">
+                       {t('button.save')}
+               </Button>
+       </Form>;
+};
+
+ModifyForm.propTypes = {
+       errors: PropTypes.shape({
+               disqualified: PropTypes.string,
+               forfeit: PropTypes.string,
+               time: PropTypes.string,
+       }),
+       handleBlur: PropTypes.func,
+       handleChange: PropTypes.func,
+       handleSubmit: PropTypes.func,
+       touched: PropTypes.shape({
+               disqualified: PropTypes.bool,
+               forfeit: PropTypes.bool,
+               time: PropTypes.bool,
+       }),
+       values: PropTypes.shape({
+               disqualified: PropTypes.bool,
+               forfeit: PropTypes.bool,
+               time: PropTypes.string,
+       }),
+};
+
+export default withFormik({
+       displayName: 'ModifyForm',
+       enableReinitialize: true,
+       handleSubmit: async (values, actions) => {
+               const { disqualified, forfeit, time } = values;
+               const { setErrors } = actions;
+               const { onSubmit } = actions.props;
+               try {
+                       await onSubmit({
+                               disqualified,
+                               forfeit,
+                               time: parseTime(time) || 0,
+                       });
+               } catch (e) {
+                       if (e.response && e.response.data && e.response.data.errors) {
+                               setErrors(laravelErrorsToFormik(e.response.data.errors));
+                       }
+               }
+       },
+       mapPropsToValues: ({ result }) => {
+               return {
+                       disqualified: result ? !!result.disqualified : false,
+                       forfeit: result ? !!result.forfeit : false,
+                       time: result && result.time ? formatTime(result) : '',
+               };
+       },
+       validationSchema: yup.object().shape({
+               disqualified: yup.boolean().required(),
+               forfeit: yup.boolean().required(),
+               time: yup.string().time().when('forfeit', {
+                       is: false,
+                       then: () => yup.string().required().time(),
+               }),
+       }),
+})(ModifyForm);
index 43113c514cd782ecf6caf0e805b776e91ec2d4ef..141b0048d93903d3489ce29a26beb294cb9dca90 100644 (file)
@@ -61,11 +61,16 @@ const Verification = ({ actions, result, round, tournament }) => {
                        </div>
                        {mayUnverify ?
                                <Button
+                                       disabled={unverifying}
                                        onClick={handleUnverifyClick}
                                        title={t('results.unverify')}
                                        variant="outline-danger"
                                >
-                                       <Icon.REMOVE title="" />
+                                       {unverifying ?
+                                               <Icon.LOADING />
+                                       :
+                                               <Icon.REMOVE title="" />
+                                       }
                                </Button>
                        : null}
                </div>;
index 833368a78e81047bf2afbc9d76e988be4a19e6ec..efa592e0f51aa5dd94115dc521ef39926b5d2546 100644 (file)
@@ -57,6 +57,9 @@ export const getIcon = (result, maySee) => {
        if (result.placement === 3 && maySee) {
                return <Icon.THIRD_PLACE className="text-bronze" size="lg" />;
        }
+       if (result.disqualified) {
+               return <Icon.DISQUALIFIED className="text-danger" size="lg" />;
+       }
        if (result.verified_at) {
                return <Icon.VERIFIED className="text-info" size="lg" />;
        }
@@ -67,12 +70,15 @@ export const getTime = (result, maySee) => {
        if (!result || !maySee) {
                return null;
        }
-       if (result.time) {
-               return formatTime(result);
+       if (result.disqualified) {
+               return 'DQ';
        }
        if (result.forfeit) {
                return 'DNF';
        }
+       if (result.time) {
+               return formatTime(result);
+       }
        return '?';
 };
 
index e6fc01c8b2ea43a4ab651f045e6765b43139892d..a1ab287837a090651125a5909e87b89fa6a261a6 100644 (file)
@@ -213,6 +213,14 @@ export const maySeeResult = (user, tournament, round, result) => {
        return maySeeResults(user, tournament, round);
 };
 
+export const mayModifyResults = (user, tournament, round) => {
+       return isTournamentCrew(user, tournament);
+};
+
+export const mayModifyResult = (user, tournament, round, result) => {
+       return mayModifyResults(user, tournament) && user && result && !result.verified_at && user.id !== result.user_id;
+};
+
 export const mayVerifyResults = (user, tournament, round) => {
        return isTournamentCrew(user, tournament);
 };
index 181f88b4f13529920120b0d528f30f1842a3bf0e..b1cf48049b4942e7e2c70024f699c67f64cf24e7 100644 (file)
@@ -584,6 +584,7 @@ export default {
                                },
                                result: {
                                        comment: 'Ergebnis von Runde {{number}} kommentiert: <1>{{comment}}</1>',
+                                       modify: 'Ergebnis in Runde {{number}} von {{runner}} angepasst (<2>{{time}}</2>)',
                                        report: 'Ergebnis von <1>{{time}}</1> bei Runde {{number}} eingetragen',
                                        unverify: 'Verifikation von Ergebnis in Runde {{number}} von {{runner}} (<2>{{time}}</2>) zurückgezogen',
                                        verify: 'Ergebnis in Runde {{number}} von {{runner}} (<2>{{time}}</2>) verifiziert',
@@ -616,12 +617,18 @@ export default {
                        createdAtFormat: '{{ date, L LT }}',
                        comment: 'Kommentar',
                        details: 'Details',
+                       disqualified: 'Disqualifiziert',
+                       disqualifiedShort: 'DQ',
                        edit: 'Ergebnis ändern',
                        editComment: 'Kommentar ändern',
                        forfeit: 'Aufgegeben',
+                       forfeitShort: 'DNF',
                        gotSeedAt: 'Seed geladen',
                        gotSeedAtFormat: '{{ date, L LT }}',
                        list: 'Liste',
+                       modify: 'Anpassen',
+                       modifyError: 'Fehler beim Speichern',
+                       modifySuccess: 'Ergebnis angepasst',
                        pending: 'Ausstehend',
                        placement: 'Platzierung',
                        points_one: '{{ count }} Punkt',
index 3b1f8759ae3bf85db871f1756389489f9d78b2d4..b52fbab40e5744bb148c31816cdc8be53626e1e4 100644 (file)
@@ -584,6 +584,7 @@ export default {
                                },
                                result: {
                                        comment: 'Result of round {{number}} commented: <1>{{comment}}</1>',
+                                       modify: 'Modified round {{number}} result of {{runner}} (<2>{{time}}</2>)',
                                        report: 'Result of <1>{{time}}</1> reported for round {{number}}',
                                        unverify: 'Revoked verification for round {{number}} result of {{runner}} (<2>{{time}}</2>)',
                                        verify: 'Verified round {{number}} result of {{runner}} (<2>{{time}}</2>)',
@@ -616,12 +617,18 @@ export default {
                        createdAt: 'Entry from',
                        createdAtFormat: '{{ date, L LT }}',
                        details: 'Details',
+                       disqualified: 'Disqualified',
+                       disqualifiedShort: 'DQ',
                        edit: 'Change result',
                        editComment: 'Edit comment',
                        forfeit: 'Forfeit',
+                       forfeitShort: 'DNF',
                        gotSeedAt: 'Got seed at',
                        gotSeedAtFormat: '{{ date, L LT }}',
                        list: 'List',
+                       modify: 'Modify',
+                       modifyError: 'Error saving modifications',
+                       modifySuccess: 'Result modified',
                        pending: 'Pending',
                        placement: 'Placement',
                        points_one: '{{ count }} point',
index 54aa92fd74681148b09fff31a7f08be714799368..a3c4170b1be3dbd86e2d69625cb290703935331e 100644 (file)
@@ -14,6 +14,7 @@ import Dialog from '../components/techniques/Dialog';
 import Detail from '../components/tournament/Detail';
 import {
        mayEditContent,
+       mayModifyResults,
        mayUnverifyResults,
        mayVerifyResults,
 } from '../helpers/permissions';
@@ -174,6 +175,17 @@ export const Component = () => {
                }
        }, [id, t]);
 
+       const modifyResult = React.useCallback(async (result, values) => {
+               try {
+                       const response = await axios.post(`/api/results/${result.id}/modify`, values);
+                       toastr.success(t('results.modifySuccess'));
+                       setTournament(tournament => patchResult(tournament, response.data));
+               } catch (e) {
+                       toastr.error(t('results.modifyError', e));
+                       throw e;
+               }
+       }, []);
+
        const unverifyResult = React.useCallback(async (result) => {
                try {
                        const response = await axios.post(`/api/results/${result.id}/unverify`);
@@ -182,7 +194,7 @@ export const Component = () => {
                } catch (e) {
                        toastr.error(t('results.unverifyError', e));
                }
-       });
+       }, []);
 
        const verifyResult = React.useCallback(async (result) => {
                try {
@@ -192,7 +204,7 @@ export const Component = () => {
                } catch (e) {
                        toastr.error(t('results.verifyError', e));
                }
-       });
+       }, []);
 
        const actions = React.useMemo(() => ({
                addRound,
@@ -200,11 +212,12 @@ export const Component = () => {
                        setEditContent(content);
                        setShowContentDialog(true);
                } : null,
+               modifyResult: mayModifyResults(user, tournament) ? modifyResult : null,
                moreRounds: canLoadMoreRounds(tournament) ? moreRounds : null,
                selfAssignGroups,
                unverifyResult: mayUnverifyResults(user, tournament) ? unverifyResult : null,
                verifyResult: mayVerifyResults(user, tournament) ? verifyResult : null,
-       }), [addRound, moreRounds, selfAssignGroups, tournament, user, verifyResult]);
+       }), [addRound, modifyResult, moreRounds, selfAssignGroups, tournament, unverifyResult, user, verifyResult]);
 
        useEffect(() => {
                const cb = (e) => {
index 00659a9a246dd43cb9559af32b37ba9708212aaa..e90bcca6903c7a127c450383062d3c0767ad8171 100644 (file)
@@ -1,4 +1,5 @@
 .result-dialog {
+       .modification,
        .verification {
                border-top: thin solid $light;
        }
index aacbf493c1caa7fbd4833f19ddecb086cf82c167..5eb9e135e05451c508e2af0570f22c0226a466b0 100644 (file)
@@ -85,6 +85,7 @@ Route::get('protocol/{tournament}', 'App\Http\Controllers\ProtocolController@for
 Route::get('protocol/{tournament}/{round}', 'App\Http\Controllers\ProtocolController@forRound');
 
 Route::post('results', 'App\Http\Controllers\ResultController@create');
+Route::post('results/{result}/modify', 'App\Http\Controllers\ResultController@modify');
 Route::post('results/{result}/verify', 'App\Http\Controllers\ResultController@verify');
 Route::post('results/{result}/unverify', 'App\Http\Controllers\ResultController@unverify');