16 Commits

  1. 37
      CHANGELOG.md
  2. 6
      assets/css/app.scss
  3. 2
      assets/js/editor.js
  4. 95
      assets/package-lock.json
  5. 3
      assets/package.json
  6. 8
      lib/mirage/notes.ex
  7. 8
      lib/mirage/notes/note_link.ex
  8. 2
      lib/mirage/notes/note_topic.ex
  9. 1
      lib/mirage_web.ex
  10. 13
      lib/mirage_web/controllers/note_controller.ex
  11. 5
      lib/mirage_web/controllers/user_auth.ex
  12. 46
      lib/mirage_web/live/show_note_live.ex
  13. 56
      lib/mirage_web/live/show_note_live.html.leex
  14. 9
      lib/mirage_web/router.ex
  15. 2
      lib/mirage_web/templates/note/index.html.eex
  16. 2
      lib/mirage_web/templates/note/show.html.eex
  17. 3
      mix.exs
  18. 12
      mix.lock
  19. 17
      priv/repo/migrations/20210210184450_remove_timestamps_from_join_tables.exs
  20. 6
      test/mirage/notes_test.exs
  21. 10
      test/mirage_web/controllers/note_controller_test.exs

37
CHANGELOG.md

@ -5,6 +5,43 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
<!-- changelog -->
## [v0.21.0](https://git.inhji.de/inhji/mirage/compare/v0.20.0...v0.21.0) (2021-02-10)
### Features:
* remove show from note controller
* add css for source links
* remove timestamps from join tables
* add note links, move note show to live view
* require note_id for NoteLink schema
* import live_render for controllers
* put user_id in session on login
* add db stats to phx dashboard
### Bug Fixes:
* clean up user_id from session on logout
* replace note_path with live_path for show action
* editor config
* remove timestamps from schemas
* add prismjs as dependency
* remove timestamps from join tables, rename note_links to notes_links
## [v0.20.0](https://git.inhji.de/inhji/mirage/compare/v0.19.2...v0.20.0) (2021-02-10)

6
assets/css/app.scss

@ -220,12 +220,12 @@ kbd {
}
}
.backlinks {
.backlinks, .sources {
h4 {
margin-bottom: 1rem;
}
.backlink {
.link {
display: block;
padding: 1rem;
border: 1px solid $border-base;
@ -233,7 +233,7 @@ kbd {
text-decoration: none;
}
.backlink:last-child {
.link:last-child {
margin-bottom: 0;
}
}

2
assets/js/editor.js

@ -27,8 +27,8 @@ export default function initEditor(element) {
markdown(),
defaultHighlightStyle,
keymap.of([
defaultTabBinding,
...defaultKeymap,
...defaultTabBinding,
...historyKeymap
]),
]

95
assets/package-lock.json

@ -12,7 +12,8 @@
"nprogress": "^0.2.0",
"phoenix": "file:../deps/phoenix",
"phoenix_html": "file:../deps/phoenix_html",
"phoenix_live_view": "file:../deps/phoenix_live_view"
"phoenix_live_view": "file:../deps/phoenix_live_view",
"prismjs": "^1.23.0"
},
"devDependencies": {
"@babel/core": "^7.x",
@ -1974,6 +1975,17 @@
"node": ">=6"
}
},
"node_modules/clipboard": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
"integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
"optional": true,
"dependencies": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
"tiny-emitter": "^2.0.0"
}
},
"node_modules/clone-deep": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@ -2661,6 +2673,12 @@
"node": ">= 0.4"
}
},
"node_modules/delegate": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
"optional": true
},
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@ -3192,6 +3210,15 @@
"node": ">=10"
}
},
"node_modules/good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
"optional": true,
"dependencies": {
"delegate": "^3.1.2"
}
},
"node_modules/graceful-fs": {
"version": "4.2.6",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
@ -5868,6 +5895,14 @@
"node": ">=0.10.0"
}
},
"node_modules/prismjs": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz",
"integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==",
"optionalDependencies": {
"clipboard": "^2.0.0"
}
},
"node_modules/promise-inflight": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@ -6137,6 +6172,12 @@
"node": ">= 8.9.0"
}
},
"node_modules/select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
"optional": true
},
"node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@ -6522,6 +6563,12 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true
},
"node_modules/tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
"optional": true
},
"node_modules/to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@ -8725,6 +8772,17 @@
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
"dev": true
},
"clipboard": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
"integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
"optional": true,
"requires": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
"tiny-emitter": "^2.0.0"
}
},
"clone-deep": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@ -9294,6 +9352,12 @@
"object-keys": "^1.0.12"
}
},
"delegate": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
"optional": true
},
"dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@ -9722,6 +9786,15 @@
"slash": "^3.0.0"
}
},
"good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
"integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
"optional": true,
"requires": {
"delegate": "^3.1.2"
}
},
"graceful-fs": {
"version": "4.2.6",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
@ -11864,6 +11937,14 @@
"integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
"dev": true
},
"prismjs": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz",
"integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==",
"requires": {
"clipboard": "^2.0.0"
}
},
"promise-inflight": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
@ -12084,6 +12165,12 @@
"ajv-keywords": "^3.5.2"
}
},
"select": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
"optional": true
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@ -12403,6 +12490,12 @@
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
"dev": true
},
"tiny-emitter": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
"optional": true
},
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",

