Skip to content
Snippets Groups Projects
Commit 211a8c33 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 456a7247
No related branches found
No related tags found
No related merge requests found
Showing
with 365 additions and 86 deletions
Loading
Loading
@@ -37,6 +37,20 @@ describe Gitlab::Graphql::Connections::Keyset::OrderInfo do
expect(order_list.count).to eq 1
end
end
context 'when order contains LOWER' do
let(:relation) { Project.order(Arel::Table.new(:projects)['name'].lower.asc).order(:id) }
it 'does not ignore the SQL order' do
expect(order_list.count).to eq 2
expect(order_list.first.attribute_name).to eq 'name'
expect(order_list.first.named_function).to be_kind_of(Arel::Nodes::NamedFunction)
expect(order_list.first.named_function.to_sql).to eq 'LOWER("projects"."name")'
expect(order_list.first.operator_for(:after)).to eq '>'
expect(order_list.last.attribute_name).to eq 'id'
expect(order_list.last.operator_for(:after)).to eq '>'
end
end
end
 
describe '#validate_ordering' do
Loading
Loading
Loading
Loading
@@ -101,5 +101,35 @@ describe Gitlab::Graphql::Connections::Keyset::QueryBuilder do
end
end
end
context 'when sorting using LOWER' do
let(:relation) { Project.order(Arel::Table.new(:projects)['name'].lower.asc).order(:id) }
let(:arel_table) { Project.arel_table }
let(:decoded_cursor) { { 'name' => 'Test', 'id' => 100 } }
context 'when no values are nil' do
context 'when :after' do
it 'generates the correct condition' do
conditions = builder.conditions
expect(conditions).to include '(LOWER("projects"."name") > \'test\')'
expect(conditions).to include '"projects"."id" > 100'
expect(conditions).to include 'OR (LOWER("projects"."name") IS NULL)'
end
end
context 'when :before' do
let(:before_or_after) { :before }
it 'generates the correct condition' do
conditions = builder.conditions
expect(conditions).to include '(LOWER("projects"."name") < \'test\')'
expect(conditions).to include '"projects"."id" < 100'
expect(conditions).to include 'LOWER("projects"."name") = \'test\''
end
end
end
end
end
end
Loading
Loading
@@ -652,10 +652,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
setup_import_export_config('light')
end
 
it 'does not import any templated services' do
it 'does not import any instance-level services' do
expect(restored_project_json).to eq(true)
 
expect(project.services.where(template: true).count).to eq(0)
expect(project.services.where(instance: true).count).to eq(0)
end
 
it 'imports labels' do
Loading
Loading
Loading
Loading
@@ -452,7 +452,7 @@ Service:
- updated_at
- active
- properties
- template
- instance
- push_events
- issues_events
- commit_events
Loading
Loading
Loading
Loading
@@ -18,7 +18,7 @@ describe Gitlab::UsageData do
create(:service, project: projects[1], type: 'SlackService', active: true)
create(:service, project: projects[2], type: 'SlackService', active: true)
create(:service, project: projects[2], type: 'MattermostService', active: false)
create(:service, project: projects[2], type: 'MattermostService', active: true, template: true)
create(:service, project: projects[2], type: 'MattermostService', active: true, instance: true)
create(:service, project: projects[2], type: 'CustomIssueTrackerService', active: true)
create(:project_error_tracking_setting, project: projects[0])
create(:project_error_tracking_setting, project: projects[1], enabled: false)
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200127111840_fix_projects_without_project_feature.rb')
describe FixProjectsWithoutProjectFeature, :migration do
let(:namespace) { table(:namespaces).create(name: 'gitlab', path: 'gitlab-org') }
let!(:projects) do
[
table(:projects).create(namespace_id: namespace.id, name: 'foo 1'),
table(:projects).create(namespace_id: namespace.id, name: 'foo 2'),
table(:projects).create(namespace_id: namespace.id, name: 'foo 3')
]
end
before do
stub_const("#{described_class.name}::BATCH_SIZE", 2)
end
around do |example|
Sidekiq::Testing.fake! do
Timecop.freeze do
example.call
end
end
end
it 'schedules jobs for ranges of projects' do
migrate!
expect(described_class::MIGRATION)
.to be_scheduled_delayed_migration(2.minutes, projects[0].id, projects[1].id)
expect(described_class::MIGRATION)
.to be_scheduled_delayed_migration(4.minutes, projects[2].id, projects[2].id)
end
it 'schedules jobs according to the configured batch size' do
expect { migrate! }.to change { BackgroundMigrationWorker.jobs.size }.by(2)
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200206111847_migrate_propagate_service_template_sidekiq_queue.rb')
describe MigratePropagateServiceTemplateSidekiqQueue, :sidekiq, :redis do
include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queue' do
it 'correctly migrates queue when migrating up' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'propagate_service_template').perform_async('Something', [1])
stub_worker(queue: 'propagate_instance_level_service').perform_async('Something', [1])
described_class.new.up
expect(sidekiq_queue_length('propagate_service_template')).to eq 0
expect(sidekiq_queue_length('propagate_instance_level_service')).to eq 2
end
end
end
context 'when there are no jobs in the queues' do
it 'does not raise error when migrating up' do
expect { described_class.new.up }.not_to raise_error
end
end
end
Loading
Loading
@@ -4,17 +4,18 @@ require 'spec_helper'
 
