diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-10-05 18:12:53 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-10-05 18:12:53 +0300 |
commit | a84626f13d61d190b2db5e44caf71b22fc541276 (patch) | |
tree | 5cf591ce134ac0ad5b8c101e3518b2e49101b6ad /app | |
parent | c9b0dfef1ba43a9e04264023b08c589bcb9eb397 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
23 files changed, 181 insertions, 339 deletions
diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue index 0a15cb56447..4adbf5362b7 100644 --- a/app/assets/javascripts/error_tracking/components/error_details.vue +++ b/app/assets/javascripts/error_tracking/components/error_details.vue @@ -128,6 +128,12 @@ export default { lastReleaseLink() { return `${this.error.externalBaseUrl}/releases/${this.error.lastReleaseVersion}`; }, + firstCommitLink() { + return `${this.error.externalBaseUrl}/-/commit/${this.error.firstReleaseVersion}`; + }, + lastCommitLink() { + return `${this.error.externalBaseUrl}/-/commit/${this.error.lastReleaseVersion}`; + }, showStacktrace() { return Boolean(this.stacktrace?.length); }, @@ -394,7 +400,7 @@ export default { <span>{{ error.gitlabIssuePath }}</span> </gl-link> </li> - <li> + <li v-if="!error.integrated"> <strong class="bold">{{ __('Sentry event') }}:</strong> <gl-link v-track-event="trackClickErrorLinkToSentryOptions(error.externalUrl)" @@ -409,15 +415,21 @@ export default { <li v-if="error.firstReleaseVersion"> <strong class="bold">{{ __('First seen') }}:</strong> <time-ago-tooltip :time="error.firstSeen" /> - <gl-link :href="firstReleaseLink" target="_blank"> - <span>{{ __('Release') }}: {{ error.firstReleaseVersion }}</span> + <gl-link v-if="error.integrated" :href="firstCommitLink"> + {{ __('GitLab commit') }}: {{ error.firstReleaseVersion }} + </gl-link> + <gl-link v-else :href="firstReleaseLink" target="_blank"> + {{ __('Release') }}: {{ error.firstReleaseVersion }} </gl-link> </li> <li v-if="error.lastReleaseVersion"> <strong class="bold">{{ __('Last seen') }}:</strong> <time-ago-tooltip :time="error.lastSeen" /> - <gl-link :href="lastReleaseLink" target="_blank"> - <span>{{ __('Release') }}: {{ error.lastReleaseVersion }}</span> + <gl-link v-if="error.integrated" :href="lastCommitLink"> + {{ __('GitLab commit') }}: {{ error.lastReleaseVersion }} + </gl-link> + <gl-link v-else :href="lastReleaseLink" target="_blank"> + {{ __('Release') }}: {{ error.lastReleaseVersion }} </gl-link> </li> <li> diff --git a/app/assets/javascripts/error_tracking/queries/details.query.graphql b/app/assets/javascripts/error_tracking/queries/details.query.graphql index 593cbf2ae52..af386528f00 100644 --- a/app/assets/javascripts/error_tracking/queries/details.query.graphql +++ b/app/assets/javascripts/error_tracking/queries/details.query.graphql @@ -23,6 +23,7 @@ query errorDetails($fullPath: ID!, $errorId: ID!) { gitlabCommit gitlabCommitPath gitlabIssuePath + integrated } } } diff --git a/app/assets/javascripts/issuable/components/csv_export_modal.vue b/app/assets/javascripts/issuable/components/csv_export_modal.vue index 1c88f8dfdca..b0af3612e05 100644 --- a/app/assets/javascripts/issuable/components/csv_export_modal.vue +++ b/app/assets/javascripts/issuable/components/csv_export_modal.vue @@ -1,9 +1,14 @@ <script> import { GlButton, GlModal, GlSprintf, GlIcon } from '@gitlab/ui'; +import { __, n__ } from '~/locale'; import { ISSUABLE_TYPE } from '../constants'; export default { - name: 'CsvExportModal', + i18n: { + exportText: __( + 'The CSV export will be created in the background. Once finished, it will be sent to %{email} in an attachment.', + ), + }, components: { GlButton, GlModal, @@ -32,53 +37,39 @@ export default { required: true, }, }, - data() { - return { - // eslint-disable-next-line @gitlab/require-i18n-strings - issuableName: this.issuableType === ISSUABLE_TYPE.issues ? 'issues' : 'merge requests', - }; + computed: { + isIssue() { + return this.issuableType === ISSUABLE_TYPE.issues; + }, + exportText() { + return this.isIssue ? __('Export issues') : __('Export merge requests'); + }, + issuableCountText() { + return this.isIssue + ? n__('1 issue selected', '%d issues selected', this.issuableCount) + : n__('1 merge request selected', '%d merge requests selected', this.issuableCount); + }, }, - issueableType: ISSUABLE_TYPE, }; </script> <template> - <gl-modal :modal-id="modalId" body-class="gl-p-0!" data-qa-selector="export_issuable_modal"> - <template #modal-title> - <gl-sprintf :message="__('Export %{name}')"> - <template #name>{{ issuableName }}</template> - </gl-sprintf> - </template> + <gl-modal + :modal-id="modalId" + body-class="gl-p-0!" + :title="exportText" + data-qa-selector="export_issuable_modal" + > <div - v-if="issuableCount > -1" class="gl-justify-content-start gl-align-items-center gl-p-4 gl-border-b-solid gl-border-1 gl-border-gray-50" > <gl-icon name="check" class="gl-color-green-400" /> - <strong class="gl-m-3"> - <gl-sprintf - v-if="issuableType === $options.issueableType.issues" - :message="n__('1 issue selected', '%d issues selected', issuableCount)" - > - <template #issuableCount>{{ issuableCount }}</template> - </gl-sprintf> - <gl-sprintf - v-else - :message="n__('1 merge request selected', '%d merge requests selected', issuableCount)" - > - <template #issuableCount>{{ issuableCount }}</template> - </gl-sprintf> - </strong> + <strong class="gl-m-3">{{ issuableCountText }}</strong> </div> <div class="modal-text gl-px-4 gl-py-5"> - <gl-sprintf - :message=" - __( - `The CSV export will be created in the background. Once finished, it will be sent to %{strongStart}${email}%{strongEnd} in an attachment.`, - ) - " - > - <template #strong="{ content }"> - <strong>{{ content }}</strong> + <gl-sprintf :message="$options.i18n.exportText"> + <template #email> + <strong>{{ email }}</strong> </template> </gl-sprintf> </div> @@ -92,9 +83,7 @@ export default { data-track-action="click_button" :data-track-label="`export_${issuableType}_csv`" > - <gl-sprintf :message="__('Export %{name}')"> - <template #name>{{ issuableName }}</template> - </gl-sprintf> + {{ exportText }} </gl-button> </template> </gl-modal> diff --git a/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue b/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue index 4fdd094072c..269f720bac9 100644 --- a/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue +++ b/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue @@ -15,6 +15,8 @@ import CsvImportModal from './csv_import_modal.vue'; export default { i18n: { exportAsCsvButtonText: __('Export as CSV'), + importCsvText: __('Import CSV'), + importFromJiraText: __('Import from Jira'), importIssuesText: __('Import issues'), }, name: 'CsvImportExportButtons', @@ -101,13 +103,16 @@ export default { :text-sr-only="!showLabel" :icon="importButtonIcon" > - <gl-dropdown-item v-gl-modal="importModalId">{{ __('Import CSV') }}</gl-dropdown-item> + <gl-dropdown-item v-gl-modal="importModalId"> + {{ $options.i18n.importCsvText }} + </gl-dropdown-item> <gl-dropdown-item v-if="canEdit" :href="projectImportJiraPath" data-qa-selector="import_from_jira_link" - >{{ __('Import from Jira') }}</gl-dropdown-item > + {{ $options.i18n.importFromJiraText }} + </gl-dropdown-item> </gl-dropdown> </gl-button-group> <csv-export-modal diff --git a/app/assets/javascripts/issuable/components/csv_import_modal.vue b/app/assets/javascripts/issuable/components/csv_import_modal.vue index c85efd60b8b..b72abe14ee1 100644 --- a/app/assets/javascripts/issuable/components/csv_import_modal.vue +++ b/app/assets/javascripts/issuable/components/csv_import_modal.vue @@ -1,23 +1,28 @@ <script> -import { GlModal, GlSprintf, GlFormGroup, GlButton } from '@gitlab/ui'; +import { GlModal, GlFormGroup } from '@gitlab/ui'; import csrf from '~/lib/utils/csrf'; -import { ISSUABLE_TYPE } from '../constants'; +import { __, sprintf } from '~/locale'; export default { - name: 'CsvImportModal', + i18n: { + maximumFileSizeText: __('The maximum file size allowed is %{size}.'), + importIssuesText: __('Import issues'), + uploadCsvFileText: __('Upload CSV file'), + mainText: __( + "Your issues will be imported in the background. Once finished, you'll get a confirmation email.", + ), + helpText: __( + 'It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected.', + ), + }, + actionPrimary: { + text: __('Import issues'), + }, components: { GlModal, - GlSprintf, GlFormGroup, - GlButton, }, inject: { - issuableType: { - default: '', - }, - exportCsvPath: { - default: '', - }, importCsvIssuesPath: { default: '', }, @@ -31,11 +36,10 @@ export default { required: true, }, }, - data() { - return { - // eslint-disable-next-line @gitlab/require-i18n-strings - issuableName: this.issuableType === ISSUABLE_TYPE.issues ? 'issues' : 'merge requests', - }; + computed: { + maxFileSizeText() { + return sprintf(this.$options.i18n.maximumFileSizeText, { size: this.maxAttachmentSize }); + }, }, methods: { submitForm() { @@ -47,34 +51,22 @@ export default { </script> <template> - <gl-modal :modal-id="modalId" :title="__('Import issues')"> + <gl-modal + :modal-id="modalId" + :title="$options.i18n.importIssuesText" + :action-primary="$options.actionPrimary" + @primary="submitForm" + > <form ref="form" :action="importCsvIssuesPath" enctype="multipart/form-data" method="post"> <input :value="$options.csrf.token" type="hidden" name="authenticity_token" /> - <p> - {{ - __( - "Your issues will be imported in the background. Once finished, you'll get a confirmation email.", - ) - }} - </p> - <gl-form-group :label="__('Upload CSV file')" label-for="file"> + <p>{{ $options.i18n.mainText }}</p> + <gl-form-group :label="$options.i18n.uploadCsvFileText" label-for="file"> <input id="file" type="file" name="file" accept=".csv,text/csv" /> </gl-form-group> <p class="text-secondary"> - {{ - __( - 'It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected.', - ) - }} - <gl-sprintf :message="__('The maximum file size allowed is %{size}.')" - ><template #size>{{ maxAttachmentSize }}</template></gl-sprintf - > + {{ $options.i18n.helpText }} + {{ maxFileSizeText }} </p> </form> - <template #modal-footer> - <gl-button category="primary" variant="confirm" @click="submitForm">{{ - __('Import issues') - }}</gl-button> - </template> </gl-modal> </template> diff --git a/app/assets/javascripts/pages/admin/serverless/domains/index.js b/app/assets/javascripts/pages/admin/serverless/domains/index.js deleted file mode 100644 index 4fab7a1d9cb..00000000000 --- a/app/assets/javascripts/pages/admin/serverless/domains/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import initSettingsPanels from '~/settings_panels'; - -// Initialize expandable settings panels -initSettingsPanels(); - -const domainCard = document.querySelector('.js-domain-cert-show'); -const domainForm = document.querySelector('.js-domain-cert-inputs'); -const domainReplaceButton = document.querySelector('.js-domain-cert-replace-btn'); -const domainSubmitButton = document.querySelector('.js-serverless-domain-submit'); - -if (domainReplaceButton && domainCard && domainForm) { - domainReplaceButton.addEventListener('click', () => { - domainCard.classList.add('hidden'); - domainForm.classList.remove('hidden'); - domainSubmitButton.removeAttribute('disabled'); - }); -} diff --git a/app/assets/stylesheets/pages/pages.scss b/app/assets/stylesheets/pages/pages.scss index 93caa345f8a..ebaf875ad8f 100644 --- a/app/assets/stylesheets/pages/pages.scss +++ b/app/assets/stylesheets/pages/pages.scss @@ -55,16 +55,4 @@ border-bottom-right-radius: $border-radius-default; border-top-right-radius: $border-radius-default; } - - &.floating-status-badge { - position: absolute; - right: $gl-padding-24; - bottom: $gl-padding-4; - margin-bottom: 0; - } -} - -.form-control.has-floating-status-badge { - position: relative; - padding-right: 120px; } diff --git a/app/controllers/admin/instance_review_controller.rb b/app/controllers/admin/instance_review_controller.rb index 88ca2c88aab..5567ffbdc84 100644 --- a/app/controllers/admin/instance_review_controller.rb +++ b/app/controllers/admin/instance_review_controller.rb @@ -3,7 +3,7 @@ class Admin::InstanceReviewController < Admin::ApplicationController feature_category :devops_reports def index - redirect_to("#{::Gitlab::SubscriptionPortal::SUBSCRIPTIONS_URL}/instance_review?#{instance_review_params}") + redirect_to("#{Gitlab::SubscriptionPortal.subscriptions_instance_review_url}?#{instance_review_params}") end def instance_review_params diff --git a/app/controllers/admin/serverless/domains_controller.rb b/app/controllers/admin/serverless/domains_controller.rb deleted file mode 100644 index 99eea8c35b4..00000000000 --- a/app/controllers/admin/serverless/domains_controller.rb +++ /dev/null @@ -1,78 +0,0 @@ -# frozen_string_literal: true - -class Admin::Serverless::DomainsController < Admin::ApplicationController - before_action :check_feature_flag - before_action :domain, only: [:update, :verify, :destroy] - - feature_category :not_owned - - def index - @domain = PagesDomain.instance_serverless.first_or_initialize - end - - def create - if PagesDomain.instance_serverless.exists? - return redirect_to admin_serverless_domains_path, notice: _('An instance-level serverless domain already exists.') - end - - @domain = PagesDomain.instance_serverless.create(create_params) - - if @domain.persisted? - redirect_to admin_serverless_domains_path, notice: _('Domain was successfully created.') - else - render 'index' - end - end - - def update - if domain.update(update_params) - redirect_to admin_serverless_domains_path, notice: _('Domain was successfully updated.') - else - render 'index' - end - end - - def destroy - if domain.serverless_domain_clusters.exists? - return redirect_to admin_serverless_domains_path, - status: :conflict, - notice: _('Domain cannot be deleted while associated to one or more clusters.') - end - - domain.destroy! - - redirect_to admin_serverless_domains_path, - status: :found, - notice: _('Domain was successfully deleted.') - end - - def verify - result = VerifyPagesDomainService.new(domain).execute - - if result[:status] == :success - flash[:notice] = _('Successfully verified domain ownership') - else - flash[:alert] = _('Failed to verify domain ownership') - end - - redirect_to admin_serverless_domains_path - end - - private - - def domain - @domain = PagesDomain.instance_serverless.find(params[:id]) - end - - def check_feature_flag - render_404 unless Feature.enabled?(:serverless_domain) - end - - def update_params - params.require(:pages_domain).permit(:user_provided_certificate, :user_provided_key) - end - - def create_params - params.require(:pages_domain).permit(:domain, :user_provided_certificate, :user_provided_key) - end -end diff --git a/app/controllers/groups/dependency_proxy_for_containers_controller.rb b/app/controllers/groups/dependency_proxy_for_containers_controller.rb index f7dc552bd3e..e19b8ae35f8 100644 --- a/app/controllers/groups/dependency_proxy_for_containers_controller.rb +++ b/app/controllers/groups/dependency_proxy_for_containers_controller.rb @@ -5,11 +5,15 @@ class Groups::DependencyProxyForContainersController < ::Groups::DependencyProxy include DependencyProxy::GroupAccess include SendFileUpload include ::PackagesHelper # for event tracking + include WorkhorseRequest before_action :ensure_group - before_action :ensure_token_granted! + before_action :ensure_token_granted!, only: [:blob, :manifest] before_action :ensure_feature_enabled! + before_action :verify_workhorse_api!, only: [:authorize_upload_blob, :upload_blob] + skip_before_action :verify_authenticity_token, only: [:authorize_upload_blob, :upload_blob] + attr_reader :token feature_category :dependency_proxy @@ -38,6 +42,8 @@ class Groups::DependencyProxyForContainersController < ::Groups::DependencyProxy end def blob + return blob_via_workhorse if Feature.enabled?(:dependency_proxy_workhorse, group, default_enabled: :yaml) + result = DependencyProxy::FindOrCreateBlobService .new(group, image, token, params[:sha]).execute @@ -50,11 +56,47 @@ class Groups::DependencyProxyForContainersController < ::Groups::DependencyProxy end end + def authorize_upload_blob + set_workhorse_internal_api_content_type + + render json: DependencyProxy::FileUploader.workhorse_authorize(has_length: false) + end + + def upload_blob + @group.dependency_proxy_blobs.create!( + file_name: blob_file_name, + file: params[:file], + size: params[:file].size + ) + + event_name = tracking_event_name(object_type: :blob, from_cache: false) + track_package_event(event_name, :dependency_proxy, namespace: group, user: auth_user) + + head :ok + end + private + def blob_via_workhorse + blob = @group.dependency_proxy_blobs.find_by_file_name(blob_file_name) + + if blob.present? + event_name = tracking_event_name(object_type: :blob, from_cache: true) + track_package_event(event_name, :dependency_proxy, namespace: group, user: auth_user) + + send_upload(blob.file) + else + send_dependency(token, DependencyProxy::Registry.blob_url(image, params[:sha]), blob_file_name) + end + end + + def blob_file_name + @blob_file_name ||= params[:sha].sub('sha256:', '') + '.gz' + end + def group strong_memoize(:group) do - Group.find_by_full_path(params[:group_id], follow_redirects: request.get?) + Group.find_by_full_path(params[:group_id], follow_redirects: true) end end diff --git a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb index 79e789d3f8b..826ae61a1a3 100644 --- a/app/graphql/types/error_tracking/sentry_detailed_error_type.rb +++ b/app/graphql/types/error_tracking/sentry_detailed_error_type.rb @@ -13,6 +13,9 @@ module Types field :id, GraphQL::Types::ID, null: false, description: 'ID (global ID) of the error.' + field :integrated, GraphQL::Types::Boolean, + null: true, + description: 'Error tracking backend.' field :sentry_id, GraphQL::Types::String, method: :id, null: false, diff --git a/app/helpers/workhorse_helper.rb b/app/helpers/workhorse_helper.rb index 8785c4cdcbb..4862282bc73 100644 --- a/app/helpers/workhorse_helper.rb +++ b/app/helpers/workhorse_helper.rb @@ -41,6 +41,15 @@ module WorkhorseHelper head :ok end + def send_dependency(token, url, filename) + headers.store(*Gitlab::Workhorse.send_dependency(token, url)) + headers['Content-Disposition'] = + ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: filename) + headers['Content-Type'] = 'application/gzip' + + head :ok + end + def set_workhorse_internal_api_content_type headers['Content-Type'] = Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE end diff --git a/app/models/error_tracking/error.rb b/app/models/error_tracking/error.rb index 39ecc487806..2d6a4694def 100644 --- a/app/models/error_tracking/error.rb +++ b/app/models/error_tracking/error.rb @@ -7,6 +7,14 @@ class ErrorTracking::Error < ApplicationRecord has_many :events, class_name: 'ErrorTracking::ErrorEvent' + has_one :first_event, + -> { order(id: :asc) }, + class_name: 'ErrorTracking::ErrorEvent' + + has_one :last_event, + -> { order(id: :desc) }, + class_name: 'ErrorTracking::ErrorEvent' + scope :for_status, -> (status) { where(status: status) } validates :project, presence: true @@ -90,7 +98,10 @@ class ErrorTracking::Error < ApplicationRecord status: status, tags: { level: nil, logger: nil }, external_url: external_url, - external_base_url: external_base_url + external_base_url: external_base_url, + integrated: true, + first_release_version: first_event&.release, + last_release_version: last_event&.release ) end @@ -106,6 +117,6 @@ class ErrorTracking::Error < ApplicationRecord # For compatibility with sentry integration def external_base_url - Gitlab::Routing.url_helpers.root_url + Gitlab::Routing.url_helpers.project_url(project) end end diff --git a/app/models/error_tracking/error_event.rb b/app/models/error_tracking/error_event.rb index 4de13de7e2e..686518a39fb 100644 --- a/app/models/error_tracking/error_event.rb +++ b/app/models/error_tracking/error_event.rb @@ -22,6 +22,10 @@ class ErrorTracking::ErrorEvent < ApplicationRecord ) end + def release + payload.dig('release') + end + private def build_stacktrace diff --git a/app/models/group.rb b/app/models/group.rb index 23b0d7e2197..77cdff68d49 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -276,7 +276,7 @@ class Group < Namespace def dependency_proxy_image_prefix # The namespace path can include uppercase letters, which # Docker doesn't allow. The proxy expects it to be downcased. - url = "#{web_url.downcase}#{DependencyProxy::URL_SUFFIX}" + url = "#{Gitlab::Routing.url_helpers.group_url(self).downcase}#{DependencyProxy::URL_SUFFIX}" # Docker images do not include the protocol url.partition('//').last diff --git a/app/models/note.rb b/app/models/note.rb index 2defa1d1ca5..37473518892 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -355,8 +355,6 @@ class Note < ApplicationRecord end def noteable_author?(noteable) - return false unless ::Feature.enabled?(:show_author_on_note, project) - noteable.author == self.author end diff --git a/app/models/project.rb b/app/models/project.rb index 39ddec223e7..7ecd736b410 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -2655,10 +2655,6 @@ class Project < ApplicationRecord ProjectStatistics.increment_statistic(self, statistic, delta) end - def merge_requests_author_approval - !!read_attribute(:merge_requests_author_approval) - end - def ci_forward_deployment_enabled? return false unless ci_cd_settings diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb index dc75fe1014a..0000e713cb4 100644 --- a/app/services/projects/update_pages_service.rb +++ b/app/services/projects/update_pages_service.rb @@ -136,13 +136,11 @@ module Projects def validate_outdated_sha! return if latest? - if Feature.enabled?(:pages_smart_check_outdated_sha, project, default_enabled: :yaml) - # use pipeline_id in case the build is retried - last_deployed_pipeline_id = project.pages_metadatum&.pages_deployment&.ci_build&.pipeline_id + # use pipeline_id in case the build is retried + last_deployed_pipeline_id = project.pages_metadatum&.pages_deployment&.ci_build&.pipeline_id - return unless last_deployed_pipeline_id - return if last_deployed_pipeline_id <= build.pipeline_id - end + return unless last_deployed_pipeline_id + return if last_deployed_pipeline_id <= build.pipeline_id raise InvalidStateError, 'build SHA is outdated for this ref' end diff --git a/app/services/users/upsert_credit_card_validation_service.rb b/app/services/users/upsert_credit_card_validation_service.rb index 70a96b3ec6b..86b5b923418 100644 --- a/app/services/users/upsert_credit_card_validation_service.rb +++ b/app/services/users/upsert_credit_card_validation_service.rb @@ -7,6 +7,14 @@ module Users end def execute + @params = { + user_id: params.fetch(:user_id), + credit_card_validated_at: params.fetch(:credit_card_validated_at), + expiration_date: get_expiration_date(params), + last_digits: Integer(params.fetch(:credit_card_mask_number), 10), + holder_name: params.fetch(:credit_card_holder_name) + } + ::Users::CreditCardValidation.upsert(@params) ServiceResponse.success(message: 'CreditCardValidation was set') @@ -16,5 +24,14 @@ module Users Gitlab::ErrorTracking.track_exception(e, params: @params, class: self.class.to_s) ServiceResponse.error(message: "Could not set CreditCardValidation: #{e.message}") end + + private + + def get_expiration_date(params) + year = params.fetch(:credit_card_expiration_year) + month = params.fetch(:credit_card_expiration_month) + + Date.new(year, month, -1) # last day of the month + end end end diff --git a/app/uploaders/dependency_proxy/file_uploader.rb b/app/uploaders/dependency_proxy/file_uploader.rb index 5154f180454..f0222d4cf06 100644 --- a/app/uploaders/dependency_proxy/file_uploader.rb +++ b/app/uploaders/dependency_proxy/file_uploader.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true class DependencyProxy::FileUploader < GitlabUploader + extend Workhorse::UploadPath include ObjectStorage::Concern before :cache, :set_content_type diff --git a/app/views/admin/serverless/domains/_form.html.haml b/app/views/admin/serverless/domains/_form.html.haml deleted file mode 100644 index a3e1ccc5d4a..00000000000 --- a/app/views/admin/serverless/domains/_form.html.haml +++ /dev/null @@ -1,99 +0,0 @@ -- form_name = 'js-serverless-domain-settings' -- form_url = @domain.persisted? ? admin_serverless_domain_path(@domain.id, anchor: form_name) : admin_serverless_domains_path(anchor: form_name) -- show_certificate_card = @domain.persisted? && @domain.errors.blank? -= form_for @domain, url: form_url, html: { class: 'fieldset-form' } do |f| - = form_errors(@domain) - - %fieldset - - if @domain.persisted? - - dns_record = "*.#{@domain.domain} CNAME #{Settings.pages.host}." - - verification_record = "#{@domain.verification_domain} TXT #{@domain.keyed_verification_code}" - .form-group.row - .col-sm-6.position-relative - = f.label :domain, _('Domain'), class: 'label-bold' - = f.text_field :domain, class: 'form-control has-floating-status-badge', readonly: true - .status-badge.floating-status-badge - - text, status = @domain.unverified? ? [_('Unverified'), 'badge-danger'] : [_('Verified'), 'badge-success'] - .badge{ class: status } - = text - = link_to sprite_icon("redo"), verify_admin_serverless_domain_path(@domain.id), method: :post, class: "gl-button btn has-tooltip", title: _("Retry verification") - - .col-sm-6 - = f.label :serverless_domain_dns, _('DNS'), class: 'label-bold' - .input-group - = text_field_tag :serverless_domain_dns, dns_record , class: "monospace js-select-on-focus form-control", readonly: true - .input-group-append - = clipboard_button(target: '#serverless_domain_dns', class: 'btn-default input-group-text d-none d-sm-block') - - .col-sm-12.form-text.text-muted - = _("To access this domain create a new DNS record") - - .form-group - = f.label :serverless_domain_verification, _('Verification status'), class: 'label-bold' - .input-group - = text_field_tag :serverless_domain_verification, verification_record, class: "monospace js-select-on-focus form-control", readonly: true - .input-group-append - = clipboard_button(target: '#serverless_domain_verification', class: 'btn-default d-none d-sm-block') - %p.form-text.text-muted - - link_to_help = link_to(_('verify ownership'), help_page_path('user/project/pages/custom_domains_ssl_tls_certification/index.md', anchor: '4-verify-the-domains-ownership')) - = _("To %{link_to_help} of your domain, add the above key to a TXT record within your DNS configuration.").html_safe % { link_to_help: link_to_help } - - - else - .form-group - = f.label :domain, _('Domain'), class: 'label-bold' - = f.text_field :domain, class: 'form-control' - - - if show_certificate_card - .card.js-domain-cert-show - .card-header - = _('Certificate') - .d-flex.justify-content-between.align-items-center.p-3 - %span - = @domain.subject || _('missing') - %button.gl-button.btn.btn-danger.btn-sm.js-domain-cert-replace-btn{ type: 'button' } - = _('Replace') - - .js-domain-cert-inputs{ class: ('hidden' if show_certificate_card) } - .form-group - = f.label :user_provided_certificate, _('Certificate (PEM)'), class: 'label-bold' - = f.text_area :user_provided_certificate, rows: 5, class: 'form-control', value: '' - %span.form-text.text-muted - = _("Upload a certificate for your domain with all intermediates") - .form-group - = f.label :user_provided_key, _('Key (PEM)'), class: 'label-bold' - = f.text_area :user_provided_key, rows: 5, class: 'form-control', value: '' - %span.form-text.text-muted - = _("Upload a private key for your certificate") - - = f.submit @domain.persisted? ? _('Save changes') : _('Add domain'), class: "gl-button btn btn-confirm js-serverless-domain-submit", disabled: @domain.persisted? - - if @domain.persisted? - %button.gl-button.btn.btn-danger{ type: 'button', data: { toggle: 'modal', target: "#modal-delete-domain" } } - = _('Delete domain') - --# haml-lint:disable NoPlainNodes -- if @domain.persisted? - - domain_attached = @domain.serverless_domain_clusters.count > 0 - .modal{ id: "modal-delete-domain", tabindex: -1 } - .modal-dialog - .modal-content - .modal-header - %h3.page-title= _('Delete serverless domain?') - %button.close{ type: "button", "data-dismiss": "modal", "aria-label" => _('Close') } - %span{ "aria-hidden": "true" } × - - .modal-body - - if domain_attached - = _("You must disassociate %{domain} from all clusters it is attached to before deletion.").html_safe % { domain: "<code>#{@domain.domain}</code>".html_safe } - - else - = _("You are about to delete %{domain} from your instance. This domain will no longer be available to any Knative application.").html_safe % { domain: "<code>#{@domain.domain}</code>".html_safe } - - .modal-footer - %a{ href: '#', data: { dismiss: 'modal' }, class: 'gl-button btn btn-default' } - = _('Cancel') - - = link_to _('Delete domain'), - admin_serverless_domain_path(@domain.id), - title: _('Delete'), - method: :delete, - class: "gl-button btn btn-danger", - disabled: domain_attached diff --git a/app/views/admin/serverless/domains/index.html.haml b/app/views/admin/serverless/domains/index.html.haml deleted file mode 100644 index c2b6baed4de..00000000000 --- a/app/views/admin/serverless/domains/index.html.haml +++ /dev/null @@ -1,25 +0,0 @@ -- breadcrumb_title _("Operations") -- page_title _("Operations") -- @content_class = "limit-container-width" unless fluid_layout - --# normally expanded_by_default? is used here, but since this is the only panel --# in this settings page, let's leave it always open by default -- expanded = true - -%section.settings.as-serverless-domain.no-animate#js-serverless-domain-settings{ class: ('expanded' if expanded) } - .settings-header - %h4 - = _('Serverless domain') - %button.gl-button.btn.btn-default.js-settings-toggle{ type: 'button' } - = expanded ? _('Collapse') : _('Expand') - %p - = _('Set an instance-wide domain that will be available to all clusters when installing Knative.') - .settings-content - - if Gitlab.config.pages.enabled - = render 'form' - - else - .card - .card-header - = s_('GitLabPages|Domains') - .nothing-here-block - = s_("GitLabPages|Support for domains and certificates is disabled. Ask your system's administrator to enable it.") diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml index 13f2bf0019e..0a91194db51 100644 --- a/app/views/layouts/nav/sidebar/_admin.html.haml +++ b/app/views/layouts/nav/sidebar/_admin.html.haml @@ -257,11 +257,6 @@ = link_to ci_cd_admin_application_settings_path, title: _('CI/CD') do %span = _('CI/CD') - - if Feature.enabled?(:serverless_domain) - = nav_link(path: 'application_settings#operations') do - = link_to admin_serverless_domains_path, title: _('Operations') do - %span - = _('Operations') = nav_link(path: 'application_settings#reporting') do = link_to reporting_admin_application_settings_path, title: _('Reporting') do %span |