Compare commits

..

No commits in common. "1c33cd09c12f5bd8115c51a1c7c3e01284548213" and "c3ceb877b2dd4ef10a74e16c1d3ba8849f7cd38f" have entirely different histories.

25 changed files with 136 additions and 173 deletions

View File

@ -1,9 +1,3 @@
# v0.1.4
- fix docker-compose
- fix newlines in notes/context/step contents
- fix user invite page
- improve tagging logic
# v0.1.3
- backlink to other notes in notes
- search tags on click

View File

@ -2,7 +2,8 @@ version: '3'
services:
memex:
image: shibaobun/memex
build:
context: .
container_name: memex
restart: always
environment:

View File

@ -4,6 +4,7 @@ defmodule Memex.Contexts do
"""
import Ecto.Query, warn: false
alias Ecto.Changeset
alias Memex.{Accounts.User, Contexts.Context, Repo}
@doc """
@ -228,4 +229,18 @@ defmodule Memex.Contexts do
def change_context(%Context{} = context, attrs \\ %{}, user) do
context |> Context.update_changeset(attrs, user)
end
@doc """
Gets a canonical string representation of the `:tags` field for a Note
"""
@spec get_tags_string(Context.t() | Context.changeset() | [String.t()] | nil) :: String.t()
def get_tags_string(nil), do: ""
def get_tags_string(tags) when tags |> is_list(), do: tags |> Enum.join(",")
def get_tags_string(%Context{tags: tags}), do: tags |> get_tags_string()
def get_tags_string(%Changeset{} = changeset) do
changeset
|> Changeset.get_field(:tags)
|> get_tags_string()
end
end

View File

@ -27,7 +27,7 @@ defmodule Memex.Contexts.Context do
slug: slug(),
content: String.t(),
tags: [String.t()] | nil,
tags_string: String.t() | nil,
tags_string: String.t(),
visibility: :public | :private | :unlisted,
user: User.t() | Ecto.Association.NotLoaded.t(),
user_id: User.id(),
@ -66,38 +66,16 @@ defmodule Memex.Contexts.Context do
|> unsafe_validate_unique(:slug, Repo)
end
defp cast_tags_string(changeset, attrs) do
changeset
|> put_change(:tags_string, changeset |> get_field(:tags) |> get_tags_string())
|> cast(attrs, [:tags_string])
|> validate_format(:tags_string, ~r/^[\p{L}\p{N}\-\,]+$/,
message:
dgettext(
"errors",
"invalid format: only numbers, letters and hyphen are accepted. tags must be comma-delimited"
)
)
|> cast_tags()
defp cast_tags_string(changeset, %{"tags_string" => tags_string})
when tags_string |> is_binary() do
tags =
tags_string
|> String.split(",", trim: true)
|> Enum.map(fn str -> str |> String.trim() end)
|> Enum.sort()
changeset |> change(tags: tags)
end
defp cast_tags(%{valid?: false} = changeset), do: changeset
defp cast_tags(%{valid?: true} = changeset) do
tags = changeset |> get_field(:tags_string) |> process_tags()
changeset |> put_change(:tags, tags)
end
defp process_tags(tags_string) when tags_string |> is_binary() do
tags_string
|> String.split(",", trim: true)
|> Enum.map(fn str -> str |> String.trim() end)
|> Enum.reject(fn str -> str |> is_nil() end)
|> Enum.sort()
end
defp process_tags(_other_tags_string), do: []
@spec get_tags_string([String.t()] | nil) :: String.t()
def get_tags_string(nil), do: ""
def get_tags_string(tags) when tags |> is_list(), do: tags |> Enum.join(",")
defp cast_tags_string(changeset, _attrs), do: changeset
end

View File