describe Sortable do
describe '.order_by' do
let(:arel_table) { Group.arel_table }
let(:relation) { Group.all }
 
describe 'ordering by id' do
it 'ascending' do
expect(relation).to receive(:reorder).with(id: :asc)
expect(relation).to receive(:reorder).with(arel_table['id'].asc)
 
relation.order_by('id_asc')
end
 
it 'descending' do
expect(relation).to receive(:reorder).with(id: :desc)
expect(relation).to receive(:reorder).with(arel_table['id'].desc)
 
relation.order_by('id_desc')
end
Loading
Loading
@@ -22,19 +23,19 @@ describe Sortable do
 
describe 'ordering by created day' do
it 'ascending' do
expect(relation).to receive(:reorder).with(created_at: :asc)
expect(relation).to receive(:reorder).with(arel_table['created_at'].asc)
 
relation.order_by('created_asc')
end
 
it 'descending' do
expect(relation).to receive(:reorder).with(created_at: :desc)
expect(relation).to receive(:reorder).with(arel_table['created_at'].desc)
 
relation.order_by('created_desc')
end
 
it 'order by "date"' do
expect(relation).to receive(:reorder).with(created_at: :desc)
expect(relation).to receive(:reorder).with(arel_table['created_at'].desc)
 
relation.order_by('created_date')
end
Loading
Loading
@@ -66,13 +67,13 @@ describe Sortable do
 
describe 'ordering by Updated Time' do
it 'ascending' do
expect(relation).to receive(:reorder).with(updated_at: :asc)
expect(relation).to receive(:reorder).with(arel_table['updated_at'].asc)
 
relation.order_by('updated_asc')
end
 
it 'descending' do
expect(relation).to receive(:reorder).with(updated_at: :desc)
expect(relation).to receive(:reorder).with(arel_table['updated_at'].desc)
 
relation.order_by('updated_desc')
end
Loading
Loading
Loading
Loading
@@ -279,6 +279,12 @@ describe Project do
end
end
 
it 'validates presence of project_feature' do
project = build(:project, project_feature: nil)
expect(project).not_to be_valid
end
describe 'import_url' do
it 'does not allow an invalid URI as import_url' do
project = build(:project, import_url: 'invalid://')
Loading
Loading
@@ -2694,16 +2700,44 @@ describe Project do
describe '#all_lfs_objects' do
let(:lfs_object) { create(:lfs_object) }
 
before do
project.lfs_objects << lfs_object
context 'when LFS object is only associated to the source' do
before do
project.lfs_objects << lfs_object
end
it 'returns the lfs object for a project' do
expect(project.all_lfs_objects).to contain_exactly(lfs_object)
end
it 'returns the lfs object for a fork' do
expect(forked_project.all_lfs_objects).to contain_exactly(lfs_object)
end
end
 
