Skip to content

Commit 4ba1b4d

Browse files
Sad-lieFaheemvc
andauthored
fix: template asset layout import and wraft json export (wraft#135)
* fix: template asset with newer asset module * fix: template asset export * fix: template validation * fix: imported data template serialized issue * chore: remove redundant code and comments --------- Co-authored-by: Faheem vc <[email protected]>
1 parent 05fcf2e commit 4ba1b4d

3 files changed

Lines changed: 178 additions & 67 deletions

File tree

lib/wraft_doc/template_assets/template_assets.ex

Lines changed: 167 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ defmodule WraftDoc.TemplateAssets do
670670

671671
defp get_theme_font_file_entries(entries) do
672672
Enum.filter(entries, fn entry ->
673-
case Regex.run(~r/^theme\/.*-(?<style>\w+)\.(otf|ttf)$/i, entry.file_name) do
673+
case Regex.run(~r/^fonts\/.*-(?<style>\w+)\.(otf|ttf)$/i, entry.file_name) do
674674
[_, style, _] when style in @font_style_name -> true
675675
_ -> false
676676
end
@@ -753,18 +753,20 @@ defmodule WraftDoc.TemplateAssets do
753753
frame_id
754754
) do
755755
with %Engine{id: engine_id} <- get_engine(engine),
756-
asset_id <- prepare_layout_assets(entries, file_path, downloaded_file, current_user),
757-
params <- prepare_layout_attrs(layouts, engine_id, asset_id, frame_id),
756+
asset_params <-
757+
prepare_layout_assets_params(entries, file_path, downloaded_file),
758+
params <- prepare_layout_attrs(layouts, engine_id, frame_id),
758759
%Engine{} = engine <- Frames.get_engine_by_frame_type(params),
759-
%Layout{} = layout <- Layouts.create_layout(current_user, engine, params) do
760+
{:ok, %{layout: layout}} <-
761+
Layouts.create_layout(current_user, engine, Map.merge(params, asset_params)) do
760762
{:ok, layout}
761763
end
762764
end
763765

764-
defp prepare_layout_assets(entries, file_path, downloaded_file, current_user) do
766+
defp prepare_layout_assets_params(entries, file_path, downloaded_file) do
765767
entries
766768
|> get_layout_file_entry(file_path)
767-
|> extract_and_prepare_layout_asset(downloaded_file, current_user)
769+
|> extract_and_prepare_layout_asset(downloaded_file)
768770
end
769771

770772
defp get_pdf_asset_path(assets, type) do
@@ -773,14 +775,13 @@ defmodule WraftDoc.TemplateAssets do
773775
end)["path"]
774776
end
775777

776-
defp prepare_layout_attrs(layout, engine_id, asset_id, frame_id) do
778+
defp prepare_layout_attrs(layout, engine_id, frame_id) do
777779
%{
778780
"name" => layout["name"],
779781
"meta" => layout["meta"],
780782
"description" => layout["description"],
781783
"slug" => layout["slug"],
782784
"engine_id" => engine_id,
783-
"assets" => asset_id,
784785
"width" => 40,
785786
"height" => 40,
786787
"unit" => "cm",
@@ -794,12 +795,10 @@ defmodule WraftDoc.TemplateAssets do
794795
end)
795796
end
796797

797-
defp extract_and_prepare_layout_asset(entry, downloaded_zip_file, current_user) do
798+
defp extract_and_prepare_layout_asset(entry, downloaded_zip_file) do
798799
with {:ok, content} <- FileHelper.extract_file_content(downloaded_zip_file, entry.file_name),
799-
{:ok, temp_file_path} <- write_temp_file(content),
800-
asset_params <- prepare_layout_asset_params(entry, temp_file_path, current_user),
801-
{:ok, asset} <- Assets.create_asset(current_user, asset_params) do
802-
asset.id
800+
{:ok, temp_file_path} <- write_temp_file(content) do
801+
prepare_layout_asset_params(entry, temp_file_path)
803802
else
804803
error ->
805804
Logger.error(
@@ -810,16 +809,15 @@ defmodule WraftDoc.TemplateAssets do
810809
end
811810
end
812811

813-
defp prepare_layout_asset_params(entry, temp_file_path, current_user) do
812+
defp prepare_layout_asset_params(entry, temp_file_path) do
814813
%{
815-
"name" => Path.basename(entry.file_name),
814+
"asset_name" => Path.basename(entry.file_name),
816815
"type" => "layout",
817816
"file" => %Plug.Upload{
818817
filename: Path.basename(entry.file_name),
819818
content_type: get_file_type(entry.file_name),
820819
path: temp_file_path
821-
},
822-
"creator_id" => current_user.id
820+
}
823821
}
824822
end
825823

@@ -916,7 +914,7 @@ defmodule WraftDoc.TemplateAssets do
916914
defp get_data_template_prosemirror(downloaded_file) do
917915
with {:ok, template_json} <-
918916
FileHelper.extract_file_content(downloaded_file, "template.json"),
919-
serialized_prosemirror <- Jason.decode!(template_json) do
917+
{:ok, serialized_prosemirror} <- Jason.decode(template_json) do
920918
{:ok, serialized_prosemirror["data"]}
921919
end
922920
end
@@ -937,14 +935,14 @@ defmodule WraftDoc.TemplateAssets do
937935
defp validate_file_entries(wraft_json, entries) do
938936
items = has_items(wraft_json)
939937

940-
{folders, files} =
938+
{_folders, files} =
941939
Enum.split_with(entries, fn entry ->
942940
String.ends_with?(entry, "/")
943941
end)
944942

945943
[]
946944
|> collect_missing_files(files)
947-
|> collect_missing_folders(folders, items)
945+
|> collect_missing_folders(items, files)
948946
|> validate_layout(files, items)
949947
|> validate_theme(files, items)
950948
|> validate_data_template(files, items)
@@ -964,17 +962,19 @@ defmodule WraftDoc.TemplateAssets do
964962
errors ++ missing_files
965963
end
966964

967-
defp collect_missing_folders(errors, folders, items) do
968-
missing_folders =
969-
items
970-
|> Enum.flat_map(fn
965+
defp collect_missing_folders(errors, items, files) do
966+
required_folders =
967+
Enum.flat_map(items, fn
971968
"theme" -> ["fonts/"]
972969
"layout" -> ["assets/"]
973970
"frame" -> ["frame/"]
974971
_ -> []
975972
end)
976-
|> Enum.filter(fn folder ->
977-
not Enum.any?(folders, &String.starts_with?(&1, folder))
973+
974+
missing_folders =
975+
required_folders
976+
|> Enum.reject(fn folder ->
977+
Enum.any?(files, &String.starts_with?(&1, folder))
978978
end)
979979
|> Enum.map(&%{type: "folder_error", message: "Missing required folder: #{&1}"})
980980

@@ -1174,20 +1174,26 @@ defmodule WraftDoc.TemplateAssets do
11741174
Prepare all the nessecary files and format for zip export.
11751175
"""
11761176
def prepare_template_format(theme, layout, c_type, data_template, current_user) do
1177-
folder_path = data_template.title
1178-
File.mkdir_p!(folder_path)
1177+
case validate_template_inputs(theme, layout, c_type, data_template) do
1178+
{:ok, _validated} ->
1179+
folder_path = data_template.title
1180+
File.mkdir_p!(folder_path)
11791181

1180-
case create_wraft_json(theme, layout, c_type, data_template, folder_path, current_user) do
1181-
:ok ->
1182-
template_name = "#{data_template.title}.zip"
1183-
{:ok, zip_path} = zip_folder(folder_path, template_name)
1182+
case create_wraft_json(theme, layout, c_type, data_template, folder_path, current_user) do
1183+
:ok ->
1184+
template_name = "#{data_template.title}.zip"
1185+
{:ok, zip_path} = zip_folder(folder_path, template_name)
11841186

1185-
File.rm_rf(folder_path)
1186-
{:ok, zip_path}
1187+
File.rm_rf(folder_path)
1188+
{:ok, zip_path}
1189+
1190+
{:error, reason} ->
1191+
File.rm_rf(folder_path)
1192+
{:error, "Failed to prepare template: #{reason}"}
1193+
end
11871194

11881195
{:error, reason} ->
1189-
File.rm_rf(folder_path)
1190-
{:error, "Failed to prepare template: #{reason}"}
1196+
{:error, "Invalid template data: #{reason}"}
11911197
end
11921198
end
11931199

@@ -1206,18 +1212,67 @@ defmodule WraftDoc.TemplateAssets do
12061212

12071213
defp zip_folder(folder_path, template_name) do
12081214
zip_path = Path.join(System.tmp_dir!(), "#{template_name}.zip")
1209-
:zip.create(String.to_charlist(zip_path), [String.to_charlist(folder_path)])
1210-
{:ok, zip_path}
1215+
1216+
files =
1217+
folder_path
1218+
|> Path.join("**")
1219+
|> Path.wildcard()
1220+
|> Enum.filter(&File.regular?/1)
1221+
|> Enum.map(fn file ->
1222+
relative = Path.relative_to(file, folder_path)
1223+
{:ok, bin} = File.read(file)
1224+
{String.to_charlist(relative), bin}
1225+
end)
1226+
1227+
case :zip.create(String.to_charlist(zip_path), files, [:memory]) do
1228+
{:ok, {_zip_name, zip_binary}} ->
1229+
File.write!(zip_path, zip_binary)
1230+
{:ok, zip_path}
1231+
1232+
{:error, reason} ->
1233+
{:error, reason}
1234+
end
12111235
end
12121236

12131237
def build_wraft_json(theme, layout, c_type, data_template, file_path, current_user) do
12141238
%{
1215-
"theme" => build_theme(theme, file_path, current_user),
1216-
"layout" => build_layout(layout, file_path, current_user),
1217-
"variant" => build_c_type(c_type),
1218-
"data_template" => %{
1219-
"title" => data_template.title,
1220-
"title_template" => data_template.title_template
1239+
"metadata" => %{
1240+
"name" => export_to_markdown(data_template, file_path) <> " template",
1241+
"description" => "Template for #{data_template.title}",
1242+
"type" => "template_asset",
1243+
"updated_at" => Date.to_string(Date.utc_today())
1244+
},
1245+
"packageContents" => %{
1246+
"rootFiles" => [
1247+
%{"name" => "template.json", "path" => "template.json"},
1248+
%{"name" => "wraft.json", "path" => "wraft.json"}
1249+
],
1250+
"assets" => [
1251+
%{
1252+
"name" => "#{layout.name}",
1253+
"path" => "assets/letterhead.pdf",
1254+
"type" => "layout",
1255+
"description" => "#{layout.description}"
1256+
}
1257+
],
1258+
"fonts" =>
1259+
Enum.map(theme.assets, fn asset ->
1260+
%{
1261+
"fontName" => asset.name,
1262+
"fontWeight" => "regular",
1263+
"path" => download_file(asset.id, current_user, file_path, "fonts")
1264+
}
1265+
end)
1266+
},
1267+
"items" => %{
1268+
"theme" => build_theme(theme, file_path, current_user),
1269+
"layout" => build_layout(layout, file_path, current_user),
1270+
"flow" => %{"name" => "Wraft flow"},
1271+
"variant" => build_c_type(c_type),
1272+
"data_template" => %{
1273+
"title" => data_template.title,
1274+
"title_template" => data_template.title_template
1275+
}
12211276
}
12221277
}
12231278
end
@@ -1231,26 +1286,30 @@ defmodule WraftDoc.TemplateAssets do
12311286
Enum.map(theme.assets, fn asset ->
12321287
%{
12331288
"fontName" => asset.name,
1234-
"filePath" => download_file(asset.id, current_user, file_path, "otf", "theme")
1289+
"path" => download_file(asset.id, current_user, file_path, "fonts")
12351290
}
12361291
end),
1237-
"color" => %{
1238-
"body_color" => theme.body_color,
1239-
"primary_color" => theme.primary_color,
1240-
"secondary_color" => theme.secondary_color
1292+
"colors" => %{
1293+
"bodyColor" => theme.body_color,
1294+
"primaryColor" => theme.primary_color,
1295+
"secondaryColor" => theme.secondary_color
12411296
}
12421297
}
12431298
end
12441299

12451300
defp build_layout(layout, file_path, current_user) do
1246-
layout = Repo.preload(layout, :assets)
1247-
[asset | _] = layout.assets
1301+
layout = Repo.preload(layout, :asset)
1302+
asset = layout.asset
12481303

12491304
%{
12501305
"name" => layout.name,
1251-
"slug" => make_slug(layout.slug, file_path),
1252-
"slug_file" => download_file(asset.id, current_user, file_path, "pdf", "layout"),
1253-
"meta" => "fields",
1306+
"slug" => "#{layout.slug}",
1307+
"slug_file" => download_file(asset.id, current_user, file_path, "assets"),
1308+
"meta" => %{
1309+
"standard_size" => "a4",
1310+
"fields" => [],
1311+
"margin" => "2.54"
1312+
},
12541313
"description" => layout.description,
12551314
"engine" => "pandoc/latex"
12561315
}
@@ -1269,31 +1328,76 @@ defmodule WraftDoc.TemplateAssets do
12691328
%{
12701329
"name" => field.name,
12711330
"description" => field.description,
1272-
"type" => field.field_type.name
1331+
"type" => String.downcase(field.field_type.name)
12731332
}
12741333
end)
12751334
}
12761335
end
12771336

1278-
defp make_slug(slug, file_path) do
1279-
path = :wraft_doc |> :code.priv_dir() |> Path.join("slugs/#{slug}/.")
1280-
System.cmd("cp", ["-a", path, file_path <> "/" <> slug])
1281-
slug
1337+
defp export_to_markdown(template, folder_path) do
1338+
template_json = """
1339+
{"data": #{Jason.encode!(template.serialized["data"])}}
1340+
"""
1341+
1342+
folder_path
1343+
|> Path.join("template.json")
1344+
|> File.write!(template_json)
1345+
1346+
markdown =
1347+
template.serialized["data"]
1348+
|> Jason.decode!()
1349+
|> ProsemirrorToMarkdown.convert()
1350+
1351+
File.write!(Path.join(folder_path, "template.md"), markdown)
1352+
1353+
template.title
1354+
end
1355+
1356+
defp validate_template_inputs(theme, layout, c_type, data_template) do
1357+
with {:ok, data_template} <- validate_data_template(data_template),
1358+
{:ok, theme} <- validate_theme(theme),
1359+
{:ok, layout} <- validate_layout(layout),
1360+
{:ok, c_type} <- validate_contract_type(c_type) do
1361+
{:ok, %{theme: theme, layout: layout, c_type: c_type, data_template: data_template}}
1362+
end
12821363
end
12831364

1365+
defp validate_data_template(nil), do: {:error, "DataTemplate is missing"}
1366+
defp validate_data_template(%{title: nil}), do: {:error, "DataTemplate title is missing"}
1367+
defp validate_data_template(%{title: ""}), do: {:error, "DataTemplate title is missing"}
1368+
1369+
defp validate_data_template(%{serialized: nil}),
1370+
do: {:error, "DataTemplate serialized data is missing"}
1371+
1372+
defp validate_data_template(dt), do: {:ok, dt}
1373+
1374+
defp validate_theme(nil), do: {:error, "Theme is missing"}
1375+
defp validate_theme(%{name: nil}), do: {:error, "Theme name is missing"}
1376+
defp validate_theme(%{assets: nil}), do: {:error, "Theme assets missing"}
1377+
defp validate_theme(%{assets: []}), do: {:error, "Theme assets missing"}
1378+
defp validate_theme(theme), do: {:ok, theme}
1379+
1380+
defp validate_layout(nil), do: {:error, "Layout is missing"}
1381+
defp validate_layout(%{name: nil}), do: {:error, "Layout name is missing"}
1382+
defp validate_layout(%{asset: nil}), do: {:error, "Layout asset is missing"}
1383+
defp validate_layout(layout), do: {:ok, layout}
1384+
1385+
defp validate_contract_type(nil), do: {:error, "Contract type is missing"}
1386+
defp validate_contract_type(%{name: nil}), do: {:error, "Contract type name is missing"}
1387+
defp validate_contract_type(c_type), do: {:ok, c_type}
1388+
12841389
defp download_file(
12851390
asset_id,
12861391
%{current_org_id: org_id} = _current_user,
12871392
file_path,
1288-
format,
12891393
folder_name
12901394
) do
1291-
file = Minio.download("organisations/#{org_id}/assets/#{asset_id}")
12921395
asset = Assets.get_asset(asset_id, %{current_org_id: org_id})
1293-
path = "#{file_path}/#{folder_name}/#{asset.name}.#{format}"
1396+
file = Minio.download("organisations/#{org_id}/assets/#{asset_id}/#{asset.file.file_name}")
1397+
path = "#{file_path}/#{folder_name}/#{asset.file.file_name}"
12941398
File.mkdir_p(Path.dirname(path))
12951399
File.write!(path, file)
1296-
"#{folder_name}/#{asset.name}.#{format}"
1400+
"#{folder_name}/#{asset.file.file_name}"
12971401
end
12981402

12991403
defp update_conflicting_name(%{"title" => title} = map, DataTemplate, current_user) do

lib/wraft_doc/utils/file_helper.ex

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,7 @@ defmodule WraftDoc.Utils.FileHelper do
124124
def get_allowed_files_from_wraft_json(%{
125125
"packageContents" => %{"rootFiles" => root_files, "assets" => assets, "fonts" => fonts}
126126
}) do
127-
[root_files, assets, fonts]
128-
|> Enum.map(&get_paths_from_section/1)
129-
|> List.flatten()
127+
Enum.flat_map([root_files, assets, fonts], &get_paths_from_section/1)
130128
end
131129

132130
defp get_paths_from_section(section) when is_list(section),

0 commit comments

Comments
 (0)