@ -4,6 +4,7 @@ defmodule Memex.Notes do
"""
import Ecto.Query, warn: false
alias Ecto.Changeset
alias Memex.{Accounts.User, Notes.Note, Repo}
@doc """
@ -228,4 +229,18 @@ defmodule Memex.Notes do
def change_note(%Note{} = note, attrs \\ %{}, user) do
note |> Note.update_changeset(attrs, user)
end
@doc """
Gets a canonical string representation of the `:tags` field for a Note
"""
@spec get_tags_string(Note.t() | Note.changeset() | [String.t()] | nil) :: String.t()
def get_tags_string(nil), do: ""
def get_tags_string(tags) when tags |> is_list(), do: tags |> Enum.join(",")
def get_tags_string(%Note{tags: tags}), do: tags |> get_tags_string()
def get_tags_string(%Changeset{} = changeset) do
changeset
|> Changeset.get_field(:tags)
|> get_tags_string()
end
end

View File

@ -26,7 +26,7 @@ defmodule Memex.Notes.Note do
slug: slug(),
content: String.t(),
tags: [String.t()] | nil,
tags_string: String.t() | nil,
tags_string: String.t(),
visibility: :public | :private | :unlisted,
user: User.t() | Ecto.Association.NotLoaded.t(),
user_id: User.id(),
@ -65,38 +65,16 @@ defmodule Memex.Notes.Note do
|> unsafe_validate_unique(:slug, Repo)
end
defp cast_tags_string(changeset, attrs) do
changeset
|> put_change(:tags_string, changeset |> get_field(:tags) |> get_tags_string())
|> cast(attrs, [:tags_string])
|> validate_format(:tags_string, ~r/^[\p{L}\p{N}\-\,]+$/,
message:
dgettext(
"errors",
"invalid format: only numbers, letters and hyphen are accepted. tags must be comma-delimited"
)
)
|> cast_tags()
defp cast_tags_string(changeset, %{"tags_string" => tags_string})
when tags_string |> is_binary() do
tags =
tags_string
|> String.split(",", trim: true)
|> Enum.map(fn str -> str |> String.trim() end)
|> Enum.sort()
changeset |> change(tags: tags)
end
defp cast_tags(%{valid?: false} = changeset), do: changeset
defp cast_tags(%{valid?: true} = changeset) do
tags = changeset |> get_field(:tags_string) |> process_tags()
changeset |> put_change(:tags, tags)
end
defp process_tags(tags_string) when tags_string |> is_binary() do
tags_string
|> String.split(",", trim: true)
|> Enum.map(fn str -> str |> String.trim() end)
|> Enum.reject(fn str -> str |> is_nil() end)
|> Enum.sort()
end
defp process_tags(_other_tags_string), do: []
@spec get_tags_string([String.t()] | nil) :: String.t()
def get_tags_string(nil), do: ""
def get_tags_string(tags) when tags |> is_list(), do: tags |> Enum.join(",")
defp cast_tags_string(changeset, _attrs), do: changeset
end

View File

@ -4,6 +4,7 @@ defmodule Memex.Pipelines do
"""
import Ecto.Query, warn: false
alias Ecto.Changeset
alias Memex.{Accounts.User, Pipelines.Pipeline, Repo}
@doc """
@ -230,4 +231,18 @@ defmodule Memex.Pipelines do
def change_pipeline(%Pipeline{} = pipeline, attrs \\ %{}, user) do
pipeline |> Pipeline.update_changeset(attrs, user)
end
@doc """
Gets a canonical string representation of the `:tags` field for a Pipeline
"""
@spec get_tags_string(Pipeline.t() | Pipeline.changeset() | [String.t()] | nil) :: String.t()
def get_tags_string(nil), do: ""
def get_tags_string(tags) when tags |> is_list(), do: tags |> Enum.join(",")
def get_tags_string(%Pipeline{tags: tags}), do: tags |> get_tags_string()
def get_tags_string(%Changeset{} = changeset) do
changeset
|> Changeset.get_field(:tags)
|> get_tags_string()
end
end

View File

