Compare commits

..

10 Commits

Author SHA1 Message Date
5dfbf7011e Add basic functions for keeping track of Deepl account usage 2023-03-15 11:35:26 +01:00
2eba3bc500 Update Translators context 2023-03-15 11:26:07 +01:00
43f3ea193f Add miscellaneous stuff 2023-03-15 10:56:30 +01:00
61253f301a Add mainly disfunctional test
Due to utter negligence test results are currently:

221 tests, 186 failures
2023-03-15 10:49:29 +01:00
5d43e61223 Update status styles 2023-03-08 21:09:12 +01:00
724d161f50 Add status preview in translation_live/show 2023-03-08 20:43:42 +01:00
1fb9a40f2c Add overlooked ids for buttons 2023-03-06 23:01:31 +01:00
459c8e6a57 Add shortcuts for saving 2023-03-05 23:13:58 +01:00
21b97bec6e Sanitize variable name 2023-03-05 22:53:52 +01:00
5d9238a65a Fix ugly bug and add more shortcuts 2023-03-05 22:05:54 +01:00
17 changed files with 466 additions and 38 deletions

View File

@ -3,7 +3,6 @@ alias Outlook.HtmlPreparations.HtmlPreparation
alias Outlook.InternalTree.{Html,InternalNode,TranslationUnit} alias Outlook.InternalTree.{Html,InternalNode,TranslationUnit}
alias Outlook.InternalTree alias Outlook.InternalTree
alias Outlook.Articles alias Outlook.Articles
alias Outlook.Artikel
alias Outlook.Accounts alias Outlook.Accounts
alias Outlook.Articles.Article alias Outlook.Articles.Article
alias Outlook.Authors alias Outlook.Authors

View File

@ -7,22 +7,41 @@
max-width: 25rem; max-width: 25rem;
} }
.article .tunit { .article span.tunit {
@apply hover:bg-gray-300; @apply hover:bg-gray-300;
} }
.dark .article .tunit { .dark .article span.tunit {
@apply hover:bg-gray-700; @apply hover:bg-gray-700;
} }
.article .tunit[current="yes"] { .article span.tunit[current="yes"] {
@apply bg-amber-300 text-stone-700 hover:bg-amber-200 hover:text-red-900; @apply bg-amber-300 text-stone-700 hover:bg-amber-200 hover:text-red-900;
} }
.dark .article .tunit[current="yes"] { .dark .article span.tunit[current="yes"] {
@apply bg-amber-500/70 text-white hover:bg-amber-500/70 hover:text-red-900; @apply bg-amber-500/70 text-white hover:bg-amber-500/70 hover:text-red-900;
} }
.article.show_status span.tunit a {
@apply text-inherit;
}
.article.show_status span.tunit[status="untranslated"] {
@apply text-red-900;
}
.article.show_status span.tunit[status="passable"] {
@apply text-amber-500;
}
.dark .article.show_status span.tunit[status="untranslated"] {
@apply text-red-500;
}
.dark .article.show_status span.tunit[status="passable"] {
@apply text-amber-100;
}
.article a.hide-link { .article a.hide-link {
display: none; display: none;
} }

View File

@ -4,34 +4,48 @@ let TranslationFormHook = {
this.el.addEventListener("keyup", this.keyupHandler.bind(this)) this.el.addEventListener("keyup", this.keyupHandler.bind(this))
this.title_input = this.el.querySelector("#translation-form_title") this.title_input = this.el.querySelector("#translation-form_title")
this.tunit_editor = this.el.querySelector("#tunit-editor-content") this.tunit_editor = this.el.querySelector("#tunit-editor-content")
this.save_edit_button = this.el.querySelector("#save-edit-button")
this.save_publish_button = this.el.querySelector("#save-publish-button")
}, },
keyupHandler(e) { keyupHandler(e) {
var push_event = true
var preaction = () => { } var preaction = () => { }
var postaction = () => { } var postaction = () => { }
var payload = {} var payload = {}
if (e.altKey){ if (e.altKey){
if (e.key == "ArrowDown"){ if (e.ctrlKey){
preaction = () => { this.title_input.focus() } if (e.key == "s"){
postaction = () => { this.tunit_editor.focus() } this.save_edit_button.click()
var handler = "select_next_tunit" } else if (e.key == "p"){
} else if (e.key == "ArrowUp"){ this.save_publish_button.click()
preaction = () => { this.title_input.focus() } }
postaction = () => { this.tunit_editor.focus() } } else {
var handler = "select_previous_tunit" if (e.key == "ArrowDown" || e.key == "n"){
} else if (e.key == "u") { preaction = () => { this.title_input.focus() }
var handler = "tunit_status" postaction = () => { this.tunit_editor.focus() }
payload = {status: "untranslated"} var handler = "select_next_tunit"
} else if (e.key == "p") { } else if (e.key == "ArrowUp" || e.key == "v"){
var handler = "tunit_status" preaction = () => { this.title_input.focus() }
payload = {status: "passable"} postaction = () => { this.tunit_editor.focus() }
} else if (e.key == "o") { var handler = "select_previous_tunit"
var handler = "tunit_status" } else if (e.key == "u") {
payload = {status: "done"} var handler = "tunit_status"
payload = {status: "untranslated"}
} else if (e.key == "p") {
var handler = "tunit_status"
payload = {status: "passable"}
} else if (e.key == "o") {
var handler = "tunit_status"
payload = {status: "done"}
} else {
push_event = false
}
if (push_event) {
preaction.call()
this.pushEventTo(this.el, handler, payload, postaction)
}
} }
preaction.call()
this.pushEventTo(this.el, handler, payload, postaction)
} }
// console.info(["keyupHandler", e, this])
}, },
} }

View File

@ -39,7 +39,7 @@ defmodule Outlook.Authors do
def get_author_with_articles!(id) do def get_author_with_articles!(id) do
Repo.get!(Author, id) Repo.get!(Author, id)
|> Repo.preload([:articles]) |> Repo.preload([articles: :translations])
end end
@doc """ @doc """

View File

@ -9,7 +9,7 @@ defmodule Outlook.Authors.Author do
field :homepage_name, :string field :homepage_name, :string
field :homepage_url, :string field :homepage_url, :string
field :name, :string field :name, :string
has_many :articles, Article has_many :articles, Article, on_delete: :delete_all
timestamps() timestamps()
end end

View File

@ -48,6 +48,19 @@ defmodule Outlook.Translators do
|> Repo.update_all([inc: [our_character_count: billed_characters]]) |> Repo.update_all([inc: [our_character_count: billed_characters]])
end end
def get_uptodate_deepl_counts(user) do
deepl_counts = Deepl.get_usage_counts(get_deepl_auth_key(user))
our_character_count = deepl_account_for_user(user)
|> select([:our_character_count])
|> Repo.one()
|> Map.get(:our_character_count)
most_accurate = max(our_character_count, deepl_counts.character_count)
%{character_limit: deepl_counts.character_limit,
character_count: deepl_counts.character_count,
our_character_count: our_character_count,
percent_used: most_accurate * 100 / deepl_counts.character_limit}
end
def translate(translation, current_user) do def translate(translation, current_user) do
%{language: target_lang, %{language: target_lang,
article: %{content: article_tree, language: source_lang} article: %{content: article_tree, language: source_lang}
@ -71,6 +84,14 @@ defmodule Outlook.Translators do
process_translation(result.translation, tunit_ids) process_translation(result.translation, tunit_ids)
end end
def update_deepl_counts(user, counts) do
deepl_account_for_user(user)
|> Repo.update_all([set: [
character_limit: counts.character_limit,
character_count: counts.character_count
]])
end
defp deepl_account_for_user(user) when is_struct(user), do: deepl_account_for_user(user.id) defp deepl_account_for_user(user) when is_struct(user), do: deepl_account_for_user(user.id)
defp deepl_account_for_user(user_id) do defp deepl_account_for_user(user_id) do
DeeplAccount |> where(user_id: ^user_id) DeeplAccount |> where(user_id: ^user_id)
@ -83,7 +104,7 @@ defmodule Outlook.Translators do
|> IO.iodata_to_binary() |> IO.iodata_to_binary()
end end
def process_translation(translation, tunit_ids) do defp process_translation(translation, tunit_ids) do
tunit_map = translation tunit_map = translation
|> Floki.parse_fragment! |> Floki.parse_fragment!
|> Floki.find("tunit") |> Floki.find("tunit")

View File

@ -54,10 +54,12 @@ defmodule Outlook.Translators.Deepl do
) )
response = Jason.decode!(response_raw.body, keys: :atoms) response = Jason.decode!(response_raw.body, keys: :atoms)
require Logger
case response do case response do
%{status: "done"} -> %{status: "done"} ->
response response
%{status: status} -> %{status: status} ->
Logger.debug "Deepl response: #{response |> inspect}"
steps = Map.get(response, :seconds_remaining, 1) * 5 steps = Map.get(response, :seconds_remaining, 1) * 5
for n <- 0..steps do for n <- 0..steps do
send(pid, {:progress, %{progress: 100 * n / steps, status: status}}) send(pid, {:progress, %{progress: 100 * n / steps, status: status}})

