Skip to content

Commit d9d9fc7

Browse files
committed
Add slug to namespace projects
1 parent c227828 commit d9d9fc7

File tree

19 files changed

+89
-6
lines changed

19 files changed

+89
-6
lines changed

app/graphql/mutations/namespaces/projects/create.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class Create < BaseMutation
1313

1414
argument :description, String, required: false, description: 'Description for the new project.'
1515
argument :name, String, required: true, description: 'Name for the new project.'
16+
argument :slug, String, required: false, description: 'Slug for the new project.'
1617

1718
def resolve(namespace_id:, **params)
1819
namespace = SagittariusSchema.object_from_id(namespace_id)

app/graphql/mutations/namespaces/projects/update.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Update < BaseMutation
1515
argument :name, String, required: false, description: 'Name for the updated project.'
1616
argument :primary_runtime_id, Types::GlobalIdType[::Runtime],
1717
required: false, description: 'The primary runtime for the updated project.'
18+
argument :slug, String, required: false, description: 'Slug for the updated project.'
1819

1920
def resolve(namespace_project_id:, **params)
2021
project = SagittariusSchema.object_from_id(namespace_project_id)

app/graphql/types/namespace_project_type.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ class NamespaceProjectType < Types::BaseObject
1010

1111
field :name, String, null: false, description: 'Name of the project'
1212

13+
field :slug, String, null: false, description: 'Slug of the project used in URLs to identify flows'
14+
1315
field :runtimes, Types::RuntimeType.connection_type, null: false, description: 'Runtimes assigned to this project'
1416

1517
field :roles, Types::NamespaceRoleType.connection_type, null: false,

app/models/flow.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def to_grpc
1818
Tucana::Shared::ValidationFlow.new(
1919
flow_id: id,
2020
project_id: project.id,
21+
project_slug: project.slug,
2122
type: flow_type.identifier,
2223
data_types: [], # TODO: when data types are creatable
2324
input_type_identifier: input_type&.identifier,

app/models/namespace_project.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ class NamespaceProject < ApplicationRecord
1414
source: :role
1515
has_many :flows, class_name: 'Flow', inverse_of: :project
1616

17+
validates :slug, presence: true,
18+
length: { minimum: 3, maximum: 50 },
19+
allow_blank: false,
20+
uniqueness: { case_sensitive: true },
21+
format: { with: /\A[a-zA-Z0-9_-]+\z/ }
22+
1723
validates :name, presence: true,
1824
length: { minimum: 3, maximum: 50 },
1925
allow_blank: false,

app/services/namespaces/projects/create_service.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,17 @@ def execute
2020
end
2121

2222
transactional do |t|
23+
unless params.key?(:slug)
24+
slug = name.parameterize
25+
26+
tries_left = 5
27+
while NamespaceProject.exists?(slug: slug) && tries_left.positive?
28+
slug = "#{slug}-#{SecureRandom.hex(4)}"
29+
tries_left -= 1
30+
end
31+
params[:slug] = slug
32+
end
33+
2334
project = NamespaceProject.create(namespace: namespace, name: name, **params)
2435
unless project.persisted?
2536
t.rollback_and_return! ServiceResponse.error(

db/fixtures/development/06_namespace_projects.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
NamespaceProject.seed_once :namespace_id, :name do |np|
44
np.namespace_id = Organization.find_by(name: 'Code1').ensure_namespace.id
55
np.name = 'First Project'
6+
np.slug = 'first-project'
67
np.description = 'A sample project for Code1 organization.'
78
np.primary_runtime = Runtime.find_by(name: 'Code1-Runtime')
89
np.runtimes = [Runtime.find_by(name: 'Code1-Runtime')]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# frozen_string_literal: true
2+
3+
class AddSlugToProjects < Code0::ZeroTrack::Database::Migration[1.0]
4+
def change
5+
# rubocop:disable Rails/NotNullColumn -- backwards compatibility intentionally ignored
6+
add_column :namespace_projects, :slug, :text, null: false
7+
add_index :namespace_projects, :slug, unique: true
8+
# rubocop:enable Rails/NotNullColumn
9+
end
10+
end
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
10c61a28b25b5ae26834648b6b679e8946f8558faa5e4f18d909398495af654b

db/structure.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ CREATE TABLE namespace_projects (
486486
updated_at timestamp with time zone NOT NULL,
487487
namespace_id bigint NOT NULL,
488488
primary_runtime_id bigint,
489+
slug text NOT NULL,
489490
CONSTRAINT check_09e881e641 CHECK ((char_length(name) <= 50)),
490491
CONSTRAINT check_a77bf7c685 CHECK ((char_length(description) <= 500))
491492
);
@@ -1175,6 +1176,8 @@ CREATE INDEX index_namespace_projects_on_namespace_id ON namespace_projects USIN
11751176

11761177
CREATE INDEX index_namespace_projects_on_primary_runtime_id ON namespace_projects USING btree (primary_runtime_id);
11771178

1179+
CREATE UNIQUE INDEX index_namespace_projects_on_slug ON namespace_projects USING btree (slug);
1180+
11781181
CREATE INDEX index_namespace_role_project_assignments_on_project_id ON namespace_role_project_assignments USING btree (project_id);
11791182

11801183
CREATE UNIQUE INDEX "index_namespace_roles_on_namespace_id_LOWER_name" ON namespace_roles USING btree (namespace_id, lower(name));

0 commit comments

Comments
 (0)