diff --git a/README.md b/README.md index 7e9e3d4e..474ded61 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ The library source code is minimal and well tested. It is suggested to read the ```elixir def deps do - [{:paper_trail, "~> 0.6.0"}] + [{:paper_trail, "~> 0.7.0"}] end ``` @@ -116,7 +116,7 @@ The library source code is minimal and well tested. It is suggested to read the 3. install and compile your dependency: - ```mix deps.get && mix deps.compile``` + ```mix deps.get && mix compile``` 4. run this command to generate the migration: @@ -160,7 +160,7 @@ PaperTrail.insert(new_user_changeset, origin: "facebook_registration") ``` ### Originator relationships -You can specify setter/originator relationship to paper_trail versions with ```originator_id``` assignment. This feature is only possible by specifying `:originator` keyword list for your application configuration: +You can specify setter/originator relationship to paper_trail versions with ```originator``` assignment. This feature is only possible by specifying `:originator` keyword list for your application configuration: ```elixir # in your config/config.exs @@ -168,14 +168,18 @@ You can specify setter/originator relationship to paper_trail versions with ```o # For most applications originator should be the user since models can be updated/created/deleted by several users. ``` -Then originator name could be used for querying and preloading however originator setting must be done via originator_id: +Then originator name could be used for querying and preloading. Originator setting must be done via ```:originator``` or originator name that is defined in the paper_trail configuration: ```elixir user = create_user() -PaperTrail.insert(changeset, originator_id: user.id) -{:ok, result} = PaperTrail.update(edit_changeset, originator_id: user.id) +# all these set originator_id's for the version records +PaperTrail.insert(changeset, originator: user) +{:ok, result} = PaperTrail.update(edit_changeset, originator: user) +# or you can use :user in the params instead of :originator if this is your config: +# paper_trail originator: [name: :user, model: YourApplication.User] +{:ok, result} = PaperTrail.update(edit_changeset, user: user) result[:version] |> Repo.preload(:user) |> Map.get(:user) # we can access the user who made the change from the version thanks to originator relationships! -PaperTrail.delete(edit_changeset, originator_id: user.id) +PaperTrail.delete(edit_changeset, user: user) ``` Also make sure you have the foreign-key constraint in the database and in your version migration file. @@ -263,7 +267,7 @@ edited_company = Company.changeset(company, %{name: "Acme Inc."}) |> PaperTrail. Additionally, you can put a null constraint on ```origin``` column, you should always put an ```origin``` reference to describe who makes the change. This is important for big applications because a model can change from many sources. ### Storing version meta data -You might want to add some meta data that doesn't belong to ``originator_id`` and ``origin`` fields. Such data could be stored in one object named ```meta``` in paper_trail versions. Meta field could be passed as the second optional parameter to PaperTrail.insert/2, PaperTrail.update/2, PaperTrail.delete/2 functions: +You might want to add some meta data that doesn't belong to ``originator`` and ``origin`` fields. Such data could be stored in one object named ```meta``` in paper_trail versions. Meta field could be passed as the second optional parameter to PaperTrail.insert/2, PaperTrail.update/2, PaperTrail.delete/2 functions: ```elixir company = Company.changeset(%Company{}, %{name: "Acme Inc."}) @@ -274,7 +278,7 @@ edited_company = Company.changeset(company, %{name: "Acme LLC"}) # or even with an originator: user = create_user() deleted_company = Company.changeset(edited_company, %{}) - |> PaperTrail.delete(origin: "worker:github", originator: user.id, meta: %{slug: "acme-llc", important: true}) + |> PaperTrail.delete(origin: "worker:github", originator: user, meta: %{slug: "acme-llc", important: true}) ``` ## Suggestions diff --git a/config/test.exs b/config/test.exs index b065d185..07c32d77 100644 --- a/config/test.exs +++ b/config/test.exs @@ -2,7 +2,7 @@ use Mix.Config config :paper_trail, ecto_repos: [PaperTrail.Repo] -config :paper_trail, repo: PaperTrail.Repo +config :paper_trail, repo: PaperTrail.Repo, originator: [name: :user, model: User] config :paper_trail, PaperTrail.Repo, adapter: Ecto.Adapters.Postgres, diff --git a/doc/404.html b/doc/404.html index b901414e..de46d845 100644 --- a/doc/404.html +++ b/doc/404.html @@ -5,7 +5,7 @@ - 404 – paper_trail v0.6.3 + 404 – paper_trail v0.7.0 @@ -28,7 +28,7 @@

paper_trail

diff --git a/doc/Mix.Tasks.Papertrail.Install.html b/doc/Mix.Tasks.Papertrail.Install.html index b6e2ea7a..44310646 100644 --- a/doc/Mix.Tasks.Papertrail.Install.html +++ b/doc/Mix.Tasks.Papertrail.Install.html @@ -5,7 +5,7 @@ - Mix.Tasks.Papertrail.Install – paper_trail v0.6.3 + Mix.Tasks.Papertrail.Install – paper_trail v0.7.0 @@ -28,7 +28,7 @@

paper_trail

@@ -60,7 +60,7 @@

- paper_trail v0.6.3 + paper_trail v0.7.0 Mix.Tasks.Papertrail.Install diff --git a/doc/PaperTrail.Migration.html b/doc/PaperTrail.Migration.html index ff4d0be5..2879136b 100644 --- a/doc/PaperTrail.Migration.html +++ b/doc/PaperTrail.Migration.html @@ -5,7 +5,7 @@ - PaperTrail.Migration – paper_trail v0.6.3 + PaperTrail.Migration – paper_trail v0.7.0 @@ -28,7 +28,7 @@

paper_trail

@@ -60,7 +60,7 @@

- paper_trail v0.6.3 + paper_trail v0.7.0 PaperTrail.Migration diff --git a/doc/PaperTrail.RepoClient.html b/doc/PaperTrail.RepoClient.html index 311876a8..7a6df3cd 100644 --- a/doc/PaperTrail.RepoClient.html +++ b/doc/PaperTrail.RepoClient.html @@ -5,7 +5,7 @@ - PaperTrail.RepoClient – paper_trail v0.6.3 + PaperTrail.RepoClient – paper_trail v0.7.0 @@ -28,7 +28,7 @@

paper_trail

@@ -60,7 +60,7 @@

- paper_trail v0.6.3 + paper_trail v0.7.0 PaperTrail.RepoClient diff --git a/doc/PaperTrail.Version.html b/doc/PaperTrail.Version.html index 0cd6be23..e1891d4c 100644 --- a/doc/PaperTrail.Version.html +++ b/doc/PaperTrail.Version.html @@ -5,7 +5,7 @@ - PaperTrail.Version – paper_trail v0.6.3 + PaperTrail.Version – paper_trail v0.7.0 @@ -28,7 +28,7 @@

paper_trail

@@ -60,7 +60,7 @@

- paper_trail v0.6.3 + paper_trail v0.7.0 PaperTrail.Version diff --git a/doc/PaperTrail.VersionQueries.html b/doc/PaperTrail.VersionQueries.html index f212cc92..3ef9f149 100644 --- a/doc/PaperTrail.VersionQueries.html +++ b/doc/PaperTrail.VersionQueries.html @@ -5,7 +5,7 @@ - PaperTrail.VersionQueries – paper_trail v0.6.3 + PaperTrail.VersionQueries – paper_trail v0.7.0 @@ -28,7 +28,7 @@

paper_trail

@@ -60,7 +60,7 @@

- paper_trail v0.6.3 + paper_trail v0.7.0 PaperTrail.VersionQueries diff --git a/doc/PaperTrail.html b/doc/PaperTrail.html index f376ccb9..d231872a 100644 --- a/doc/PaperTrail.html +++ b/doc/PaperTrail.html @@ -5,7 +5,7 @@ - PaperTrail – paper_trail v0.6.3 + PaperTrail – paper_trail v0.7.0 @@ -28,7 +28,7 @@

paper_trail

@@ -60,7 +60,7 @@

- paper_trail v0.6.3 + paper_trail v0.7.0 PaperTrail @@ -85,7 +85,7 @@

- delete(struct, options \\ [origin: nil, meta: nil, originator_id: nil]) + delete(struct, options \\ [origin: nil, meta: nil, originator: nil])

Deletes a record from the database with a related version insertion in one transaction

@@ -139,7 +139,7 @@

Inserts a record to the database with a related version insertion in one transaction

@@ -148,7 +148,7 @@

Updates a record from the database with a related version insertion in one transaction

@@ -184,7 +184,7 @@

- delete(struct, options \\ [origin: nil, meta: nil, originator_id: nil]) + delete(struct, options \\ [origin: nil, meta: nil, originator: nil]) @@ -282,7 +282,7 @@

- insert(changeset, options \\ [origin: nil, meta: nil, originator_id: nil]) + insert(changeset, options \\ [origin: nil, meta: nil, originator: nil]) @@ -300,7 +300,7 @@

- update(changeset, options \\ [origin: nil, meta: nil, originator_id: nil]) + update(changeset, options \\ [origin: nil, meta: nil, originator: nil]) diff --git a/doc/api-reference.html b/doc/api-reference.html index 7eed0c0b..2c1947b6 100644 --- a/doc/api-reference.html +++ b/doc/api-reference.html @@ -5,7 +5,7 @@ - API Reference – paper_trail v0.6.3 + API Reference – paper_trail v0.7.0 @@ -28,7 +28,7 @@

paper_trail

@@ -60,7 +60,7 @@

- paper_trail v0.6.3 + paper_trail v0.7.0 API Reference

diff --git a/doc/index.html b/doc/index.html index 5e30ee32..2a32d159 100644 --- a/doc/index.html +++ b/doc/index.html @@ -2,7 +2,7 @@ - paper_trail v0.6.3 – Documentation + paper_trail v0.7.0 – Documentation diff --git a/lib/paper_trail.ex b/lib/paper_trail.ex index 1e22378d..c80a61fe 100644 --- a/lib/paper_trail.ex +++ b/lib/paper_trail.ex @@ -6,7 +6,8 @@ defmodule PaperTrail do alias Ecto.Multi alias PaperTrail.Version - @repo PaperTrail.RepoClient.repo + @repo PaperTrail.RepoClient.repo() + @originator PaperTrail.RepoClient.originator() @client PaperTrail.RepoClient @doc """ @@ -47,7 +48,7 @@ defmodule PaperTrail do @doc """ Inserts a record to the database with a related version insertion in one transaction """ - def insert(changeset, options \\ [origin: nil, meta: nil, originator_id: nil]) do + def insert(changeset, options \\ [origin: nil, meta: nil, originator: nil]) do case @client.strict_mode() do true -> transaction = Multi.new @@ -98,7 +99,7 @@ defmodule PaperTrail do @doc """ Updates a record from the database with a related version insertion in one transaction """ - def update(changeset, options \\ [origin: nil, meta: nil, originator_id: nil]) do + def update(changeset, options \\ [origin: nil, meta: nil, originator: nil]) do case @client.strict_mode() do true -> transaction = Multi.new @@ -145,7 +146,7 @@ defmodule PaperTrail do @doc """ Deletes a record from the database with a related version insertion in one transaction """ - def delete(struct, options \\ [origin: nil, meta: nil, originator_id: nil]) do + def delete(struct, options \\ [origin: nil, meta: nil, originator: nil]) do transaction = Multi.new |> Multi.delete(:model, struct) |> Multi.run(:version, fn %{} -> @@ -161,34 +162,49 @@ defmodule PaperTrail do end defp make_version_struct(%{event: "insert"}, model, options) do + originator_ref = options[@originator[:name]] || options[:originator] + originator_id = case originator_ref do + nil -> nil + _ -> originator_ref |> Map.get(:id) + end %Version{ event: "insert", item_type: model.__struct__ |> Module.split |> List.last, item_id: model.id, item_changes: serialize(model), - originator_id: options[:originator_id], + originator_id: originator_id, origin: options[:origin], meta: options[:meta] } end defp make_version_struct(%{event: "update"}, changeset, options) do + originator_ref = options[@originator[:name]] || options[:originator] + originator_id = case originator_ref do + nil -> nil + _ -> originator_ref |> Map.get(:id) + end %Version{ event: "update", item_type: changeset.data.__struct__ |> Module.split |> List.last, item_id: changeset.data.id, item_changes: changeset.changes, - originator_id: options[:originator_id], + originator_id: originator_id, origin: options[:origin], meta: options[:meta] } end defp make_version_struct(%{event: "delete"}, model, options) do + originator_ref = options[@originator[:name]] || options[:originator] + originator_id = case originator_ref do + nil -> nil + _ -> originator_ref |> Map.get(:id) + end %Version{ event: "delete", item_type: model.__struct__ |> Module.split |> List.last, item_id: model.id, item_changes: serialize(model), - originator_id: options[:originator_id], + originator_id: originator_id, origin: options[:origin], meta: options[:meta] } diff --git a/lib/paper_trail/repo_client.ex b/lib/paper_trail/repo_client.ex index 6a806c61..da2e3cbd 100644 --- a/lib/paper_trail/repo_client.ex +++ b/lib/paper_trail/repo_client.ex @@ -1,9 +1,8 @@ defmodule PaperTrail.RepoClient do - @doc """ Gets the configured repo module or defaults to Repo if none configured """ - def repo, do: Application.get_env(:paper_trail, :repo) || Repo - def originator, do: Application.get_env(:paper_trail, :originator) || nil - def strict_mode, do: Application.get_env(:paper_trail, :strict_mode) || false + def repo, do: Application.get_env(:paper_trail, :repo, Repo) + def originator, do: Application.get_env(:paper_trail, :originator, nil) + def strict_mode, do: Application.get_env(:paper_trail, :strict_mode, false) end diff --git a/mix.exs b/mix.exs index e4bbf7cd..461b9609 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule PaperTrail.Mixfile do def project do [ app: :paper_trail, - version: "0.6.3", + version: "0.7.0", elixir: "~> 1.4", description: description(), build_embedded: Mix.env == :prod, diff --git a/test/paper_trail_strict_mode_test.exs b/test/paper_trail_strict_mode_test.exs index 49917c49..103574d6 100644 --- a/test/paper_trail_strict_mode_test.exs +++ b/test/paper_trail_strict_mode_test.exs @@ -1,3 +1,4 @@ +# test one with user:, one with originator defmodule PaperTrailStrictModeTest do use ExUnit.Case @@ -32,7 +33,7 @@ defmodule PaperTrailStrictModeTest do test "creating a company creates a company version with correct attributes" do user = create_user() - {:ok, result} = create_company_with_version(@create_company_params, originator_id: user.id) + {:ok, result} = create_company_with_version(@create_company_params, user: user) company_count = Company.count() version_count = Version.count() @@ -78,7 +79,7 @@ defmodule PaperTrailStrictModeTest do user = create_user() {:ok, insert_company_result} = create_company_with_version() {:ok, result} = update_company_with_version( - insert_company_result[:model], @update_company_params, originator_id: user.id + insert_company_result[:model], @update_company_params, originator: user ) company_count = Company.count() @@ -137,7 +138,7 @@ defmodule PaperTrailStrictModeTest do {:ok, insert_company_result} = create_company_with_version() {:ok, update_company_result} = update_company_with_version(insert_company_result[:model]) company_before_deletion = first(Company, :id) |> @repo.one |> serialize - {:ok, result} = PaperTrail.delete(update_company_result[:model], originator_id: user.id) + {:ok, result} = PaperTrail.delete(update_company_result[:model], user: user) company_count = Company.count() version_count = Version.count() diff --git a/test/paper_trail_test.exs b/test/paper_trail_test.exs index 93e612bb..be2e4800 100644 --- a/test/paper_trail_test.exs +++ b/test/paper_trail_test.exs @@ -32,7 +32,7 @@ defmodule PaperTrailTest do test "creating a company creates a company version with correct attributes" do user = create_user() - {:ok, result} = create_company_with_version(@create_company_params, originator_id: user.id) + {:ok, result} = create_company_with_version(@create_company_params, originator: user) company_count = Company.count() version_count = Version.count() @@ -72,11 +72,50 @@ defmodule PaperTrailTest do assert result == ecto_result end - test "updating a company creates a company version with correct item_changes" do + test "updating a company with originator creates a correct company version" do user = create_user() {:ok, insert_result} = create_company_with_version() {:ok, result} = update_company_with_version( - insert_result[:model], @update_company_params, originator_id: user.id + insert_result[:model], @update_company_params, user: user + ) + + company_count = Company.count() + version_count = Version.count() + + company = result[:model] |> serialize + version = result[:version] |> serialize + + assert Map.keys(result) == [:model, :version] + assert company_count == 1 + assert version_count == 2 + assert Map.drop(company, [:id, :inserted_at, :updated_at]) == %{ + name: "Acme LLC", + is_active: true, + city: "Hong Kong", + website: "http://www.acme.com", + address: nil, + facebook: "acme.llc", + twitter: nil, + founded_in: nil + } + assert Map.drop(version, [:id, :inserted_at]) == %{ + event: "update", + item_type: "SimpleCompany", + item_id: company.id, + item_changes: %{city: "Hong Kong", website: "http://www.acme.com", facebook: "acme.llc"}, + originator_id: user.id, + origin: nil, + meta: nil + } + assert company == first(Company, :id) |> @repo.one |> serialize + end + + + test "updating a company with originator[user] creates a correct company version" do + user = create_user() + {:ok, insert_result} = create_company_with_version() + {:ok, result} = update_company_with_version( + insert_result[:model], @update_company_params, user: user ) company_count = Company.count() @@ -128,7 +167,7 @@ defmodule PaperTrailTest do {:ok, insert_result} = create_company_with_version() {:ok, update_result} = update_company_with_version(insert_result[:model]) company_before_deletion = first(Company, :id) |> @repo.one |> serialize - {:ok, result} = PaperTrail.delete(update_result[:model], originator_id: user.id) + {:ok, result} = PaperTrail.delete(update_result[:model], originator: user) company_count = Company.count() version_count = Version.count()