@ -28,7 +28,7 @@ defmodule Memex.Pipelines.Pipeline do
slug: slug(),
description: String.t(),
tags: [String.t()] | nil,
tags_string: String.t() | nil,
tags_string: String.t(),
visibility: :public | :private | :unlisted,
user: User.t() | Ecto.Association.NotLoaded.t(),
user_id: User.id(),
@ -67,38 +67,16 @@ defmodule Memex.Pipelines.Pipeline do
|> unsafe_validate_unique(:slug, Repo)
end
defp cast_tags_string(changeset, attrs) do
changeset
|> put_change(:tags_string, changeset |> get_field(:tags) |> get_tags_string())
|> cast(attrs, [:tags_string])
|> validate_format(:tags_string, ~r/^[\p{L}\p{N}\-\,]+$/,
message:
dgettext(
"errors",
"invalid format: only numbers, letters and hyphen are accepted. tags must be comma-delimited"
)
)
|> cast_tags()
defp cast_tags_string(changeset, %{"tags_string" => tags_string})
when tags_string |> is_binary() do
tags =
tags_string
|> String.split(",", trim: true)
|> Enum.map(fn str -> str |> String.trim() end)
|> Enum.sort()
changeset |> change(tags: tags)
end
defp cast_tags(%{valid?: false} = changeset), do: changeset
defp cast_tags(%{valid?: true} = changeset) do
tags = changeset |> get_field(:tags_string) |> process_tags()
changeset |> put_change(:tags, tags)
end
defp process_tags(tags_string) when tags_string |> is_binary() do
tags_string
|> String.split(",", trim: true)
|> Enum.map(fn str -> str |> String.trim() end)
|> Enum.reject(fn str -> str |> is_nil() end)
|> Enum.sort()
end
defp process_tags(_other_tags_string), do: []
@spec get_tags_string([String.t()] | nil) :: String.t()
def get_tags_string(nil), do: ""
def get_tags_string(tags) when tags |> is_list(), do: tags |> Enum.join(",")
defp cast_tags_string(changeset, _attrs), do: changeset
end

View File

@ -39,7 +39,6 @@ defmodule MemexWeb.Components.ContextContent do
"</p>#{link}<p class=\"inline\">"
end
)
|> String.replace("\n", "<br>")
|> HTML.raw()
end
end

View File

@ -39,7 +39,6 @@ defmodule MemexWeb.Components.NoteContent do
"</p>#{link}<p class=\"inline\">"
end
)
|> String.replace("\n", "<br>")
|> HTML.raw()
end
end

View File

@ -39,7 +39,6 @@ defmodule MemexWeb.Components.StepContent do
"</p>#{link}<p class=\"inline\">"
end
)
|> String.replace("\n", "<br>")
|> HTML.raw()
end
end

View File

@ -22,15 +22,15 @@ defmodule MemexWeb.Components.UserCard do
<%= if @user.confirmed_at |> is_nil() do %>
<%= gettext("email unconfirmed") %>
<% else %>
<p>
<%= gettext("user confirmed on") %>
<%= @user.confirmed_at |> display_datetime() %>
</p>
<%= gettext(
"user was confirmed at %{relative_datetime}",
relative_datetime: @user.confirmed_at |> display_datetime()
) %>
<% end %>
</p>
<p>
<%= gettext("user registered on") %>
<%= gettext("User registered on") %>
<%= @user.inserted_at |> display_datetime() %>
</p>
</h3>

View File

@ -27,7 +27,9 @@
<%= text_input(f, :tags_string,
id: "tags-input",
class: "input input-primary",
placeholder: gettext("tag1,tag2")
placeholder: gettext("tag1,tag2"),
phx_update: "ignore",
value: Contexts.get_tags_string(@changeset)
) %>
<%= error_tag(f, :tags_string) %>

View File

@ -27,7 +27,9 @@
<%= text_input(f, :tags_string,
id: "tags-input",
class: "input input-primary",
placeholder: gettext("tag1,tag2")
placeholder: gettext("tag1,tag2"),
phx_update: "ignore",
value: Notes.get_tags_string(@changeset)
) %>
<%= error_tag(f, :tags_string) %>

View File

@ -27,7 +27,9 @@
<%= text_input(f, :tags_string,
id: "tags-input",
class: "input input-primary",
placeholder: gettext("tag1,tag2")
placeholder: gettext("tag1,tag2"),
phx_update: "ignore",
value: Pipelines.get_tags_string(@changeset)
) %>
<%= error_tag(f, :tags_string) %>

View File

@ -4,7 +4,7 @@ defmodule Memex.MixProject do
def project do
[
app: :memex,
version: "0.1.4",
version: "0.1.3",
elixir: "~> 1.14",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: Mix.compilers(),

View File

@ -124,9 +124,9 @@ msgstr ""
msgid "register"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:40
#: lib/memex_web/live/note_live/form_component.html.heex:40
#: lib/memex_web/live/pipeline_live/form_component.html.heex:40
#: lib/memex_web/live/context_live/form_component.html.heex:42
#: lib/memex_web/live/note_live/form_component.html.heex:42
#: lib/memex_web/live/pipeline_live/form_component.html.heex:42
#: lib/memex_web/live/step_live/form_component.html.heex:28
#, elixir-autogen, elixir-format
msgid "save"

View File

@ -125,9 +125,9 @@ msgstr ""
msgid "register"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:40
#: lib/memex_web/live/note_live/form_component.html.heex:40
#: lib/memex_web/live/pipeline_live/form_component.html.heex:40
#: lib/memex_web/live/context_live/form_component.html.heex:42
#: lib/memex_web/live/note_live/form_component.html.heex:42
#: lib/memex_web/live/pipeline_live/form_component.html.heex:42
#: lib/memex_web/live/step_live/form_component.html.heex:28
#, elixir-autogen, elixir-format
msgid "save"

View File

@ -66,6 +66,11 @@ msgstr ""
msgid "Settings"
msgstr ""
#: lib/memex_web/components/user_card.ex:33
#, elixir-autogen, elixir-format
msgid "User registered on"
msgstr ""
#: lib/memex_web/components/invite_card.ex:19
#, elixir-autogen, elixir-format
msgid "Uses Left:"
@ -301,17 +306,17 @@ msgstr ""
msgid "report bugs or request features"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:41
#: lib/memex_web/live/note_live/form_component.html.heex:41
#: lib/memex_web/live/pipeline_live/form_component.html.heex:41
#: lib/memex_web/live/context_live/form_component.html.heex:43
#: lib/memex_web/live/note_live/form_component.html.heex:43
#: lib/memex_web/live/pipeline_live/form_component.html.heex:43
#: lib/memex_web/live/step_live/form_component.html.heex:29
#, elixir-autogen, elixir-format
msgid "saving..."
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:37
#: lib/memex_web/live/note_live/form_component.html.heex:37
#: lib/memex_web/live/pipeline_live/form_component.html.heex:37
#: lib/memex_web/live/context_live/form_component.html.heex:39
#: lib/memex_web/live/note_live/form_component.html.heex:39
#: lib/memex_web/live/pipeline_live/form_component.html.heex:39
#, elixir-autogen, elixir-format
msgid "select privacy"
msgstr ""
@ -345,6 +350,11 @@ msgstr ""
msgid "unlimited"
msgstr ""
#: lib/memex_web/components/user_card.ex:25
#, elixir-autogen, elixir-format
msgid "user was confirmed at %{relative_datetime}"
msgstr ""
#: lib/memex_web/live/invite_live/index.html.heex:120
#, elixir-autogen, elixir-format
msgid "users"
@ -655,13 +665,3 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "while memEx fully supports multiple users, each memEx instance should be treated as a single cohesive and collaborative document."
msgstr ""
#: lib/memex_web/components/user_card.ex:26
#, elixir-autogen, elixir-format
msgid "user confirmed on"
msgstr ""
#: lib/memex_web/components/user_card.ex:33
#, elixir-autogen, elixir-format, fuzzy
msgid "user registered on"
msgstr ""

View File

@ -131,10 +131,3 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "unauthorized"
msgstr ""
#: lib/memex/contexts/context.ex:75
#: lib/memex/notes/note.ex:74
#: lib/memex/pipelines/pipeline.ex:76
#, elixir-autogen, elixir-format, fuzzy
msgid "invalid format: only numbers, letters and hyphen are accepted. tags must be comma-delimited"
msgstr ""

View File

@ -55,6 +55,11 @@ msgstr ""
msgid "Settings"
msgstr ""
#: lib/memex_web/components/user_card.ex:33
#, elixir-autogen, elixir-format
msgid "User registered on"
msgstr ""
#: lib/memex_web/components/invite_card.ex:19
#, elixir-autogen, elixir-format
msgid "Uses Left:"
@ -290,17 +295,17 @@ msgstr ""
msgid "report bugs or request features"
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:41
#: lib/memex_web/live/note_live/form_component.html.heex:41
#: lib/memex_web/live/pipeline_live/form_component.html.heex:41
#: lib/memex_web/live/context_live/form_component.html.heex:43
#: lib/memex_web/live/note_live/form_component.html.heex:43
#: lib/memex_web/live/pipeline_live/form_component.html.heex:43
#: lib/memex_web/live/step_live/form_component.html.heex:29
#, elixir-autogen, elixir-format
msgid "saving..."
msgstr ""
#: lib/memex_web/live/context_live/form_component.html.heex:37
#: lib/memex_web/live/note_live/form_component.html.heex:37
#: lib/memex_web/live/pipeline_live/form_component.html.heex:37
#: lib/memex_web/live/context_live/form_component.html.heex:39
#: lib/memex_web/live/note_live/form_component.html.heex:39
#: lib/memex_web/live/pipeline_live/form_component.html.heex:39
#, elixir-autogen, elixir-format
msgid "select privacy"
msgstr ""
@ -334,6 +339,11 @@ msgstr ""
msgid "unlimited"
msgstr ""
#: lib/memex_web/components/user_card.ex:25
#, elixir-autogen, elixir-format
msgid "user was confirmed at %{relative_datetime}"
msgstr ""
#: lib/memex_web/live/invite_live/index.html.heex:120
#, elixir-autogen, elixir-format
msgid "users"
@ -644,13 +654,3 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "while memEx fully supports multiple users, each memEx instance should be treated as a single cohesive and collaborative document."
msgstr ""
#: lib/memex_web/components/user_card.ex:26
#, elixir-autogen, elixir-format
msgid "user confirmed on"
msgstr ""
#: lib/memex_web/components/user_card.ex:33
#, elixir-autogen, elixir-format
msgid "user registered on"
msgstr ""

View File

@ -130,10 +130,3 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "unauthorized"
msgstr ""
#: lib/memex/contexts/context.ex:75
#: lib/memex/notes/note.ex:74
#: lib/memex/pipelines/pipeline.ex:76
#, elixir-autogen, elixir-format
msgid "invalid format: only numbers, letters and hyphen are accepted. tags must be comma-delimited"
msgstr ""

View File

@ -22,6 +22,6 @@ defmodule Memex.ContextsFixtures do
})
|> Contexts.create_context(user)
%{context | tags_string: nil}
context
end
end

View File

@ -22,6 +22,6 @@ defmodule Memex.NotesFixtures do
})
|> Notes.create_note(user)
%{note | tags_string: nil}
note
end
end

View File

@ -22,6 +22,6 @@ defmodule Memex.PipelinesFixtures do
})
|> Pipelines.create_pipeline(user)
%{pipeline | tags_string: nil}
pipeline
end
end