Commit 04fabe2a authored by Peter Leitzen's avatar Peter Leitzen

Merge branch '273470-create-csv-exports-table' into 'master'

Migration and model changes for User permission uploads

See merge request gitlab-org/gitlab!47846
parents 70f58e6d fd1416fa
---
title: Adds migration for user permission uploads
merge_request: 47846
author:
type: added
# frozen_string_literal: true
class CreateUserPermissionExportUploads < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
with_lock_retries do
unless table_exists?(:user_permission_export_uploads)
create_table :user_permission_export_uploads do |t|
t.timestamps_with_timezone null: false
t.references :user, foreign_key: { on_delete: :cascade }, index: false, null: false
t.integer :file_store
t.integer :status, limit: 2, null: false, default: 0
t.text :file
t.index [:user_id, :status]
end
end
end
add_text_limit :user_permission_export_uploads, :file, 255
end
def down
with_lock_retries do
drop_table :user_permission_export_uploads
end
end
end
ecec9923058e58a5279f75dd9c2ff61263f187a1d893bb84241c57a4061dadf8
\ No newline at end of file
......@@ -16884,6 +16884,26 @@ CREATE TABLE user_interacted_projects (
project_id integer NOT NULL
);
CREATE TABLE user_permission_export_uploads (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
user_id bigint NOT NULL,
file_store integer,
status smallint DEFAULT 0 NOT NULL,
file text,
CONSTRAINT check_1956806648 CHECK ((char_length(file) <= 255))
);
CREATE SEQUENCE user_permission_export_uploads_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE user_permission_export_uploads_id_seq OWNED BY user_permission_export_uploads.id;
CREATE TABLE user_preferences (
id integer NOT NULL,
user_id integer NOT NULL,
......@@ -18357,6 +18377,8 @@ ALTER TABLE ONLY user_custom_attributes ALTER COLUMN id SET DEFAULT nextval('use
ALTER TABLE ONLY user_details ALTER COLUMN user_id SET DEFAULT nextval('user_details_user_id_seq'::regclass);
ALTER TABLE ONLY user_permission_export_uploads ALTER COLUMN id SET DEFAULT nextval('user_permission_export_uploads_id_seq'::regclass);
ALTER TABLE ONLY user_preferences ALTER COLUMN id SET DEFAULT nextval('user_preferences_id_seq'::regclass);
ALTER TABLE ONLY user_statuses ALTER COLUMN user_id SET DEFAULT nextval('user_statuses_user_id_seq'::regclass);
......@@ -19808,6 +19830,9 @@ ALTER TABLE ONLY user_highest_roles
ALTER TABLE ONLY user_interacted_projects
ADD CONSTRAINT user_interacted_projects_pkey PRIMARY KEY (project_id, user_id);
ALTER TABLE ONLY user_permission_export_uploads
ADD CONSTRAINT user_permission_export_uploads_pkey PRIMARY KEY (id);
ALTER TABLE ONLY user_preferences
ADD CONSTRAINT user_preferences_pkey PRIMARY KEY (id);
......@@ -22226,6 +22251,8 @@ CREATE INDEX index_user_highest_roles_on_user_id_and_highest_access_level ON use
CREATE INDEX index_user_interacted_projects_on_user_id ON user_interacted_projects USING btree (user_id);
CREATE INDEX index_user_permission_export_uploads_on_user_id_and_status ON user_permission_export_uploads USING btree (user_id, status);
CREATE INDEX index_user_preferences_on_gitpod_enabled ON user_preferences USING btree (gitpod_enabled);
CREATE UNIQUE INDEX index_user_preferences_on_user_id ON user_preferences USING btree (user_id);
......@@ -24298,6 +24325,9 @@ ALTER TABLE ONLY user_preferences
ALTER TABLE ONLY sentry_issues
ADD CONSTRAINT fk_rails_a6a9612965 FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
ALTER TABLE ONLY user_permission_export_uploads
ADD CONSTRAINT fk_rails_a7130085e3 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
ALTER TABLE ONLY repository_languages
ADD CONSTRAINT fk_rails_a750ec87a8 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
......
......@@ -66,6 +66,8 @@ module EE
belongs_to :managing_group, class_name: 'Group', optional: true, inverse_of: :managed_users
has_many :user_permission_export_uploads
scope :not_managed, ->(group: nil) {
scope = where(managing_group_id: nil)
scope = scope.or(where.not(managing_group_id: group.id)) if group
......
# frozen_string_literal: true
class UserPermissionExportUpload < ApplicationRecord
include WithUploads
include ObjectStorage::BackgroundMove
belongs_to :user, -> { where(admin: true) }
mount_uploader :file, AttachmentUploader
validates :status, presence: true
validates :file, length: { maximum: 255 }
validate :file_presence, if: :finished?
state_machine :status, initial: :created do
event :start do
transition created: :running
end
event :finish do
transition running: :finished
end
event :failed do
transition [:created, :running] => :failed
end
state :created, value: 0
state :running, value: 1
state :finished, value: 2
state :failed, value: 3
end
private
def file_presence
errors.add(:file, "can't be blank") unless file.present?
end
end
# frozen_string_literal: true
FactoryBot.define do
factory :user_permission_export_upload do
user
created
trait :created do
status { 0 }
end
trait :running do
status { 1 }
end
trait :finished do
status { 2 }
file { fixture_file_upload('spec/fixtures/csv_comma.csv') }
end
trait :failed do
status { 3 }
end
end
end
......@@ -27,6 +27,7 @@ RSpec.describe User do
it { is_expected.to have_many(:security_dashboard_projects) }
it { is_expected.to have_many(:board_preferences) }
it { is_expected.to have_many(:boards_epic_user_preferences).class_name('Boards::EpicUserPreference') }
it { is_expected.to have_many(:user_permission_export_uploads) }
end
describe 'nested attributes' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe UserPermissionExportUpload, type: :model do
let_it_be(:upload) { build(:user_permission_export_upload) }
subject { upload }
describe 'associations' do
it { is_expected.to belong_to(:user).conditions(admin: true) }
end
describe 'validations' do
it { is_expected.to validate_presence_of(:status) }
context 'when status is finished' do
before do
allow(upload).to receive(:finished?).and_return true
end
it 'validates file presence' do
expect(upload).not_to be_valid
expect(upload.errors.full_messages).to include("File can't be blank")
end
end
end
describe 'state transitions' do
using RSpec::Parameterized::TableSyntax
where(:status, :can_start, :can_finish, :can_fail) do
0 | true | false | true
1 | false | true | true
2 | false | false | false
3 | false | false | false
end
with_them do
it 'adheres to state machine rules', :aggregate_failures do
upload.status = status
expect(upload.can_start?).to eq(can_start)
expect(upload.can_finish?).to eq(can_finish)
expect(upload.can_failed?).to eq(can_fail)
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