Skip to content

Commit bc2c630

Browse files
Apply unique name validation rule to createProject mutation (#3409)
While Postgres enforces unique project names correctly, the resulting error message for this common situation is a standard server error. This commit moves the createProject validation logic to a dedicated validator and adds a unique name validation rule.
1 parent 1bc48b9 commit bc2c630

File tree

3 files changed

+71
-6
lines changed

3 files changed

+71
-6
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace App\GraphQL\Validators;
4+
5+
use App\Models\Project;
6+
use App\Rules\ProjectAuthenticateSubmissionsRule;
7+
use App\Rules\ProjectNameRule;
8+
use App\Rules\ProjectVisibilityRule;
9+
use Illuminate\Validation\Rule;
10+
use Nuwave\Lighthouse\Validation\Validator;
11+
12+
final class CreateProjectInputValidator extends Validator
13+
{
14+
public function rules(): array
15+
{
16+
return [
17+
'name' => [
18+
Rule::unique(Project::class, 'name'),
19+
new ProjectNameRule(),
20+
],
21+
'homeurl' => [
22+
'prohibits:homeUrl',
23+
],
24+
'homeUrl' => [
25+
'prohibits:homeurl',
26+
],
27+
'visibility' => [
28+
new ProjectVisibilityRule(),
29+
],
30+
'authenticateSubmissions' => [
31+
new ProjectAuthenticateSubmissionsRule(),
32+
],
33+
];
34+
}
35+
36+
public function messages(): array
37+
{
38+
return [
39+
'name.unique' => 'A project with this name already exists.',
40+
];
41+
}
42+
}

graphql/schema.graphql

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,24 +214,24 @@ enum ProjectVisibility {
214214
PRIVATE @enum(value: 0)
215215
}
216216

217-
input CreateProjectInput {
217+
input CreateProjectInput @validator {
218218
"Unique name."
219-
name: String! @rules(apply: ["App\\Rules\\ProjectNameRule"])
219+
name: String!
220220

221221
"Description."
222222
description: String
223223

224224
"Project homepage"
225-
homeurl: Url @deprecated(reason: "Use 'homeUrl' instead.") @rules(apply: ["prohibits:homeUrl"])
225+
homeurl: Url @deprecated(reason: "Use 'homeUrl' instead.")
226226

227227
"Project homepage"
228-
homeUrl: Url @rename(attribute: "homeurl") @rules(apply: ["prohibits:homeurl"])
228+
homeUrl: Url @rename(attribute: "homeurl") @deprecated(reason: "This field will be removed in the next major version of CDash.")
229229

230230
"Visibility."
231-
visibility: ProjectVisibility! @rename(attribute: "public") @rules(attribute: "public", apply: ["App\\Rules\\ProjectVisibilityRule"])
231+
visibility: ProjectVisibility! @rename(attribute: "public")
232232

233233
"A boolean indicating whether authenticated submissions are required."
234-
authenticateSubmissions: Boolean! @rename(attribute: "authenticatesubmissions") @rules(attribute: "authenticatesubmissions", apply: ["App\\Rules\\ProjectAuthenticateSubmissionsRule"])
234+
authenticateSubmissions: Boolean! @rename(attribute: "authenticatesubmissions")
235235

236236
"A LDAP group users must be a member of to access the project."
237237
ldapFilter: String @deprecated(reason: "This field will be removed in the next major version of CDash.") @rename(attribute: "ldapfilter")

tests/Browser/Pages/CreateProjectPageTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Models\Project;
66
use App\Models\User;
7+
use App\Services\ProjectService;
78
use Illuminate\Support\Str;
89
use Laravel\Dusk\Browser;
910
use PHPUnit\Framework\Attributes\DataProvider;
@@ -79,6 +80,28 @@ public function testShowsErrorWhenInvalidProjectNameProvided(): void
7980
});
8081
}
8182

83+
public function testShowsErrorWhenProjectAlreadyExists(): void
84+
{
85+
$this->users['admin'] = $this->makeAdminUser();
86+
87+
$project_name = Str::uuid()->toString();
88+
89+
$this->projects[] = ProjectService::create([
90+
'name' => $project_name,
91+
]);
92+
93+
$this->browse(function (Browser $browser) use ($project_name): void {
94+
$browser->loginAs($this->users['admin'])
95+
->visit('/projects/new')
96+
->waitFor('@create-project-page')
97+
->type('@project-name-input', $project_name)
98+
->click('@create-project-button')
99+
->waitFor('@project-name-validation-errors')
100+
->assertSeeIn('@project-name-validation-errors', 'A project with this name already exists.')
101+
;
102+
});
103+
}
104+
82105
public function testCreateProjectSetDescription(): void
83106
{
84107
$this->users['admin'] = $this->makeAdminUser();

0 commit comments

Comments
 (0)