summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-29 18:08:47 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-29 18:08:47 +0000
commit6b9d3a4e8351e662c4586b24bb152de78ae9e3bf (patch)
tree883e9db60c047c54418fc1d2b1c5517f97e0f185 /app
parent23288f62da73fb0e30d8e7ce306665e8fda1b932 (diff)
downloadgitlab-ce-6b9d3a4e8351e662c4586b24bb152de78ae9e3bf.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/editor/editor_lite.js68
-rw-r--r--app/assets/javascripts/editor/utils.js11
-rw-r--r--app/assets/javascripts/ide/lib/editor.js9
-rw-r--r--app/assets/javascripts/vue_shared/components/changed_file_icon.vue18
-rw-r--r--app/assets/stylesheets/pages/tree.scss4
-rw-r--r--app/controllers/application_controller.rb2
-rw-r--r--app/controllers/concerns/membership_actions.rb4
-rw-r--r--app/controllers/concerns/send_file_upload.rb16
-rw-r--r--app/controllers/projects/releases_controller.rb17
-rw-r--r--app/helpers/markup_helper.rb2
-rw-r--r--app/models/commit_status.rb4
-rw-r--r--app/models/concerns/issuable.rb4
-rw-r--r--app/models/concerns/mirror_authentication.rb2
-rw-r--r--app/models/merge_request.rb2
-rw-r--r--app/models/notification_setting.rb5
-rw-r--r--app/presenters/project_presenter.rb2
-rw-r--r--app/serializers/concerns/user_status_tooltip.rb2
-rw-r--r--app/services/concerns/spam_check_methods.rb2
-rw-r--r--app/services/metrics/dashboard/clone_dashboard_service.rb26
-rw-r--r--app/services/projects/detect_repository_languages_service.rb2
-rw-r--r--app/services/projects/move_access_service.rb2
-rw-r--r--app/services/projects/transfer_service.rb6
-rw-r--r--app/services/spam/spam_check_service.rb68
-rw-r--r--app/services/spam_check_service.rb66
-rw-r--r--app/uploaders/object_storage.rb2
-rw-r--r--app/views/projects/_home_panel.html.haml7
-rw-r--r--app/views/projects/buttons/_clone.html.haml7
-rw-r--r--app/views/projects/empty.html.haml7
-rw-r--r--app/views/projects/network/show.json.erb2
-rw-r--r--app/views/projects/releases/show.html.haml4
-rw-r--r--app/views/projects/tree/_tree_header.html.haml6
-rw-r--r--app/views/shared/_mobile_clone_panel.html.haml2
-rw-r--r--app/workers/mail_scheduler/notification_service_worker.rb41
33 files changed, 255 insertions, 167 deletions
diff --git a/app/assets/javascripts/editor/editor_lite.js b/app/assets/javascripts/editor/editor_lite.js
new file mode 100644
index 00000000000..bdfbcf71267
--- /dev/null
+++ b/app/assets/javascripts/editor/editor_lite.js
@@ -0,0 +1,68 @@
+import { editor as monacoEditor, languages as monacoLanguages, Uri } from 'monaco-editor';
+import gitlabTheme from '~/ide/lib/themes/gl_theme';
+import { defaultEditorOptions } from '~/ide/lib/editor_options';
+import { clearDomElement } from './utils';
+
+export default class Editor {
+ constructor(options = {}) {
+ this.editorEl = null;
+ this.blobContent = '';
+ this.blobPath = '';
+ this.instance = null;
+ this.model = null;
+ this.options = {
+ ...defaultEditorOptions,
+ ...options,
+ };
+
+ Editor.setupMonacoTheme();
+ }
+
+ static setupMonacoTheme() {
+ monacoEditor.defineTheme(gitlabTheme.themeName, gitlabTheme.monacoTheme);
+ monacoEditor.setTheme('gitlab');
+ }
+
+ createInstance({ el = undefined, blobPath = '', blobContent = '' } = {}) {
+ if (!el) return;
+ this.editorEl = el;
+ this.blobContent = blobContent;
+ this.blobPath = blobPath;
+
+ clearDomElement(this.editorEl);
+
+ this.model = monacoEditor.createModel(
+ this.blobContent,
+ undefined,
+ new Uri('gitlab', false, this.blobPath),
+ );
+
+ monacoEditor.onDidCreateEditor(this.renderEditor.bind(this));
+
+ this.instance = monacoEditor.create(this.editorEl, this.options);
+ this.instance.setModel(this.model);
+ }
+
+ dispose() {
+ return this.instance && this.instance.dispose();
+ }
+
+ renderEditor() {
+ delete this.editorEl.dataset.editorLoading;
+ }
+
+ updateModelLanguage(path) {
+ if (path === this.blobPath) return;
+ this.blobPath = path;
+ const ext = `.${path.split('.').pop()}`;
+ const language = monacoLanguages
+ .getLanguages()
+ .find(lang => lang.extensions.indexOf(ext) !== -1);
+ const id = language ? language.id : 'plaintext';
+ monacoEditor.setModelLanguage(this.model, id);
+ }
+
+ getValue() {
+ return this.model.getValue();
+ }
+}
diff --git a/app/assets/javascripts/editor/utils.js b/app/assets/javascripts/editor/utils.js
new file mode 100644
index 00000000000..d8b6396b671
--- /dev/null
+++ b/app/assets/javascripts/editor/utils.js
@@ -0,0 +1,11 @@
+export const clearDomElement = el => {
+ if (!el || !el.firstChild) return;
+
+ while (el.firstChild) {
+ el.removeChild(el.firstChild);
+ }
+};
+
+export default () => ({
+ clearDomElement,
+});
diff --git a/app/assets/javascripts/ide/lib/editor.js b/app/assets/javascripts/ide/lib/editor.js
index d1056ea6b98..a0f689065aa 100644
--- a/app/assets/javascripts/ide/lib/editor.js
+++ b/app/assets/javascripts/ide/lib/editor.js
@@ -8,20 +8,13 @@ import ModelManager from './common/model_manager';
import editorOptions, { defaultEditorOptions } from './editor_options';
import gitlabTheme from './themes/gl_theme';
import keymap from './keymap.json';
+import { clearDomElement } from '~/editor/utils';
function setupMonacoTheme() {
monacoEditor.defineTheme(gitlabTheme.themeName, gitlabTheme.monacoTheme);
monacoEditor.setTheme('gitlab');
}
-export const clearDomElement = el => {
- if (!el || !el.firstChild) return;
-
- while (el.firstChild) {
- el.removeChild(el.firstChild);
- }
-};
-
export default class Editor {
static create(options = {}) {
if (!this.editorInstance) {
diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
index 75c3c544c77..9ec99ac93d7 100644
--- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
@@ -41,7 +41,7 @@ export default {
changedIcon() {
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
- const suffix = !this.file.changed && this.file.staged && this.showStagedIcon ? '-solid' : '';
+ const suffix = this.file.staged && this.showStagedIcon ? '-solid' : '';
return `${getCommitIconMap(this.file).icon}${suffix}`;
},
@@ -49,25 +49,19 @@ export default {
return `${this.changedIcon} float-left d-block`;
},
tooltipTitle() {
- if (!this.showTooltip) return undefined;
+ if (!this.showTooltip || !this.file.changed) return undefined;
const type = this.file.tempFile ? 'addition' : 'modification';
- if (this.file.changed && !this.file.staged) {
- return sprintf(__('Unstaged %{type}'), {
- type,
- });
- } else if (!this.file.changed && this.file.staged) {
+ if (this.file.staged) {
return sprintf(__('Staged %{type}'), {
type,
});
- } else if (this.file.changed && this.file.staged) {
- return sprintf(__('Unstaged and staged %{type}'), {
- type,
- });
}
- return undefined;
+ return sprintf(__('Unstaged %{type}'), {
+ type,
+ });
},
showIcon() {
return (
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index 79ad0bd7735..c14ae8a3711 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -21,10 +21,6 @@
margin-left: 8px;
}
- .btn-group {
- margin-left: 10px;
- }
-
.control {
float: left;
margin-left: 10px;
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index c6d91308123..789bccf268a 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -120,7 +120,7 @@ class ApplicationController < ActionController::Base
def render(*args)
super.tap do
# Set a header for custom error pages to prevent them from being intercepted by gitlab-workhorse
- if (400..599).cover?(response.status) && workhorse_excluded_content_types.include?(response.content_type)
+ if (400..599).cover?(response.status) && workhorse_excluded_content_types.include?(response.media_type)
response.headers['X-GitLab-Custom-Error'] = '1'
end
end
diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb
index 993f091b0e6..1cf9046e30f 100644
--- a/app/controllers/concerns/membership_actions.rb
+++ b/app/controllers/concerns/membership_actions.rb
@@ -21,9 +21,9 @@ module MembershipActions
member = Members::UpdateService
.new(current_user, update_params)
.execute(member)
- .present(current_user: current_user)
- present_members([member])
+ member = present_members([member]).first
+
respond_to do |format|
format.js { render 'shared/members/update', locals: { member: member } }
end
diff --git a/app/controllers/concerns/send_file_upload.rb b/app/controllers/concerns/send_file_upload.rb
index 28e4cece548..2f5dc09be4a 100644
--- a/app/controllers/concerns/send_file_upload.rb
+++ b/app/controllers/concerns/send_file_upload.rb
@@ -3,7 +3,7 @@
module SendFileUpload
def send_upload(file_upload, send_params: {}, redirect_params: {}, attachment: nil, proxy: false, disposition: 'attachment')
if attachment
- response_disposition = ::Gitlab::ContentDisposition.format(disposition: disposition, filename: attachment)
+ response_disposition = ActionDispatch::Http::ContentDisposition.format(disposition: disposition, filename: attachment)
# Response-Content-Type will not override an existing Content-Type in
# Google Cloud Storage, so the metadata needs to be cleared on GCS for
@@ -15,7 +15,7 @@ module SendFileUpload
# cross-origin JavaScript protection.
send_params[:content_type] = 'text/plain' if File.extname(attachment) == '.js'
- send_params.merge!(filename: attachment, disposition: utf8_encoded_disposition(disposition, attachment))
+ send_params.merge!(filename: attachment, disposition: disposition)
end
if file_upload.file_storage?
@@ -28,18 +28,6 @@ module SendFileUpload
end
end
- # Since Rails 5 doesn't properly support support non-ASCII filenames,
- # we have to add our own to ensure RFC 5987 compliance. However, Rails
- # 5 automatically appends `filename#{filename}` here:
- # https://github.com/rails/rails/blob/v5.0.7/actionpack/lib/action_controller/metal/data_streaming.rb#L137
- # Rails 6 will have https://github.com/rails/rails/pull/33829, so we
- # can get rid of this special case handling when we upgrade.
- def utf8_encoded_disposition(disposition, filename)
- content = ::Gitlab::ContentDisposition.new(disposition: disposition, filename: filename)
-
- "#{disposition}; #{content.utf8_filename}"
- end
-
def guess_content_type(filename)
types = MIME::Types.type_for(filename)
diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb
index 08a57a9b146..7ad841d645d 100644
--- a/app/controllers/projects/releases_controller.rb
+++ b/app/controllers/projects/releases_controller.rb
@@ -3,11 +3,12 @@
class Projects::ReleasesController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project, except: [:index]
- before_action :release, only: %i[edit update]
+ before_action :release, only: %i[edit show update]
before_action :authorize_read_release!
before_action do
push_frontend_feature_flag(:release_issue_summary, project)
push_frontend_feature_flag(:release_evidence_collection, project, default_enabled: true)
+ push_frontend_feature_flag(:release_show_page, project)
end
before_action :authorize_update_release!, only: %i[edit update]
before_action :authorize_read_release_evidence!, only: [:evidence]
@@ -29,6 +30,16 @@ class Projects::ReleasesController < Projects::ApplicationController
end
end
+ def show
+ return render_404 unless Feature.enabled?(:release_show_page, project)
+
+ respond_to do |format|
+ format.html do
+ render :show
+ end
+ end
+ end
+
protected
def releases
@@ -37,7 +48,9 @@ class Projects::ReleasesController < Projects::ApplicationController
def edit
respond_to do |format|
- format.html { render 'edit' }
+ format.html do
+ render :edit
+ end
end
end
diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb
index e24d6a0e8db..e42ea3861b8 100644
--- a/app/helpers/markup_helper.rb
+++ b/app/helpers/markup_helper.rb
@@ -4,7 +4,7 @@ require 'nokogiri'
module MarkupHelper
include ActionView::Helpers::TextHelper
- include ::Gitlab::ActionViewOutput::Context
+ include ActionView::Context
def plain?(filename)
Gitlab::MarkupHelper.plain?(filename)
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index f9101609f89..5a917588a33 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -200,6 +200,10 @@ class CommitStatus < ApplicationRecord
update_all('processed=TRUE, lock_version=COALESCE(lock_version,0)+1')
end
+ def self.locking_enabled?
+ false
+ end
+
def locking_enabled?
will_save_change_to_status?
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 653dc9c0b47..a6961df1b51 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -130,6 +130,10 @@ module Issuable
strip_attributes :title
+ def self.locking_enabled?
+ false
+ end
+
# We want to use optimistic lock for cases when only title or description are involved
# http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html
def locking_enabled?
diff --git a/app/models/concerns/mirror_authentication.rb b/app/models/concerns/mirror_authentication.rb
index 948094221e5..4dbf4dcec77 100644
--- a/app/models/concerns/mirror_authentication.rb
+++ b/app/models/concerns/mirror_authentication.rb
@@ -37,6 +37,8 @@ module MirrorAuthentication
end
define_method("#{name}=") do |value|
+ credentials_will_change!
+
self.credentials ||= {}
# Removal of the password, username, etc, generally causes an update of
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 3174a3269b4..62f34ae6525 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -712,7 +712,7 @@ class MergeRequest < ApplicationRecord
end
def validate_branch_name(attr)
- return unless changes_include?(attr)
+ return unless will_save_change_to_attribute?(attr)
branch = read_attribute(attr)
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
index 2b3443f24d7..1447f822513 100644
--- a/app/models/notification_setting.rb
+++ b/app/models/notification_setting.rb
@@ -21,7 +21,10 @@ class NotificationSetting < ApplicationRecord
# pending delete).
#
scope :for_projects, -> do
- includes(:project).references(:projects).where(source_type: 'Project').where.not(projects: { id: nil, pending_delete: true })
+ includes(:project).references(:projects)
+ .where(source_type: 'Project')
+ .where.not(projects: { id: nil })
+ .where.not(projects: { pending_delete: true })
end
EMAIL_EVENTS = [
diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb
index 8c24d07675a..42c707908e6 100644
--- a/app/presenters/project_presenter.rb
+++ b/app/presenters/project_presenter.rb
@@ -208,7 +208,7 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
AnchorData.new(false,
statistic_icon + _('New file'),
project_new_blob_path(project, default_branch || 'master'),
- 'success')
+ 'missing')
end
end
diff --git a/app/serializers/concerns/user_status_tooltip.rb b/app/serializers/concerns/user_status_tooltip.rb
index a81e377691e..633b117d392 100644
--- a/app/serializers/concerns/user_status_tooltip.rb
+++ b/app/serializers/concerns/user_status_tooltip.rb
@@ -3,7 +3,7 @@
module UserStatusTooltip
extend ActiveSupport::Concern
include ActionView::Helpers::TagHelper
- include ::Gitlab::ActionViewOutput::Context
+ include ActionView::Context
include EmojiHelper
include UsersHelper
diff --git a/app/services/concerns/spam_check_methods.rb b/app/services/concerns/spam_check_methods.rb
index 5eb663c97ff..695bdf92b49 100644
--- a/app/services/concerns/spam_check_methods.rb
+++ b/app/services/concerns/spam_check_methods.rb
@@ -23,7 +23,7 @@ module SpamCheckMethods
# attribute values.
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def spam_check(spammable, user)
- SpamCheckService.new(
+ Spam::SpamCheckService.new(
spammable: spammable,
request: @request
).execute(
diff --git a/app/services/metrics/dashboard/clone_dashboard_service.rb b/app/services/metrics/dashboard/clone_dashboard_service.rb
index b2ec44cb814..990dc462432 100644
--- a/app/services/metrics/dashboard/clone_dashboard_service.rb
+++ b/app/services/metrics/dashboard/clone_dashboard_service.rb
@@ -8,8 +8,18 @@ module Metrics
ALLOWED_FILE_TYPE = '.yml'
USER_DASHBOARDS_DIR = ::Metrics::Dashboard::ProjectDashboardService::DASHBOARD_ROOT
- def self.allowed_dashboard_templates
- @allowed_dashboard_templates ||= Set[::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH].freeze
+ class << self
+ def allowed_dashboard_templates
+ @allowed_dashboard_templates ||= Set[::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH].freeze
+ end
+
+ def sequences
+ @sequences ||= {
+ ::Metrics::Dashboard::SystemDashboardService::DASHBOARD_PATH => [::Gitlab::Metrics::Dashboard::Stages::CommonMetricsInserter,
+ ::Gitlab::Metrics::Dashboard::Stages::ProjectMetricsInserter,
+ ::Gitlab::Metrics::Dashboard::Stages::Sorter].freeze
+ }.freeze
+ end
end
def execute
@@ -92,7 +102,9 @@ module Metrics
end
def new_dashboard_content
- File.read(Rails.root.join(dashboard_template))
+ ::Gitlab::Metrics::Dashboard::Processor
+ .new(project, raw_dashboard, sequence, {})
+ .process.deep_stringify_keys.to_yaml
end
def repository
@@ -106,6 +118,14 @@ module Metrics
result
end
end
+
+ def raw_dashboard
+ YAML.safe_load(File.read(Rails.root.join(dashboard_template)))
+ end
+
+ def sequence
+ self.class.sequences[dashboard_template]
+ end
end
end
end
diff --git a/app/services/projects/detect_repository_languages_service.rb b/app/services/projects/detect_repository_languages_service.rb
index d3680637217..942cd8162e4 100644
--- a/app/services/projects/detect_repository_languages_service.rb
+++ b/app/services/projects/detect_repository_languages_service.rb
@@ -12,7 +12,7 @@ module Projects
matching_programming_languages = ensure_programming_languages(detection)
RepositoryLanguage.transaction do
- project.repository_languages.where(programming_language_id: detection.deletions).delete_all
+ RepositoryLanguage.where(project_id: project.id, programming_language_id: detection.deletions).delete_all
detection.updates.each do |update|
RepositoryLanguage
diff --git a/app/services/projects/move_access_service.rb b/app/services/projects/move_access_service.rb
index 8e2c3ad2f69..cddc544170f 100644
--- a/app/services/projects/move_access_service.rb
+++ b/app/services/projects/move_access_service.rb
@@ -20,6 +20,8 @@ module Projects
::Projects::MoveProjectAuthorizationsService.new(@project, @current_user)
.execute(source_project, remove_remaining_elements: remove_remaining_elements)
+ @project.save(touch: false)
+
success
end
end
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 718416a03d4..309eab59463 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -13,8 +13,6 @@ module Projects
include Gitlab::ShellAdapter
TransferError = Class.new(StandardError)
- attr_reader :new_namespace
-
def execute(new_namespace)
@new_namespace = new_namespace
@@ -39,6 +37,8 @@ module Projects
private
+ attr_reader :old_path, :new_path, :new_namespace
+
# rubocop: disable CodeReuse/ActiveRecord
def transfer(project)
@old_path = project.full_path
@@ -132,6 +132,8 @@ module Projects
end
def rollback_folder_move
+ return if project.hashed_storage?(:repository)
+
move_repo_folder(@new_path, @old_path)
move_repo_folder("#{@new_path}.wiki", "#{@old_path}.wiki")
end
diff --git a/app/services/spam/spam_check_service.rb b/app/services/spam/spam_check_service.rb
new file mode 100644
index 00000000000..d19ef03976f
--- /dev/null
+++ b/app/services/spam/spam_check_service.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+module Spam
+ class SpamCheckService
+ include AkismetMethods
+
+ attr_accessor :spammable, :request, :options
+ attr_reader :spam_log
+
+ def initialize(spammable:, request:)
+ @spammable = spammable
+ @request = request
+ @options = {}
+
+ if @request
+ @options[:ip_address] = @request.env['action_dispatch.remote_ip'].to_s
+ @options[:user_agent] = @request.env['HTTP_USER_AGENT']
+ @options[:referrer] = @request.env['HTTP_REFERRER']
+ else
+ @options[:ip_address] = @spammable.ip_address
+ @options[:user_agent] = @spammable.user_agent
+ end
+ end
+
+ def execute(api: false, recaptcha_verified:, spam_log_id:, user_id:)
+ if recaptcha_verified
+ # If it's a request which is already verified through recaptcha,
+ # update the spam log accordingly.
+ SpamLog.verify_recaptcha!(user_id: user_id, id: spam_log_id)
+ else
+ # Otherwise, it goes to Akismet for spam check.
+ # If so, it assigns spammable object as "spam" and creates a SpamLog record.
+ possible_spam = check(api)
+ spammable.spam = possible_spam unless spammable.allow_possible_spam?
+ spammable.spam_log = spam_log
+ end
+ end
+
+ private
+
+ def check(api)
+ return unless request
+ return unless check_for_spam?
+ return unless akismet.spam?
+
+ create_spam_log(api)
+ true
+ end
+
+ def check_for_spam?
+ spammable.check_for_spam?
+ end
+
+ def create_spam_log(api)
+ @spam_log = SpamLog.create!(
+ {
+ user_id: spammable.author_id,
+ title: spammable.spam_title,
+ description: spammable.spam_description,
+ source_ip: options[:ip_address],
+ user_agent: options[:user_agent],
+ noteable_type: spammable.class.to_s,
+ via_api: api
+ }
+ )
+ end
+ end
+end
diff --git a/app/services/spam_check_service.rb b/app/services/spam_check_service.rb
deleted file mode 100644
index e1f5efabcaf..00000000000
--- a/app/services/spam_check_service.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-# frozen_string_literal: true
-
-class SpamCheckService
- include AkismetMethods
-
- attr_accessor :spammable, :request, :options
- attr_reader :spam_log
-
- def initialize(spammable:, request:)
- @spammable = spammable
- @request = request
- @options = {}
-
- if @request
- @options[:ip_address] = @request.env['action_dispatch.remote_ip'].to_s
- @options[:user_agent] = @request.env['HTTP_USER_AGENT']
- @options[:referrer] = @request.env['HTTP_REFERRER']
- else
- @options[:ip_address] = @spammable.ip_address
- @options[:user_agent] = @spammable.user_agent
- end
- end
-
- def execute(api: false, recaptcha_verified:, spam_log_id:, user_id:)
- if recaptcha_verified
- # If it's a request which is already verified through recaptcha,
- # update the spam log accordingly.
- SpamLog.verify_recaptcha!(user_id: user_id, id: spam_log_id)
- else
- # Otherwise, it goes to Akismet for spam check.
- # If so, it assigns spammable object as "spam" and creates a SpamLog record.
- possible_spam = check(api)
- spammable.spam = possible_spam unless spammable.allow_possible_spam?
- spammable.spam_log = spam_log
- end
- end
-
- private
-
- def check(api)
- return unless request
- return unless check_for_spam?
- return unless akismet.spam?
-
- create_spam_log(api)
- true
- end
-
- def check_for_spam?
- spammable.check_for_spam?
- end
-
- def create_spam_log(api)
- @spam_log = SpamLog.create!(
- {
- user_id: spammable.author_id,
- title: spammable.spam_title,
- description: spammable.spam_description,
- source_ip: options[:ip_address],
- user_agent: options[:user_agent],
- noteable_type: spammable.class.to_s,
- via_api: api
- }
- )
- end
-end
diff --git a/app/uploaders/object_storage.rb b/app/uploaders/object_storage.rb
index 36bde629f9c..450ebb00b49 100644
--- a/app/uploaders/object_storage.rb
+++ b/app/uploaders/object_storage.rb
@@ -125,7 +125,7 @@ module ObjectStorage
included do
include AfterCommitQueue
- after_save on: [:create, :update] do
+ after_save do
background_upload(changed_mounts)
end
end
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index daedc52f298..7796db5ba63 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -49,13 +49,6 @@
= render 'projects/buttons/star'
= render 'projects/buttons/fork'
- - if can?(current_user, :download_code, @project)
- .project-clone-holder.d-inline-flex.d-md-none.btn-block
- = render "shared/mobile_clone_panel"
-
- .project-clone-holder.d-none.d-md-inline-flex
- = render "projects/buttons/clone"
-
- if can?(current_user, :download_code, @project)
%nav.project-stats
.nav-links.quick-links
diff --git a/app/views/projects/buttons/_clone.html.haml b/app/views/projects/buttons/_clone.html.haml
index ed22573b23e..7507be52f44 100644
--- a/app/views/projects/buttons/_clone.html.haml
+++ b/app/views/projects/buttons/_clone.html.haml
@@ -1,11 +1,12 @@
- project = project || @project
+- dropdown_class = local_assigns.fetch(:dropdown_class, '')
-.git-clone-holder.js-git-clone-holder.input-group
- %a#clone-dropdown.input-group-text.btn.btn-primary.btn-xs.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } }
+.git-clone-holder.js-git-clone-holder
+ %a#clone-dropdown.btn.btn-primary.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } }
%span.append-right-4.js-clone-dropdown-label
= _('Clone')
= sprite_icon("arrow-down", css_class: "icon")
- %ul.p-3.dropdown-menu.dropdown-menu-right.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown.qa-clone-options
+ %ul.p-3.dropdown-menu.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown.qa-clone-options{ class: dropdown_class }
- if ssh_enabled?
%li
%label.label-bold
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index a9b6b397968..9e06358beba 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -11,9 +11,14 @@
- if @project.can_current_user_push_code?
%p.append-bottom-0
- = _('You can create files directly in GitLab using one of the following options.')
+ = _('You can get started by cloning the repository or start adding files to it with one of the following options.')
.project-buttons.qa-quick-actions
+ .project-clone-holder.d-block.d-md-none.mt-2.mr-2
+ = render "shared/mobile_clone_panel"
+
+ .project-clone-holder.d-none.d-md-inline-block.mt-2.mr-2.float-left
+ = render "projects/buttons/clone"
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons
- if can?(current_user, :push_code, @project)
diff --git a/app/views/projects/network/show.json.erb b/app/views/projects/network/show.json.erb
index a0e82e891ff..a146d137c55 100644
--- a/app/views/projects/network/show.json.erb
+++ b/app/views/projects/network/show.json.erb
@@ -1,4 +1,4 @@
-<% self.formats = ["html"] %>
+<% self.formats = [:html] %>
<%= raw(
{
diff --git a/app/views/projects/releases/show.html.haml b/app/views/projects/releases/show.html.haml
new file mode 100644
index 00000000000..188262fb34c
--- /dev/null
+++ b/app/views/projects/releases/show.html.haml
@@ -0,0 +1,4 @@
+- add_to_breadcrumbs _("Releases"), project_releases_path(@project)
+- page_title @release.name
+
+#js-show-release-page{ data: { project_id: @project.id, tag_name: @release.tag } }
diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml
index 2d987744dfd..52a11642f32 100644
--- a/app/views/projects/tree/_tree_header.html.haml
+++ b/app/views/projects/tree/_tree_header.html.haml
@@ -101,3 +101,9 @@
= render "projects/buttons/xcode_link"
= render 'projects/buttons/download', project: @project, ref: @ref
+
+ .project-clone-holder.d-block.d-md-none.mt-sm-2.mt-md-0>
+ = render "shared/mobile_clone_panel"
+
+ .project-clone-holder.d-none.d-md-inline-block>
+ = render "projects/buttons/clone", dropdown_class: 'dropdown-menu-right'
diff --git a/app/views/shared/_mobile_clone_panel.html.haml b/app/views/shared/_mobile_clone_panel.html.haml
index 2887acf7cd7..df2ed5cfd97 100644
--- a/app/views/shared/_mobile_clone_panel.html.haml
+++ b/app/views/shared/_mobile_clone_panel.html.haml
@@ -4,7 +4,7 @@
.btn-group.mobile-git-clone.js-mobile-git-clone.btn-block
= clipboard_button(button_text: default_clone_label, text: default_url_to_repo(project), hide_button_icon: true, class: "btn-primary flex-fill bold justify-content-center input-group-text clone-dropdown-btn js-clone-dropdown-label")
- %button.btn.btn-primary.dropdown-toggle.js-dropdown-toggle.flex-grow-0.d-flex-center{ type: "button", data: { toggle: "dropdown" } }
+ %button.btn.btn-primary.dropdown-toggle.js-dropdown-toggle.flex-grow-0.d-flex-center.w-auto.ml-0{ type: "button", data: { toggle: "dropdown" } }
= sprite_icon("arrow-down", css_class: "dropdown-btn-icon icon")
%ul.dropdown-menu.dropdown-menu-selectable.dropdown-menu-right.clone-options-dropdown{ data: { dropdown: true } }
- if ssh_enabled?
diff --git a/app/workers/mail_scheduler/notification_service_worker.rb b/app/workers/mail_scheduler/notification_service_worker.rb
index 4130ce25878..ec659e39b24 100644
--- a/app/workers/mail_scheduler/notification_service_worker.rb
+++ b/app/workers/mail_scheduler/notification_service_worker.rb
@@ -26,49 +26,26 @@ module MailScheduler
end
def self.perform_async(*args)
- super(*Arguments.serialize(args))
+ super(*ActiveJob::Arguments.serialize(args))
end
private
- # If an argument is in the ActiveJob::Arguments::TYPE_WHITELIST list,
+ # This is copied over from https://github.com/rails/rails/blob/v6.0.1/activejob/lib/active_job/arguments.rb#L50
+ # because it is declared as a private constant
+ PERMITTED_TYPES = [NilClass, String, Integer, Float, BigDecimal, TrueClass, FalseClass].freeze
+
+ private_constant :PERMITTED_TYPES
+
+ # If an argument is in the PERMITTED_TYPES list,
# it means the argument cannot be deserialized.
# Which means there's something wrong with our code.
def check_arguments!(args)
args.each do |arg|
- if arg.class.in?(ActiveJob::Arguments::TYPE_WHITELIST)
+ if arg.class.in?(PERMITTED_TYPES)
raise(ArgumentError, "Argument `#{arg}` cannot be deserialized because of its type")
end
end
end
-
- # Permit ActionController::Parameters for serializable Hash
- #
- # Port of
- # https://github.com/rails/rails/commit/945fdd76925c9f615bf016717c4c8db2b2955357#diff-fc90ec41ef75be8b2259526fe1a8b663
- module Arguments
- include ActiveJob::Arguments
- extend self
-
- private
-
- def serialize_argument(argument)
- case argument
- when -> (arg) { arg.respond_to?(:permitted?) }
- serialize_hash(argument.to_h).tap do |result|
- result[WITH_INDIFFERENT_ACCESS_KEY] = serialize_argument(true)
- end
- else
- super
- end
- end
- end
-
- # Make sure we remove this patch starting with Rails 6.0.
- if Rails.version.start_with?('6.0')
- raise <<~MSG
- Please remove the patch `Arguments` module and use `ActiveJob::Arguments` again.
- MSG
- end
end
end