Added designs importer

Necessary to handle the validation and importing of data into the database for a design (screen template).

Milestone: minor
This commit is contained in:
Brooke Kuhlmann
2026-08-12 11:42:35 -06:00
parent a37e1acbe5
commit 2f33d0b791
2 changed files with 121 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
# frozen_string_literal: true
require "core"
require "dry/monads"
require "initable"
require "pipeable"
require "yaml"
module Terminus
module Aspects
module Designs
# Imports (creates) screen template from zip file.
class Importer
include Deps["aspects.unzipper", :logger, repository: "repositories.screen_template"]
include Initable[
key_map: {
"configuration.yml" => :configuration,
"index.html.liquid" => :content
},
problem: Aspects::Errors::Problem
]
include Dry::Monads[:result]
include Pipeable
def initialize(
schema: Schemas::Designs::Import,
error_joiner: Aspects::Errors::ResultJoiner,
**
)
@schema = schema
@error_joiner = error_joiner
super(**)
end
def call io
process io
rescue ROM::SQL::UniqueConstraintError => error
Failure problem.duplicate(error.message, nil).detail
end
private
attr_reader :schema, :error_joiner
def process io
pipe(
unzipper.call(io),
fmap { |entries| transform entries },
validate(schema),
amap { error_joiner.call "Import", it },
fmap { create it.to_h }
)
end
def transform entries
entries.transform_keys!(key_map).then { {**it, **YAML.load(it[:configuration])} }
end
def create attributes
repository.create(attributes).tap { |screen_template| log screen_template }
end
def log screen_template
logger.debug do
{tags: [{screen_template_id: screen_template.id}], message: "Imported design."}
end
end
end
end
end
end
+50
View File
@@ -0,0 +1,50 @@
# frozen_string_literal: true
require "hanami_helper"
RSpec.describe Terminus::Aspects::Designs::Importer, :db do
subject(:creator) { described_class.new }
describe "#call" do
let :io do
manifest = {"configuration.yml" => configuration, "index.html.liquid" => "<h1>Test</h1>"}
Terminus::Aspects::Zipper.new.call(manifest).value!
end
let :configuration do
<<~CONTENT
version: 1.2.3
name: test
label: Test
CONTENT
end
it "creates screen template" do
relation = Hanami.app["relations.screen_template"]
expectation = proc { creator.call io }
count = proc { relation.count }
expect(&expectation).to change(&count).by(1)
end
it "answers success" do
expect(creator.call(io)).to match(Success(kind_of(Terminus::Structs::ScreenTemplate)))
end
context "with invalid configuration" do
let(:configuration) { "version: 1.2.3" }
it "answers failure configuration is missing keys" do
expect(creator.call(io)).to be_failure("Import name is missing and label is missing.")
end
end
it "answers failure when screen template isn't unique" do
Factory[:screen_template, name: "test"]
expect(creator.call(io)).to be_failure(
%(Name must be unique. Please use a value other than "test".)
)
end
end
end