View File

@ -36,11 +36,11 @@ defmodule OutlookWeb.TranslationLive.FormComponent do
<input type="hidden" id="publish" name="publish" value="false" /> <input type="hidden" id="publish" name="publish" value="false" />
<:actions> <:actions>
<.button phx-click={JS.set_attribute({"value", "false"}, to: "#continue_edit") |> JS.set_attribute({"value", "false"}, to: "#publish")} <.button phx-click={JS.set_attribute({"value", "false"}, to: "#continue_edit") |> JS.set_attribute({"value", "false"}, to: "#publish")}
phx-disable-with="Saving...">Save Translation</.button> id="save-button" phx-disable-with="Saving...">Save Translation</.button>
<.button phx-click={JS.set_attribute({"value", "false"}, to: "#continue_edit") |> JS.set_attribute({"value", "true"}, to: "#publish")} <.button phx-click={JS.set_attribute({"value", "false"}, to: "#continue_edit") |> JS.set_attribute({"value", "true"}, to: "#publish")}
phx-disable-with="Saving...">Save and Publish</.button> id="save-publish-button" phx-disable-with="Saving...">Save and Publish</.button>
<.button phx-click={JS.set_attribute({"value", "true"}, to: "#continue_edit") |> JS.set_attribute({"value", "false"}, to: "#publish")} <.button phx-click={JS.set_attribute({"value", "true"}, to: "#continue_edit") |> JS.set_attribute({"value", "false"}, to: "#publish")}
phx-disable-with="Saving...">Save and Edit</.button> id="save-edit-button" phx-disable-with="Saving...">Save and Edit</.button>
</:actions> </:actions>
</.simple_form> </.simple_form>
<.tunit_editor current_tunit={@current_tunit} target={@myself} /> <.tunit_editor current_tunit={@current_tunit} target={@myself} />

View File

@ -10,10 +10,18 @@ defmodule OutlookWeb.TranslationLive.Show do
@impl true @impl true
def handle_params(%{"id" => id}, _, socket) do def handle_params(%{"id" => id}, _, socket) do
translation = Translations.get_translation!(id)
{:noreply, {:noreply,
socket socket
|> assign(:page_title, page_title(socket.assigns.live_action)) |> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:translation, Translations.get_translation!(id))} |> assign(:translation, translation)
|> assign(:translation_tree,
InternalTree.render_translation(
translation.article.content, translation.content
) |> InternalTree.garnish(
%{tunits: %{status: fn n -> n.status end, class: :tunit}}
)
)}
end end
defp page_title(:show), do: "Show Translation" defp page_title(:show), do: "Show Translation"

View File

@ -18,8 +18,8 @@
<:item title="Unauthorized"><%= @translation.unauthorized %></:item> <:item title="Unauthorized"><%= @translation.unauthorized %></:item>
</.list> </.list>
<div class="article"> <div class="article show_status">
<.render_doc tree={InternalTree.render_translation(@translation.article.content, @translation.content)} /> <.render_doc tree={@translation_tree} />
</div> </div>
<.back navigate={~p"/articles/#{@translation.article}"}>Back to <article></article></.back> <.back navigate={~p"/articles/#{@translation.article}"}>Back to <article></article></.back>

View File

@ -12,4 +12,10 @@ defmodule OutlookWeb.ViewHelpers do
def tidy_raw(whatever) do def tidy_raw(whatever) do
whatever whatever
end end
# TODO: implement (and use) the following function
@doc "Strip <a> tags to prevent broken html (or 'breaking') from user input."
def strip_links(html) do
raise "Yet to be implemented!"
end
end end

View File

@ -0,0 +1,131 @@
defmodule Outlook.PublicTest do
use Outlook.DataCase
# TODO: make this work
alias Outlook.Public
describe "artikel" do
alias Outlook.Public.Artikel
import Outlook.PublicFixtures
@invalid_attrs %{date: nil, public_content: nil, teaser: nil, title: nil, translator: nil, unauthorized: nil}
test "list_artikel/0 returns all artikel" do
artikel = artikel_fixture()
assert Artikel.list_artikel() == [artikel]
end
test "get_artikel!/1 returns the artikel with given id" do
artikel = artikel_fixture()
assert Artikel.get_artikel!(artikel.id) == artikel
end
test "create_artikel/1 with valid data creates a artikel" do
valid_attrs = %{date: "some date", public_content: "some public_content", teaser: "some teaser", title: "some title", translator: "some translator", unauthorized: true}
assert {:ok, %Artikel{} = artikel} = Artikel.create_artikel(valid_attrs)
assert artikel.date == "some date"
assert artikel.public_content == "some public_content"
assert artikel.teaser == "some teaser"
assert artikel.title == "some title"
assert artikel.translator == "some translator"
assert artikel.unauthorized == true
end
test "create_artikel/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Artikel.create_artikel(@invalid_attrs)
end
test "update_artikel/2 with valid data updates the artikel" do
artikel = artikel_fixture()
update_attrs = %{date: "some updated date", public_content: "some updated public_content", teaser: "some updated teaser", title: "some updated title", translator: "some updated translator", unauthorized: false}
assert {:ok, %Artikel{} = artikel} = Artikel.update_artikel(artikel, update_attrs)
assert artikel.date == "some updated date"
assert artikel.public_content == "some updated public_content"
assert artikel.teaser == "some updated teaser"
assert artikel.title == "some updated title"
assert artikel.translator == "some updated translator"
assert artikel.unauthorized == false
end
test "update_artikel/2 with invalid data returns error changeset" do
artikel = artikel_fixture()
assert {:error, %Ecto.Changeset{}} = Artikel.update_artikel(artikel, @invalid_attrs)
assert artikel == Artikel.get_artikel!(artikel.id)
end
test "delete_artikel/1 deletes the artikel" do
artikel = artikel_fixture()
assert {:ok, %Artikel{}} = Artikel.delete_artikel(artikel)
assert_raise Ecto.NoResultsError, fn -> Artikel.get_artikel!(artikel.id) end
end
test "change_artikel/1 returns a artikel changeset" do
artikel = artikel_fixture()
assert %Ecto.Changeset{} = Artikel.change_artikel(artikel)
end
end
describe "autoren" do
alias Outlook.Public.Autor
import Outlook.PublicFixtures
@invalid_attrs %{description: nil, homepage_name: nil, homepage_url: nil, name: nil}
test "list_autoren/0 returns all autoren" do
autor = autor_fixture()
assert Autoren.list_autoren() == [autor]
end
test "get_autor!/1 returns the autor with given id" do
autor = autor_fixture()
assert Autoren.get_autor!(autor.id) == autor
end
test "create_autor/1 with valid data creates a autor" do
valid_attrs = %{description: "some description", homepage_name: "some homepage_name", homepage_url: "some homepage_url", name: "some name"}
assert {:ok, %Autor{} = autor} = Autoren.create_autor(valid_attrs)
assert autor.description == "some description"
assert autor.homepage_name == "some homepage_name"
assert autor.homepage_url == "some homepage_url"
assert autor.name == "some name"
end
test "create_autor/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Autoren.create_autor(@invalid_attrs)
end
test "update_autor/2 with valid data updates the autor" do
autor = autor_fixture()
update_attrs = %{description: "some updated description", homepage_name: "some updated homepage_name", homepage_url: "some updated homepage_url", name: "some updated name"}
assert {:ok, %Autor{} = autor} = Autoren.update_autor(autor, update_attrs)
assert autor.description == "some updated description"
assert autor.homepage_name == "some updated homepage_name"
assert autor.homepage_url == "some updated homepage_url"
assert autor.name == "some updated name"
end
test "update_autor/2 with invalid data returns error changeset" do
autor = autor_fixture()
assert {:error, %Ecto.Changeset{}} = Autoren.update_autor(autor, @invalid_attrs)
assert autor == Autoren.get_autor!(autor.id)
end
test "delete_autor/1 deletes the autor" do
autor = autor_fixture()
assert {:ok, %Autor{}} = Autoren.delete_autor(autor)
assert_raise Ecto.NoResultsError, fn -> Autoren.get_autor!(autor.id) end
end
test "change_autor/1 returns a autor changeset" do
autor = autor_fixture()
assert %Ecto.Changeset{} = Autoren.change_autor(autor)
end
end
end

View File

@ -0,0 +1,86 @@
defmodule OutlookWeb.ArtikelControllerTest do
use OutlookWeb.ConnCase
# TODO: make this work
import Outlook.PublicFixtures
@create_attrs %{date: "some date", public_content: "some public_content", teaser: "some teaser", title: "some title", translator: "some translator", unauthorized: true}
@update_attrs %{date: "some updated date", public_content: "some updated public_content", teaser: "some updated teaser", title: "some updated title", translator: "some updated translator", unauthorized: false}
@invalid_attrs %{date: nil, public_content: nil, teaser: nil, title: nil, translator: nil, unauthorized: nil}
describe "index" do
test "lists all artikel", %{conn: conn} do
conn = get(conn, ~p"/artikel")
assert html_response(conn, 200) =~ "Listing Artikel"
end
end
describe "new artikel" do
test "renders form", %{conn: conn} do
conn = get(conn, ~p"/artikel/new")
assert html_response(conn, 200) =~ "New Artikel"
end
end
describe "create artikel" do
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, ~p"/artikel", artikel: @create_attrs)
assert %{id: id} = redirected_params(conn)
assert redirected_to(conn) == ~p"/artikel/#{id}"
conn = get(conn, ~p"/artikel/#{id}")
assert html_response(conn, 200) =~ "Artikel #{id}"
end
test "renders errors when data is invalid", %{conn: conn} do
conn = post(conn, ~p"/artikel", artikel: @invalid_attrs)
assert html_response(conn, 200) =~ "New Artikel"
end
end
describe "edit artikel" do
setup [:create_artikel]
test "renders form for editing chosen artikel", %{conn: conn, artikel: artikel} do
conn = get(conn, ~p"/artikel/#{artikel}/edit")
assert html_response(conn, 200) =~ "Edit Artikel"
end
end
describe "update artikel" do
setup [:create_artikel]
test "redirects when data is valid", %{conn: conn, artikel: artikel} do
conn = put(conn, ~p"/artikel/#{artikel}", artikel: @update_attrs)
assert redirected_to(conn) == ~p"/artikel/#{artikel}"
conn = get(conn, ~p"/artikel/#{artikel}")
assert html_response(conn, 200) =~ "some updated date"
end
test "renders errors when data is invalid", %{conn: conn, artikel: artikel} do
conn = put(conn, ~p"/artikel/#{artikel}", artikel: @invalid_attrs)
assert html_response(conn, 200) =~ "Edit Artikel"
end
end
describe "delete artikel" do
setup [:create_artikel]
test "deletes chosen artikel", %{conn: conn, artikel: artikel} do
conn = delete(conn, ~p"/artikel/#{artikel}")
assert redirected_to(conn) == ~p"/artikel"
assert_error_sent 404, fn ->
get(conn, ~p"/artikel/#{artikel}")
end
end
end
defp create_artikel(_) do
artikel = artikel_fixture()
%{artikel: artikel}
end
end

View File

@ -0,0 +1,86 @@
defmodule OutlookWeb.AutorControllerTest do
use OutlookWeb.ConnCase
# TODO: make this work
import Outlook.PublicFixtures
@create_attrs %{description: "some description", homepage_name: "some homepage_name", homepage_url: "some homepage_url", name: "some name"}
@update_attrs %{description: "some updated description", homepage_name: "some updated homepage_name", homepage_url: "some updated homepage_url", name: "some updated name"}
@invalid_attrs %{description: nil, homepage_name: nil, homepage_url: nil, name: nil}
describe "index" do
test "lists all autoren", %{conn: conn} do
conn = get(conn, ~p"/autoren")
assert html_response(conn, 200) =~ "Listing Autoren"
end
end
describe "new autor" do
test "renders form", %{conn: conn} do
conn = get(conn, ~p"/autoren/new")
assert html_response(conn, 200) =~ "New Autor"
end
end
describe "create autor" do
test "redirects to show when data is valid", %{conn: conn} do
conn = post(conn, ~p"/autoren", autor: @create_attrs)
assert %{id: id} = redirected_params(conn)
assert redirected_to(conn) == ~p"/autoren/#{id}"
conn = get(conn, ~p"/autoren/#{id}")
assert html_response(conn, 200) =~ "Autor #{id}"
end
test "renders errors when data is invalid", %{conn: conn} do
conn = post(conn, ~p"/autoren", autor: @invalid_attrs)
assert html_response(conn, 200) =~ "New Autor"
end
end
describe "edit autor" do
setup [:create_autor]
test "renders form for editing chosen autor", %{conn: conn, autor: autor} do
conn = get(conn, ~p"/autoren/#{autor}/edit")
assert html_response(conn, 200) =~ "Edit Autor"
end
end
describe "update autor" do
setup [:create_autor]
test "redirects when data is valid", %{conn: conn, autor: autor} do
conn = put(conn, ~p"/autoren/#{autor}", autor: @update_attrs)
assert redirected_to(conn) == ~p"/autoren/#{autor}"
conn = get(conn, ~p"/autoren/#{autor}")
assert html_response(conn, 200) =~ "some updated description"
end
test "renders errors when data is invalid", %{conn: conn, autor: autor} do
conn = put(conn, ~p"/autoren/#{autor}", autor: @invalid_attrs)
assert html_response(conn, 200) =~ "Edit Autor"
end
end
describe "delete autor" do
setup [:create_autor]
test "deletes chosen autor", %{conn: conn, autor: autor} do
conn = delete(conn, ~p"/autoren/#{autor}")
assert redirected_to(conn) == ~p"/autoren"
assert_error_sent 404, fn ->
get(conn, ~p"/autoren/#{autor}")
end
end
end
defp create_autor(_) do
autor = autor_fixture()
%{autor: autor}
end
end

View File

@ -4,6 +4,8 @@ defmodule Outlook.ArticlesFixtures do
entities via the `Outlook.Articles` context. entities via the `Outlook.Articles` context.
""" """
# TODO: make this work
@doc """ @doc """
Generate a article. Generate a article.
""" """
@ -11,11 +13,17 @@ defmodule Outlook.ArticlesFixtures do
{:ok, article} = {:ok, article} =
attrs attrs
|> Enum.into(%{ |> Enum.into(%{
content: "some content", content: [%Outlook.InternalTree.InternalNode{name: "p", attributes: %{}, type: :element, nid: "54e8cedb-6459-4605-8301-367758675bb8", content: [
%Outlook.InternalTree.TranslationUnit{status: :untranslated, nid: "c0fcdf61-ae2d-482e-81b4-9b6e3baacd8b",
content: "A sentence with many letters <a href=\"dingsda.com\">and many, many <b>words. </b></a>"},
%Outlook.InternalTree.TranslationUnit{status: :untranslated, nid: "eac12d97-623d-4237-9f33-666298c7f494",
content: "<a href=\"dingsda.com\"><b>A</b> sentence</a> with many letters and many, many words. "}],
eph: %{sibling_with: :block}}],
date: ~U[2022-12-25 16:16:00Z], date: ~U[2022-12-25 16:16:00Z],
language: "some language", language: "EN",
title: "some title", title: "some title",
url: "some url" url: "some url",
author_id: 1
}) })
|> Outlook.Articles.create_article() |> Outlook.Articles.create_article()

View File

@ -0,0 +1,45 @@
defmodule Outlook.PublicFixtures do
@moduledoc """
This module defines test helpers for creating
entities via the `Outlook.Public` context.
"""
# TODO: make this work
@doc """
Generate an artikel.
"""
def artikel_fixture(attrs \\ %{}) do
{:ok, artikel} =
attrs
|> Enum.into(%{
date: "some date",
public_content: "some public_content",
teaser: "some teaser",
title: "some title",
translator: "some translator",
unauthorized: true
})
|> Outlook.Public.create_artikel()
artikel
end
@doc """
Generate an autor.
"""
def autor_fixture(attrs \\ %{}) do
{:ok, autor} =
attrs
|> Enum.into(%{
description: "some description",
homepage_name: "some homepage_name",
homepage_url: "some homepage_url",
name: "some name"
})
|> Outlook.Public.create_autor()
autor
end
end

View File

@ -4,6 +4,8 @@ defmodule Outlook.TranslationsFixtures do
entities via the `Outlook.Translations` context. entities via the `Outlook.Translations` context.
""" """
# TODO: make this work
@doc """ @doc """
Generate a translation. Generate a translation.
""" """
@ -17,7 +19,8 @@ defmodule Outlook.TranslationsFixtures do
public: true, public: true,
teaser: "some teaser", teaser: "some teaser",
title: "some title", title: "some title",
unauthorized: true unauthorized: true,
article_id: 1
}) })
|> Outlook.Translations.create_translation() |> Outlook.Translations.create_translation()