Commit 7c570163 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent cf77b17717a3
# frozen_string_literal: true
module Types
module PermissionTypes
class Snippet < BasePermissionType
graphql_name 'SnippetPermissions'
abilities :create_note, :award_emoji
permission_field :read_snippet, method: :can_read_snippet?
permission_field :update_snippet, method: :can_update_snippet?
permission_field :admin_snippet, method: :can_admin_snippet?
end
end
end
# frozen_string_literal: true
module Types
module PermissionTypes
class User < BasePermissionType
graphql_name 'UserPermissions'
permission_field :create_snippet
def create_snippet
Ability.allowed?(context[:current_user], :create_personal_snippet)
end
end
end
end
......@@ -151,5 +151,11 @@ class ProjectType < BaseObject
null: true,
description: 'Detailed version of a Sentry error on the project',
resolver: Resolvers::ErrorTracking::SentryDetailedErrorResolver
field :snippets,
Types::SnippetType.connection_type,
null: true,
description: 'Snippets of the project',
resolver: Resolvers::Projects::SnippetsResolver
end
end
......@@ -29,6 +29,12 @@ class QueryType < ::Types::BaseObject
resolver: Resolvers::MetadataResolver,
description: 'Metadata about GitLab'
field :snippets,
Types::SnippetType.connection_type,
null: true,
resolver: Resolvers::SnippetsResolver,
description: 'Find Snippets visible to the current user'
field :echo, GraphQL::STRING_TYPE, null: false, resolver: Resolvers::EchoResolver # rubocop:disable Graphql/Descriptions
end
end
# frozen_string_literal: true
module Types
class SnippetType < BaseObject
graphql_name 'Snippet'
description 'Represents a snippet entry'
implements(Types::Notes::NoteableType)
present_using SnippetPresenter
authorize :read_snippet
expose_permissions Types::PermissionTypes::Snippet
field :id, GraphQL::ID_TYPE,
description: 'Id of the snippet',
null: false
field :title, GraphQL::STRING_TYPE,
description: 'Title of the snippet',
null: false
field :project, Types::ProjectType,
description: 'The project the snippet is associated with',
null: true,
authorize: :read_project,
resolve: -> (snippet, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(Project, snippet.project_id).find }
field :author, Types::UserType,
description: 'The owner of the snippet',
null: false,
resolve: -> (snippet, args, context) { Gitlab::Graphql::Loaders::BatchModelLoader.new(User, snippet.author_id).find }
field :file_name, GraphQL::STRING_TYPE,
description: 'File Name of the snippet',
null: true
field :content, GraphQL::STRING_TYPE,
description: 'Content of the snippet',
null: false
field :description, GraphQL::STRING_TYPE,
description: 'Description of the snippet',
null: true
field :visibility, GraphQL::STRING_TYPE,
description: 'Visibility of the snippet',
null: false
field :created_at, Types::TimeType,
description: 'Timestamp this snippet was created',
null: false
field :updated_at, Types::TimeType,
description: 'Timestamp this snippet was updated',
null: false
field :web_url, type: GraphQL::STRING_TYPE,
description: 'Web URL of the snippet',
null: false
field :raw_url, type: GraphQL::STRING_TYPE,
description: 'Raw URL of the snippet',
null: false
markdown_field :description_html, null: true, method: :description
end
end
# frozen_string_literal: true
module Types
module Snippets
class TypeEnum < BaseEnum
value 'personal', value: 'personal'
value 'project', value: 'project'
end
end
end
# frozen_string_literal: true
module Types
module Snippets
class VisibilityScopesEnum < BaseEnum
value 'private', value: 'are_private'
value 'internal', value: 'are_internal'
value 'public', value: 'are_public'
end
end
end
......@@ -8,6 +8,8 @@ class UserType < BaseObject
present_using UserPresenter
expose_permissions Types::PermissionTypes::User
field :name, GraphQL::STRING_TYPE, null: false,
description: 'Human-readable name of the user'
field :username, GraphQL::STRING_TYPE, null: false,
......@@ -19,5 +21,11 @@ class UserType < BaseObject
field :todos, Types::TodoType.connection_type, null: false,
resolver: Resolvers::TodoResolver,
description: 'Todos of the user'
field :snippets,
Types::SnippetType.connection_type,
null: true,
description: 'Snippets authored by the user',
resolver: Resolvers::Users::SnippetsResolver
end
end
......@@ -32,6 +32,18 @@ def new_gpg_key_email(gpg_key_id)
mail(to: @user.notification_email, subject: subject("GPG key was added to your account"))
end
# rubocop: enable CodeReuse/ActiveRecord
def access_token_about_to_expire_email(user)
return unless user
@user = user
@target_url = profile_personal_access_tokens_url
@days_to_expire = PersonalAccessToken::DAYS_TO_EXPIRE
Gitlab::I18n.with_locale(@user.preferred_language) do
mail(to: @user.notification_email, subject: subject(_("Your Personal Access Tokens will expire in %{days_to_expire} days or less") % { days_to_expire: @days_to_expire }))
end
end
end
end
......
......@@ -13,15 +13,21 @@ class Prometheus < ApplicationRecord
include ::Clusters::Concerns::ApplicationStatus
include ::Clusters::Concerns::ApplicationVersion
include ::Clusters::Concerns::ApplicationData
include AfterCommitQueue
default_value_for :version, VERSION
after_destroy :disable_prometheus_integration
after_destroy do
run_after_commit do
disable_prometheus_integration
end
end
state_machine :status do
after_transition any => [:installed] do |application|
application.cluster.projects.each do |project|
project.find_or_initialize_service('prometheus').update!(active: true)
application.run_after_commit do
Clusters::Applications::ActivateServiceWorker
.perform_async(application.cluster_id, ::PrometheusService.to_param) # rubocop:disable CodeReuse/ServiceClass
end
end
end
......@@ -98,9 +104,8 @@ def configured?
private
def disable_prometheus_integration
cluster.projects.each do |project|
project.prometheus_service&.update!(active: false)
end
::Clusters::Applications::DeactivateServiceWorker
.perform_async(cluster_id, ::PrometheusService.to_param) # rubocop:disable CodeReuse/ServiceClass
end
def kube_client
......
......@@ -34,6 +34,7 @@ class Cluster < ApplicationRecord
has_many :cluster_groups, class_name: 'Clusters::Group'
has_many :groups, through: :cluster_groups, class_name: '::Group'
has_many :groups_projects, through: :groups, source: :projects, class_name: '::Project'
# we force autosave to happen when we save `Cluster` model
has_one :provider_gcp, class_name: 'Clusters::Providers::Gcp', autosave: true
......@@ -177,6 +178,13 @@ def self.ancestor_clusters_for_clusterable(clusterable, hierarchy_order: :asc)
end
end
def all_projects
return projects if project_type?
return groups_projects if group_type?
::Project.all
end
def status_name
return cleanup_status_name if cleanup_errored?
return :cleanup_ongoing unless cleanup_not_started?
......
......@@ -17,6 +17,7 @@ module Metadatable
delegate :timeout, to: :metadata, prefix: true, allow_nil: true
delegate :interruptible, to: :metadata, prefix: false, allow_nil: true
delegate :has_exposed_artifacts?, to: :metadata, prefix: false, allow_nil: true
delegate :environment_auto_stop_in, to: :metadata, prefix: false, allow_nil: true
before_create :ensure_metadata
end
......@@ -47,8 +48,11 @@ def yaml_variables
def options=(value)
write_metadata_attribute(:options, :config_options, value)
# Store presence of exposed artifacts in build metadata to make it easier to query
ensure_metadata.has_exposed_artifacts = value&.dig(:artifacts, :expose_as).present?
ensure_metadata.tap do |metadata|
# Store presence of exposed artifacts in build metadata to make it easier to query
metadata.has_exposed_artifacts = value&.dig(:artifacts, :expose_as).present?
metadata.environment_auto_stop_in = value&.dig(:environment, :auto_stop_in)
end
end
def yaml_variables=(value)
......
......@@ -3,6 +3,8 @@
module Expirable
extend ActiveSupport::Concern
DAYS_TO_EXPIRE = 7
included do
scope :expired, -> { where('expires_at <= ?', Time.current) }
end
......@@ -16,6 +18,6 @@ def expires?
end
def expires_soon?
expires? && expires_at < 7.days.from_now
expires? && expires_at < DAYS_TO_EXPIRE.days.from_now
end
end
......@@ -162,6 +162,10 @@ def stop_with_action!(current_user)
stop_action&.play(current_user)
end
def reset_auto_stop
update_column(:auto_stop_at, nil)
end
def actions_for(environment)
return [] unless manual_actions
......@@ -261,6 +265,17 @@ def knative_services_finder
end
end
def auto_stop_in
auto_stop_at - Time.now if auto_stop_at
end
def auto_stop_in=(value)
return unless value
return unless parsed_result = ChronicDuration.parse(value)
self.auto_stop_at = parsed_result.seconds.from_now
end
private
def generate_slug
......
......@@ -341,6 +341,6 @@ def dates_within_4_digits
end
def issues_finder_params
{ project_id: project_id, group_id: group_id }.compact
{ project_id: project_id, group_id: group_id, include_subgroups: group_id.present? }.compact
end
end
......@@ -16,6 +16,7 @@ class PersonalAccessToken < ApplicationRecord
before_save :ensure_token
scope :active, -> { where("revoked = false AND (expires_at >= NOW() OR expires_at IS NULL)") }
scope :expiring_and_not_notified, ->(date) { where(["revoked = false AND expire_notification_delivered = false AND expires_at >= NOW() AND expires_at <= ?", date]) }
scope :inactive, -> { where("revoked = true OR expires_at < NOW()") }
scope :with_impersonation, -> { where(impersonation: true) }
scope :without_impersonation, -> { where(impersonation: false) }
......
......@@ -404,6 +404,7 @@ class Project < ApplicationRecord
scope :with_push, -> { joins(:events).where('events.action = ?', Event::PUSHED) }
scope :with_project_feature, -> { joins('LEFT JOIN project_features ON projects.id = project_features.project_id') }
scope :with_statistics, -> { includes(:statistics) }
scope :with_service, ->(service) { joins(service).eager_load(service) }
scope :with_shared_runners, -> { where(shared_runners_enabled: true) }
scope :with_container_registry, -> { where(container_registry_enabled: true) }
scope :inside_path, ->(path) do
......@@ -1256,8 +1257,9 @@ def code
def all_clusters
group_clusters = Clusters::Cluster.joins(:groups).where(cluster_groups: { group_id: ancestors_upto } )
instance_clusters = Clusters::Cluster.instance_type
Clusters::Cluster.from_union([clusters, group_clusters])
Clusters::Cluster.from_union([clusters, group_clusters, instance_clusters])
end
def items_for(entity)
......
......@@ -88,7 +88,7 @@ def prometheus_available?
return false if template?
return false unless project
project.clusters.enabled.any? { |cluster| cluster.application_prometheus_available? }
project.all_clusters.enabled.any? { |cluster| cluster.application_prometheus_available? }
end
def allow_local_api_url?
......
......@@ -310,6 +310,13 @@ def inactive_message
scope :with_dashboard, -> (dashboard) { where(dashboard: dashboard) }
scope :with_public_profile, -> { where(private_profile: false) }
scope :with_expiring_and_not_notified_personal_access_tokens, ->(at) do
where('EXISTS (?)',
::PersonalAccessToken
.where('personal_access_tokens.user_id = users.id')
.expiring_and_not_notified(at).select(1))
end
def self.with_visible_profile(user)
return with_public_profile if user.nil?
......
......@@ -27,4 +27,7 @@ class PersonalSnippetPolicy < BasePolicy
rule { can?(:create_note) }.enable :award_emoji
rule { can?(:read_all_resources) }.enable :read_personal_snippet
# Aliasing the ability to ease GraphQL permissions check
rule { can?(:read_personal_snippet) }.enable :read_snippet
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment