Compare commits
8 Commits
0.1.3
...
7813738f91
Author | SHA1 | Date | |
---|---|---|---|
7813738f91 | |||
c1337ebc10 | |||
59283a0217 | |||
634891ee73 | |||
571f6fffdb | |||
926805ba9b | |||
220122dec6 | |||
de399b4819 |
13
changelog.md
13
changelog.md
@ -1,3 +1,16 @@
|
||||
# v0.1.6
|
||||
- fix formatting in note/context/step contents
|
||||
- add json export for data
|
||||
|
||||
# v0.1.5
|
||||
- fix overflow on note/contexts/step contents
|
||||
|
||||
# v0.1.4
|
||||
- fix docker-compose
|
||||
- fix newlines in note/context/step contents
|
||||
- fix user invite page
|
||||
- improve tagging logic
|
||||
|
||||
# v0.1.3
|
||||
- backlink to other notes in notes
|
||||
- search tags on click
|
||||
|
10
de.tbx
Normal file
10
de.tbx
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE martif PUBLIC "ISO 12200:1999A//DTD MARTIF core (DXFcdV04)//EN" "TBXcdv04.dtd">
|
||||
<martif type="TBX">
|
||||
<martifHeader>
|
||||
<fileDesc>
|
||||
<sourceDesc><p>Translate Toolkit</p></sourceDesc>
|
||||
</fileDesc>
|
||||
</martifHeader>
|
||||
<text><body></body></text>
|
||||
</martif>
|
@ -2,8 +2,7 @@ version: '3'
|
||||
|
||||
services:
|
||||
memex:
|
||||
build:
|
||||
context: .
|
||||
image: shibaobun/memex
|
||||
container_name: memex
|
||||
restart: always
|
||||
environment:
|
||||
|
@ -9,6 +9,16 @@ defmodule Memex.Accounts.User do
|
||||
alias Ecto.{Changeset, UUID}
|
||||
alias Memex.Invites.Invite
|
||||
|
||||
@derive {Jason.Encoder,
|
||||
only: [
|
||||
:id,
|
||||
:email,
|
||||
:confirmed_at,
|
||||
:role,
|
||||
:locale,
|
||||
:inserted_at,
|
||||
:updated_at
|
||||
]}
|
||||
@derive {Inspect, except: [:password]}
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
|
@ -4,7 +4,6 @@ defmodule Memex.Contexts do
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Ecto.Changeset
|
||||
alias Memex.{Accounts.User, Contexts.Context, Repo}
|
||||
|
||||
@doc """
|
||||
@ -229,18 +228,4 @@ 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
|
||||
|
@ -9,6 +9,15 @@ defmodule Memex.Contexts.Context do
|
||||
alias Ecto.{Changeset, UUID}
|
||||
alias Memex.{Accounts.User, Repo}
|
||||
|
||||
@derive {Jason.Encoder,
|
||||
only: [
|
||||
:slug,
|
||||
:content,
|
||||
:tags,
|
||||
:visibility,
|
||||
:inserted_at,
|
||||
:updated_at
|
||||
]}
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
schema "contexts" do
|
||||
@ -27,7 +36,7 @@ defmodule Memex.Contexts.Context do
|
||||
slug: slug(),
|
||||
content: String.t(),
|
||||
tags: [String.t()] | nil,
|
||||
tags_string: String.t(),
|
||||
tags_string: String.t() | nil,
|
||||
visibility: :public | :private | :unlisted,
|
||||
user: User.t() | Ecto.Association.NotLoaded.t(),
|
||||
user_id: User.id(),
|
||||
@ -66,16 +75,38 @@ defmodule Memex.Contexts.Context do
|
||||
|> unsafe_validate_unique(:slug, Repo)
|
||||
end
|
||||
|
||||
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)
|
||||
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()
|
||||
end
|
||||
|
||||
defp cast_tags_string(changeset, _attrs), do: changeset
|
||||
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(",")
|
||||
end
|
||||
|
@ -4,7 +4,6 @@ defmodule Memex.Notes do
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Ecto.Changeset
|
||||
alias Memex.{Accounts.User, Notes.Note, Repo}
|
||||
|
||||
@doc """
|
||||
@ -229,18 +228,4 @@ 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
|
||||
|
@ -8,6 +8,15 @@ defmodule Memex.Notes.Note do
|
||||
alias Ecto.{Changeset, UUID}
|
||||
alias Memex.{Accounts.User, Repo}
|
||||
|
||||
@derive {Jason.Encoder,
|
||||
only: [
|
||||
:slug,
|
||||
:content,
|
||||
:tags,
|
||||
:visibility,
|
||||
:inserted_at,
|
||||
:updated_at
|
||||
]}
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
schema "notes" do
|
||||
@ -26,7 +35,7 @@ defmodule Memex.Notes.Note do
|
||||
slug: slug(),
|
||||
content: String.t(),
|
||||
tags: [String.t()] | nil,
|
||||
tags_string: String.t(),
|
||||
tags_string: String.t() | nil,
|
||||
visibility: :public | :private | :unlisted,
|
||||
user: User.t() | Ecto.Association.NotLoaded.t(),
|
||||
user_id: User.id(),
|
||||
@ -65,16 +74,38 @@ defmodule Memex.Notes.Note do
|
||||
|> unsafe_validate_unique(:slug, Repo)
|
||||
end
|
||||
|
||||
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)
|
||||
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()
|
||||
end
|
||||
|
||||
defp cast_tags_string(changeset, _attrs), do: changeset
|
||||
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(",")
|
||||
end
|
||||
|
@ -4,7 +4,6 @@ defmodule Memex.Pipelines do
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Ecto.Changeset
|
||||
alias Memex.{Accounts.User, Pipelines.Pipeline, Repo}
|
||||
|
||||
@doc """
|
||||
@ -231,18 +230,4 @@ 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
|
||||
|
@ -8,6 +8,16 @@ defmodule Memex.Pipelines.Pipeline do
|
||||
alias Ecto.{Changeset, UUID}
|
||||
alias Memex.{Accounts.User, Pipelines.Steps.Step, Repo}
|
||||
|
||||
@derive {Jason.Encoder,
|
||||
only: [
|
||||
:slug,
|
||||
:description,
|
||||
:tags,
|
||||
:visibility,
|
||||
:inserted_at,
|
||||
:steps,
|
||||
:updated_at
|
||||
]}
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
schema "pipelines" do
|
||||
@ -28,7 +38,7 @@ defmodule Memex.Pipelines.Pipeline do
|
||||
slug: slug(),
|
||||
description: String.t(),
|
||||
tags: [String.t()] | nil,
|
||||
tags_string: String.t(),
|
||||
tags_string: String.t() | nil,
|
||||
visibility: :public | :private | :unlisted,
|
||||
user: User.t() | Ecto.Association.NotLoaded.t(),
|
||||
user_id: User.id(),
|
||||
@ -67,16 +77,38 @@ defmodule Memex.Pipelines.Pipeline do
|
||||
|> unsafe_validate_unique(:slug, Repo)
|
||||
end
|
||||
|
||||
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)
|
||||
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()
|
||||
end
|
||||
|
||||
defp cast_tags_string(changeset, _attrs), do: changeset
|
||||
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(",")
|
||||
end
|
||||
|
@ -7,6 +7,14 @@ defmodule Memex.Pipelines.Steps.Step do
|
||||
alias Ecto.{Changeset, UUID}
|
||||
alias Memex.{Accounts.User, Pipelines.Pipeline}
|
||||
|
||||
@derive {Jason.Encoder,
|
||||
only: [
|
||||
:title,
|
||||
:content,
|
||||
:position,
|
||||
:inserted_at,
|
||||
:updated_at
|
||||
]}
|
||||
@primary_key {:id, :binary_id, autogenerate: true}
|
||||
@foreign_key_type :binary_id
|
||||
schema "steps" do
|
||||
|
@ -12,7 +12,7 @@ defmodule MemexWeb.Components.ContextContent do
|
||||
~H"""
|
||||
<div
|
||||
id={"show-context-content-#{@context.id}"}
|
||||
class="input input-primary h-128 min-h-128 inline-block"
|
||||
class="input input-primary h-128 min-h-128 inline-block whitespace-pre-wrap overflow-x-hidden overflow-y-auto"
|
||||
phx-hook="MaintainAttrs"
|
||||
phx-update="ignore"
|
||||
readonly
|
||||
|
@ -12,7 +12,7 @@ defmodule MemexWeb.Components.NoteContent do
|
||||
~H"""
|
||||
<div
|
||||
id={"show-note-content-#{@note.id}"}
|
||||
class="input input-primary h-128 min-h-128 inline-block"
|
||||
class="input input-primary h-128 min-h-128 inline-block whitespace-pre-wrap overflow-x-hidden overflow-y-auto"
|
||||
phx-hook="MaintainAttrs"
|
||||
phx-update="ignore"
|
||||
readonly
|
||||
|
@ -12,7 +12,7 @@ defmodule MemexWeb.Components.StepContent do
|
||||
~H"""
|
||||
<div
|
||||
id={"show-step-content-#{@step.id}"}
|
||||
class="input input-primary h-32 min-h-32 inline-block"
|
||||
class="input input-primary h-32 min-h-32 inline-block whitespace-pre-wrap overflow-x-hidden overflow-y-auto"
|
||||
phx-hook="MaintainAttrs"
|
||||
phx-update="ignore"
|
||||
readonly
|
||||
|
@ -22,15 +22,15 @@ defmodule MemexWeb.Components.UserCard do
|
||||
<%= if @user.confirmed_at |> is_nil() do %>
|
||||
<%= gettext("email unconfirmed") %>
|
||||
<% else %>
|
||||
<%= gettext(
|
||||
"user was confirmed at %{relative_datetime}",
|
||||
relative_datetime: @user.confirmed_at |> display_datetime()
|
||||
) %>
|
||||
<p>
|
||||
<%= gettext("user confirmed on") %>
|
||||
<%= @user.confirmed_at |> display_datetime() %>
|
||||
</p>
|
||||
<% end %>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<%= gettext("User registered on") %>
|
||||
<%= gettext("user registered on") %>
|
||||
<%= @user.inserted_at |> display_datetime() %>
|
||||
</p>
|
||||
</h3>
|
||||
|
17
lib/memex_web/controllers/export_controller.ex
Normal file
17
lib/memex_web/controllers/export_controller.ex
Normal file
@ -0,0 +1,17 @@
|
||||
defmodule MemexWeb.ExportController do
|
||||
use MemexWeb, :controller
|
||||
alias Memex.{Contexts, Notes, Pipelines, Pipelines.Steps}
|
||||
|
||||
def export(%{assigns: %{current_user: current_user}} = conn, %{"mode" => "json"}) do
|
||||
pipelines =
|
||||
Pipelines.list_pipelines(current_user)
|
||||
|> Enum.map(fn pipeline -> Steps.preload_steps(pipeline, current_user) end)
|
||||
|
||||
json(conn, %{
|
||||
user: current_user,
|
||||
notes: Notes.list_notes(current_user),
|
||||
contexts: Contexts.list_contexts(current_user),
|
||||
pipelines: pipelines
|
||||
})
|
||||
end
|
||||
end
|
@ -27,9 +27,7 @@
|
||||
<%= text_input(f, :tags_string,
|
||||
id: "tags-input",
|
||||
class: "input input-primary",
|
||||
placeholder: gettext("tag1,tag2"),
|
||||
phx_update: "ignore",
|
||||
value: Contexts.get_tags_string(@changeset)
|
||||
placeholder: gettext("tag1,tag2")
|
||||
) %>
|
||||
<%= error_tag(f, :tags_string) %>
|
||||
|
||||
|
@ -27,9 +27,7 @@
|
||||
<%= text_input(f, :tags_string,
|
||||
id: "tags-input",
|
||||
class: "input input-primary",
|
||||
placeholder: gettext("tag1,tag2"),
|
||||
phx_update: "ignore",
|
||||
value: Notes.get_tags_string(@changeset)
|
||||
placeholder: gettext("tag1,tag2")
|
||||
) %>
|
||||
<%= error_tag(f, :tags_string) %>
|
||||
|
||||
|
@ -27,9 +27,7 @@
|
||||
<%= text_input(f, :tags_string,
|
||||
id: "tags-input",
|
||||
class: "input input-primary",
|
||||
placeholder: gettext("tag1,tag2"),
|
||||
phx_update: "ignore",
|
||||
value: Pipelines.get_tags_string(@changeset)
|
||||
placeholder: gettext("tag1,tag2")
|
||||
) %>
|
||||
<%= error_tag(f, :tags_string) %>
|
||||
|
||||
|
@ -76,6 +76,7 @@ defmodule MemexWeb.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
|
||||
end
|
||||
|
||||
scope "/", MemexWeb do
|
||||
|
@ -136,12 +136,22 @@
|
||||
|
||||
<hr class="hr" />
|
||||
|
||||
<.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>
|
||||
<div class="flex justify-center items-center">
|
||||
<.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>
|
||||
|
||||
<.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") %>
|
||||
</.link>
|
||||
</div>
|
||||
</div>
|
||||
|
2
mix.exs
2
mix.exs
@ -4,7 +4,7 @@ defmodule Memex.MixProject do
|
||||
def project do
|
||||
[
|
||||
app: :memex,
|
||||
version: "0.1.3",
|
||||
version: "0.1.6",
|
||||
elixir: "~> 1.14",
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
compilers: Mix.compilers(),
|
||||
|
@ -66,7 +66,7 @@ msgstr ""
|
||||
msgid "delete"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex_web/templates/user_settings/edit.html.heex:145
|
||||
#: lib/memex_web/templates/user_settings/edit.html.heex:154
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "delete user"
|
||||
msgstr ""
|
||||
@ -124,9 +124,9 @@ msgstr ""
|
||||
msgid "register"
|
||||
msgstr ""
|
||||
|
||||
#: 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/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/step_live/form_component.html.heex:28
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "save"
|
||||
@ -155,3 +155,8 @@ msgstr ""
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "send instructions to reset password"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex_web/templates/user_settings/edit.html.heex:145
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "export data as json"
|
||||
msgstr ""
|
||||
|
@ -67,7 +67,7 @@ msgstr ""
|
||||
msgid "delete"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex_web/templates/user_settings/edit.html.heex:145
|
||||
#: lib/memex_web/templates/user_settings/edit.html.heex:154
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "delete user"
|
||||
msgstr ""
|
||||
@ -125,9 +125,9 @@ msgstr ""
|
||||
msgid "register"
|
||||
msgstr ""
|
||||
|
||||
#: 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/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/step_live/form_component.html.heex:28
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "save"
|
||||
@ -156,3 +156,8 @@ msgstr ""
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "send instructions to reset password"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex_web/templates/user_settings/edit.html.heex:145
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "export data as json"
|
||||
msgstr ""
|
||||
|
@ -66,11 +66,6 @@ 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:"
|
||||
@ -306,17 +301,17 @@ msgstr ""
|
||||
msgid "report bugs or request features"
|
||||
msgstr ""
|
||||
|
||||
#: 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/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/step_live/form_component.html.heex:29
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "saving..."
|
||||
msgstr ""
|
||||
|
||||
#: 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
|
||||
#: 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
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "select privacy"
|
||||
msgstr ""
|
||||
@ -350,11 +345,6 @@ 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"
|
||||
@ -665,3 +655,13 @@ 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 ""
|
||||
|
@ -76,22 +76,22 @@ msgstr ""
|
||||
msgid "You must confirm your account and log in to access this page."
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/accounts/user.ex:129
|
||||
#: lib/memex/accounts/user.ex:139
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "did not change"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/accounts/user.ex:150
|
||||
#: lib/memex/accounts/user.ex:160
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "does not match password"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/accounts/user.ex:187
|
||||
#: lib/memex/accounts/user.ex:197
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "is not valid"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/accounts/user.ex:85
|
||||
#: lib/memex/accounts/user.ex:95
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "must have the @ sign and no spaces"
|
||||
msgstr ""
|
||||
@ -102,12 +102,12 @@ msgstr ""
|
||||
msgid "oops, something went wrong! Please check the errors below"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/contexts/context.ex:49
|
||||
#: lib/memex/contexts/context.ex:62
|
||||
#: lib/memex/notes/note.ex:48
|
||||
#: lib/memex/notes/note.ex:61
|
||||
#: lib/memex/pipelines/pipeline.ex:50
|
||||
#: lib/memex/pipelines/pipeline.ex:63
|
||||
#: lib/memex/contexts/context.ex:58
|
||||
#: lib/memex/contexts/context.ex:71
|
||||
#: lib/memex/notes/note.ex:57
|
||||
#: lib/memex/notes/note.ex:70
|
||||
#: lib/memex/pipelines/pipeline.ex:60
|
||||
#: lib/memex/pipelines/pipeline.ex:73
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "invalid format: only numbers, letters and hyphen are accepted"
|
||||
msgstr ""
|
||||
@ -131,3 +131,10 @@ msgstr ""
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "unauthorized"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/contexts/context.ex:84
|
||||
#: lib/memex/notes/note.ex:83
|
||||
#: lib/memex/pipelines/pipeline.ex:86
|
||||
#, elixir-autogen, elixir-format, fuzzy
|
||||
msgid "invalid format: only numbers, letters and hyphen are accepted. tags must be comma-delimited"
|
||||
msgstr ""
|
||||
|
@ -122,7 +122,7 @@ msgstr ""
|
||||
msgid "are you sure you want to delete the invite for %{invite_name}?"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex_web/templates/user_settings/edit.html.heex:143
|
||||
#: lib/memex_web/templates/user_settings/edit.html.heex:152
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "are you sure you want to delete your account?"
|
||||
msgstr ""
|
||||
|
@ -55,11 +55,6 @@ 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:"
|
||||
@ -295,17 +290,17 @@ msgstr ""
|
||||
msgid "report bugs or request features"
|
||||
msgstr ""
|
||||
|
||||
#: 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/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/step_live/form_component.html.heex:29
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "saving..."
|
||||
msgstr ""
|
||||
|
||||
#: 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
|
||||
#: 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
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "select privacy"
|
||||
msgstr ""
|
||||
@ -339,11 +334,6 @@ 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"
|
||||
@ -654,3 +644,13 @@ 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 ""
|
||||
|
@ -75,22 +75,22 @@ msgstr ""
|
||||
msgid "You must confirm your account and log in to access this page."
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/accounts/user.ex:129
|
||||
#: lib/memex/accounts/user.ex:139
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "did not change"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/accounts/user.ex:150
|
||||
#: lib/memex/accounts/user.ex:160
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "does not match password"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/accounts/user.ex:187
|
||||
#: lib/memex/accounts/user.ex:197
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "is not valid"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/accounts/user.ex:85
|
||||
#: lib/memex/accounts/user.ex:95
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "must have the @ sign and no spaces"
|
||||
msgstr ""
|
||||
@ -101,12 +101,12 @@ msgstr ""
|
||||
msgid "oops, something went wrong! Please check the errors below"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/contexts/context.ex:49
|
||||
#: lib/memex/contexts/context.ex:62
|
||||
#: lib/memex/notes/note.ex:48
|
||||
#: lib/memex/notes/note.ex:61
|
||||
#: lib/memex/pipelines/pipeline.ex:50
|
||||
#: lib/memex/pipelines/pipeline.ex:63
|
||||
#: lib/memex/contexts/context.ex:58
|
||||
#: lib/memex/contexts/context.ex:71
|
||||
#: lib/memex/notes/note.ex:57
|
||||
#: lib/memex/notes/note.ex:70
|
||||
#: lib/memex/pipelines/pipeline.ex:60
|
||||
#: lib/memex/pipelines/pipeline.ex:73
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "invalid format: only numbers, letters and hyphen are accepted"
|
||||
msgstr ""
|
||||
@ -130,3 +130,10 @@ msgstr ""
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "unauthorized"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex/contexts/context.ex:84
|
||||
#: lib/memex/notes/note.ex:83
|
||||
#: lib/memex/pipelines/pipeline.ex:86
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "invalid format: only numbers, letters and hyphen are accepted. tags must be comma-delimited"
|
||||
msgstr ""
|
||||
|
@ -121,7 +121,7 @@ msgstr ""
|
||||
msgid "are you sure you want to delete the invite for %{invite_name}?"
|
||||
msgstr ""
|
||||
|
||||
#: lib/memex_web/templates/user_settings/edit.html.heex:143
|
||||
#: lib/memex_web/templates/user_settings/edit.html.heex:152
|
||||
#, elixir-autogen, elixir-format
|
||||
msgid "are you sure you want to delete your account?"
|
||||
msgstr ""
|
||||
|
101
test/memex_web/controllers/export_controller_test.exs
Normal file
101
test/memex_web/controllers/export_controller_test.exs
Normal file
@ -0,0 +1,101 @@
|
||||
defmodule MemexWeb.ExportControllerTest do
|
||||
@moduledoc """
|
||||
Tests the export function
|
||||
"""
|
||||
|
||||
use MemexWeb.ConnCase
|
||||
import Memex.{ContextsFixtures, NotesFixtures, PipelinesFixtures, StepsFixtures}
|
||||
|
||||
@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
|
||||
note = note_fixture(current_user)
|
||||
context = context_fixture(current_user)
|
||||
pipeline = pipeline_fixture(current_user)
|
||||
step = step_fixture(0, pipeline, current_user)
|
||||
|
||||
%{
|
||||
note: note,
|
||||
context: context,
|
||||
pipeline: pipeline,
|
||||
step: step
|
||||
}
|
||||
end
|
||||
|
||||
describe "Exports data" do
|
||||
setup [:add_data]
|
||||
|
||||
test "in JSON", %{
|
||||
conn: conn,
|
||||
current_user: current_user,
|
||||
note: note,
|
||||
context: context,
|
||||
pipeline: pipeline,
|
||||
step: step
|
||||
} do
|
||||
conn = get(conn, Routes.export_path(conn, :export, :json))
|
||||
|
||||
ideal_note = %{
|
||||
"slug" => note.slug,
|
||||
"content" => note.content,
|
||||
"tags" => note.tags,
|
||||
"visibility" => note.visibility |> to_string(),
|
||||
"inserted_at" => note.inserted_at |> NaiveDateTime.to_iso8601(),
|
||||
"updated_at" => note.updated_at |> NaiveDateTime.to_iso8601()
|
||||
}
|
||||
|
||||
ideal_context = %{
|
||||
"slug" => context.slug,
|
||||
"content" => context.content,
|
||||
"tags" => context.tags,
|
||||
"visibility" => context.visibility |> to_string(),
|
||||
"inserted_at" => context.inserted_at |> NaiveDateTime.to_iso8601(),
|
||||
"updated_at" => context.updated_at |> NaiveDateTime.to_iso8601()
|
||||
}
|
||||
|
||||
ideal_pipeline = %{
|
||||
"slug" => pipeline.slug,
|
||||
"description" => pipeline.description,
|
||||
"tags" => pipeline.tags,
|
||||
"visibility" => pipeline.visibility |> to_string(),
|
||||
"inserted_at" => pipeline.inserted_at |> NaiveDateTime.to_iso8601(),
|
||||
"updated_at" => pipeline.updated_at |> NaiveDateTime.to_iso8601(),
|
||||
"steps" => [
|
||||
%{
|
||||
"title" => step.title,
|
||||
"content" => step.content,
|
||||
"position" => step.position,
|
||||
"inserted_at" => step.inserted_at |> NaiveDateTime.to_iso8601(),
|
||||
"updated_at" => step.updated_at |> NaiveDateTime.to_iso8601()
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
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),
|
||||
"inserted_at" => current_user.inserted_at |> NaiveDateTime.to_iso8601(),
|
||||
"updated_at" => current_user.updated_at |> NaiveDateTime.to_iso8601()
|
||||
}
|
||||
|
||||
json_resp = conn |> json_response(200)
|
||||
assert %{"notes" => [^ideal_note]} = json_resp
|
||||
assert %{"contexts" => [^ideal_context]} = json_resp
|
||||
assert %{"pipelines" => [^ideal_pipeline]} = json_resp
|
||||
assert %{"user" => ^ideal_user} = json_resp
|
||||
end
|
||||
end
|
||||
end
|
@ -18,7 +18,7 @@ defmodule MemexWeb.ContextLiveTest do
|
||||
}
|
||||
@invalid_attrs %{
|
||||
"content" => nil,
|
||||
"tags_string" => "",
|
||||
"tags_string" => " ",
|
||||
"slug" => nil,
|
||||
"visibility" => nil
|
||||
}
|
||||
@ -114,9 +114,13 @@ defmodule MemexWeb.ContextLiveTest do
|
||||
|
||||
assert_patch(show_live, Routes.context_show_path(conn, :edit, context.slug))
|
||||
|
||||
assert show_live
|
||||
|> form("#context-form", context: @invalid_attrs)
|
||||
|> render_change() =~ "can't be blank"
|
||||
html =
|
||||
show_live
|
||||
|> form("#context-form", context: @invalid_attrs)
|
||||
|> render_change()
|
||||
|
||||
assert html =~ "can't be blank"
|
||||
assert html =~ "tags must be comma-delimited"
|
||||
|
||||
{:ok, _, html} =
|
||||
show_live
|
||||
|
@ -19,7 +19,7 @@ defmodule MemexWeb.NoteLiveTest do
|
||||
}
|
||||
@invalid_attrs %{
|
||||
"content" => nil,
|
||||
"tags_string" => "",
|
||||
"tags_string" => " ",
|
||||
"slug" => nil,
|
||||
"visibility" => nil
|
||||
}
|
||||
@ -54,9 +54,13 @@ defmodule MemexWeb.NoteLiveTest do
|
||||
|
||||
assert_patch(index_live, Routes.note_index_path(conn, :new))
|
||||
|
||||
assert index_live
|
||||
|> form("#note-form", note: @invalid_attrs)
|
||||
|> render_change() =~ "can't be blank"
|
||||
html =
|
||||
index_live
|
||||
|> form("#note-form", note: @invalid_attrs)
|
||||
|> render_change()
|
||||
|
||||
assert html =~ "can't be blank"
|
||||
assert html =~ "tags must be comma-delimited"
|
||||
|
||||
{:ok, _, html} =
|
||||
index_live
|
||||
|
@ -17,7 +17,7 @@ defmodule MemexWeb.PipelineLiveTest do
|
||||
}
|
||||
@invalid_attrs %{
|
||||
"description" => nil,
|
||||
"tags_string" => "",
|
||||
"tags_string" => " ",
|
||||
"slug" => nil,
|
||||
"visibility" => nil
|
||||
}
|
||||
@ -128,9 +128,13 @@ defmodule MemexWeb.PipelineLiveTest do
|
||||
|
||||
assert_patch(show_live, Routes.pipeline_show_path(conn, :edit, pipeline.slug))
|
||||
|
||||
assert show_live
|
||||
|> form("#pipeline-form", pipeline: @invalid_attrs)
|
||||
|> render_change() =~ "can't be blank"
|
||||
html =
|
||||
show_live
|
||||
|> form("#pipeline-form", pipeline: @invalid_attrs)
|
||||
|> render_change()
|
||||
|
||||
assert html =~ "can't be blank"
|
||||
assert html =~ "tags must be comma-delimited"
|
||||
|
||||
{:ok, _, html} =
|
||||
show_live
|
||||
|
@ -22,6 +22,6 @@ defmodule Memex.ContextsFixtures do
|
||||
})
|
||||
|> Contexts.create_context(user)
|
||||
|
||||
context
|
||||
%{context | tags_string: nil}
|
||||
end
|
||||
end
|
||||
|
@ -22,6 +22,6 @@ defmodule Memex.NotesFixtures do
|
||||
})
|
||||
|> Notes.create_note(user)
|
||||
|
||||
note
|
||||
%{note | tags_string: nil}
|
||||
end
|
||||
end
|
||||
|
@ -22,6 +22,6 @@ defmodule Memex.PipelinesFixtures do
|
||||
})
|
||||
|> Pipelines.create_pipeline(user)
|
||||
|
||||
pipeline
|
||||
%{pipeline | tags_string: nil}
|
||||
end
|
||||
end
|
||||
|
Reference in New Issue
Block a user