3
assets/package.json

@ -12,7 +12,8 @@
"nprogress": "^0.2.0",
"phoenix": "file:../deps/phoenix",
"phoenix_html": "file:../deps/phoenix_html",
"phoenix_live_view": "file:../deps/phoenix_live_view"
"phoenix_live_view": "file:../deps/phoenix_live_view",
"prismjs": "^1.23.0"
},
"devDependencies": {
"@babel/core": "^7.x",

8
lib/mirage/notes.ex

@ -6,7 +6,7 @@ defmodule Mirage.Notes do
import Ecto.Query, warn: false
alias Mirage.Repo
alias Mirage.Notes.{Note, Topic, NoteNote}
alias Mirage.Notes.{Note, Topic, NoteNote, NoteLink}
@note_preloads [:links, :topics, :backlinks]
@topic_preloads [:notes]
@ -159,6 +159,12 @@ defmodule Mirage.Notes do
Repo.transaction(multi)
end
def create_note_link(attrs \\ %{}) do
%NoteLink{}
|> NoteLink.changeset(attrs)
|> Repo.insert()
end
@doc """
Returns the list of topics.

8
lib/mirage/notes/note_link.ex

@ -2,19 +2,17 @@ defmodule Mirage.Notes.NoteLink do
use Ecto.Schema
import Ecto.Changeset
schema "note_links" do
schema "notes_links" do
field :title, :string
field :url, :string
belongs_to :note, Mirage.Notes.Note
timestamps()
end
@doc false
def changeset(link, attrs) do
link
|> cast(attrs, [:title, :url])
|> validate_required([:title, :url])
|> cast(attrs, [:title, :url, :note_id])
|> validate_required([:url, :note_id])
end
end

2
lib/mirage/notes/note_topic.ex

@ -6,8 +6,6 @@ defmodule Mirage.Notes.NoteTopic do
schema "notes_topics" do
belongs_to :note, Note
belongs_to :topic, Topic
timestamps()
end
@attrs [:note_id, :topic_id]

1
lib/mirage_web.ex

@ -24,6 +24,7 @@ defmodule MirageWeb do
import Plug.Conn
import MirageWeb.Gettext
import MirageWeb.UserAuth, only: [require_authenticated_user: 2]
import Phoenix.LiveView.Controller, only: [live_render: 2, live_render: 3]
alias MirageWeb.Router.Helpers, as: Routes
end
end

13
lib/mirage_web/controllers/note_controller.ex

@ -26,22 +26,13 @@ defmodule MirageWeb.NoteController do
conn
|> put_flash(:info, "Note created successfully.")
|> redirect(to: Routes.note_path(conn, :show, note))
|> redirect(to: Routes.live_path(conn, MirageWeb.ShowNoteLive, note))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
def show(conn, %{"id" => id}) do
note =
id
|> Notes.get_note!()
|> Notes.preload_note()
render(conn, "show.html", note: note)
end
def edit(conn, %{"id" => id}) do
note =
id
@ -66,7 +57,7 @@ defmodule MirageWeb.NoteController do
conn
|> put_flash(:info, "Note updated successfully.")
|> redirect(to: Routes.note_path(conn, :show, note))
|> redirect(to: Routes.live_path(conn, MirageWeb.ShowNoteLive, note))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "edit.html", note: note, changeset: changeset)

5
lib/mirage_web/controllers/user_auth.ex

@ -91,7 +91,10 @@ defmodule MirageWeb.UserAuth do
def fetch_current_user(conn, _opts) do
{user_token, conn} = ensure_user_token(conn)
user = user_token && Accounts.get_user_by_session_token(user_token)
assign(conn, :current_user, user)
conn
|> assign(:current_user, user)
|> put_session(:user_id, user && user.id)
end
defp ensure_user_token(conn) do

46
lib/mirage_web/live/show_note_live.ex

@ -0,0 +1,46 @@
defmodule MirageWeb.ShowNoteLive do
use MirageWeb, :live_view
alias Mirage.Notes
alias Mirage.Notes.NoteLink
@impl true
def mount(_params, %{"user_id" => user_id}, socket) do
current_user = user_id && Mirage.Accounts.get_user!(user_id)
{:ok, socket |> assign(%{current_user: current_user})}
end
@impl true
def handle_params(%{"id" => note_id}, uri, socket) do
note =
note_id
|> Notes.get_note!()
|> Notes.preload_note()
link_changeset = NoteLink.changeset(%NoteLink{}, %{note_id: note_id})
{:noreply, socket |> assign(%{note: note, link_changeset: link_changeset})}
end
@impl true
def handle_event("save_link", %{"note_link" => link}, socket) do
case Notes.create_note_link(link) do
{:ok, _link} ->
note_id = socket.assigns.note.id
note =
note_id
|> Notes.get_note!()
|> Notes.preload_note()
{:noreply,
socket
|> assign(%{
note: note,
link_changeset: NoteLink.changeset(%NoteLink{}, %{note_id: note_id})
})}
_ ->
{:noreply, socket}
end
end
end

56
lib/mirage_web/live/show_note_live.html.leex

@ -0,0 +1,56 @@
<div class="hero">
<h1><span class="id"><%= "##{@note.id}" %></span> <%= @note.title %></h1>
<p><time datetime="<%= @note.inserted_at %>"><%= Timex.from_now(@note.inserted_at) %></time> / <time datetime="<%= @note.updated_at %>"><%= Timex.from_now(@note.updated_at) %></time></p>
<p class="tags">
<%= for topic <- @note.topics do %>
<span class="tag"><%= topic.text %></span>
<% end %>
</p>
</div>
<div class="width-full bg-content">
<article>
<div class="content html">
<%= raw @note.content_html %>
</div>
</article>
</div>
<%= if not Enum.empty?(@note.backlinks) do %>
<section class="backlinks">
<h4>Backlinks</h4>
<%= for backlink <- @note.backlinks do %>
<%= live_patch backlink.title, to: Routes.live_path(@socket, MirageWeb.ShowNoteLive, backlink), class: "link bg-content" %>
<% end %>
</section>
<% end %>
<%= if not Enum.empty?(@note.links) do %>
<section class="sources">
<h4>Sources</h4>
<%= if @current_user do %>
<%= f = form_for @link_changeset, "#", [phx_submit: :save_link] %>
<fieldset>
<%= hidden_input f, :note_id %>
<%= url_input f, :url, placeholder: "Add new link and press ENTER" %>
</fieldset>
</form>
<% end %>
<%= for link <- @note.links do %>
<%= link link.title || link.url, to: link.url, class: "link bg-content" %>
<% end %>
</section>
<% end %>
<%= if @current_user do %>
<div class="buttons">
<span><%= link "Edit", to: Routes.note_path(MirageWeb.Endpoint, :edit, @note), class: "button" %></span>
<span><%= link "Back", to: Routes.note_path(MirageWeb.Endpoint, :index), class: "button" %></span>
<span><%= link "Delete", to: Routes.note_path(MirageWeb.Endpoint, :delete, @note), method: :delete, data: [confirm: "Are you sure?"], class: "button" %></span>
</div>
<% end %>

9
lib/mirage_web/router.ex

@ -28,9 +28,11 @@ defmodule MirageWeb.Router do
live "/", PageLive, :index
resources "/notes", NoteController
resources "/notes", NoteController, except: [:show]
resources "/topics", TopicController
resources "/settings", SettingController, only: [:index, :show, :edit, :update]
live "/notes/:id", ShowNoteLive
end
# Other scopes may use custom stacks.
@ -50,7 +52,10 @@ defmodule MirageWeb.Router do
scope "/" do
pipe_through :browser
live_dashboard "/dashboard", metrics: MirageWeb.Telemetry
live_dashboard "/dashboard",
metrics: MirageWeb.Telemetry,
ecto_repos: [Mirage.Repo]
end
end

2
lib/mirage_web/templates/note/index.html.eex

@ -5,7 +5,7 @@
<section class="notes">
<%= for note <- @notes do %>
<article>
<%= link to: Routes.note_path(@conn, :show, note) do %>
<%= link to: Routes.live_path(@conn, MirageWeb.ShowNoteLive, note) do %>
<header class="width-full bg-content">
<h2 class="title">
<span class="id"><%= "##{note.id}" %></span> <%= note.title %>

2
lib/mirage_web/templates/note/show.html.eex

@ -21,7 +21,7 @@
<h4>Backlinks</h4>
<%= for backlink <- @note.backlinks do %>
<%= link backlink.title, to: Routes.note_path(@conn, :show, backlink), class: "backlink bg-content" %>
<%= link backlink.title, to: Routes.live_path(@conn, MirageWeb.ShowNoteLive, backlink), class: "backlink bg-content" %>
<% end %>
</section>
<% end %>

3
mix.exs

@ -1,7 +1,7 @@
defmodule Mirage.MixProject do
use Mix.Project
@version "0.20.0"
@version "0.21.0"
def project do
[
@ -38,6 +38,7 @@ defmodule Mirage.MixProject do
{:bcrypt_elixir, "~> 2.0"},
{:earmark, "~> 1.4"},
{:ecto_sql, "~> 3.4"},
{:ecto_psql_extras, "~> 0.2"},
{:floki, ">= 0.27.0", only: :test},
{:gettext, "~> 0.11"},
{:git_ops, "~> 2.4.2", only: [:dev]},

12
mix.lock

@ -2,7 +2,7 @@
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.0", "6cb662d5c1b0a8858801cf20997bd006e7016aa8c52959c9ef80e0f34fb60b7a", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2c81d61d4f6ed0e5cf7bf27a9109b791ff216a1034b3d541327484f46dd43769"},
"certifi": {:hex, :certifi, "2.5.3", "70bdd7e7188c804f3a30ee0e7c99655bc35d8ac41c23e12325f36ab449b70651", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "ed516acb3929b101208a9d700062d520f3953da3b6b918d866106ffa980e1c10"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"comeonin": {:hex, :comeonin, "5.3.1", "7fe612b739c78c9c1a75186ef2d322ce4d25032d119823269d0aa1e2f1e20025", [:mix], [], "hexpm", "d6222483060c17f0977fad1b7401ef0c5863c985a64352755f366aee3799c245"},
"comeonin": {:hex, :comeonin, "5.3.2", "5c2f893d05c56ae3f5e24c1b983c2d5dfb88c6d979c9287a76a7feb1e1d8d646", [:mix], [], "hexpm", "d0993402844c49539aeadb3fe46a3c9bd190f1ecf86b6f9ebd71957534c95f04"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cowboy": {:hex, :cowboy, "2.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", [:rebar3], [{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.3.1", "ebd1a1d7aff97f27c66654e78ece187abdc646992714164380d8a041eda16754", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3a6efd3366130eab84ca372cbd4a7d3c3a97bdfcfb4911233b035d117063f0af"},
@ -11,11 +11,12 @@
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"earmark": {:hex, :earmark, "1.4.13", "2c6ce9768fc9fdbf4046f457e207df6360ee6c91ee1ecb8e9a139f96a4289d91", [:mix], [{:earmark_parser, ">= 1.4.12", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "a0cf3ed88ef2b1964df408889b5ecb886d1a048edde53497fc935ccd15af3403"},
"earmark_parser": {:hex, :earmark_parser, "1.4.12", "b245e875ec0a311a342320da0551da407d9d2b65d98f7a9597ae078615af3449", [:mix], [], "hexpm", "711e2cc4d64abb7d566d43f54b78f7dc129308a63bc103fbd88550d2174b3160"},
"ecto": {:hex, :ecto, "3.5.5", "48219a991bb86daba6e38a1e64f8cea540cded58950ff38fbc8163e062281a07", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "98dd0e5e1de7f45beca6130d13116eae675db59adfa055fb79612406acf6f6f1"},
"ecto_sql": {:hex, :ecto_sql, "3.5.3", "1964df0305538364b97cc4661a2bd2b6c89d803e66e5655e4e55ff1571943efd", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.5.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d2f53592432ce17d3978feb8f43e8dc0705e288b0890caf06d449785f018061c"},
"ecto": {:hex, :ecto, "3.5.7", "f440a476bf1be361173a43a4a18f04a2fdf4e6fac5b0457f03d8686e55f13f7e", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "04c4e69d4f1cc2bb085aa760d50389ba8ae3003f80c112fbde87d57f5ed75d39"},
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.6.2", "ff964dcfd80ee285797025734484742faa04b56c2674380014e7233851c5f8b2", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.15.7", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.0.0", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "7e7f88140f14a8aed4b82269aece28498086edd032cd94fac7d05059f9b09c7e"},
"ecto_sql": {:hex, :ecto_sql, "3.5.4", "a9e292c40bd79fff88885f95f1ecd7b2516e09aa99c7dd0201aa84c54d2358e4", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.5.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1fff1a28a898d7bbef263f1f3ea425b04ba9f33816d843238c84eff883347343"},
"elixir_make": {:hex, :elixir_make, "0.6.2", "7dffacd77dec4c37b39af867cedaabb0b59f6a871f89722c25b28fcd4bd70530", [:mix], [], "hexpm", "03e49eadda22526a7e5279d53321d1cced6552f344ba4e03e619063de75348d9"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"floki": {:hex, :floki, "0.29.0", "b1710d8c93a2f860dc2d7adc390dd808dc2fb8f78ee562304457b75f4c640881", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "008585ce64b9f74c07d32958ec9866f4b8a124bf4da1e2941b28e41384edaaad"},
"floki": {:hex, :floki, "0.30.0", "22ebbe681a5d3777cdd830ca091b1b806d33c3449c26312eadca7f7be685c0c8", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "a9e128a4ca9bb71f11affa315b6768a9ad326d5996ff1e92acf1d7a01a10076a"},
"gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"},
"git_cli": {:hex, :git_cli, "0.3.0", "a5422f9b95c99483385b976f5d43f7e8233283a47cda13533d7c16131cb14df5", [:mix], [], "hexpm", "78cb952f4c86a41f4d3511f1d3ecb28edb268e3a7df278de2faa1bd4672eaf9b"},
"git_ops": {:hex, :git_ops, "2.4.2", "291a4f105dfa3d34cffa56cf8faf0e8c2699b49d3316270aa4881e75c62b1832", [:mix], [{:git_cli, "~> 0.2", [hex: :git_cli, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "bd9051c49e17d0dc2e0ae9306292f9f5f671d402227f5dda12e69a702198dec4"},
@ -39,10 +40,11 @@
"plug": {:hex, :plug, "1.11.0", "f17217525597628298998bc3baed9f8ea1fa3f1160aa9871aee6df47a6e4d38e", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2d9c633f0499f9dc5c2fd069161af4e2e7756890b81adcbb2ceaa074e8308876"},
"plug_cowboy": {:hex, :plug_cowboy, "2.4.1", "779ba386c0915027f22e14a48919a9545714f849505fa15af2631a0d298abf0f", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d72113b6dff7b37a7d9b2a5b68892808e3a9a752f2bf7e503240945385b70507"},
"plug_crypto": {:hex, :plug_crypto, "1.2.0", "1cb20793aa63a6c619dd18bb33d7a3aa94818e5fd39ad357051a67f26dfa2df6", [:mix], [], "hexpm", "a48b538ae8bf381ffac344520755f3007cc10bd8e90b240af98ea29b69683fc2"},
"postgrex": {:hex, :postgrex, "0.15.7", "724410acd48abac529d0faa6c2a379fb8ae2088e31247687b16cacc0e0883372", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "88310c010ff047cecd73d5ceca1d99205e4b1ab1b9abfdab7e00f5c9d20ef8f9"},
"postgrex": {:hex, :postgrex, "0.15.8", "f5e782bbe5e8fa178d5e3cd1999c857dc48eda95f0a4d7f7bd92a50e84a0d491", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "698fbfacea34c4cf22c8281abeb5cf68d99628d541874f085520ab3b53d356fe"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"},
"slugger": {:hex, :slugger, "0.3.0", "efc667ab99eee19a48913ccf3d038b1fb9f165fa4fbf093be898b8099e61b6ed", [:mix], [], "hexpm", "20d0ded0e712605d1eae6c5b4889581c3460d92623a930ddda91e0e609b5afba"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"table_rex": {:hex, :table_rex, "3.0.0", "5189b71b3b92ed461358f40f7b7b630dc37716bf6c8ab3e934b2bc63a99028bd", [:mix], [], "hexpm", "582776d24cbe6a4d30a39a7f02035b1bc979b6cd64923d7234dd2f0ad21a18c7"},
"telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.0", "da9d49ee7e6bb1c259d36ce6539cd45ae14d81247a2b0c90edf55e2b50507f7b", [:mix], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5cfe67ad464b243835512aa44321cee91faed6ea868d7fb761d7016e02915c3d"},
"telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},

17
priv/repo/migrations/20210210184450_remove_timestamps_from_join_tables.exs

@ -0,0 +1,17 @@
defmodule Mirage.Repo.Migrations.RemoveTimestampsFromJoinTables do
use Ecto.Migration
def change do
alter table(:notes_topics) do
remove :inserted_at
remove :updated_at
end
alter table(:note_links) do
remove :inserted_at
remove :updated_at
end
rename table(:note_links), to: table(:notes_links)
end
end

6
test/mirage/notes_test.exs

@ -88,12 +88,6 @@ defmodule Mirage.NotesTest do
}]]"
assert note.content_html =~ "Link to myself"
note =
Notes.get_note!(note.id)
|> Notes.preload_note()
IO.inspect(note)
end
test "update_note/2 with invalid data returns error changeset" do

10
test/mirage_web/controllers/note_controller_test.exs

@ -36,9 +36,9 @@ defmodule MirageWeb.NoteControllerTest do
conn = post(conn, Routes.note_path(conn, :create), note: @create_attrs)
assert %{id: id} = redirected_params(conn)
assert redirected_to(conn) == Routes.note_path(conn, :show, id)
assert redirected_to(conn) == Routes.live_path(conn, MirageWeb.ShowNoteLive, id)
conn = get(conn, Routes.note_path(conn, :show, id))
conn = get(conn, Routes.live_path(conn, MirageWeb.ShowNoteLive, id))
assert html_response(conn, 200) =~ "some title"
assert html_response(conn, 200) =~ "some tag"
end
@ -68,9 +68,9 @@ defmodule MirageWeb.NoteControllerTest do
end)
conn = put(conn, Routes.note_path(conn, :update, note), note: attrs)
assert redirected_to(conn) == Routes.note_path(conn, :show, note)
assert redirected_to(conn) == Routes.live_path(conn, MirageWeb.ShowNoteLive, note)
conn = get(conn, Routes.note_path(conn, :show, note))
conn = get(conn, Routes.live_path(conn, MirageWeb.ShowNoteLive, note))
assert html_response(conn, 200) =~ "some updated content with link"
assert html_response(conn, 200) =~ "some other tag"
refute html_response(conn, 200) =~ "some tag"
@ -90,7 +90,7 @@ defmodule MirageWeb.NoteControllerTest do
assert redirected_to(conn) == Routes.note_path(conn, :index)
assert_error_sent 404, fn ->
get(conn, Routes.note_path(conn, :show, note))
get(conn, Routes.live_path(conn, MirageWeb.ShowNoteLive, note))
end
end
end

Loading…
Cancel
Save