Compare commits
20 Commits
3a2769eed1
...
feature/de
| Author | SHA1 | Date | |
|---|---|---|---|
| 5dfbf7011e | |||
| 2eba3bc500 | |||
| 43f3ea193f | |||
| 61253f301a | |||
| 5d43e61223 | |||
| 724d161f50 | |||
| 1fb9a40f2c | |||
| 459c8e6a57 | |||
| 21b97bec6e | |||
| 5d9238a65a | |||
| e20f8e33ee | |||
| 4e6c516cb6 | |||
| bacb61252f | |||
| 8a513b1452 | |||
| 895860baa6 | |||
| 5319785855 | |||
| b20bbb232c | |||
| cbea9450e4 | |||
| 3fe4a331ac | |||
| 6d0ae825d8 |
@ -3,7 +3,6 @@ alias Outlook.HtmlPreparations.HtmlPreparation
|
||||
alias Outlook.InternalTree.{Html,InternalNode,TranslationUnit}
|
||||
alias Outlook.InternalTree
|
||||
alias Outlook.Articles
|
||||
alias Outlook.Artikel
|
||||
alias Outlook.Accounts
|
||||
alias Outlook.Articles.Article
|
||||
alias Outlook.Authors
|
||||
@ -12,6 +11,8 @@ alias Outlook.Translations
|
||||
alias Outlook.Translations.Translation
|
||||
alias Outlook.Translators.{Deepl,DeeplAccount}
|
||||
alias Outlook.Translators
|
||||
alias Outlook.Public
|
||||
alias Outlook.Public.{Artikel,Autor}
|
||||
alias Outlook.Repo
|
||||
import Ecto.Query, warn: false
|
||||
html = """
|
||||
|
||||
@ -7,14 +7,41 @@
|
||||
max-width: 25rem;
|
||||
}
|
||||
|
||||
.article .tunit {
|
||||
.article span.tunit {
|
||||
@apply hover:bg-gray-300;
|
||||
}
|
||||
|
||||
.dark .article .tunit {
|
||||
.dark .article span.tunit {
|
||||
@apply hover:bg-gray-700;
|
||||
}
|
||||
|
||||
.article span.tunit[current="yes"] {
|
||||
@apply bg-amber-300 text-stone-700 hover:bg-amber-200 hover:text-red-900;
|
||||
}
|
||||
|
||||
.dark .article span.tunit[current="yes"] {
|
||||
@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 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@ -23,11 +23,14 @@ import {LiveSocket} from "phoenix_live_view"
|
||||
import topbar from "../vendor/topbar"
|
||||
|
||||
import {DarkModeHook} from './dark-mode-widget'
|
||||
import {TranslationFormHook} from "./translation-form"
|
||||
|
||||
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
|
||||
let liveSocket = new LiveSocket("/live", Socket, {
|
||||
params: {_csrf_token: csrfToken},
|
||||
hooks: {dark_mode_widget: DarkModeHook},
|
||||
hooks: {translation_form: TranslationFormHook,
|
||||
// tunit_editor: TunitEditorHook,
|
||||
dark_mode_widget: DarkModeHook},
|
||||
})
|
||||
|
||||
// Show progress bar on live navigation and form submits
|
||||
|
||||
52
assets/js/translation-form.js
Normal file
52
assets/js/translation-form.js
Normal file
@ -0,0 +1,52 @@
|
||||
let TranslationFormHook = {
|
||||
|
||||
mounted() {
|
||||
this.el.addEventListener("keyup", this.keyupHandler.bind(this))
|
||||
this.title_input = this.el.querySelector("#translation-form_title")
|
||||
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) {
|
||||
var push_event = true
|
||||
var preaction = () => { }
|
||||
var postaction = () => { }
|
||||
var payload = {}
|
||||
if (e.altKey){
|
||||
if (e.ctrlKey){
|
||||
if (e.key == "s"){
|
||||
this.save_edit_button.click()
|
||||
} else if (e.key == "p"){
|
||||
this.save_publish_button.click()
|
||||
}
|
||||
} else {
|
||||
if (e.key == "ArrowDown" || e.key == "n"){
|
||||
preaction = () => { this.title_input.focus() }
|
||||
postaction = () => { this.tunit_editor.focus() }
|
||||
var handler = "select_next_tunit"
|
||||
} else if (e.key == "ArrowUp" || e.key == "v"){
|
||||
preaction = () => { this.title_input.focus() }
|
||||
postaction = () => { this.tunit_editor.focus() }
|
||||
var handler = "select_previous_tunit"
|
||||
} else if (e.key == "u") {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export {TranslationFormHook}
|
||||
@ -39,7 +39,7 @@ defmodule Outlook.Authors do
|
||||
|
||||
def get_author_with_articles!(id) do
|
||||
Repo.get!(Author, id)
|
||||
|> Repo.preload([:articles])
|
||||
|> Repo.preload([articles: :translations])
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
||||
@ -9,7 +9,7 @@ defmodule Outlook.Authors.Author do
|
||||
field :homepage_name, :string
|
||||
field :homepage_url, :string
|
||||
field :name, :string
|
||||
has_many :articles, Article
|
||||
has_many :articles, Article, on_delete: :delete_all
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@ -10,11 +10,6 @@ defmodule Outlook.InternalTree do
|
||||
|> Html.to_html()
|
||||
end
|
||||
|
||||
def render_html_preview(tree, target \\ "1") do
|
||||
tree
|
||||
|> Html.to_html_preview(target)
|
||||
end
|
||||
|
||||
require Logger
|
||||
def apply_modifier(tree, modifier, nids, opts \\ %{}) do
|
||||
# Logger.info modifier
|
||||
|
||||
@ -51,30 +51,6 @@ defmodule Outlook.InternalTree.Html do
|
||||
|
||||
def to_html([]), do: ""
|
||||
|
||||
def to_html_preview([ %InternalNode{type: :element} = node | rest], target_id) do
|
||||
attr_string = Map.put(node.attributes, :nid, node.nid)
|
||||
|> Enum.map_join(" ", fn {k,v} -> "#{k}=\"#{v}\"" end)
|
||||
"<#{node.name} #{attr_string}>" <>
|
||||
to_html_preview(node.content, target_id) <>
|
||||
"</#{node.name}>" <>
|
||||
to_html_preview(rest, target_id)
|
||||
end
|
||||
|
||||
def to_html_preview([ %InternalNode{type: :text} = node | rest], target_id) do
|
||||
~s(<span nid="#{node.nid}">#{node.content}</span>) <> to_html_preview(rest, target_id)
|
||||
end
|
||||
|
||||
def to_html_preview([ %InternalNode{type: :comment} = node | rest], target_id) do
|
||||
~s(<span nid="#{node.nid}"><!--#{node.content}--></span>) <> to_html_preview(rest, target_id)
|
||||
end
|
||||
|
||||
def to_html_preview([ %TranslationUnit{} = tunit | rest], target_id) do
|
||||
~s|<span class="tunit" nid="#{tunit.nid}" tu-status="#{tunit.status}" phx-click="select_current_tunit"
|
||||
phx-value-nid="#{tunit.nid}" phx-target="#{target_id}">#{tunit.content}</span>| <> to_html_preview(rest, target_id)
|
||||
end
|
||||
|
||||
def to_html_preview([], _target_id), do: ""
|
||||
|
||||
|
||||
def render_doc(tree) do
|
||||
OutlookWeb.HtmlDocComponent.render_doc(%{tree: tree})
|
||||
|
||||
@ -8,7 +8,7 @@ implement to_param protocol (no more needed for Outlook.Translations.Translation
|
||||
alias Outlook.Translations.Translation
|
||||
alias Outlook.Articles.Article
|
||||
alias Outlook.Authors.Author
|
||||
alias Outlook.Public.Artikel
|
||||
alias Outlook.Public.{Artikel,Autor}
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Outlook.Repo
|
||||
@ -17,19 +17,17 @@ implement to_param protocol (no more needed for Outlook.Translations.Translation
|
||||
q = from t in Translation,
|
||||
join: a in Article, on: t.article_id == a.id,
|
||||
join: au in Author, on: a.author_id == au.id,
|
||||
select: [
|
||||
select: %Artikel{
|
||||
title: t.title,
|
||||
date: t.date,
|
||||
teaser: t.teaser,
|
||||
id: t.id,
|
||||
date_org: a.date,
|
||||
autor_name: au.name,
|
||||
],
|
||||
},
|
||||
where: t.public == true and t.language == ^language,
|
||||
order_by: [desc: t.date]
|
||||
Repo.all(q)
|
||||
|> Enum.map(fn rec -> Enum.into(rec, %{}) end)
|
||||
|> Enum.map(fn map -> struct(Artikel, map) end)
|
||||
end
|
||||
|
||||
def get_artikel!(artikel) when is_struct(artikel), do: get_artikel!(artikel.id)
|
||||
@ -37,7 +35,7 @@ implement to_param protocol (no more needed for Outlook.Translations.Translation
|
||||
q = from t in Translation,
|
||||
join: a in Article, on: t.article_id == a.id,
|
||||
join: au in Author, on: a.author_id == au.id,
|
||||
select: [
|
||||
select: %Artikel{
|
||||
title: t.title,
|
||||
date: t.date,
|
||||
public_content: t.public_content,
|
||||
@ -45,12 +43,12 @@ implement to_param protocol (no more needed for Outlook.Translations.Translation
|
||||
url_org: a.url,
|
||||
date_org: a.date,
|
||||
autor_name: au.name,
|
||||
author_id: au.id
|
||||
],
|
||||
autor_id: au.id
|
||||
},
|
||||
where: t.id == ^id and t.public == true
|
||||
case Repo.one(q) do
|
||||
nil -> {:error, "Artikel does not exist, or isn't public."}
|
||||
artikel -> {:ok, struct(Artikel, artikel |> Enum.into(%{}))}
|
||||
artikel -> {:ok, artikel}
|
||||
end
|
||||
end
|
||||
|
||||
@ -69,7 +67,28 @@ implement to_param protocol (no more needed for Outlook.Translations.Translation
|
||||
end
|
||||
|
||||
def get_autor!(id) do
|
||||
Repo.get!(Author, id)
|
||||
|> Repo.preload([articles: [:translations]])
|
||||
q = from au in Author,
|
||||
select: %Autor{
|
||||
name: au.name,
|
||||
description: au.description,
|
||||
homepage_name: au.homepage_name,
|
||||
homepage_url: au.homepage_url,
|
||||
},
|
||||
where: au.id == ^id
|
||||
autor = Repo.one(q)
|
||||
|
||||
q2 = from a in Article,
|
||||
join: t in Translation, on: t.article_id == a.id,
|
||||
select: %Artikel{
|
||||
title: t.title,
|
||||
date: t.date,
|
||||
teaser: t.teaser,
|
||||
id: t.id,
|
||||
date_org: a.date
|
||||
},
|
||||
where: a.author_id == ^id and t.public == true
|
||||
artikel = Repo.all(q2)
|
||||
|
||||
%Autor{autor | artikel: artikel}
|
||||
end
|
||||
end
|
||||
|
||||
@ -11,7 +11,7 @@ defmodule Outlook.Public.Artikel do
|
||||
field :url_org, :string
|
||||
field :date_org, :utc_datetime
|
||||
field :autor_name, :string
|
||||
field :author_id, :integer
|
||||
field :autor_id, :integer
|
||||
field :teaser, :string
|
||||
# field :autor, Autor
|
||||
end
|
||||
|
||||
13
lib/outlook/public/autor.ex
Normal file
13
lib/outlook/public/autor.ex
Normal file
@ -0,0 +1,13 @@
|
||||
defmodule Outlook.Public.Autor do
|
||||
use Ecto.Schema
|
||||
|
||||
alias Outlook.Public.Artikel
|
||||
|
||||
embedded_schema do
|
||||
field :name, :string
|
||||
field :description, :string
|
||||
field :homepage_name, :string
|
||||
field :homepage_url, :string
|
||||
has_many :artikel, Artikel
|
||||
end
|
||||
end
|
||||
@ -4,7 +4,7 @@ defmodule Outlook.Translations.Translation do
|
||||
|
||||
alias Outlook.Accounts.User
|
||||
alias Outlook.Articles.Article
|
||||
alias Outlook.Translations.{TranslationUnitsMap,Translation}
|
||||
alias Outlook.Translations.TranslationUnitsMap
|
||||
|
||||
schema "translations" do
|
||||
field :content, TranslationUnitsMap
|
||||
@ -32,30 +32,4 @@ defmodule Outlook.Translations.Translation do
|
||||
name: :article_id_lang_unique_index)
|
||||
|> foreign_key_constraint(:article_id)
|
||||
end
|
||||
|
||||
def translate_unicode(str) do
|
||||
mapping = %{"Ä" => "Ae",
|
||||
"Ö" => "Oe",
|
||||
"Ü" => "Ue",
|
||||
"ä" => "ae",
|
||||
"ö" => "oe",
|
||||
"ü" => "ue",
|
||||
"ß" => "ss"}
|
||||
{:ok, re} = "[#{Map.keys(mapping) |> Enum.join}]" |> Regex.compile("u")
|
||||
Regex.replace(re, str, fn(c) -> mapping[c] end)
|
||||
end
|
||||
|
||||
def spit_title(title) do
|
||||
title
|
||||
|> translate_unicode()
|
||||
# |> String.replace(~r/[^-0-9A-Za-z ]/u, "_")
|
||||
|> String.replace(~r/[^\w\s-]/u, "")
|
||||
|> String.replace(~r/(\s|-)+/u, "-")
|
||||
end
|
||||
|
||||
defimpl Phoenix.Param, for: Translation do
|
||||
def to_param(%{id: id, title: title}) do
|
||||
"#{Translation.spit_title(title)}--#{Integer.to_string(id, 36) |> String.downcase()}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -48,6 +48,19 @@ defmodule Outlook.Translators do
|
||||
|> Repo.update_all([inc: [our_character_count: billed_characters]])
|
||||
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
|
||||
%{language: target_lang,
|
||||
article: %{content: article_tree, language: source_lang}
|
||||
@ -71,6 +84,14 @@ defmodule Outlook.Translators do
|
||||
process_translation(result.translation, tunit_ids)
|
||||
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_id) do
|
||||
DeeplAccount |> where(user_id: ^user_id)
|
||||
@ -83,7 +104,7 @@ defmodule Outlook.Translators do
|
||||
|> IO.iodata_to_binary()
|
||||
end
|
||||
|
||||
def process_translation(translation, tunit_ids) do
|
||||
defp process_translation(translation, tunit_ids) do
|
||||
tunit_map = translation
|
||||
|> Floki.parse_fragment!
|
||||
|> Floki.find("tunit")
|
||||
|
||||
@ -54,10 +54,12 @@ defmodule Outlook.Translators.Deepl do
|
||||
)
|
||||
response = Jason.decode!(response_raw.body, keys: :atoms)
|
||||
|
||||
require Logger
|
||||
case response do
|
||||
%{status: "done"} ->
|
||||
response
|
||||
%{status: status} ->
|
||||
Logger.debug "Deepl response: #{response |> inspect}"
|
||||
steps = Map.get(response, :seconds_remaining, 1) * 5
|
||||
for n <- 0..steps do
|
||||
send(pid, {:progress, %{progress: 100 * n / steps, status: status}})
|
||||
|
||||
@ -464,11 +464,11 @@ defmodule OutlookWeb.CoreComponents do
|
||||
<th class="relative p-0 pb-4"><span class="sr-only"><%= gettext("Actions") %></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="relative divide-y divide-zinc-100 border-t border-zinc-200 text-sm leading-6 text-zinc-700">
|
||||
<tbody class="relative divide-y divide-zinc-100 border-t border-zinc-200 dark:border-zinc-500 text-sm leading-6 text-zinc-700 dark:text-zinc-400">
|
||||
<tr
|
||||
:for={row <- @rows}
|
||||
id={"#{@id}-#{Phoenix.Param.to_param(row)}"}
|
||||
class="relative group hover:bg-zinc-50"
|
||||
class="relative group hover:bg-zinc-50 dark:hover:bg-zinc-800 "
|
||||
>
|
||||
<td
|
||||
:for={{col, i} <- Enum.with_index(@col)}
|
||||
@ -476,11 +476,11 @@ defmodule OutlookWeb.CoreComponents do
|
||||
class={["p-0", @row_click && "hover:cursor-pointer"]}
|
||||
>
|
||||
<div :if={i == 0}>
|
||||
<span class="absolute h-full w-4 top-0 -left-4 group-hover:bg-zinc-50 sm:rounded-l-xl" />
|
||||
<span class="absolute h-full w-4 top-0 -right-4 group-hover:bg-zinc-50 sm:rounded-r-xl" />
|
||||
<span class="absolute h-full w-4 top-0 -left-4 group-hover:bg-zinc-50 dark:group-hover:bg-zinc-800 sm:rounded-l-xl" />
|
||||
<span class="absolute h-full w-4 top-0 -right-4 group-hover:bg-zinc-50 dark:group-hover:bg-zinc-800 sm:rounded-r-xl" />
|
||||
</div>
|
||||
<div class="block py-4 pr-6">
|
||||
<span class={["relative", i == 0 && "font-semibold text-zinc-900"]}>
|
||||
<span class={["relative", i == 0 && "font-semibold text-zinc-900 dark:text-zinc-300"]}>
|
||||
<%= render_slot(col, row) %>
|
||||
</span>
|
||||
</div>
|
||||
@ -489,7 +489,7 @@ defmodule OutlookWeb.CoreComponents do
|
||||
<div class="relative whitespace-nowrap py-4 text-right text-sm font-medium">
|
||||
<span
|
||||
:for={action <- @action}
|
||||
class="relative ml-4 font-semibold leading-6 text-zinc-900 hover:text-zinc-700"
|
||||
class="relative ml-4 font-semibold leading-6 text-zinc-900 hover:text-zinc-700 dark:text-zinc-500 dark:hover:text-zinc-400"
|
||||
>
|
||||
<%= render_slot(action, row) %>
|
||||
</span>
|
||||
|
||||
@ -13,7 +13,7 @@ defmodule OutlookWeb.PublicComponents do
|
||||
|
||||
def autor(assigns) do
|
||||
~H"""
|
||||
<a href={"/autoren/#{@autor.id}"}>
|
||||
<a href={~p"/autoren/#{@autor}"}>
|
||||
<div class="p-4 my-2 border rounded-lg border-stone-400 text-stone-800 dark:text-stone-300 ">
|
||||
<div class="font-bold"><%= @autor.name %></div>
|
||||
<div class=""><%= @autor.description |> tidy_raw %></div>
|
||||
|
||||
@ -14,7 +14,7 @@ defmodule OutlookWeb.TunitEditorComponent do
|
||||
<%= @current_tunit.content |> raw %>
|
||||
</div> --%>
|
||||
<form phx-change="update_current_tunit" phx-target={@target}>
|
||||
<textarea name="content" class="h-48 rounded border-slate-500 resize-none bg-transparent w-full"
|
||||
<textarea id="tunit-editor-content" name="content" class="h-48 rounded border-slate-500 resize-none bg-transparent w-full"
|
||||
disabled={!@current_tunit.status}><%= @current_tunit.content %></textarea>
|
||||
</form>
|
||||
<.status_selector target={@target} disabled={!@current_tunit.status} tunit={@current_tunit} />
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<header class="mb-6">
|
||||
<h1 class="text-lg font-semibold leading-tight text-stone-800 dark:text-stone-200"><%= @artikel.title %></h1>
|
||||
<p class="my-2"><.link href={~p"/autoren/#{@artikel.author_id}"}><%= @artikel.autor_name %></.link>
|
||||
<p class="my-2"><.link href={~p"/autoren/#{@artikel.autor_id}"}><%= @artikel.autor_name %></.link>
|
||||
— <%= Calendar.strftime(@artikel.date_org, "%d.%m.%Y") %></p>
|
||||
<div>Original Artikel:
|
||||
<.link class="hover:text-sky-700" href={@artikel.url_org} >
|
||||
@ -14,4 +14,4 @@
|
||||
|
||||
<div class="article w-full mx-auto max-w-xs"><%= @artikel.public_content |> raw %></div>
|
||||
|
||||
<.back navigate={~p"/autoren/#{@artikel.author_id}"}>Back to Autor</.back>
|
||||
<.back navigate={~p"/autoren/#{@artikel.autor_id}"}>Back to Autor</.back>
|
||||
|
||||
@ -4,10 +4,6 @@
|
||||
<:subtitle><.link href={@autor.homepage_url}><%= @autor.homepage_name %></.link></:subtitle>
|
||||
</.header>
|
||||
|
||||
|
||||
|
||||
<%= for article <- @autor.articles do %>
|
||||
<.artikel :for={translation <- article.translations} artikel={translation} show_autor={false} />
|
||||
<% end %>
|
||||
<.artikel :for={artikel <- @autor.artikel} artikel={artikel} show_autor={false} />
|
||||
|
||||
<.back navigate={~p"/autoren"}>Back to autoren</.back>
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
</:actions>
|
||||
</.header>
|
||||
|
||||
<.table id="translations" rows={@article.translations} row_click={&JS.navigate(~p"/translations/#{(&1).id}")}>
|
||||
<.table id="translations" rows={@article.translations} row_click={&JS.navigate(~p"/translations/#{&1}")}>
|
||||
<:col :let={translation} label="Language"><%= translation.language %></:col>
|
||||
<:col :let={translation} label="Title"><%= translation.title %></:col>
|
||||
<:col :let={translation} label="Teaser"><%= translation.teaser |> tidy_raw %></:col>
|
||||
@ -24,9 +24,9 @@
|
||||
<:col :let={translation} label="Public"><%= translation.public %></:col>
|
||||
<:action :let={translation}>
|
||||
<div class="sr-only">
|
||||
<.link navigate={~p"/translations/#{translation.id}"}>Show</.link>
|
||||
<.link navigate={~p"/translations/#{translation}"}>Show</.link>
|
||||
</div>
|
||||
<.link navigate={~p"/translations/#{translation.id}/edit"}>Edit</.link>
|
||||
<.link navigate={~p"/translations/#{translation}/edit"}>Edit</.link>
|
||||
</:action>
|
||||
<:action :let={translation}>
|
||||
<.link phx-click={JS.push("delete_translation", value: %{id: translation.id})} data-confirm="Are you sure?">
|
||||
|
||||
@ -8,7 +8,7 @@ defmodule OutlookWeb.TranslationLive.FormComponent do
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<div class="flex gap-8 max-h-fit">
|
||||
<div class="basis-1/2 overflow-auto">
|
||||
<div class="basis-1/2 overflow-auto" id="translation-form-container" target="@myself" phx-hook="translation_form">
|
||||
<.header>
|
||||
<%= @title %>
|
||||
<:subtitle>Use this form to manage translation records in your database.</:subtitle>
|
||||
@ -36,11 +36,11 @@ defmodule OutlookWeb.TranslationLive.FormComponent do
|
||||
<input type="hidden" id="publish" name="publish" value="false" />
|
||||
<:actions>
|
||||
<.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")}
|
||||
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")}
|
||||
phx-disable-with="Saving...">Save and Edit</.button>
|
||||
id="save-edit-button" phx-disable-with="Saving...">Save and Edit</.button>
|
||||
</:actions>
|
||||
</.simple_form>
|
||||
<.tunit_editor current_tunit={@current_tunit} target={@myself} />
|
||||
@ -63,6 +63,7 @@ defmodule OutlookWeb.TranslationLive.FormComponent do
|
||||
socket
|
||||
|> assign(assigns)
|
||||
|> assign(:current_tunit, %TranslationUnit{status: nil})
|
||||
|> assign(:tunit_ids, InternalTree.get_tunit_ids(translation.article.content))
|
||||
|> assign(:changeset, changeset)
|
||||
|> assign_article_tree(translation)
|
||||
|> assign(:deepl_progress, nil)}
|
||||
@ -118,11 +119,33 @@ defmodule OutlookWeb.TranslationLive.FormComponent do
|
||||
{:noreply, socket |> assign(:current_tunit, tunit)}
|
||||
end
|
||||
|
||||
def handle_event("select_current_tunit", %{"nid" => nid}, socket) do
|
||||
{:noreply,
|
||||
socket
|
||||
|> update_translation_with_current_tunit(socket.assigns.current_tunit.status)
|
||||
|> assign(:current_tunit, socket.assigns.translation_content[nid])}
|
||||
def handle_event("select_tunit_by_nid", %{"nid" => nid}, socket) do
|
||||
{:noreply, change_tunit(socket, nid)}
|
||||
end
|
||||
|
||||
def handle_event("select_next_tunit", _, socket) do
|
||||
{:noreply, select_next_tunit(socket, &Kernel.+/2)}
|
||||
end
|
||||
|
||||
def handle_event("select_previous_tunit", _, socket) do
|
||||
{:noreply, select_next_tunit(socket, &Kernel.-/2)}
|
||||
end
|
||||
|
||||
defp select_next_tunit(socket, direction) do
|
||||
tunit_ids = socket.assigns.tunit_ids
|
||||
current_tunit_nid = socket.assigns.current_tunit.status && socket.assigns.current_tunit.nid || List.last(tunit_ids)
|
||||
index_current = Enum.find_index(tunit_ids, fn nid -> nid == current_tunit_nid end)
|
||||
index_next = direction.(index_current, 1) |> Integer.mod(length(tunit_ids))
|
||||
next_nid = Enum.at(tunit_ids, index_next)
|
||||
change_tunit(socket, next_nid)
|
||||
end
|
||||
|
||||
defp change_tunit(socket, nid) do
|
||||
fun = fn n -> n.nid == nid && "yes" || "no" end
|
||||
socket
|
||||
|> assign(:article_tree, InternalTree.garnish(socket.assigns.article_tree, %{tunits: %{current: fun}}))
|
||||
|> update_translation_with_current_tunit(socket.assigns.current_tunit.status)
|
||||
|> assign(:current_tunit, socket.assigns.translation_content[nid])
|
||||
end
|
||||
|
||||
@doc "updating on browser events"
|
||||
@ -146,7 +169,7 @@ defmodule OutlookWeb.TranslationLive.FormComponent do
|
||||
:article_tree,
|
||||
InternalTree.add_phx_click_event(translation.article.content,
|
||||
nodes: :tunits,
|
||||
click: "select_current_tunit",
|
||||
click: "select_tunit_by_nid",
|
||||
target: socket.assigns.myself)
|
||||
|> InternalTree.garnish(%{tunits: %{class: "tunit"}}))
|
||||
end
|
||||
@ -187,6 +210,7 @@ defmodule OutlookWeb.TranslationLive.FormComponent do
|
||||
|
||||
defp continue_edit(socket, :edit, %{"continue_edit" => "true"}) do
|
||||
socket
|
||||
|> assign(:translation, Translations.get_translation!(socket.assigns.translation.id))
|
||||
end
|
||||
defp continue_edit(socket, :new, %{"continue_edit" => "true"} = params) do
|
||||
socket |> push_patch(to: ~p(/translations/#{params["id"]}/edit))
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
Listing Translations
|
||||
</.header>
|
||||
|
||||
<.table id="translations" rows={@translations} row_click={&JS.navigate(~p(/translations/#{(&1).id}))}>
|
||||
<.table id="translations" rows={@translations} row_click={&JS.navigate(~p(/translations/#{&1}))}>
|
||||
<:col :let={translation} label="Language"><%= translation.language %></:col>
|
||||
<:col :let={translation} label="Title"><%= translation.title %></:col>
|
||||
<:col :let={translation} label="Teaser"><%= translation.teaser |> tidy_raw %></:col>
|
||||
@ -12,9 +12,9 @@
|
||||
<:col :let={translation} label="Unauthorized"><%= translation.unauthorized %></:col>
|
||||
<:action :let={translation}>
|
||||
<div class="sr-only">
|
||||
<.link navigate={~p"/translations/#{translation.id}"}>Show</.link>
|
||||
<.link navigate={~p"/translations/#{translation}"}>Show</.link>
|
||||
</div>
|
||||
<.link navigate={~p"/translations/#{translation.id}/edit"}>Edit</.link>
|
||||
<.link navigate={~p"/translations/#{translation}/edit"}>Edit</.link>
|
||||
</:action>
|
||||
<:action :let={translation}>
|
||||
<.link phx-click={JS.push("delete", value: %{id: translation.id})} data-confirm="Are you sure?">
|
||||
|
||||
@ -10,10 +10,18 @@ defmodule OutlookWeb.TranslationLive.Show do
|
||||
|
||||
@impl true
|
||||
def handle_params(%{"id" => id}, _, socket) do
|
||||
translation = Translations.get_translation!(id)
|
||||
{:noreply,
|
||||
socket
|
||||
|> 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
|
||||
|
||||
defp page_title(:show), do: "Show Translation"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
Translation <%= @translation.id %>
|
||||
<:subtitle>This is a translation record from your database.</:subtitle>
|
||||
<:actions>
|
||||
<.link navigate={~p"/translations/#{@translation.id}/edit"} phx-click={JS.push_focus()}>
|
||||
<.link navigate={~p"/translations/#{@translation}/edit"} phx-click={JS.push_focus()}>
|
||||
<.button>Edit translation</.button>
|
||||
</.link>
|
||||
</:actions>
|
||||
@ -18,8 +18,8 @@
|
||||
<:item title="Unauthorized"><%= @translation.unauthorized %></:item>
|
||||
</.list>
|
||||
|
||||
<div class="article">
|
||||
<.render_doc tree={InternalTree.render_translation(@translation.article.content, @translation.content)} />
|
||||
<div class="article show_status">
|
||||
<.render_doc tree={@translation_tree} />
|
||||
</div>
|
||||
|
||||
<.back navigate={~p"/articles/#{@translation.article}"}>Back to <article></article></.back>
|
||||
|
||||
@ -12,4 +12,10 @@ defmodule OutlookWeb.ViewHelpers do
|
||||
def tidy_raw(whatever) do
|
||||
whatever
|
||||
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
|
||||
|
||||
131
test/outlook/public_test.exs
Normal file
131
test/outlook/public_test.exs
Normal 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
|
||||
86
test/outlook_web/controllers/artikel_controller_test.exs
Normal file
86
test/outlook_web/controllers/artikel_controller_test.exs
Normal 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
|
||||
86
test/outlook_web/controllers/autor_controller_test.exs
Normal file
86
test/outlook_web/controllers/autor_controller_test.exs
Normal 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
|
||||
@ -4,6 +4,8 @@ defmodule Outlook.ArticlesFixtures do
|
||||
entities via the `Outlook.Articles` context.
|
||||
"""
|
||||
|
||||
# TODO: make this work
|
||||
|
||||
@doc """
|
||||
Generate a article.
|
||||
"""
|
||||
@ -11,11 +13,17 @@ defmodule Outlook.ArticlesFixtures do
|
||||
{:ok, article} =
|
||||
attrs
|
||||
|> 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],
|
||||
language: "some language",
|
||||
language: "EN",
|
||||
title: "some title",
|
||||
url: "some url"
|
||||
url: "some url",
|
||||
author_id: 1
|
||||
})
|
||||
|> Outlook.Articles.create_article()
|
||||
|
||||
|
||||
45
test/support/fixtures/public_fixtures.ex
Normal file
45
test/support/fixtures/public_fixtures.ex
Normal 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
|
||||
@ -4,6 +4,8 @@ defmodule Outlook.TranslationsFixtures do
|
||||
entities via the `Outlook.Translations` context.
|
||||
"""
|
||||
|
||||
# TODO: make this work
|
||||
|
||||
@doc """
|
||||
Generate a translation.
|
||||
"""
|
||||
@ -17,7 +19,8 @@ defmodule Outlook.TranslationsFixtures do
|
||||
public: true,
|
||||
teaser: "some teaser",
|
||||
title: "some title",
|
||||
unauthorized: true
|
||||
unauthorized: true,
|
||||
article_id: 1
|
||||
})
|
||||
|> Outlook.Translations.create_translation()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user