Commit 22d8f04c authored by Dylan Griffith's avatar Dylan Griffith

Merge branch '235883-user-data-export-api' into 'master'

Resolve "Add API endpoint for generating the user data export file"

See merge request gitlab-org/gitlab!42026
parents 308c7ba9 d25e82aa
# frozen_string_literal: true
module Admin
module LicenseRequest
private
def license
@license ||= begin
License.reset_current
License.reset_future_dated
License.current
end
end
def require_license
return if license
flash.keep
redirect_to new_admin_license_path
end
end
end
# frozen_string_literal: true
module Admin
module Licenses
class UsageExportsController < Admin::ApplicationController
include Admin::LicenseRequest
before_action :require_license, only: :show
def show
historical_data = HistoricalData.in_license_term(license)
respond_to do |format|
format.csv do
csv_data = HistoricalUserData::CsvService.new(historical_data).generate
send_data(csv_data, type: 'text/csv; charset=utf-8', filename: 'license_usage.csv')
end
end
end
end
end
end
# frozen_string_literal: true # frozen_string_literal: true
class Admin::LicensesController < Admin::ApplicationController class Admin::LicensesController < Admin::ApplicationController
include Admin::LicenseRequest
before_action :license, only: [:show, :download, :destroy] before_action :license, only: [:show, :download, :destroy]
before_action :require_license, only: [:download, :destroy] before_action :require_license, only: [:download, :destroy]
...@@ -62,21 +64,6 @@ class Admin::LicensesController < Admin::ApplicationController ...@@ -62,21 +64,6 @@ class Admin::LicensesController < Admin::ApplicationController
private private
def license
@license ||= begin
License.reset_current
License.reset_future_dated
License.current
end
end
def require_license
return if license
flash.keep
redirect_to new_admin_license_path
end
def build_license def build_license
@license ||= License.new(data: params[:trial_key]) @license ||= License.new(data: params[:trial_key])
end end
......
...@@ -29,5 +29,12 @@ class HistoricalData < ApplicationRecord ...@@ -29,5 +29,12 @@ class HistoricalData < ApplicationRecord
HistoricalData.during(from..to).maximum(:active_user_count) || 0 HistoricalData.during(from..to).maximum(:active_user_count) || 0
end end
def in_license_term(license)
start_date = license.starts_at
expiration_date = license.expires_at || Date.current
HistoricalData.during(start_date..expiration_date)
end
end end
end end
...@@ -35,8 +35,8 @@ module HistoricalUserData ...@@ -35,8 +35,8 @@ module HistoricalUserData
CSV.generate do |csv| CSV.generate do |csv|
csv << ['License Key', license.data] csv << ['License Key', license.data]
csv << ['Email', license.licensee['Email']] csv << ['Email', license.licensee['Email']]
csv << ['License Start Date', license.starts_at.to_s(:csv)] csv << ['License Start Date', license.starts_at&.to_s(:csv)]
csv << ['License End Date', license.expires_at.to_s(:csv)] csv << ['License End Date', license.expires_at&.to_s(:csv)]
csv << ['Company', license.licensee['Company']] csv << ['Company', license.licensee['Company']]
csv << ['Generated At', Time.current.to_s(:csv)] csv << ['Generated At', Time.current.to_s(:csv)]
csv << [''] csv << ['']
......
...@@ -29,6 +29,8 @@ namespace :admin do ...@@ -29,6 +29,8 @@ namespace :admin do
resource :license, only: [:show, :new, :create, :destroy] do resource :license, only: [:show, :new, :create, :destroy] do
get :download, on: :member get :download, on: :member
resource :usage_export, controller: 'licenses/usage_exports', only: [:show]
end end
# using `only: []` to keep duplicate routes from being created # using `only: []` to keep duplicate routes from being created
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Admin::Licenses::UsageExportsController do
let(:admin) { create(:admin) }
before do
sign_in(admin)
end
describe 'GET show' do
subject { get :show, format: :csv }
context 'with no current license' do
before do
allow(License).to receive(:current).and_return(nil)
allow(HistoricalUserData::CsvService).to receive(:new).and_call_original
end
it 'redirects the user' do
subject
expect(response).to have_gitlab_http_status(:redirect)
end
it 'does not attempt to create the CSV' do
subject
expect(HistoricalUserData::CsvService).not_to have_received(:new)
end
end
context 'with a current license' do
let(:csv_data) do
<<~CSV
Date,Active User Count
2020-08-26,1
2020-08-27,2
CSV
end
let(:csv_service) { instance_double(HistoricalUserData::CsvService, generate: csv_data) }
let(:historical_data_relation) { :historical_data_relation }
before do
allow(HistoricalData).to receive(:in_license_term).with(License.current).and_return(historical_data_relation)
allow(HistoricalUserData::CsvService).to receive(:new).with(historical_data_relation).and_return(csv_service)
end
it 'returns a csv file in response' do
subject
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Type']).to eq('text/csv; charset=utf-8')
end
it 'returns the expected response body' do
subject
expect(CSV.parse(response.body)).to eq([
['Date', 'Active User Count'],
%w[2020-08-26 1],
%w[2020-08-27 2]
])
end
end
end
end
...@@ -21,7 +21,7 @@ FactoryBot.define do ...@@ -21,7 +21,7 @@ FactoryBot.define do
starts_at { Date.new(1970, 1, 1) } starts_at { Date.new(1970, 1, 1) }
expires_at { Date.current + 11.months } expires_at { Date.current + 11.months }
block_changes_at { expires_at + 2.weeks } block_changes_at { expires_at ? expires_at + 2.weeks : nil }
notify_users_at { expires_at } notify_users_at { expires_at }
notify_admins_at { expires_at } notify_admins_at { expires_at }
......
...@@ -136,4 +136,44 @@ RSpec.describe HistoricalData do ...@@ -136,4 +136,44 @@ RSpec.describe HistoricalData do
end end
end end
end end
describe '.in_license_term' do
let_it_be(:now) { DateTime.new(2014, 12, 15) }
let_it_be(:license) do
create_current_license(
starts_at: Date.new(2014, 7, 1),
expires_at: Date.new(2014, 12, 31)
)
end
before_all do
described_class.create!(date: license.starts_at - 1.day, active_user_count: 1)
described_class.create!(date: license.expires_at + 1.day, active_user_count: 2)
described_class.create!(date: now - 1.year - 1.day, active_user_count: 3)
described_class.create!(date: now + 1.day, active_user_count: 4)
end
around do |example|
travel_to(now) { example.run }
end
context 'with a license that has a start and end date' do
it 'returns correct number of records within the license range' do
expect(described_class.in_license_term(license).count).to eq(7)
end
end
context 'with a license that has no end date' do
let_it_be(:license) do
create_current_license(
starts_at: Date.new(2014, 7, 1),
expires_at: nil
)
end
it 'returns correct number of records within the past year' do
expect(described_class.in_license_term(license).count).to eq(6)
end
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