it 'returns the lfs object for a project' do
expect(project.all_lfs_objects).to contain_exactly(lfs_object)
context 'when LFS object is only associated to the fork' do
before do
forked_project.lfs_objects << lfs_object
end
it 'returns nothing' do
expect(project.all_lfs_objects).to be_empty
end
it 'returns the lfs object for a fork' do
expect(forked_project.all_lfs_objects).to contain_exactly(lfs_object)
end
end
 
it 'returns the lfs object for a fork' do
expect(forked_project.all_lfs_objects).to contain_exactly(lfs_object)
context 'when LFS object is associated to both source and fork' do
before do
project.lfs_objects << lfs_object
forked_project.lfs_objects << lfs_object
end
it 'returns the lfs object for the source and fork' do
expect(project.all_lfs_objects).to contain_exactly(lfs_object)
expect(forked_project.all_lfs_objects).to contain_exactly(lfs_object)
end
end
end
end
Loading
Loading
@@ -5519,6 +5553,31 @@ describe Project do
end
end
 
describe '#lfs_objects_oids' do
let(:project) { create(:project) }
let(:lfs_object) { create(:lfs_object) }
let(:another_lfs_object) { create(:lfs_object) }
subject { project.lfs_objects_oids }
context 'when project has associated LFS objects' do
before do
create(:lfs_objects_project, lfs_object: lfs_object, project: project)
create(:lfs_objects_project, lfs_object: another_lfs_object, project: project)
end
it 'returns OIDs of LFS objects' do
expect(subject).to match_array([lfs_object.oid, another_lfs_object.oid])
end
end
context 'when project has no associated LFS objects' do
it 'returns empty array' do
expect(subject).to be_empty
end
end
end
def rugged_config
rugged_repo(project.repository).config
end
Loading
Loading
Loading
Loading
@@ -97,23 +97,23 @@ describe Service do
end
end
 
describe "Template" do
describe "Instance" do
let(:project) { create(:project) }
 
describe '.build_from_template' do
context 'when template is invalid' do
it 'sets service template to inactive when template is invalid' do
template = build(:prometheus_service, template: true, active: true, properties: {})
template.save(validate: false)
describe '.build_from_instance' do
context 'when instance level integration is invalid' do
it 'sets instance level integration to inactive when instance is invalid' do
instance = build(:prometheus_service, instance: true, active: true, properties: {})
instance.save(validate: false)
 
service = described_class.build_from_template(project.id, template)
service = described_class.build_from_instance(project.id, instance)
 
expect(service).to be_valid
expect(service.active).to be false
end
end
 
describe 'build issue tracker from a template' do
describe 'build issue tracker from a instance level integration' do
let(:title) { 'custom title' }
let(:description) { 'custom description' }
let(:url) { 'http://jira.example.com' }
Loading
Loading
@@ -127,9 +127,9 @@ describe Service do
}
end
 
shared_examples 'service creation from a template' do
shared_examples 'integration creation from instance level' do
it 'creates a correct service' do
service = described_class.build_from_template(project.id, template)
service = described_class.build_from_instance(project.id, instance_level_integration)
 
expect(service).to be_active
expect(service.title).to eq(title)
Loading
Loading
@@ -144,38 +144,38 @@ describe Service do
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
context 'when data are stored in properties' do
let(:properties) { data_params.merge(title: title, description: description) }
let!(:template) do
create(:jira_service, :without_properties_callback, template: true, properties: properties.merge(additional: 'something'))
let!(:instance_level_integration) do
create(:jira_service, :without_properties_callback, instance: true, properties: properties.merge(additional: 'something'))
end
 
it_behaves_like 'service creation from a template'
it_behaves_like 'integration creation from instance level'
end
 
context 'when data are stored in separated fields' do
let(:template) do
create(:jira_service, data_params.merge(properties: {}, title: title, description: description, template: true))
let(:instance_level_integration) do
create(:jira_service, data_params.merge(properties: {}, title: title, description: description, instance: true))
end
 
it_behaves_like 'service creation from a template'
it_behaves_like 'integration creation from instance level'
end
 
context 'when data are stored in both properties and separated fields' do
let(:properties) { data_params.merge(title: title, description: description) }
let(:template) do
create(:jira_service, :without_properties_callback, active: true, template: true, properties: properties).tap do |service|
let(:instance_level_integration) do
create(:jira_service, :without_properties_callback, active: true, instance: true, properties: properties).tap do |service|
create(:jira_tracker_data, data_params.merge(service: service))
end
end
 
it_behaves_like 'service creation from a template'
it_behaves_like 'integration creation from instance level'
end
end
end
 
describe "for pushover service" do
let!(:service_template) do
let!(:instance_level_integration) do
PushoverService.create(
template: true,
instance: true,
properties: {
device: 'MyDevice',
sound: 'mic',
Loading
Loading
@@ -188,7 +188,7 @@ describe Service do
it "has all fields prefilled" do
service = project.find_or_initialize_service('pushover')
 
expect(service.template).to eq(false)
expect(service.instance).to eq(false)
expect(service.device).to eq('MyDevice')
expect(service.sound).to eq('mic')
expect(service.priority).to eq(4)
Loading
Loading
@@ -391,14 +391,6 @@ describe Service do
end
end
 
describe '.find_by_template' do
let!(:service) { create(:service, template: true) }
it 'returns service template' do
expect(described_class.find_by_template).to eq(service)
end
end
describe '#api_field_names' do
let(:fake_service) do
Class.new(Service) do
Loading
Loading
Loading
Loading
@@ -467,7 +467,7 @@ describe ProjectPresenter do
 
expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(
is_link: false,
label: a_string_including('Kubernetes configured'),
label: a_string_including('Kubernetes'),
link: presenter.project_cluster_path(project, cluster)
)
end
Loading
Loading
@@ -480,7 +480,7 @@ describe ProjectPresenter do
 
expect(presenter.kubernetes_cluster_anchor_data).to have_attributes(
is_link: false,
label: a_string_including('Kubernetes configured'),
label: a_string_including('Kubernetes'),
link: presenter.project_clusters_path(project)
)
end
Loading
Loading
Loading
Loading
@@ -1492,7 +1492,7 @@ describe API::MergeRequests do
end
end
 
context 'forked projects' do
context 'forked projects', :sidekiq_might_not_need_inline do
let!(:user2) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let!(:forked_project) { fork_project(project, user2, repository: true) }
Loading
Loading
Loading
Loading
@@ -1193,8 +1193,8 @@ describe 'Git LFS API and storage' do
 
it_behaves_like 'LFS http 200 response'
 
it 'LFS object is linked to the source project' do
expect(lfs_object.projects.pluck(:id)).to include(upstream_project.id)
it 'LFS object is linked to the forked project' do
expect(lfs_object.projects.pluck(:id)).to include(project.id)
end
end
end
Loading
Loading
Loading
Loading
@@ -483,6 +483,14 @@ describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
expect(merge_request).to be_persisted
end
 
it 'calls MergeRequests::LinkLfsObjectsService#execute', :sidekiq_might_not_need_inline do
expect_next_instance_of(MergeRequests::LinkLfsObjectsService) do |service|
expect(service).to receive(:execute).with(instance_of(MergeRequest))
end
described_class.new(project, user, opts).execute
end
it 'does not create the merge request when the target project is archived' do
target_project.update!(archived: true)
 
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe MergeRequests::LinkLfsObjectsService, :sidekiq_inline do
include ProjectForksHelper
include RepoHelpers
let(:target_project) { create(:project, :public, :repository) }
let(:merge_request) do
create(
:merge_request,
target_project: target_project,
target_branch: 'lfs',
source_project: source_project,
source_branch: 'link-lfs-objects'
)
end
subject { described_class.new(target_project) }
shared_examples_for 'linking LFS objects' do
context 'when source project is the same as target project' do
let(:source_project) { target_project }
it 'does not call Projects::LfsPointers::LfsLinkService#execute' do
expect(Projects::LfsPointers::LfsLinkService).not_to receive(:new)
execute
end
end
context 'when source project is different from target project' do
let(:user) { create(:user) }
let(:source_project) { fork_project(target_project, user, namespace: user.namespace, repository: true) }
before do
create_branch(source_project, 'link-lfs-objects', 'lfs')
end
context 'and there are changes' do
before do
allow(source_project).to receive(:lfs_enabled?).and_return(true)
end
context 'and there are LFS objects added' do
before do
create_file_in_repo(source_project, 'link-lfs-objects', 'link-lfs-objects', 'one.lfs', 'One')
create_file_in_repo(source_project, 'link-lfs-objects', 'link-lfs-objects', 'two.lfs', 'Two')
end
it 'calls Projects::LfsPointers::LfsLinkService#execute with OIDs of LFS objects in merge request' do
expect_next_instance_of(Projects::LfsPointers::LfsLinkService) do |service|
expect(service).to receive(:execute).with(%w[
8b12507783d5becacbf2ebe5b01a60024d8728a8f86dcc818bce699e8b3320bc
94a72c074cfe574742c9e99e863322f73feff82981d065ff65a0308f44f19f62
])
end
execute
end
end
context 'but there are no LFS objects added' do
before do
create_file_in_repo(source_project, 'link-lfs-objects', 'link-lfs-objects', 'one.txt', 'One')
end
it 'does not call Projects::LfsPointers::LfsLinkService#execute' do
expect(Projects::LfsPointers::LfsLinkService).not_to receive(:new)
execute
end
end
end
context 'and there are no changes' do
it 'does not call Projects::LfsPointers::LfsLinkService#execute' do
expect(Projects::LfsPointers::LfsLinkService).not_to receive(:new)
execute
end
end
end
end
context 'when no oldrev and newrev passed' do
let(:execute) { subject.execute(merge_request) }
it_behaves_like 'linking LFS objects'
end
context 'when oldrev and newrev are passed' do
let(:execute) { subject.execute(merge_request, oldrev: merge_request.diff_base_sha, newrev: merge_request.diff_head_sha) }
it_behaves_like 'linking LFS objects'
end
def create_branch(project, new_name, branch_name)
::Branches::CreateService.new(project, user).execute(new_name, branch_name)
end
end
Loading
Loading
@@ -384,6 +384,14 @@ describe MergeRequests::RefreshService do
end
 
context 'open fork merge request' do
it 'calls MergeRequests::LinkLfsObjectsService#execute' do
expect_next_instance_of(MergeRequests::LinkLfsObjectsService) do |svc|
expect(svc).to receive(:execute).with(@fork_merge_request, oldrev: @oldrev, newrev: @newrev)
end
refresh
end
it 'executes hooks with update action' do
refresh
 
Loading
Loading
Loading
Loading
@@ -15,7 +15,7 @@ describe Projects::CreateService, '#execute' do
}
end
 
it 'creates labels on Project creation if there are templates' do
it 'creates labels on Project creation if there are instance level services' do
Label.create(title: "bug", template: true)
project = create_project(user, opts)
 
Loading
Loading
@@ -90,7 +90,7 @@ describe Projects::CreateService, '#execute' do
end
 
it 'sets invalid service as inactive' do
create(:service, type: 'JiraService', project: nil, template: true, active: true)
create(:service, type: 'JiraService', project: nil, instance: true, active: true)
 
project = create_project(user, opts)
service = project.services.first
Loading
Loading
@@ -336,22 +336,22 @@ describe Projects::CreateService, '#execute' do
end
end
 
context 'when there is an active service template' do
context 'when there is an active instance level service' do
before do
create(:service, project: nil, template: true, active: true)
create(:service, project: nil, instance: true, active: true)
end
 
it 'creates a service from this template' do
it 'creates a service from instance level service' do
project = create_project(user, opts)
 
expect(project.services.count).to eq 1
end
end
 
context 'when a bad service template is created' do
context 'when a bad instance level service is created' do
it 'sets service to be inactive' do
opts[:import_url] = 'http://www.gitlab.com/gitlab-org/gitlab-foss'
create(:service, type: 'DroneCiService', project: nil, template: true, active: true)
create(:service, type: 'DroneCiService', project: nil, instance: true, active: true)
 
project = create_project(user, opts)
service = project.services.first
Loading
Loading
Loading
Loading
@@ -375,14 +375,6 @@ describe Projects::ForkService do
expect(fork_from_project.forks_count).to eq(1)
end
 
it 'leaves no LFS objects dangling' do
create(:lfs_objects_project, project: fork_to_project)
expect { subject.execute(fork_to_project) }
.to change { fork_to_project.lfs_objects_projects.count }
.to(0)
end
context 'if the fork is not allowed' do
let(:fork_from_project) { create(:project, :private) }
 
Loading
Loading
Loading
Loading
@@ -48,10 +48,11 @@ describe Projects::LfsPointers::LfsDownloadService do
end
 
shared_examples 'lfs object is created' do
it do
it 'creates and associate the LFS object to project' do
expect(subject).to receive(:download_and_save_file!).and_call_original
 
expect { subject.execute }.to change { LfsObject.count }.by(1)
expect(LfsObject.first.projects).to include(project)
end
 
it 'returns success result' do
Loading
Loading
Loading
Loading
@@ -2,11 +2,11 @@
 
require 'spec_helper'
 
describe Projects::PropagateServiceTemplate do
describe Projects::PropagateInstanceLevelService do
describe '.propagate' do
let!(:service_template) do
let!(:instance_level_integration) do
PushoverService.create(
template: true,
instance: true,
active: true,
properties: {
device: 'MyDevice',
Loading
Loading
@@ -22,14 +22,14 @@ describe Projects::PropagateServiceTemplate do
it 'creates services for projects' do
expect(project.pushover_service).to be_nil
 
described_class.propagate(service_template)
described_class.propagate(instance_level_integration)
 
expect(project.reload.pushover_service).to be_present
end
 
it 'creates services for a project that has another service' do
BambooService.create(
template: true,
instance: true,
active: true,
project: project,
properties: {
Loading
Loading
@@ -42,14 +42,14 @@ describe Projects::PropagateServiceTemplate do
 
expect(project.pushover_service).to be_nil
 
described_class.propagate(service_template)
described_class.propagate(instance_level_integration)
 
expect(project.reload.pushover_service).to be_present
end
 
it 'does not create the service if it exists already' do
other_service = BambooService.create(
template: true,
instance: true,
active: true,
properties: {
bamboo_url: 'http://gitlab.com',
Loading
Loading
@@ -59,17 +59,17 @@ describe Projects::PropagateServiceTemplate do
}
)
 
Service.build_from_template(project.id, service_template).save!
Service.build_from_template(project.id, other_service).save!
Service.build_from_instance(project.id, instance_level_integration).save!
Service.build_from_instance(project.id, other_service).save!
 
expect { described_class.propagate(service_template) }
expect { described_class.propagate(instance_level_integration) }
.not_to change { Service.count }
end
 
it 'creates the service containing the template attributes' do
described_class.propagate(service_template)
it 'creates the service containing the instance attributes' do
described_class.propagate(instance_level_integration)
 
expect(project.pushover_service.properties).to eq(service_template.properties)
expect(project.pushover_service.properties).to eq(instance_level_integration.properties)
end
 
describe 'bulk update', :use_sql_query_cache do
Loading
Loading
@@ -80,7 +80,7 @@ describe Projects::PropagateServiceTemplate do
 
project_total.times { create(:project) }
 
described_class.propagate(service_template)
described_class.propagate(instance_level_integration)
end
 
it 'creates services for all projects' do
Loading
Loading
@@ -90,18 +90,18 @@ describe Projects::PropagateServiceTemplate do
 
describe 'external tracker' do
it 'updates the project external tracker' do
service_template.update!(category: 'issue_tracker', default: false)
instance_level_integration.update!(category: 'issue_tracker', default: false)
 
expect { described_class.propagate(service_template) }
expect { described_class.propagate(instance_level_integration) }
.to change { project.reload.has_external_issue_tracker }.to(true)
end
end
 
describe 'external wiki' do
it 'updates the project external tracker' do
service_template.update!(type: 'ExternalWikiService')
instance_level_integration.update!(type: 'ExternalWikiService')
 
expect { described_class.propagate(service_template) }
expect { described_class.propagate(instance_level_integration) }
.to change { project.reload.has_external_wiki }.to(true)
end
end
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment