Commit 3528e388 authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch '8046-geo-rename-recheck-actions-on-the-projects-page-to-reverify' into 'master'

Geo - Rename recheck actions to reverify

See merge request gitlab-org/gitlab-ee!14979
parents 630d4df0 f361b479
...@@ -34,10 +34,10 @@ class Admin::Geo::ProjectsController < Admin::Geo::ApplicationController ...@@ -34,10 +34,10 @@ class Admin::Geo::ProjectsController < Admin::Geo::ApplicationController
redirect_back_or_admin_geo_projects(notice: s_('Geo|Tracking entry for project (%{project_id}) was successfully removed.') % { project_id: @registry.project_id }) redirect_back_or_admin_geo_projects(notice: s_('Geo|Tracking entry for project (%{project_id}) was successfully removed.') % { project_id: @registry.project_id })
end end
def recheck def reverify
@registry.flag_repository_for_recheck! @registry.flag_repository_for_reverify!
redirect_back_or_admin_geo_projects(notice: s_('Geo|%{name} is scheduled for re-check') % { name: @registry.project.full_name }) redirect_back_or_admin_geo_projects(notice: s_('Geo|%{name} is scheduled for re-verify') % { name: @registry.project.full_name })
end end
def resync def resync
...@@ -52,10 +52,10 @@ class Admin::Geo::ProjectsController < Admin::Geo::ApplicationController ...@@ -52,10 +52,10 @@ class Admin::Geo::ProjectsController < Admin::Geo::ApplicationController
redirect_back_or_admin_geo_projects(notice: s_('Geo|%{name} is scheduled for forced re-download') % { name: @registry.project.full_name }) redirect_back_or_admin_geo_projects(notice: s_('Geo|%{name} is scheduled for forced re-download') % { name: @registry.project.full_name })
end end
def recheck_all def reverify_all
Geo::Batch::ProjectRegistrySchedulerWorker.perform_async(:recheck_repositories) Geo::Batch::ProjectRegistrySchedulerWorker.perform_async(:reverify_repositories)
redirect_back_or_admin_geo_projects(notice: s_('Geo|All projects are being scheduled for re-check')) redirect_back_or_admin_geo_projects(notice: s_('Geo|All projects are being scheduled for re-verify'))
end end
def resync_all def resync_all
......
...@@ -186,7 +186,7 @@ class Geo::ProjectRegistry < Geo::BaseRegistry ...@@ -186,7 +186,7 @@ class Geo::ProjectRegistry < Geo::BaseRegistry
) )
end end
def self.flag_repositories_for_recheck! def self.flag_repositories_for_reverify!
update_all( update_all(
repository_verification_checksum_sha: nil, repository_verification_checksum_sha: nil,
last_repository_verification_failure: nil, last_repository_verification_failure: nil,
...@@ -389,8 +389,8 @@ class Geo::ProjectRegistry < Geo::BaseRegistry ...@@ -389,8 +389,8 @@ class Geo::ProjectRegistry < Geo::BaseRegistry
# Flag the repository to be re-checked # Flag the repository to be re-checked
# #
# This operation happens only in the database and the recheck will be triggered after by the cron job # This operation happens only in the database and the reverify will be triggered after by the cron job
def flag_repository_for_recheck! def flag_repository_for_reverify!
self.update(repository_verification_checksum_sha: nil, last_repository_verification_failure: nil, repository_checksum_mismatch: false) self.update(repository_verification_checksum_sha: nil, last_repository_verification_failure: nil, repository_checksum_mismatch: false)
end end
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
%strong.header-text-primary.flex-fill %strong.header-text-primary.flex-fill
= link_to project_registry.project.full_name, admin_namespace_project_path(project_registry.project.namespace, project_registry.project) = link_to project_registry.project.full_name, admin_namespace_project_path(project_registry.project.namespace, project_registry.project)
- unless project_registry.pending_verification? - unless project_registry.pending_verification?
= link_to(recheck_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default btn-sm mr-2') do = link_to(reverify_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default btn-sm mr-2') do
= s_('Geo|Recheck') = s_('Geo|Reverify')
- unless project_registry.resync_repository? - unless project_registry.resync_repository?
= link_to(resync_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default-primary btn-sm') do = link_to(resync_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default-primary btn-sm') do
= s_('Geo|Resync') = s_('Geo|Resync')
......
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
%strong.header-text-primary.flex-fill %strong.header-text-primary.flex-fill
= link_to project_registry.project.full_name, admin_namespace_project_path(project_registry.project.namespace, project_registry.project) = link_to project_registry.project.full_name, admin_namespace_project_path(project_registry.project.namespace, project_registry.project)
- unless project_registry.pending_verification? - unless project_registry.pending_verification?
= link_to(recheck_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default btn-sm mr-2') do = link_to(reverify_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default btn-sm mr-2') do
= s_('Geo|Recheck') = s_('Geo|Reverify')
- unless project_registry.resync_repository? - unless project_registry.resync_repository?
= link_to(resync_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default-primary btn-sm') do = link_to(resync_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default-primary btn-sm') do
= s_('Geo|Resync') = s_('Geo|Resync')
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
- else - else
%strong.header-text-primary.flex-fill %strong.header-text-primary.flex-fill
= link_to project_registry.project.full_name, admin_namespace_project_path(project_registry.project.namespace, project_registry.project) = link_to project_registry.project.full_name, admin_namespace_project_path(project_registry.project.namespace, project_registry.project)
= link_to(recheck_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default btn-sm mr-2') do = link_to(reverify_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default btn-sm mr-2') do
= s_('Geo|Recheck') = s_('Geo|Reverify')
= link_to(resync_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default-primary btn-sm') do = link_to(resync_admin_geo_project_path(project_registry), method: :post, class: 'btn btn-default-primary btn-sm') do
= s_('Geo|Resync') = s_('Geo|Resync')
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
%ul.dropdown-menu.dropdown-menu-right %ul.dropdown-menu.dropdown-menu-right
%li.dropdown-header= s_('Geo|Batch operations') %li.dropdown-header= s_('Geo|Batch operations')
%li= link_to s_('Geo|Resync all projects'), resync_all_admin_geo_projects_path, method: :post %li= link_to s_('Geo|Resync all projects'), resync_all_admin_geo_projects_path, method: :post
%li= link_to s_('Geo|Recheck all projects'), recheck_all_admin_geo_projects_path, method: :post %li= link_to s_('Geo|Reverify all projects'), reverify_all_admin_geo_projects_path, method: :post
- case params[:sync_status] - case params[:sync_status]
- when 'never' - when 'never'
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
.card-header .card-header
= s_('Geo|Geo Status') = s_('Geo|Geo Status')
.float-right .float-right
= link_to(recheck_admin_geo_project_path(@project.project_registry), method: :post, class: 'btn btn-default btn-sm mr-2') do = link_to(reverify_admin_geo_project_path(@project.project_registry), method: :post, class: 'btn btn-default btn-sm mr-2') do
= s_('Geo|Recheck') = s_('Geo|Reverify')
= link_to(resync_admin_geo_project_path(@project.project_registry), method: :post, class: 'btn btn-default-primary btn-sm') do = link_to(resync_admin_geo_project_path(@project.project_registry), method: :post, class: 'btn btn-default-primary btn-sm') do
= s_('Geo|Resync') = s_('Geo|Resync')
= render partial: "admin/geo/projects/registry_#{@project.project_registry.synchronization_state}", locals: { project_registry: @project.project_registry } = render partial: "admin/geo/projects/registry_#{@project.project_registry.synchronization_state}", locals: { project_registry: @project.project_registry }
...@@ -15,10 +15,17 @@ module Geo ...@@ -15,10 +15,17 @@ module Geo
BATCH_SIZE = 10000 BATCH_SIZE = 10000
LEASE_TIMEOUT = 2.minutes # TTL for X amount of loops to happen until it is renewed LEASE_TIMEOUT = 2.minutes # TTL for X amount of loops to happen until it is renewed
RENEW_AFTER_LOOPS = 20 # renew lease at every 20 loops has finished RENEW_AFTER_LOOPS = 20 # renew lease at every 20 loops has finished
OPERATIONS = [:resync_repositories, :recheck_repositories].freeze OPERATIONS = [:resync_repositories, :reverify_repositories].freeze
DELAY_INTERVAL = 10.seconds.to_i # base delay for scheduling batch execution DELAY_INTERVAL = 10.seconds.to_i # base delay for scheduling batch execution
def perform(operation) def perform(operation)
# TODO: This is a temporary workaround for backward compatibility
# to avoid jobs that have been already scheduled to fail.
# See https://gitlab.com/gitlab-org/gitlab-ee/issues/13318
if operation.to_sym == :recheck_repositories
operation = :reverify_repositories
end
return fail_invalid_operation!(operation) unless OPERATIONS.include?(operation.to_sym) return fail_invalid_operation!(operation) unless OPERATIONS.include?(operation.to_sym)
try_obtain_lease do try_obtain_lease do
......
...@@ -12,14 +12,21 @@ module Geo ...@@ -12,14 +12,21 @@ module Geo
include ::Gitlab::Geo::LogHelpers include ::Gitlab::Geo::LogHelpers
BATCH_SIZE = 250 BATCH_SIZE = 250
OPERATIONS = [:resync_repositories, :recheck_repositories].freeze OPERATIONS = [:resync_repositories, :reverify_repositories].freeze
def perform(operation, range) def perform(operation, range)
# TODO: This is a temporary workaround for backward compatibility
# to avoid jobs that have been already scheduled to fail.
# See https://gitlab.com/gitlab-org/gitlab-ee/issues/13318
if operation.to_sym == :recheck_repositories
operation = :reverify_repositories
end
case operation.to_sym case operation.to_sym
when :resync_repositories when :resync_repositories
resync_repositories(range) resync_repositories(range)
when :recheck_repositories when :reverify_repositories
recheck_repositories(range) reverify_repositories(range)
else else
fail_invalid_operation!(operation) fail_invalid_operation!(operation)
end end
...@@ -33,9 +40,9 @@ module Geo ...@@ -33,9 +40,9 @@ module Geo
end end
end end
def recheck_repositories(range) def reverify_repositories(range)
Geo::ProjectRegistry.with_range(range[0], range[1]).each_batch(of: BATCH_SIZE) do |batch| Geo::ProjectRegistry.with_range(range[0], range[1]).each_batch(of: BATCH_SIZE) do |batch|
batch.flag_repositories_for_recheck! batch.flag_repositories_for_reverify!
end end
end end
......
---
title: Geo - Rename recheck actions to reverify
merge_request: 14979
author:
type: other
...@@ -30,13 +30,13 @@ namespace :admin do ...@@ -30,13 +30,13 @@ namespace :admin do
resources :projects, only: [:index, :destroy] do resources :projects, only: [:index, :destroy] do
member do member do
post :recheck post :reverify
post :resync post :resync
post :force_redownload post :force_redownload
end end
collection do collection do
post :recheck_all post :reverify_all
post :resync_all post :resync_all
end end
end end
......
...@@ -12,7 +12,7 @@ module EE ...@@ -12,7 +12,7 @@ module EE
}.freeze }.freeze
WHITELISTED_GEO_ROUTES_TRACKING_DB = { WHITELISTED_GEO_ROUTES_TRACKING_DB = {
'admin/geo/projects' => %w{destroy resync recheck force_redownload resync_all recheck_all}, 'admin/geo/projects' => %w{destroy resync reverify force_redownload resync_all reverify_all},
'admin/geo/uploads' => %w{destroy} 'admin/geo/uploads' => %w{destroy}
}.freeze }.freeze
......
...@@ -118,8 +118,8 @@ describe Admin::Geo::ProjectsController, :geo do ...@@ -118,8 +118,8 @@ describe Admin::Geo::ProjectsController, :geo do
end end
end end
describe '#recheck' do describe '#reverify' do
subject { post :recheck, params: { id: synced_registry } } subject { post :reverify, params: { id: synced_registry } }
it_behaves_like 'license required' it_behaves_like 'license required'
...@@ -128,9 +128,9 @@ describe Admin::Geo::ProjectsController, :geo do ...@@ -128,9 +128,9 @@ describe Admin::Geo::ProjectsController, :geo do
stub_licensed_features(geo: true) stub_licensed_features(geo: true)
end end
it 'flags registry for recheck' do it 'flags registry for reverify' do
expect(subject).to redirect_to(admin_geo_projects_path) expect(subject).to redirect_to(admin_geo_projects_path)
expect(flash[:notice]).to include('is scheduled for re-check') expect(flash[:notice]).to include('is scheduled for re-verify')
expect(synced_registry.reload.pending_verification?).to be_truthy expect(synced_registry.reload.pending_verification?).to be_truthy
end end
end end
...@@ -154,8 +154,8 @@ describe Admin::Geo::ProjectsController, :geo do ...@@ -154,8 +154,8 @@ describe Admin::Geo::ProjectsController, :geo do
end end
end end
describe '#recheck_all' do describe '#reverify_all' do
subject { post :recheck_all } subject { post :reverify_all }
it_behaves_like 'license required' it_behaves_like 'license required'
...@@ -167,14 +167,14 @@ describe Admin::Geo::ProjectsController, :geo do ...@@ -167,14 +167,14 @@ describe Admin::Geo::ProjectsController, :geo do
it 'schedules a batch job' do it 'schedules a batch job' do
Sidekiq::Testing.fake! do Sidekiq::Testing.fake! do
expect { subject }.to change(Geo::Batch::ProjectRegistrySchedulerWorker.jobs, :size).by(1) expect { subject }.to change(Geo::Batch::ProjectRegistrySchedulerWorker.jobs, :size).by(1)
expect(Geo::Batch::ProjectRegistrySchedulerWorker.jobs.last['args']).to include('recheck_repositories') expect(Geo::Batch::ProjectRegistrySchedulerWorker.jobs.last['args']).to include('reverify_repositories')
end end
end end
it 'redirects back and display confirmation' do it 'redirects back and display confirmation' do
Sidekiq::Testing.inline! do Sidekiq::Testing.inline! do
expect(subject).to redirect_to(admin_geo_projects_path) expect(subject).to redirect_to(admin_geo_projects_path)
expect(flash[:notice]).to include('All projects are being scheduled for re-check') expect(flash[:notice]).to include('All projects are being scheduled for re-verify')
end end
end end
end end
......
...@@ -57,9 +57,9 @@ describe Gitlab::Middleware::ReadOnly do ...@@ -57,9 +57,9 @@ describe Gitlab::Middleware::ReadOnly do
it_behaves_like 'whitelisted request', :post, '/admin/geo/projects/1/resync' it_behaves_like 'whitelisted request', :post, '/admin/geo/projects/1/resync'
it_behaves_like 'whitelisted request', :post, '/admin/geo/projects/1/recheck' it_behaves_like 'whitelisted request', :post, '/admin/geo/projects/1/reverify'
it_behaves_like 'whitelisted request', :post, '/admin/geo/projects/recheck_all' it_behaves_like 'whitelisted request', :post, '/admin/geo/projects/reverify_all'
it_behaves_like 'whitelisted request', :post, '/admin/geo/projects/resync_all' it_behaves_like 'whitelisted request', :post, '/admin/geo/projects/resync_all'
......
...@@ -175,11 +175,11 @@ describe Geo::ProjectRegistry do ...@@ -175,11 +175,11 @@ describe Geo::ProjectRegistry do
end end
end end
describe '.flag_repositories_for_recheck!' do describe '.flag_repositories_for_reverify!' do
it 'modified record to a recheck state' do it 'modified record to a reverify state' do
registry = create(:geo_project_registry, :repository_verified) registry = create(:geo_project_registry, :repository_verified)
described_class.flag_repositories_for_recheck! described_class.flag_repositories_for_reverify!
expect(registry.reload).to have_attributes( expect(registry.reload).to have_attributes(
repository_verification_checksum_sha: nil, repository_verification_checksum_sha: nil,
...@@ -930,10 +930,10 @@ describe Geo::ProjectRegistry do ...@@ -930,10 +930,10 @@ describe Geo::ProjectRegistry do
end end
end end
describe '#flag_repository_for_recheck!' do describe '#flag_repository_for_reverify!' do
it 'modified record to a recheck state' do it 'modified record to a reverify state' do
registry = create(:geo_project_registry, :repository_verified) registry = create(:geo_project_registry, :repository_verified)
registry.flag_repository_for_recheck! registry.flag_repository_for_reverify!
expect(registry).to have_attributes( expect(registry).to have_attributes(
repository_verification_checksum_sha: nil, repository_verification_checksum_sha: nil,
...@@ -962,7 +962,7 @@ describe Geo::ProjectRegistry do ...@@ -962,7 +962,7 @@ describe Geo::ProjectRegistry do
end end
describe '#flag_repository_for_redownload!' do describe '#flag_repository_for_redownload!' do
it 'modified record to a recheck state' do it 'modified record to a redownload state' do
registry = create(:geo_project_registry, :repository_verified) registry = create(:geo_project_registry, :repository_verified)
registry.flag_repository_for_redownload! registry.flag_repository_for_redownload!
......
...@@ -13,8 +13,8 @@ describe 'EE-specific admin routing' do ...@@ -13,8 +13,8 @@ describe 'EE-specific admin routing' do
expect(delete("/admin/geo/projects/#{project_registry.id}")).to route_to('admin/geo/projects#destroy', id: project_registry.to_param) expect(delete("/admin/geo/projects/#{project_registry.id}")).to route_to('admin/geo/projects#destroy', id: project_registry.to_param)
end end
it 'routes post /:id/recheck to #recheck' do it 'routes post /:id/reverify to #reverify' do
expect(post("admin/geo/projects/#{project_registry.id}/recheck")).to route_to('admin/geo/projects#recheck', id: project_registry.to_param) expect(post("admin/geo/projects/#{project_registry.id}/reverify")).to route_to('admin/geo/projects#reverify', id: project_registry.to_param)
end end
it 'routes post /:id/resync to #resync' do it 'routes post /:id/resync to #resync' do
......
...@@ -19,10 +19,21 @@ RSpec.describe Geo::Batch::ProjectRegistrySchedulerWorker do ...@@ -19,10 +19,21 @@ RSpec.describe Geo::Batch::ProjectRegistrySchedulerWorker do
context 'when operation is :recheck_repositories' do context 'when operation is :recheck_repositories' do
let!(:registry) { create(:geo_project_registry, :repository_verified) } let!(:registry) { create(:geo_project_registry, :repository_verified) }
it 'schedules batches of repositories for recheck' do it 'schedules batches of repositories for reverify' do
Sidekiq::Testing.fake! do Sidekiq::Testing.fake! do
expect { subject.perform(:recheck_repositories) }.to change(Geo::Batch::ProjectRegistryWorker.jobs, :size).by(1) expect { subject.perform(:recheck_repositories) }.to change(Geo::Batch::ProjectRegistryWorker.jobs, :size).by(1)
expect(Geo::Batch::ProjectRegistryWorker.jobs.last['args']).to include('recheck_repositories') expect(Geo::Batch::ProjectRegistryWorker.jobs.last['args']).to include('reverify_repositories')
end
end
end
context 'when operation is :reverify_repositories' do
let!(:registry) { create(:geo_project_registry, :repository_verified) }
it 'schedules batches of repositories for reverify' do
Sidekiq::Testing.fake! do
expect { subject.perform(:reverify_repositories) }.to change(Geo::Batch::ProjectRegistryWorker.jobs, :size).by(1)
expect(Geo::Batch::ProjectRegistryWorker.jobs.last['args']).to include('reverify_repositories')
end end
end end
...@@ -30,7 +41,7 @@ RSpec.describe Geo::Batch::ProjectRegistrySchedulerWorker do ...@@ -30,7 +41,7 @@ RSpec.describe Geo::Batch::ProjectRegistrySchedulerWorker do
stub_exclusive_lease_taken(lease_key, timeout: lease_timeout) stub_exclusive_lease_taken(lease_key, timeout: lease_timeout)
Sidekiq::Testing.fake! do Sidekiq::Testing.fake! do
expect { subject.perform(:recheck_repositories) }.not_to change(Geo::Batch::ProjectRegistryWorker.jobs, :size) expect { subject.perform(:reverify_repositories) }.not_to change(Geo::Batch::ProjectRegistryWorker.jobs, :size)
end end
end end
end end
......
...@@ -17,7 +17,7 @@ RSpec.describe Geo::Batch::ProjectRegistryWorker do ...@@ -17,7 +17,7 @@ RSpec.describe Geo::Batch::ProjectRegistryWorker do
context 'when operation is :recheck_repositories' do context 'when operation is :recheck_repositories' do
let!(:registry) { create(:geo_project_registry, :repository_verified) } let!(:registry) { create(:geo_project_registry, :repository_verified) }
it 'flags repositories for recheck' do it 'flags repositories for reverify' do
Sidekiq::Testing.inline! do Sidekiq::Testing.inline! do
subject.perform(:recheck_repositories, range) subject.perform(:recheck_repositories, range)
end end
...@@ -26,6 +26,18 @@ RSpec.describe Geo::Batch::ProjectRegistryWorker do ...@@ -26,6 +26,18 @@ RSpec.describe Geo::Batch::ProjectRegistryWorker do
end end
end end
context 'when operation is :reverify_repositories' do
let!(:registry) { create(:geo_project_registry, :repository_verified) }
it 'flags repositories for reverify' do
Sidekiq::Testing.inline! do
subject.perform(:reverify_repositories, range)
end
expect(registry.reload.repository_verification_pending?).to be_truthy
end
end
context 'when operation is :resync_repositories' do context 'when operation is :resync_repositories' do
let!(:registry) { create(:geo_project_registry, :synced) } let!(:registry) { create(:geo_project_registry, :synced) }
......
...@@ -6685,10 +6685,10 @@ msgstr "" ...@@ -6685,10 +6685,10 @@ msgstr ""
msgid "Geo|%{name} is scheduled for forced re-download" msgid "Geo|%{name} is scheduled for forced re-download"
msgstr "" msgstr ""
msgid "Geo|%{name} is scheduled for re-check" msgid "Geo|%{name} is scheduled for re-sync"
msgstr "" msgstr ""
msgid "Geo|%{name} is scheduled for re-sync" msgid "Geo|%{name} is scheduled for re-verify"
msgstr "" msgstr ""
msgid "Geo|All" msgid "Geo|All"
...@@ -6697,10 +6697,10 @@ msgstr "" ...@@ -6697,10 +6697,10 @@ msgstr ""
msgid "Geo|All projects" msgid "Geo|All projects"
msgstr "" msgstr ""
msgid "Geo|All projects are being scheduled for re-check" msgid "Geo|All projects are being scheduled for re-sync"
msgstr "" msgstr ""
msgid "Geo|All projects are being scheduled for re-sync" msgid "Geo|All projects are being scheduled for re-verify"
msgstr "" msgstr ""
msgid "Geo|Batch operations" msgid "Geo|Batch operations"
...@@ -6790,12 +6790,6 @@ msgstr "" ...@@ -6790,12 +6790,6 @@ msgstr ""
msgid "Geo|Re-verification interval" msgid "Geo|Re-verification interval"
msgstr "" msgstr ""
msgid "Geo|Recheck"
msgstr ""
msgid "Geo|Recheck all projects"
msgstr ""
msgid "Geo|Redownload" msgid "Geo|Redownload"
msgstr "" msgstr ""
...@@ -6814,6 +6808,12 @@ msgstr "" ...@@ -6814,6 +6808,12 @@ msgstr ""
msgid "Geo|Retry count" msgid "Geo|Retry count"
msgstr "" msgstr ""
msgid "Geo|Reverify"
msgstr ""
msgid "Geo|Reverify all projects"
msgstr ""
msgid "Geo|Select groups to replicate." msgid "Geo|Select groups to replicate."
msgstr "" msgstr ""
......
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