summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-12-13 09:08:01 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-12-13 09:08:01 +0000
commit17b91a3c6ab73fff087e91665e9afb8046cbf045 (patch)
tree04655a8630478d9846571875f69469f018d4bdcc /app
parentb3db40398ce9ad335270617e834fde96d46f90ea (diff)
downloadgitlab-ce-17b91a3c6ab73fff087e91665e9afb8046cbf045.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js37
-rw-r--r--app/controllers/projects/jobs_controller.rb4
-rw-r--r--app/graphql/mutations/snippets/base.rb30
-rw-r--r--app/graphql/mutations/snippets/create.rb77
-rw-r--r--app/graphql/mutations/snippets/destroy.rb33
-rw-r--r--app/graphql/mutations/snippets/update.rb54
-rw-r--r--app/graphql/resolvers/base_resolver.rb10
-rw-r--r--app/graphql/types/mutation_type.rb3
-rw-r--r--app/graphql/types/snippet_type.rb4
-rw-r--r--app/graphql/types/visibility_levels_enum.rb9
-rw-r--r--app/presenters/snippet_presenter.rb2
-rw-r--r--app/views/admin/runners/index.html.haml4
12 files changed, 257 insertions, 10 deletions
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index 202a44d5694..6a61d92d9e8 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -1,4 +1,6 @@
-import { join as joinPaths } from 'path';
+const PATH_SEPARATOR = '/';
+const PATH_SEPARATOR_LEADING_REGEX = new RegExp(`^${PATH_SEPARATOR}+`);
+const PATH_SEPARATOR_ENDING_REGEX = new RegExp(`${PATH_SEPARATOR}+$`);
// Returns a decoded url parameter value
// - Treats '+' as '%20'
@@ -6,6 +8,37 @@ function decodeUrlParameter(val) {
return decodeURIComponent(val.replace(/\+/g, '%20'));
}
+function cleanLeadingSeparator(path) {
+ return path.replace(PATH_SEPARATOR_LEADING_REGEX, '');
+}
+
+function cleanEndingSeparator(path) {
+ return path.replace(PATH_SEPARATOR_ENDING_REGEX, '');
+}
+
+/**
+ * Safely joins the given paths which might both start and end with a `/`
+ *
+ * Example:
+ * - `joinPaths('abc/', '/def') === 'abc/def'`
+ * - `joinPaths(null, 'abc/def', 'zoo) === 'abc/def/zoo'`
+ *
+ * @param {...String} paths
+ * @returns {String}
+ */
+export function joinPaths(...paths) {
+ return paths.reduce((acc, path) => {
+ if (!path) {
+ return acc;
+ }
+ if (!acc) {
+ return path;
+ }
+
+ return [cleanEndingSeparator(acc), PATH_SEPARATOR, cleanLeadingSeparator(path)].join('');
+ }, '');
+}
+
// Returns an array containing the value(s) of the
// of the key passed as an argument
export function getParameterValues(sParam, url = window.location) {
@@ -212,5 +245,3 @@ export function objectToQuery(obj) {
.map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`)
.join('&');
}
-
-export { joinPaths };
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index 9480900b57a..796f3ff603f 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -12,7 +12,7 @@ class Projects::JobsController < Projects::ApplicationController
before_action :authorize_use_build_terminal!, only: [:terminal, :terminal_websocket_authorize]
before_action :verify_api_request!, only: :terminal_websocket_authorize
before_action only: [:show] do
- push_frontend_feature_flag(:job_log_json, project)
+ push_frontend_feature_flag(:job_log_json, project, default_enabled: true)
end
layout 'project'
@@ -53,7 +53,7 @@ class Projects::JobsController < Projects::ApplicationController
format.json do
# TODO: when the feature flag is removed we should not pass
# content_format to serialize method.
- content_format = Feature.enabled?(:job_log_json, @project) ? :json : :html
+ content_format = Feature.enabled?(:job_log_json, @project, default_enabled: true) ? :json : :html
build_trace = Ci::BuildTrace.new(
build: @build,
diff --git a/app/graphql/mutations/snippets/base.rb b/app/graphql/mutations/snippets/base.rb
new file mode 100644
index 00000000000..9dc6d49774e
--- /dev/null
+++ b/app/graphql/mutations/snippets/base.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Snippets
+ class Base < BaseMutation
+ field :snippet,
+ Types::SnippetType,
+ null: true,
+ description: 'The snippet after mutation'
+
+ private
+
+ def find_object(id:)
+ GitlabSchema.object_from_id(id)
+ end
+
+ def authorized_resource?(snippet)
+ Ability.allowed?(context[:current_user], ability_for(snippet), snippet)
+ end
+
+ def ability_for(snippet)
+ "#{ability_name}_#{snippet.to_ability_name}".to_sym
+ end
+
+ def ability_name
+ raise NotImplementedError
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/snippets/create.rb b/app/graphql/mutations/snippets/create.rb
new file mode 100644
index 00000000000..fe1f543ea1a
--- /dev/null
+++ b/app/graphql/mutations/snippets/create.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Snippets
+ class Create < BaseMutation
+ include Mutations::ResolvesProject
+
+ graphql_name 'CreateSnippet'
+
+ field :snippet,
+ Types::SnippetType,
+ null: true,
+ description: 'The snippet after mutation'
+
+ argument :title, GraphQL::STRING_TYPE,
+ required: true,
+ description: 'Title of the snippet'
+
+ argument :file_name, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'File name of the snippet'
+
+ argument :content, GraphQL::STRING_TYPE,
+ required: true,
+ description: 'Content of the snippet'
+
+ argument :description, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Description of the snippet'
+
+ argument :visibility_level, Types::VisibilityLevelsEnum,
+ description: 'The visibility level of the snippet',
+ required: true
+
+ argument :project_path, GraphQL::ID_TYPE,
+ required: false,
+ description: 'The project full path the snippet is associated with'
+
+ def resolve(args)
+ project_path = args.delete(:project_path)
+
+ if project_path.present?
+ project = find_project!(project_path: project_path)
+ elsif !can_create_personal_snippet?
+ raise_resource_not_avaiable_error!
+ end
+
+ snippet = CreateSnippetService.new(project,
+ context[:current_user],
+ args).execute
+
+ {
+ snippet: snippet.valid? ? snippet : nil,
+ errors: errors_on_object(snippet)
+ }
+ end
+
+ private
+
+ def find_project!(project_path:)
+ authorized_find!(full_path: project_path)
+ end
+
+ def find_object(full_path:)
+ resolve_project(full_path: full_path)
+ end
+
+ def authorized_resource?(project)
+ Ability.allowed?(context[:current_user], :create_project_snippet, project)
+ end
+
+ def can_create_personal_snippet?
+ Ability.allowed?(context[:current_user], :create_personal_snippet)
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/snippets/destroy.rb b/app/graphql/mutations/snippets/destroy.rb
new file mode 100644
index 00000000000..115fcfd6488
--- /dev/null
+++ b/app/graphql/mutations/snippets/destroy.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Snippets
+ class Destroy < Base
+ graphql_name 'DestroySnippet'
+
+ ERROR_MSG = 'Error deleting the snippet'
+
+ argument :id,
+ GraphQL::ID_TYPE,
+ required: true,
+ description: 'The global id of the snippet to destroy'
+
+ def resolve(id:)
+ snippet = authorized_find!(id: id)
+
+ result = snippet.destroy
+ errors = result ? [] : [ERROR_MSG]
+
+ {
+ errors: errors
+ }
+ end
+
+ private
+
+ def ability_name
+ "admin"
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/snippets/update.rb b/app/graphql/mutations/snippets/update.rb
new file mode 100644
index 00000000000..27c232bc7f8
--- /dev/null
+++ b/app/graphql/mutations/snippets/update.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Snippets
+ class Update < Base
+ graphql_name 'UpdateSnippet'
+
+ argument :id,
+ GraphQL::ID_TYPE,
+ required: true,
+ description: 'The global id of the snippet to update'
+
+ argument :title, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Title of the snippet'
+
+ argument :file_name, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'File name of the snippet'
+
+ argument :content, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Content of the snippet'
+
+ argument :description, GraphQL::STRING_TYPE,
+ required: false,
+ description: 'Description of the snippet'
+
+ argument :visibility_level, Types::VisibilityLevelsEnum,
+ description: 'The visibility level of the snippet',
+ required: false
+
+ def resolve(args)
+ snippet = authorized_find!(id: args.delete(:id))
+
+ result = UpdateSnippetService.new(snippet.project,
+ context[:current_user],
+ snippet,
+ args).execute
+
+ {
+ snippet: result ? snippet : snippet.reset,
+ errors: errors_on_object(snippet)
+ }
+ end
+
+ private
+
+ def ability_name
+ "update"
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/base_resolver.rb b/app/graphql/resolvers/base_resolver.rb
index 85d6b377934..62dcc41dd9c 100644
--- a/app/graphql/resolvers/base_resolver.rb
+++ b/app/graphql/resolvers/base_resolver.rb
@@ -2,6 +2,8 @@
module Resolvers
class BaseResolver < GraphQL::Schema::Resolver
+ extend ::Gitlab::Utils::Override
+
def self.single
@single ||= Class.new(self) do
def resolve(**args)
@@ -36,5 +38,13 @@ module Resolvers
# complexity difference is minimal in this case.
[args[:iid], args[:iids]].any? ? 0 : 0.01
end
+
+ override :object
+ def object
+ super.tap do |obj|
+ # If the field this resolver is used in is wrapped in a presenter, go back to it's subject
+ break obj.subject if obj.is_a?(Gitlab::View::Presenter::Base)
+ end
+ end
end
end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index e8f4ec06177..998dfdc7815 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -25,6 +25,9 @@ module Types
mount_mutation Mutations::Todos::MarkDone
mount_mutation Mutations::Todos::Restore
mount_mutation Mutations::Todos::MarkAllDone
+ mount_mutation Mutations::Snippets::Destroy
+ mount_mutation Mutations::Snippets::Update
+ mount_mutation Mutations::Snippets::Create
end
end
diff --git a/app/graphql/types/snippet_type.rb b/app/graphql/types/snippet_type.rb
index 3b4dce1d486..3f780528945 100644
--- a/app/graphql/types/snippet_type.rb
+++ b/app/graphql/types/snippet_type.rb
@@ -44,8 +44,8 @@ module Types
description: 'Description of the snippet',
null: true
- field :visibility, GraphQL::STRING_TYPE,
- description: 'Visibility of the snippet',
+ field :visibility_level, Types::VisibilityLevelsEnum,
+ description: 'Visibility Level of the snippet',
null: false
field :created_at, Types::TimeType,
diff --git a/app/graphql/types/visibility_levels_enum.rb b/app/graphql/types/visibility_levels_enum.rb
new file mode 100644
index 00000000000..d5ace24455e
--- /dev/null
+++ b/app/graphql/types/visibility_levels_enum.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Types
+ class VisibilityLevelsEnum < BaseEnum
+ Gitlab::VisibilityLevel.string_options.each do |name, int_value|
+ value name.downcase, value: int_value
+ end
+ end
+end
diff --git a/app/presenters/snippet_presenter.rb b/app/presenters/snippet_presenter.rb
index ca8ae8d60c4..37c9ebd3305 100644
--- a/app/presenters/snippet_presenter.rb
+++ b/app/presenters/snippet_presenter.rb
@@ -30,6 +30,6 @@ class SnippetPresenter < Gitlab::View::Presenter::Delegated
end
def ability_name(ability_prefix)
- "#{ability_prefix}_#{snippet.class.underscore}".to_sym
+ "#{ability_prefix}_#{snippet.to_ability_name}".to_sym
end
end
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index 2bf2b5fce8d..f8ef7a45f7f 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -10,7 +10,7 @@
%br
%div
- %span= _('Each Runner can be in one of the following states:')
+ %span= _('Each Runner can be in one of the following states and/or belong to one of the following types:')
%ul
%li
%span.badge.badge-success shared
@@ -120,7 +120,7 @@
.runners-content.content-list
.table-holder
.gl-responsive-table-row.table-row-header{ role: 'row' }
- .table-section.section-10{ role: 'rowheader' }= _('Type')
+ .table-section.section-10{ role: 'rowheader' }= _('Type/State')
.table-section.section-10{ role: 'rowheader' }= _('Runner token')
.table-section.section-20{ role: 'rowheader' }= _('Description')
.table-section.section-10{ role: 'rowheader' }= _('Version')