Skip to content
代码片段 群组 项目
未验证 提交 4dff8c5e 编辑于 作者: Bishwa Hang Rai's avatar Bishwa Hang Rai 提交者: GitLab
浏览文件

Add UserActivity class

This is a new ee only service class to track
members activity using new model SeatAssignment

EE: true
Changelog: added
上级 cc23d565
No related branches found
No related tags found
无相关合并请求
......@@ -6,5 +6,12 @@ class SeatAssignment < ApplicationRecord
belongs_to :user, optional: false
validates :namespace_id, uniqueness: { scope: :user_id }
scope :by_namespace, ->(namespace) { where(namespace: namespace) }
scope :by_user, ->(user) { where(user: user) }
def self.find_by_namespace_and_user(namespace, user)
by_namespace(namespace).by_user(user).first
end
end
end
# frozen_string_literal: true
module GitlabSubscriptions
module Members
class ActivityService
include ExclusiveLeaseGuard
def initialize(user, namespace)
@user = user
@namespace = namespace&.root_ancestor
end
def execute
return ServiceResponse.error(message: 'Invalid params') unless namespace&.group_namespace? && user
try_obtain_lease do
if seat_assignment
seat_assignment.update!(last_activity_on: Time.current)
else
GitlabSubscriptions::SeatAssignment.create!(
namespace: namespace, user: user, last_activity_on: Time.current
)
end
end
ServiceResponse.success(message: 'Member activity tracked')
end
private
attr_reader :user, :namespace
def lease_timeout
(Time.current.end_of_day - Time.current).to_i
end
# Used by ExclusiveLeaseGuard
# do not update the record, if it has been already updated within the last lease_timeout
def lease_release?
false
end
def lease_key
"gitlab_subscriptions:members_activity_event:#{namespace.id}:#{user.id}"
end
def seat_assignment
@seat_assignment ||= GitlabSubscriptions::SeatAssignment.find_by_namespace_and_user(namespace, user)
end
end
end
end
......@@ -2,7 +2,15 @@
FactoryBot.define do
factory :gitlab_subscription_seat_assignment, class: 'GitlabSubscriptions::SeatAssignment' do
namespace
namespace { association(:group) }
user
trait :active do
last_activity_on { 1.day.ago }
end
trait :dormant do
last_activity_on { 91.days.ago }
end
end
end
......@@ -3,6 +3,10 @@
require 'spec_helper'
RSpec.describe GitlabSubscriptions::SeatAssignment, feature_category: :seat_cost_management do
let_it_be(:namespace) { create(:group) }
let_it_be(:user) { create(:user) }
let_it_be(:extra_dummy_record) { create(:gitlab_subscription_seat_assignment) }
subject { build(:gitlab_subscription_seat_assignment) }
describe 'associations' do
......@@ -13,4 +17,30 @@
describe 'validations' do
it { is_expected.to validate_uniqueness_of(:namespace_id).scoped_to(:user_id) }
end
describe 'scopes' do
describe '.by_namespace' do
it 'returns records filtered by namespace' do
result = create(:gitlab_subscription_seat_assignment, namespace: namespace)
expect(described_class.by_namespace(namespace)).to match_array(result)
end
end
describe '.by_user' do
it 'returns records filtered by namespace' do
result = create(:gitlab_subscription_seat_assignment, user: user)
expect(described_class.by_user(user)).to match_array(result)
end
end
end
describe '.find_by_namespace_and_user' do
it 'returns single record by namespace and user' do
result = create(:gitlab_subscription_seat_assignment, user: user, namespace: namespace)
expect(described_class.find_by_namespace_and_user(namespace, user)).to eq(result)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSubscriptions::Members::ActivityService, :clean_gitlab_redis_shared_state, feature_category: :seat_cost_management do
include ExclusiveLeaseHelpers
let_it_be(:user) { create(:user) }
let_it_be(:namespace) { create(:group) }
let(:lease_key) { "gitlab_subscriptions:members_activity_event:#{namespace.id}:#{user.id}" }
let(:instance) { described_class.new(user, namespace) }
describe '#execute' do
subject(:execute) { instance.execute }
describe 'with valid params', :freeze_time do
it 'create a new seat assignment record' do
expect do
expect(execute).to be_success
end.to change {
GitlabSubscriptions::SeatAssignment.where(
namespace: namespace, user: user, last_activity_on: Time.current
).count
}
end
it 'updates the existing seat_assignment record' do
seat_assignment = create(:gitlab_subscription_seat_assignment, namespace: namespace, user: user)
expect do
expect(execute).to be_success
end.to change { seat_assignment.reload.last_activity_on }
.from(nil).to(Time.current)
end
context 'with project belonging to a group' do
let(:namespace) { build(:project, :in_group) }
it 'returns success' do
expect do
expect(execute).to be_success
end.to change { GitlabSubscriptions::SeatAssignment.count }.by(1)
end
end
it 'tries to obtain a lease' do
ttl = (Time.current.end_of_day - Time.current).to_i
expect_to_obtain_exclusive_lease(lease_key, timeout: ttl)
expect(execute).to be_success
end
context 'when a lease cannot be obtained' do
it 'returns success, without updating any record' do
stub_exclusive_lease_taken(lease_key)
expect(instance).not_to receive(:seat_assignment)
expect(execute).to be_success
end
end
end
shared_examples 'returns an error' do
it do
response = execute
expect(response).to be_error
expect(response.message).to eq('Invalid params')
end
end
context 'with no namespace' do
let(:namespace) { nil }
it_behaves_like 'returns an error'
end
context 'with namespace not belonging to a group' do
let(:namespace) { create(:user_namespace) }
it_behaves_like 'returns an error'
end
context 'with no user' do
let(:user) { nil }
it_behaves_like 'returns an error'
end
end
end
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册