Commit 007c3ded authored by Reuben Pereira's avatar Reuben Pereira

Add helper for displaying upcoming reconciliation alert

The helper checks:
- The current_user's permissions.
- Whether there is an upcoming reconciliation recorded.
- Whether the current_user has already seen and dismissed this alert.
parent 786a4e5f
# frozen_string_literal: true
module GitlabSubscriptions
module UpcomingReconciliationHelper
include Gitlab::Utils::StrongMemoize
COOKIE_KEY_PREFIX = 'hide_upcoming_reconciliation_alert'
def upcoming_reconciliation_hash(namespace = nil)
return {} unless display_upcoming_reconciliation_alert?(namespace)
reconciliation = upcoming_reconciliation(namespace&.id)
{
reconciliation_date: reconciliation.next_reconciliation_date.to_s,
cookie_key: cookie_key(reconciliation, namespace&.id)
}
end
def display_upcoming_reconciliation_alert?(namespace = nil)
return false unless has_permissions?(namespace)
reconciliation = upcoming_reconciliation(namespace&.id)
return false unless reconciliation&.display_alert?
return false if alert_dismissed?(reconciliation, namespace&.id)
true
end
private
def upcoming_reconciliation(namespace_id)
strong_memoize(:upcoming_reconciliation) do
UpcomingReconciliation.next(namespace_id)
end
end
def alert_dismissed?(reconciliation, namespace_id)
key = cookie_key(reconciliation, namespace_id)
cookies[key] == 'true'
end
def cookie_key(reconciliation, namespace_id)
if saas?
"#{COOKIE_KEY_PREFIX}_#{current_user.id}_#{namespace_id}_#{reconciliation.next_reconciliation_date}"
else
"#{COOKIE_KEY_PREFIX}_#{current_user.id}_#{reconciliation.next_reconciliation_date}"
end
end
def has_permissions?(namespace)
if saas?
user_can_admin?(namespace)
else
user_is_admin?
end
end
def user_is_admin?
current_user.can_admin_all_resources?
end
def user_can_admin?(namespace)
Ability.allowed?(current_user, :admin_namespace, namespace)
end
def saas?
::Gitlab.com?
end
end
end
......@@ -6,8 +6,14 @@ module GitlabSubscriptions
validates :namespace, uniqueness: true, presence: { if: proc { ::Gitlab.com? } }
def self.for_self_managed
self.find_by(namespace_id: nil)
def self.next(namespace_id = nil)
if ::Gitlab.com?
return unless namespace_id
self.find_by(namespace_id: namespace_id)
else
self.find_by(namespace_id: nil)
end
end
def display_alert?
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSubscriptions::UpcomingReconciliationHelper do
include AdminModeHelper
before do
allow(helper).to receive(:current_user).and_return(user)
end
context 'with namespace' do
let_it_be(:user) { create(:user) }
let_it_be(:namespace) { create(:namespace, owner: user) }
let_it_be(:upcoming_reconciliation) { create(:upcoming_reconciliation, :saas, namespace: namespace) }
let(:cookie_key) do
"hide_upcoming_reconciliation_alert_#{user.id}_#{namespace.id}_#{upcoming_reconciliation.next_reconciliation_date}"
end
before do
allow(::Gitlab).to receive(:com?).and_return(true)
end
it 'returns true and reconciliation date' do
expect(helper.display_upcoming_reconciliation_alert?(namespace)).to eq(true)
expect(helper.upcoming_reconciliation_hash(namespace)).to eq(
reconciliation_date: upcoming_reconciliation.next_reconciliation_date.to_s,
cookie_key: cookie_key
)
end
context 'with a group' do
let_it_be(:group) { create(:group) }
let_it_be(:upcoming_reconciliation2) { create(:upcoming_reconciliation, :saas, namespace: group) }
let(:cookie_key) do
"hide_upcoming_reconciliation_alert_#{user.id}_#{group.id}_#{upcoming_reconciliation.next_reconciliation_date}"
end
before do
group.add_owner(user)
end
it 'returns true and reconciliation date' do
expect(helper.display_upcoming_reconciliation_alert?(group)).to eq(true)
expect(helper.upcoming_reconciliation_hash(group)).to eq(
reconciliation_date: upcoming_reconciliation2.next_reconciliation_date.to_s,
cookie_key: cookie_key
)
end
end
context 'when not gitlab.com' do
it 'returns false and empty hash' do
allow(::Gitlab).to receive(:com?).and_return(false)
expect(helper.display_upcoming_reconciliation_alert?(namespace)).to eq(false)
expect(helper.upcoming_reconciliation_hash(namespace)).to eq({})
end
end
context 'when user is not owner' do
before do
allow(helper).to receive(:current_user).and_return(create(:user))
end
it 'returns false and empty hash' do
expect(helper.display_upcoming_reconciliation_alert?(namespace)).to eq(false)
expect(helper.upcoming_reconciliation_hash(namespace)).to eq({})
end
end
context 'when namespace does not exist in upcoming_reconciliations table' do
before do
upcoming_reconciliation.destroy!
end
it 'returns false and empty hash' do
expect(helper.display_upcoming_reconciliation_alert?(namespace)).to eq(false)
expect(helper.upcoming_reconciliation_hash(namespace)).to eq({})
end
end
end
context 'without namespace' do
let_it_be(:upcoming_reconciliation) { create(:upcoming_reconciliation, :self_managed) }
let_it_be(:user) { create(:user, :admin) }
let(:cookie_key) do
"hide_upcoming_reconciliation_alert_#{user.id}_#{upcoming_reconciliation.next_reconciliation_date}"
end
it 'returns true and reconciliation date' do
enable_admin_mode!(user)
expect(helper.display_upcoming_reconciliation_alert?).to eq(true)
expect(helper.upcoming_reconciliation_hash).to eq(
reconciliation_date: upcoming_reconciliation.next_reconciliation_date.to_s,
cookie_key: cookie_key
)
end
context 'when not in admin mode or user is not admin' do
it 'returns false and empty hash' do
expect(helper.display_upcoming_reconciliation_alert?).to eq(false)
expect(helper.upcoming_reconciliation_hash).to eq({})
end
end
context 'when there is no row in upcoming_reconciliations table' do
before do
upcoming_reconciliation.destroy!
end
it 'returns false and empty hash' do
expect(helper.display_upcoming_reconciliation_alert?).to eq(false)
expect(helper.upcoming_reconciliation_hash).to eq({})
end
end
context 'when gitlab.com' do
it 'returns false and empty hash' do
allow(::Gitlab).to receive(:com?).and_return(true)
enable_admin_mode!(user)
expect(helper.display_upcoming_reconciliation_alert?).to eq(false)
expect(helper.upcoming_reconciliation_hash).to eq({})
end
end
end
end
......@@ -65,15 +65,39 @@ RSpec.describe GitlabSubscriptions::UpcomingReconciliation do
end
end
describe '.for_self_managed' do
it 'returns row where namespace_id is nil' do
upcoming_reconciliation = create(:upcoming_reconciliation, :self_managed)
describe '.next' do
context 'when self managed' do
it 'returns row where namespace_id is nil' do
upcoming_reconciliation = create(:upcoming_reconciliation, :self_managed)
expect(described_class.for_self_managed).to eq(upcoming_reconciliation)
expect(described_class.next).to eq(upcoming_reconciliation)
end
it 'returns nil when there is no row with namespace_id nil' do
expect(described_class.next).to eq(nil)
end
end
it 'returns nil when there is no row with namespace_id nil' do
expect(described_class.for_self_managed).to eq(nil)
context 'when SaaS' do
let_it_be(:upcoming_reconciliation) { create(:upcoming_reconciliation, :saas) }
let(:namespace_id) { upcoming_reconciliation.namespace_id }
before do
allow(::Gitlab).to receive(:com?).and_return(true)
end
it 'returns row for given namespace' do
expect(described_class.next(namespace_id)).to eq(upcoming_reconciliation)
end
it 'returns nil when there is no row with given namespace_id' do
expect(described_class.next(non_existing_record_id)).to eq(nil)
end
it 'returns nil if namespace_id is nil' do
expect(described_class.next).to eq(nil)
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment