diff --git a/CHANGELOG.md b/CHANGELOG.md
index fcaa6acb..253c8839 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,7 @@
- Make container show page filter used-up ammo
- Forgot to add the logo as the favicon whoops
- Add graph to range page
+- Add JSON export of data
- Update project dependencies
# v0.5.4
diff --git a/lib/cannery/accounts/user.ex b/lib/cannery/accounts/user.ex
index 88ff9cf5..3ecab160 100644
--- a/lib/cannery/accounts/user.ex
+++ b/lib/cannery/accounts/user.ex
@@ -9,6 +9,14 @@ defmodule Cannery.Accounts.User do
alias Ecto.{Changeset, UUID}
alias Cannery.{Accounts.User, Invites.Invite}
+ @derive {Jason.Encoder,
+ only: [
+ :id,
+ :email,
+ :confirmed_at,
+ :role,
+ :locale
+ ]}
@derive {Inspect, except: [:password]}
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
diff --git a/lib/cannery/activity_log/shot_group.ex b/lib/cannery/activity_log/shot_group.ex
index d2d14618..769f4f69 100644
--- a/lib/cannery/activity_log/shot_group.ex
+++ b/lib/cannery/activity_log/shot_group.ex
@@ -9,6 +9,14 @@ defmodule Cannery.ActivityLog.ShotGroup do
alias Cannery.{Accounts.User, ActivityLog.ShotGroup, Ammo.AmmoGroup, Repo}
alias Ecto.{Changeset, UUID}
+ @derive {Jason.Encoder,
+ only: [
+ :id,
+ :count,
+ :date,
+ :notes,
+ :ammo_group_id
+ ]}
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "shot_groups" do
diff --git a/lib/cannery/ammo/ammo_group.ex b/lib/cannery/ammo/ammo_group.ex
index 09426f0b..395ec4a1 100644
--- a/lib/cannery/ammo/ammo_group.ex
+++ b/lib/cannery/ammo/ammo_group.ex
@@ -13,6 +13,16 @@ defmodule Cannery.Ammo.AmmoGroup do
alias Cannery.{Accounts.User, ActivityLog.ShotGroup, Containers.Container}
alias Ecto.{Changeset, UUID}
+ @derive {Jason.Encoder,
+ only: [
+ :id,
+ :count,
+ :notes,
+ :price_paid,
+ :staged,
+ :ammo_type_id,
+ :container_id
+ ]}
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "ammo_groups" do
diff --git a/lib/cannery/ammo/ammo_type.ex b/lib/cannery/ammo/ammo_type.ex
index c6e5012a..b9f91a9a 100644
--- a/lib/cannery/ammo/ammo_type.ex
+++ b/lib/cannery/ammo/ammo_type.ex
@@ -11,6 +11,31 @@ defmodule Cannery.Ammo.AmmoType do
alias Cannery.Ammo.{AmmoGroup, AmmoType}
alias Ecto.{Changeset, UUID}
+ @derive {Jason.Encoder,
+ only: [
+ :id,
+ :name,
+ :desc,
+ :bullet_type,
+ :bullet_core,
+ :cartridge,
+ :caliber,
+ :case_material,
+ :jacket_type,
+ :muzzle_velocity,
+ :powder_type,
+ :powder_grains_per_charge,
+ :grains,
+ :pressure,
+ :primer_type,
+ :firing_type,
+ :tracer,
+ :incendiary,
+ :blank,
+ :corrosive,
+ :manufacturer,
+ :upc
+ ]}
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "ammo_types" do
diff --git a/lib/cannery/containers/container.ex b/lib/cannery/containers/container.ex
index c6bd8ae6..c4ea2360 100644
--- a/lib/cannery/containers/container.ex
+++ b/lib/cannery/containers/container.ex
@@ -9,6 +9,15 @@ defmodule Cannery.Containers.Container do
alias Cannery.Containers.{Container, ContainerTag}
alias Cannery.{Accounts.User, Ammo.AmmoGroup, Tags.Tag}
+ @derive {Jason.Encoder,
+ only: [
+ :id,
+ :name,
+ :desc,
+ :location,
+ :type,
+ :tags
+ ]}
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "containers" do
diff --git a/lib/cannery/tags/tag.ex b/lib/cannery/tags/tag.ex
index a0dd0d77..0fce3114 100644
--- a/lib/cannery/tags/tag.ex
+++ b/lib/cannery/tags/tag.ex
@@ -9,6 +9,13 @@ defmodule Cannery.Tags.Tag do
alias Ecto.{Changeset, UUID}
alias Cannery.{Accounts.User, Tags.Tag}
+ @derive {Jason.Encoder,
+ only: [
+ :id,
+ :name,
+ :bg_color,
+ :text_color
+ ]}
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "tags" do
diff --git a/lib/cannery_web/controllers/export_controller.ex b/lib/cannery_web/controllers/export_controller.ex
new file mode 100644
index 00000000..d7697ab5
--- /dev/null
+++ b/lib/cannery_web/controllers/export_controller.ex
@@ -0,0 +1,65 @@
+defmodule CanneryWeb.ExportController do
+ use CanneryWeb, :controller
+ alias Cannery.{ActivityLog, Ammo, Containers}
+
+ def export(%{assigns: %{current_user: current_user}} = conn, %{"mode" => "json"}) do
+ ammo_types =
+ Ammo.list_ammo_types(current_user)
+ |> Enum.map(fn ammo_type ->
+ average_cost = ammo_type |> Ammo.get_average_cost_for_ammo_type!(current_user)
+ round_count = ammo_type |> Ammo.get_round_count_for_ammo_type(current_user)
+ used_count = ammo_type |> Ammo.get_used_count_for_ammo_type(current_user)
+ ammo_group_count = ammo_type |> Ammo.get_ammo_groups_count_for_type(current_user, true)
+
+ ammo_type
+ |> Jason.encode!()
+ |> Jason.decode!()
+ |> Map.merge(%{
+ "average_cost" => average_cost,
+ "round_count" => round_count,
+ "used_count" => used_count,
+ "ammo_group_count" => ammo_group_count
+ })
+ end)
+
+ ammo_groups =
+ Ammo.list_ammo_groups(current_user, true)
+ |> Enum.map(fn ammo_group ->
+ used_count = ammo_group |> Ammo.get_used_count()
+ percentage_remaining = ammo_group |> Ammo.get_percentage_remaining()
+
+ ammo_group
+ |> Jason.encode!()
+ |> Jason.decode!()
+ |> Map.merge(%{
+ "used_count" => used_count,
+ "percentage_remaining" => percentage_remaining
+ })
+ end)
+
+ shot_groups = ActivityLog.list_shot_groups(current_user)
+
+ containers =
+ Containers.list_containers(current_user)
+ |> Enum.map(fn container ->
+ ammo_group_count = container |> Containers.get_container_ammo_group_count!()
+ round_count = container |> Containers.get_container_rounds!()
+
+ container
+ |> Jason.encode!()
+ |> Jason.decode!()
+ |> Map.merge(%{
+ "ammo_group_count" => ammo_group_count,
+ "round_count" => round_count
+ })
+ end)
+
+ json(conn, %{
+ user: current_user,
+ ammo_types: ammo_types,
+ ammo_groups: ammo_groups,
+ shot_groups: shot_groups,
+ containers: containers
+ })
+ end
+end
diff --git a/lib/cannery_web/live/home_live.ex b/lib/cannery_web/live/home_live.ex
index a13ae8fa..86cfac94 100644
--- a/lib/cannery_web/live/home_live.ex
+++ b/lib/cannery_web/live/home_live.ex
@@ -138,7 +138,7 @@ defmodule CanneryWeb.HomeLive do
target="_blank"
rel="noopener noreferrer"
>
-
0.5.5
+ 0.6.0
diff --git a/lib/cannery_web/router.ex b/lib/cannery_web/router.ex
index 2d46e378..0594d92c 100644
--- a/lib/cannery_web/router.ex
+++ b/lib/cannery_web/router.ex
@@ -60,6 +60,7 @@ defmodule CanneryWeb.Router do
put "/users/settings", UserSettingsController, :update
delete "/users/settings/:id", UserSettingsController, :delete
get "/users/settings/confirm_email/:token", UserSettingsController, :confirm_email
+ get "/export/:mode", ExportController, :export
live "/tags", TagLive.Index, :index
live "/tags/new", TagLive.Index, :new
diff --git a/lib/cannery_web/templates/user_settings/edit.html.heex b/lib/cannery_web/templates/user_settings/edit.html.heex
index 9b09934c..687cadf0 100644
--- a/lib/cannery_web/templates/user_settings/edit.html.heex
+++ b/lib/cannery_web/templates/user_settings/edit.html.heex
@@ -139,12 +139,22 @@
- <.link
- href={Routes.user_settings_path(@conn, :delete, @current_user)}
- method={:delete}
- class="btn btn-alert"
- data-confirm={dgettext("prompts", "Are you sure you want to delete your account?")}
- >
- <%= dgettext("actions", "Delete User") %>
-
+
+ <.link
+ href={Routes.export_path(@conn, :export, :json)}
+ class="mx-4 my-2 btn btn-primary"
+ target="_blank"
+ >
+ <%= dgettext("actions", "Export Data as JSON") %>
+
+
+ <.link
+ href={Routes.user_settings_path(@conn, :delete, @current_user)}
+ method={:delete}
+ class="mx-4 my-2 btn btn-alert"
+ data-confirm={dgettext("prompts", "Are you sure you want to delete your account?")}
+ >
+ <%= dgettext("actions", "Delete User") %>
+
+
diff --git a/priv/gettext/actions.pot b/priv/gettext/actions.pot
index 7c4e37c3..ad771b9d 100644
--- a/priv/gettext/actions.pot
+++ b/priv/gettext/actions.pot
@@ -48,7 +48,7 @@ msgstr ""
msgid "Create Invite"
msgstr ""
-#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#: lib/cannery_web/templates/user_settings/edit.html.heex:157
#, elixir-autogen, elixir-format
msgid "Delete User"
msgstr ""
@@ -248,3 +248,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Unstage from range"
msgstr ""
+
+#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#, elixir-autogen, elixir-format
+msgid "Export Data as JSON"
+msgstr ""
diff --git a/priv/gettext/de/LC_MESSAGES/actions.po b/priv/gettext/de/LC_MESSAGES/actions.po
index d357341a..70e34dde 100644
--- a/priv/gettext/de/LC_MESSAGES/actions.po
+++ b/priv/gettext/de/LC_MESSAGES/actions.po
@@ -61,7 +61,7 @@ msgstr "Passwort ändern"
msgid "Create Invite"
msgstr "Einladung erstellen"
-#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#: lib/cannery_web/templates/user_settings/edit.html.heex:157
#, elixir-autogen, elixir-format
msgid "Delete User"
msgstr "Benutzer löschen"
@@ -261,3 +261,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Unstage from range"
msgstr ""
+
+#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#, elixir-autogen, elixir-format
+msgid "Export Data as JSON"
+msgstr ""
diff --git a/priv/gettext/de/LC_MESSAGES/errors.po b/priv/gettext/de/LC_MESSAGES/errors.po
index 43dcee31..d3992c08 100644
--- a/priv/gettext/de/LC_MESSAGES/errors.po
+++ b/priv/gettext/de/LC_MESSAGES/errors.po
@@ -121,22 +121,22 @@ msgstr "Sie sind nicht berechtigt, diese Seite aufzurufen"
msgid "You are not authorized to view this page."
msgstr "Sie sind nicht berechtigt, diese Seite aufzurufen."
-#: lib/cannery/accounts/user.ex:130
+#: lib/cannery/accounts/user.ex:138
#, elixir-autogen, elixir-format
msgid "did not change"
msgstr "hat sich nicht geändert"
-#: lib/cannery/accounts/user.ex:151
+#: lib/cannery/accounts/user.ex:159
#, elixir-autogen, elixir-format
msgid "does not match password"
msgstr "Passwort stimmt nicht überein"
-#: lib/cannery/accounts/user.ex:188
+#: lib/cannery/accounts/user.ex:196
#, elixir-autogen, elixir-format
msgid "is not valid"
msgstr "ist nicht gültig"
-#: lib/cannery/accounts/user.ex:84
+#: lib/cannery/accounts/user.ex:92
#, elixir-autogen, elixir-format
msgid "must have the @ sign and no spaces"
msgstr "Muss ein @ Zeichen und keine Leerzeichen haben"
@@ -151,13 +151,13 @@ msgstr "Tag nicht gefunden"
msgid "Tag could not be added"
msgstr "Tag konnte nicht hinzugefügt werden"
-#: lib/cannery/activity_log/shot_group.ex:115
+#: lib/cannery/activity_log/shot_group.ex:123
#, elixir-autogen, elixir-format
msgid "Count must be at least 1"
msgstr "Anzahl muss mindestens 1 sein"
-#: lib/cannery/activity_log/shot_group.ex:74
-#: lib/cannery/activity_log/shot_group.ex:111
+#: lib/cannery/activity_log/shot_group.ex:82
+#: lib/cannery/activity_log/shot_group.ex:119
#, elixir-autogen, elixir-format
msgid "Count must be less than %{count}"
msgstr "Anzahl muss weniger als %{count} betragen"
@@ -192,12 +192,12 @@ msgstr ""
msgid "Invalid multiplier"
msgstr ""
-#: lib/cannery/ammo/ammo_group.ex:84
+#: lib/cannery/ammo/ammo_group.ex:94
#, elixir-autogen, elixir-format
msgid "Please select an ammo type and container"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:69
+#: lib/cannery/activity_log/shot_group.ex:77
#, elixir-autogen, elixir-format
msgid "Please select a valid user and ammo group"
msgstr ""
diff --git a/priv/gettext/de/LC_MESSAGES/prompts.po b/priv/gettext/de/LC_MESSAGES/prompts.po
index fb545186..6737f51b 100644
--- a/priv/gettext/de/LC_MESSAGES/prompts.po
+++ b/priv/gettext/de/LC_MESSAGES/prompts.po
@@ -105,7 +105,7 @@ msgstr "Sind Sie sicher, dass sie die Einladung für %{name} löschen möchten?"
msgid "Are you sure you want to delete this ammo?"
msgstr "Sind Sie sicher, dass sie diese Munition löschen möchten?"
-#: lib/cannery_web/templates/user_settings/edit.html.heex:146
+#: lib/cannery_web/templates/user_settings/edit.html.heex:155
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete your account?"
msgstr "Sind Sie sicher, dass sie Ihren Account löschen möchten?"
diff --git a/priv/gettext/en/LC_MESSAGES/actions.po b/priv/gettext/en/LC_MESSAGES/actions.po
index 8e8064f4..e59e43a9 100644
--- a/priv/gettext/en/LC_MESSAGES/actions.po
+++ b/priv/gettext/en/LC_MESSAGES/actions.po
@@ -49,7 +49,7 @@ msgstr ""
msgid "Create Invite"
msgstr ""
-#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#: lib/cannery_web/templates/user_settings/edit.html.heex:157
#, elixir-autogen, elixir-format
msgid "Delete User"
msgstr ""
@@ -249,3 +249,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Unstage from range"
msgstr ""
+
+#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#, elixir-autogen, elixir-format
+msgid "Export Data as JSON"
+msgstr ""
diff --git a/priv/gettext/en/LC_MESSAGES/errors.po b/priv/gettext/en/LC_MESSAGES/errors.po
index 0e616668..a4218370 100644
--- a/priv/gettext/en/LC_MESSAGES/errors.po
+++ b/priv/gettext/en/LC_MESSAGES/errors.po
@@ -107,23 +107,23 @@ msgstr ""
msgid "You are not authorized to view this page."
msgstr ""
-#: lib/cannery/accounts/user.ex:130
+#: lib/cannery/accounts/user.ex:138
#, elixir-autogen, elixir-format
msgid "did not change"
msgstr ""
-#: lib/cannery/accounts/user.ex:151
+#: lib/cannery/accounts/user.ex:159
#, elixir-autogen, elixir-format
msgid "does not match password"
msgstr ""
## From Ecto.Changeset.put_change/3
-#: lib/cannery/accounts/user.ex:188
+#: lib/cannery/accounts/user.ex:196
#, elixir-autogen, elixir-format, fuzzy
msgid "is not valid"
msgstr ""
-#: lib/cannery/accounts/user.ex:84
+#: lib/cannery/accounts/user.ex:92
#, elixir-autogen, elixir-format
msgid "must have the @ sign and no spaces"
msgstr ""
@@ -138,13 +138,13 @@ msgstr ""
msgid "Tag could not be added"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:115
+#: lib/cannery/activity_log/shot_group.ex:123
#, elixir-autogen, elixir-format
msgid "Count must be at least 1"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:74
-#: lib/cannery/activity_log/shot_group.ex:111
+#: lib/cannery/activity_log/shot_group.ex:82
+#: lib/cannery/activity_log/shot_group.ex:119
#, elixir-autogen, elixir-format
msgid "Count must be less than %{count}"
msgstr ""
@@ -175,12 +175,12 @@ msgstr ""
msgid "Invalid multiplier"
msgstr ""
-#: lib/cannery/ammo/ammo_group.ex:84
+#: lib/cannery/ammo/ammo_group.ex:94
#, elixir-autogen, elixir-format
msgid "Please select an ammo type and container"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:69
+#: lib/cannery/activity_log/shot_group.ex:77
#, elixir-autogen, elixir-format
msgid "Please select a valid user and ammo group"
msgstr ""
diff --git a/priv/gettext/en/LC_MESSAGES/prompts.po b/priv/gettext/en/LC_MESSAGES/prompts.po
index a359e9cb..d4db1d15 100644
--- a/priv/gettext/en/LC_MESSAGES/prompts.po
+++ b/priv/gettext/en/LC_MESSAGES/prompts.po
@@ -91,7 +91,7 @@ msgstr ""
msgid "Are you sure you want to delete this ammo?"
msgstr ""
-#: lib/cannery_web/templates/user_settings/edit.html.heex:146
+#: lib/cannery_web/templates/user_settings/edit.html.heex:155
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete your account?"
msgstr ""
diff --git a/priv/gettext/errors.pot b/priv/gettext/errors.pot
index 618e01f6..39485141 100644
--- a/priv/gettext/errors.pot
+++ b/priv/gettext/errors.pot
@@ -107,22 +107,22 @@ msgstr ""
msgid "You are not authorized to view this page."
msgstr ""
-#: lib/cannery/accounts/user.ex:130
+#: lib/cannery/accounts/user.ex:138
#, elixir-autogen, elixir-format
msgid "did not change"
msgstr ""
-#: lib/cannery/accounts/user.ex:151
+#: lib/cannery/accounts/user.ex:159
#, elixir-autogen, elixir-format
msgid "does not match password"
msgstr ""
-#: lib/cannery/accounts/user.ex:188
+#: lib/cannery/accounts/user.ex:196
#, elixir-autogen, elixir-format
msgid "is not valid"
msgstr ""
-#: lib/cannery/accounts/user.ex:84
+#: lib/cannery/accounts/user.ex:92
#, elixir-autogen, elixir-format
msgid "must have the @ sign and no spaces"
msgstr ""
@@ -137,13 +137,13 @@ msgstr ""
msgid "Tag could not be added"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:115
+#: lib/cannery/activity_log/shot_group.ex:123
#, elixir-autogen, elixir-format
msgid "Count must be at least 1"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:74
-#: lib/cannery/activity_log/shot_group.ex:111
+#: lib/cannery/activity_log/shot_group.ex:82
+#: lib/cannery/activity_log/shot_group.ex:119
#, elixir-autogen, elixir-format
msgid "Count must be less than %{count}"
msgstr ""
@@ -174,12 +174,12 @@ msgstr ""
msgid "Invalid multiplier"
msgstr ""
-#: lib/cannery/ammo/ammo_group.ex:84
+#: lib/cannery/ammo/ammo_group.ex:94
#, elixir-autogen, elixir-format
msgid "Please select an ammo type and container"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:69
+#: lib/cannery/activity_log/shot_group.ex:77
#, elixir-autogen, elixir-format
msgid "Please select a valid user and ammo group"
msgstr ""
diff --git a/priv/gettext/es/LC_MESSAGES/actions.po b/priv/gettext/es/LC_MESSAGES/actions.po
index d356a551..4b6bf725 100644
--- a/priv/gettext/es/LC_MESSAGES/actions.po
+++ b/priv/gettext/es/LC_MESSAGES/actions.po
@@ -61,7 +61,7 @@ msgstr "Cambiar contraseña"
msgid "Create Invite"
msgstr "Crear Invitación"
-#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#: lib/cannery_web/templates/user_settings/edit.html.heex:157
#, elixir-autogen, elixir-format
msgid "Delete User"
msgstr "Eliminar cuenta de Usuario"
@@ -261,3 +261,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Unstage from range"
msgstr ""
+
+#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#, elixir-autogen, elixir-format
+msgid "Export Data as JSON"
+msgstr ""
diff --git a/priv/gettext/es/LC_MESSAGES/errors.po b/priv/gettext/es/LC_MESSAGES/errors.po
index c541b1b4..26245488 100644
--- a/priv/gettext/es/LC_MESSAGES/errors.po
+++ b/priv/gettext/es/LC_MESSAGES/errors.po
@@ -123,22 +123,22 @@ msgstr ""
msgid "You are not authorized to view this page."
msgstr ""
-#: lib/cannery/accounts/user.ex:130
+#: lib/cannery/accounts/user.ex:138
#, elixir-autogen, elixir-format
msgid "did not change"
msgstr ""
-#: lib/cannery/accounts/user.ex:151
+#: lib/cannery/accounts/user.ex:159
#, elixir-autogen, elixir-format
msgid "does not match password"
msgstr ""
-#: lib/cannery/accounts/user.ex:188
+#: lib/cannery/accounts/user.ex:196
#, elixir-autogen, elixir-format
msgid "is not valid"
msgstr ""
-#: lib/cannery/accounts/user.ex:84
+#: lib/cannery/accounts/user.ex:92
#, elixir-autogen, elixir-format
msgid "must have the @ sign and no spaces"
msgstr ""
@@ -153,13 +153,13 @@ msgstr ""
msgid "Tag could not be added"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:115
+#: lib/cannery/activity_log/shot_group.ex:123
#, elixir-autogen, elixir-format
msgid "Count must be at least 1"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:74
-#: lib/cannery/activity_log/shot_group.ex:111
+#: lib/cannery/activity_log/shot_group.ex:82
+#: lib/cannery/activity_log/shot_group.ex:119
#, elixir-autogen, elixir-format
msgid "Count must be less than %{count}"
msgstr ""
@@ -190,12 +190,12 @@ msgstr ""
msgid "Invalid multiplier"
msgstr ""
-#: lib/cannery/ammo/ammo_group.ex:84
+#: lib/cannery/ammo/ammo_group.ex:94
#, elixir-autogen, elixir-format
msgid "Please select an ammo type and container"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:69
+#: lib/cannery/activity_log/shot_group.ex:77
#, elixir-autogen, elixir-format
msgid "Please select a valid user and ammo group"
msgstr ""
diff --git a/priv/gettext/es/LC_MESSAGES/prompts.po b/priv/gettext/es/LC_MESSAGES/prompts.po
index b38646c2..134ed15d 100644
--- a/priv/gettext/es/LC_MESSAGES/prompts.po
+++ b/priv/gettext/es/LC_MESSAGES/prompts.po
@@ -105,7 +105,7 @@ msgstr "Está seguro que quiere eliminar la invitación para %{name}?"
msgid "Are you sure you want to delete this ammo?"
msgstr "Está seguro que desea eliminar esta munición?"
-#: lib/cannery_web/templates/user_settings/edit.html.heex:146
+#: lib/cannery_web/templates/user_settings/edit.html.heex:155
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete your account?"
msgstr "Está seguro que desea eliminar su cuenta?"
diff --git a/priv/gettext/fr/LC_MESSAGES/actions.po b/priv/gettext/fr/LC_MESSAGES/actions.po
index 92e358d9..a96c5a56 100644
--- a/priv/gettext/fr/LC_MESSAGES/actions.po
+++ b/priv/gettext/fr/LC_MESSAGES/actions.po
@@ -61,7 +61,7 @@ msgstr "Changer le mot de passe"
msgid "Create Invite"
msgstr "Créer une invitation"
-#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#: lib/cannery_web/templates/user_settings/edit.html.heex:157
#, elixir-autogen, elixir-format
msgid "Delete User"
msgstr "Supprimer utilisateur"
@@ -261,3 +261,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Unstage from range"
msgstr ""
+
+#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#, elixir-autogen, elixir-format
+msgid "Export Data as JSON"
+msgstr ""
diff --git a/priv/gettext/fr/LC_MESSAGES/errors.po b/priv/gettext/fr/LC_MESSAGES/errors.po
index 19a684da..ddb5c568 100644
--- a/priv/gettext/fr/LC_MESSAGES/errors.po
+++ b/priv/gettext/fr/LC_MESSAGES/errors.po
@@ -122,22 +122,22 @@ msgstr "Vous n’êtes pas autorisé·e à voir cette page"
msgid "You are not authorized to view this page."
msgstr "Vous n’êtes pas autorisé·e à voir cette page."
-#: lib/cannery/accounts/user.ex:130
+#: lib/cannery/accounts/user.ex:138
#, elixir-autogen, elixir-format
msgid "did not change"
msgstr "est inchangé"
-#: lib/cannery/accounts/user.ex:151
+#: lib/cannery/accounts/user.ex:159
#, elixir-autogen, elixir-format
msgid "does not match password"
msgstr "le mot de passe ne correspond pas"
-#: lib/cannery/accounts/user.ex:188
+#: lib/cannery/accounts/user.ex:196
#, elixir-autogen, elixir-format
msgid "is not valid"
msgstr "n’est pas valide"
-#: lib/cannery/accounts/user.ex:84
+#: lib/cannery/accounts/user.ex:92
#, elixir-autogen, elixir-format
msgid "must have the @ sign and no spaces"
msgstr "doit contenir le symbole @ et aucune espace"
@@ -152,13 +152,13 @@ msgstr "Tag pas trouvé"
msgid "Tag could not be added"
msgstr "Le tag n’a pas pu être ajouté"
-#: lib/cannery/activity_log/shot_group.ex:115
+#: lib/cannery/activity_log/shot_group.ex:123
#, elixir-autogen, elixir-format
msgid "Count must be at least 1"
msgstr "Le nombre doit être au moins égal à 1"
-#: lib/cannery/activity_log/shot_group.ex:74
-#: lib/cannery/activity_log/shot_group.ex:111
+#: lib/cannery/activity_log/shot_group.ex:82
+#: lib/cannery/activity_log/shot_group.ex:119
#, elixir-autogen, elixir-format
msgid "Count must be less than %{count}"
msgstr "La quantité doit être inférieur à %{count}"
@@ -191,12 +191,12 @@ msgstr "Nombre de copies invalide, doit être 1 et %{max}. Été %{multiplier}"
msgid "Invalid multiplier"
msgstr "Multiplicateur invalide"
-#: lib/cannery/ammo/ammo_group.ex:84
+#: lib/cannery/ammo/ammo_group.ex:94
#, elixir-autogen, elixir-format
msgid "Please select an ammo type and container"
msgstr "Veuillez choisir un type de munitions et un conteneur"
-#: lib/cannery/activity_log/shot_group.ex:69
+#: lib/cannery/activity_log/shot_group.ex:77
#, elixir-autogen, elixir-format
msgid "Please select a valid user and ammo group"
msgstr "Veuillez choisir un utilisateur valide et un groupe de munitions"
diff --git a/priv/gettext/fr/LC_MESSAGES/prompts.po b/priv/gettext/fr/LC_MESSAGES/prompts.po
index a22232e0..b8bd2105 100644
--- a/priv/gettext/fr/LC_MESSAGES/prompts.po
+++ b/priv/gettext/fr/LC_MESSAGES/prompts.po
@@ -106,7 +106,7 @@ msgstr "Êtes-vous certain·e de supprimer l’invitation pour %{name} ?"
msgid "Are you sure you want to delete this ammo?"
msgstr "Êtes-vous certain·e de supprimer cette munition ?"
-#: lib/cannery_web/templates/user_settings/edit.html.heex:146
+#: lib/cannery_web/templates/user_settings/edit.html.heex:155
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete your account?"
msgstr "Êtes-vous certain·e de supprimer votre compte ?"
diff --git a/priv/gettext/ga/LC_MESSAGES/actions.po b/priv/gettext/ga/LC_MESSAGES/actions.po
index d50f480f..e058e4fe 100644
--- a/priv/gettext/ga/LC_MESSAGES/actions.po
+++ b/priv/gettext/ga/LC_MESSAGES/actions.po
@@ -59,7 +59,7 @@ msgstr ""
msgid "Create Invite"
msgstr ""
-#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#: lib/cannery_web/templates/user_settings/edit.html.heex:157
#, elixir-autogen, elixir-format
msgid "Delete User"
msgstr ""
@@ -259,3 +259,8 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Unstage from range"
msgstr ""
+
+#: lib/cannery_web/templates/user_settings/edit.html.heex:148
+#, elixir-autogen, elixir-format
+msgid "Export Data as JSON"
+msgstr ""
diff --git a/priv/gettext/ga/LC_MESSAGES/errors.po b/priv/gettext/ga/LC_MESSAGES/errors.po
index 0cc928a5..ff0f77ec 100644
--- a/priv/gettext/ga/LC_MESSAGES/errors.po
+++ b/priv/gettext/ga/LC_MESSAGES/errors.po
@@ -123,22 +123,22 @@ msgstr "Níl cead agaibh féachaint ar an leathanach seo"
msgid "You are not authorized to view this page."
msgstr "Níl cead agaibh féachaint ar an leathanach seo."
-#: lib/cannery/accounts/user.ex:130
+#: lib/cannery/accounts/user.ex:138
#, elixir-autogen, elixir-format
msgid "did not change"
msgstr "Níor athraigh sé"
-#: lib/cannery/accounts/user.ex:151
+#: lib/cannery/accounts/user.ex:159
#, elixir-autogen, elixir-format
msgid "does not match password"
msgstr ""
-#: lib/cannery/accounts/user.ex:188
+#: lib/cannery/accounts/user.ex:196
#, elixir-autogen, elixir-format
msgid "is not valid"
msgstr ""
-#: lib/cannery/accounts/user.ex:84
+#: lib/cannery/accounts/user.ex:92
#, elixir-autogen, elixir-format
msgid "must have the @ sign and no spaces"
msgstr ""
@@ -153,13 +153,13 @@ msgstr ""
msgid "Tag could not be added"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:115
+#: lib/cannery/activity_log/shot_group.ex:123
#, elixir-autogen, elixir-format
msgid "Count must be at least 1"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:74
-#: lib/cannery/activity_log/shot_group.ex:111
+#: lib/cannery/activity_log/shot_group.ex:82
+#: lib/cannery/activity_log/shot_group.ex:119
#, elixir-autogen, elixir-format
msgid "Count must be less than %{count}"
msgstr ""
@@ -190,12 +190,12 @@ msgstr ""
msgid "Invalid multiplier"
msgstr ""
-#: lib/cannery/ammo/ammo_group.ex:84
+#: lib/cannery/ammo/ammo_group.ex:94
#, elixir-autogen, elixir-format
msgid "Please select an ammo type and container"
msgstr ""
-#: lib/cannery/activity_log/shot_group.ex:69
+#: lib/cannery/activity_log/shot_group.ex:77
#, elixir-autogen, elixir-format
msgid "Please select a valid user and ammo group"
msgstr ""
diff --git a/priv/gettext/ga/LC_MESSAGES/prompts.po b/priv/gettext/ga/LC_MESSAGES/prompts.po
index e1e67276..a375d409 100644
--- a/priv/gettext/ga/LC_MESSAGES/prompts.po
+++ b/priv/gettext/ga/LC_MESSAGES/prompts.po
@@ -101,7 +101,7 @@ msgstr ""
msgid "Are you sure you want to delete this ammo?"
msgstr ""
-#: lib/cannery_web/templates/user_settings/edit.html.heex:146
+#: lib/cannery_web/templates/user_settings/edit.html.heex:155
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete your account?"
msgstr ""
diff --git a/priv/gettext/prompts.pot b/priv/gettext/prompts.pot
index 5e5f65d0..575917a8 100644
--- a/priv/gettext/prompts.pot
+++ b/priv/gettext/prompts.pot
@@ -90,7 +90,7 @@ msgstr ""
msgid "Are you sure you want to delete this ammo?"
msgstr ""
-#: lib/cannery_web/templates/user_settings/edit.html.heex:146
+#: lib/cannery_web/templates/user_settings/edit.html.heex:155
#, elixir-autogen, elixir-format
msgid "Are you sure you want to delete your account?"
msgstr ""
diff --git a/test/cannery_web/controllers/export_controller_test.exs b/test/cannery_web/controllers/export_controller_test.exs
new file mode 100644
index 00000000..3baad053
--- /dev/null
+++ b/test/cannery_web/controllers/export_controller_test.exs
@@ -0,0 +1,136 @@
+defmodule CanneryWeb.ExportControllerTest do
+ @moduledoc """
+ Tests the export function
+ """
+
+ use CanneryWeb.ConnCase
+ alias Cannery.{Ammo, Containers, Repo}
+
+ @moduletag :export_controller_test
+
+ setup %{conn: conn} do
+ current_user = user_fixture() |> confirm_user()
+
+ [
+ current_user: current_user,
+ conn: conn |> log_in_user(current_user)
+ ]
+ end
+
+ defp add_data(%{current_user: current_user}) do
+ ammo_type = ammo_type_fixture(current_user)
+ container = container_fixture(current_user)
+ tag = tag_fixture(current_user)
+ Containers.add_tag!(container, tag, current_user)
+ {1, [ammo_group]} = ammo_group_fixture(ammo_type, container, current_user)
+ shot_group = shot_group_fixture(current_user, ammo_group)
+ ammo_group = ammo_group |> Repo.reload!()
+
+ %{
+ ammo_type: ammo_type,
+ ammo_group: ammo_group,
+ container: container,
+ shot_group: shot_group,
+ tag: tag
+ }
+ end
+
+ describe "Exports data" do
+ setup [:add_data]
+
+ test "in JSON", %{
+ conn: conn,
+ current_user: current_user,
+ container: container,
+ ammo_type: ammo_type,
+ ammo_group: ammo_group,
+ shot_group: shot_group,
+ tag: tag
+ } do
+ conn = get(conn, Routes.export_path(conn, :export, :json))
+
+ ideal_ammo_group = %{
+ "ammo_type_id" => ammo_group.ammo_type_id,
+ "container_id" => ammo_group.container_id,
+ "count" => ammo_group.count,
+ "id" => ammo_group.id,
+ "notes" => ammo_group.notes,
+ "price_paid" => ammo_group.price_paid,
+ "staged" => ammo_group.staged,
+ "used_count" => ammo_group |> Ammo.get_used_count(),
+ "percentage_remaining" => ammo_group |> Ammo.get_percentage_remaining()
+ }
+
+ ideal_ammo_type = %{
+ "blank" => ammo_type.blank,
+ "bullet_core" => ammo_type.bullet_core,
+ "bullet_type" => ammo_type.bullet_type,
+ "caliber" => ammo_type.caliber,
+ "cartridge" => ammo_type.cartridge,
+ "case_material" => ammo_type.case_material,
+ "corrosive" => ammo_type.corrosive,
+ "desc" => ammo_type.desc,
+ "firing_type" => ammo_type.firing_type,
+ "grains" => ammo_type.grains,
+ "id" => ammo_type.id,
+ "incendiary" => ammo_type.incendiary,
+ "jacket_type" => ammo_type.jacket_type,
+ "manufacturer" => ammo_type.manufacturer,
+ "muzzle_velocity" => ammo_type.muzzle_velocity,
+ "name" => ammo_type.name,
+ "powder_grains_per_charge" => ammo_type.powder_grains_per_charge,
+ "powder_type" => ammo_type.powder_type,
+ "pressure" => ammo_type.pressure,
+ "primer_type" => ammo_type.primer_type,
+ "tracer" => ammo_type.tracer,
+ "upc" => ammo_type.upc,
+ "average_cost" => ammo_type |> Ammo.get_average_cost_for_ammo_type!(current_user),
+ "round_count" => ammo_type |> Ammo.get_round_count_for_ammo_type(current_user),
+ "used_count" => ammo_type |> Ammo.get_used_count_for_ammo_type(current_user),
+ "ammo_group_count" => ammo_type |> Ammo.get_ammo_groups_count_for_type(current_user, true)
+ }
+
+ ideal_container = %{
+ "desc" => container.desc,
+ "id" => container.id,
+ "location" => container.location,
+ "name" => container.name,
+ "tags" => [
+ %{
+ "id" => tag.id,
+ "name" => tag.name,
+ "bg_color" => tag.bg_color,
+ "text_color" => tag.text_color
+ }
+ ],
+ "type" => container.type,
+ "ammo_group_count" => container |> Containers.get_container_ammo_group_count!(),
+ "round_count" => container |> Containers.get_container_rounds!()
+ }
+
+ ideal_shot_group = %{
+ "ammo_group_id" => shot_group.ammo_group_id,
+ "count" => shot_group.count,
+ "date" => to_string(shot_group.date),
+ "id" => shot_group.id,
+ "notes" => shot_group.notes
+ }
+
+ ideal_user = %{
+ "confirmed_at" =>
+ current_user.confirmed_at |> Jason.encode!() |> String.replace(~r/\"/, ""),
+ "email" => current_user.email,
+ "id" => current_user.id,
+ "locale" => current_user.locale,
+ "role" => to_string(current_user.role)
+ }
+
+ json_resp = conn |> json_response(200)
+ assert %{"ammo_groups" => [^ideal_ammo_group]} = json_resp
+ assert %{"ammo_types" => [^ideal_ammo_type]} = json_resp
+ assert %{"containers" => [^ideal_container]} = json_resp
+ assert %{"shot_groups" => [^ideal_shot_group]} = json_resp
+ assert %{"user" => ^ideal_user} = json_resp
+ end
+ end
+end