Compare commits
31 Commits
faf2bb0e2e
...
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 | |||
| 3a2769eed1 | |||
| e8089eb24e | |||
| 02e6340c0a | |||
| ed98f4cbc4 | |||
| b87b54ec71 | |||
| fc0818678c | |||
| dc4c8e4790 | |||
| e98187200a | |||
| b47d7d081d | |||
| 2ffea3e490 | |||
| cb8e9ef14f |
22
.iex-local.exs
Normal file
22
.iex-local.exs
Normal file
@ -0,0 +1,22 @@
|
||||
alias Outlook.HtmlPreparations
|
||||
alias Outlook.HtmlPreparations.HtmlPreparation
|
||||
alias Outlook.InternalTree.{Html,InternalNode,TranslationUnit}
|
||||
alias Outlook.InternalTree
|
||||
alias Outlook.Articles
|
||||
alias Outlook.Accounts
|
||||
alias Outlook.Articles.Article
|
||||
alias Outlook.Authors
|
||||
alias Outlook.Authors.Author
|
||||
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 = """
|
||||
<p class="">Das Young-Global-Leaders-Programm des WEF von Klaus Schwab tut seit Anfang der 90er Jahre das gleiche und wäre es ein Konkurrenzprodukt gegen die bestehenden, transatlantischen US-Programme, wäre das Projekt sofort abgewürgt worden. Stattdessen ist es ein großer Erfolg und sehr viele der heute weltweit führenden Politiker sind durch die Schule von Klaus Schwab gegangen und setzen als Minister und sogar Regierungschefs brav die Politik um, für die sich Schwab selbst einsetzt.</p>
|
||||
<p>Die Frage ist also, wie und mit wessen Hilfe es der aus kleinen Verhältnissen stammende Klaus Schwab geschafft hat, so mächtig zu werden. Die Antwort ist verblüffend einfach: Er hat als Student selbst so ein Programm durchlaufen. Damals war es noch die CIA, die relativ offen hinter diesem Programm stand und junge Leute gesucht hat, deren Karriere die CIA gefördert hat, damit diese Leute später das umsetzen, was von der CIA gewollt ist. Inzwischen hat Schwab mit seinem WEF diese Funktion übernommen und sein Young-Global-Leaders-Programm ist nichts anderes, als das Nachfolgeprogramm eines CIA-Programms aus den 1950er Jahren.</p>
|
||||
<p>Auf den Artikel bin ich durch einen Hinweis eines Lesers auf einen <a rel="noreferrer noopener" href="https://tkp.at/2022/09/02/das-young-global-leaders-programm-des-wef-und-sein-ursprung-in-den-usa/" target="_blank">Artikel bei tkp </a>gestoßen, der den englischen Artikel zusammengefasst hat. Da die Informationen im Original so spannend und die Details zum Verständnis so wichtig sind, habe ich den <a rel="noreferrer noopener" href="https://unlimitedhangout.com/2022/08/investigative-reports/the-kissinger-continuum-the-unauthorized-history-of-the-wefs-young-global-leaders-program/" target="_blank" class="">englischen Originalartikel</a> übersetzt, um mich nicht mit fremden Federn zu schmücken. Die Links habe ich aus dem Originalartikel übernommen.</p>
|
||||
"""
|
||||
@ -1,12 +1,47 @@
|
||||
.main {
|
||||
@apply place-content-center;
|
||||
}
|
||||
|
||||
.article {
|
||||
/* @apply pr-8 */
|
||||
max-width: 25rem;
|
||||
}
|
||||
|
||||
.article .tunit {
|
||||
.article span.tunit {
|
||||
@apply hover:bg-gray-300;
|
||||
}
|
||||
|
||||
.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}
|
||||
@ -1,33 +0,0 @@
|
||||
defmodule Outlook.Artikel do
|
||||
@moduledoc """
|
||||
The Artikel context.
|
||||
"""
|
||||
|
||||
alias Outlook.Translations.Translation
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Outlook.Repo
|
||||
|
||||
def list_artikel do
|
||||
Repo.all(from t in Translation, where: t.public == true)
|
||||
|> Repo.preload([article: :author])
|
||||
end
|
||||
|
||||
def get_artikel!(artikel) when is_struct(artikel), do: get_artikel!(artikel.id)
|
||||
def get_artikel!(id) do
|
||||
Repo.one(from t in Translation, where: t.id == ^id and t.public == true)
|
||||
|> Repo.preload([article: :author])
|
||||
end
|
||||
|
||||
def get_artikel_by_tid(tid) do
|
||||
artikel = tid
|
||||
|> String.split(~r/--(?=[0-9A-Za-z])/)
|
||||
|> List.last()
|
||||
|> String.to_integer(36)
|
||||
|> get_artikel!()
|
||||
case artikel do
|
||||
%Translation{} -> {:ok, artikel}
|
||||
_ -> {:error, "Artikel does not exist, or isn't public."}
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -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
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
defmodule Outlook.Autoren do
|
||||
@moduledoc """
|
||||
The Autoren context.
|
||||
"""
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Outlook.Repo
|
||||
|
||||
alias Outlook.Articles.Article
|
||||
alias Outlook.Translations.Translation
|
||||
|
||||
alias Outlook.Authors.Author
|
||||
|
||||
def list_autoren do
|
||||
Repo.all(Author)
|
||||
end
|
||||
|
||||
def get_autor!(id) do
|
||||
Repo.get!(Author, id)
|
||||
|> Repo.preload([articles: [:translations]])
|
||||
end
|
||||
|
||||
@doc "This is ugly"
|
||||
def list_artikel(author) when is_struct(author), do: list_artikel(author.id)
|
||||
def list_artikel(author_id) do
|
||||
aids = Repo.all(from a in Article,
|
||||
select: [:id],
|
||||
where: a.author_id == ^author_id)
|
||||
|> Enum.map(fn a -> a.id end)
|
||||
Repo.all(from t in Translation,
|
||||
select: [t.title, t.teaser, t.date, t.user_id],
|
||||
where: t.article_id in ^aids and t.public == true)
|
||||
end
|
||||
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})
|
||||
|
||||
@ -58,4 +58,19 @@ defmodule Outlook.InternalTree.InternalTree do
|
||||
|> Enum.into(node_atts)
|
||||
%{node | eph: Map.put(node.eph, :attributes, attributes)}
|
||||
end
|
||||
|
||||
|
||||
def collect_tunit_ids([%TranslationUnit{} = node | rest]) do
|
||||
[node.nid | collect_tunit_ids(rest)]
|
||||
end
|
||||
|
||||
def collect_tunit_ids([%{type: :element} = node | rest]) do
|
||||
collect_tunit_ids(node.content) ++ collect_tunit_ids(rest)
|
||||
end
|
||||
|
||||
def collect_tunit_ids([node | rest]) do
|
||||
collect_tunit_ids(rest)
|
||||
end
|
||||
|
||||
def collect_tunit_ids([]), do: []
|
||||
end
|
||||
|
||||
94
lib/outlook/public.ex
Normal file
94
lib/outlook/public.ex
Normal file
@ -0,0 +1,94 @@
|
||||
defmodule Outlook.Public do
|
||||
@moduledoc """
|
||||
This should replace Outlook.Artikel and Outlook.Autoren for
|
||||
both of which embedded schemas should be created, for Artikel the schema should
|
||||
implement to_param protocol (no more needed for Outlook.Translations.Translation then).
|
||||
"""
|
||||
|
||||
alias Outlook.Translations.Translation
|
||||
alias Outlook.Articles.Article
|
||||
alias Outlook.Authors.Author
|
||||
alias Outlook.Public.{Artikel,Autor}
|
||||
|
||||
import Ecto.Query, warn: false
|
||||
alias Outlook.Repo
|
||||
|
||||
def list_artikel(language \\ "DE") do
|
||||
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: %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)
|
||||
end
|
||||
|
||||
def get_artikel!(artikel) when is_struct(artikel), do: get_artikel!(artikel.id)
|
||||
def get_artikel!(id) do
|
||||
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: %Artikel{
|
||||
title: t.title,
|
||||
date: t.date,
|
||||
public_content: t.public_content,
|
||||
title_org: a.title,
|
||||
url_org: a.url,
|
||||
date_org: a.date,
|
||||
autor_name: au.name,
|
||||
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, artikel}
|
||||
end
|
||||
end
|
||||
|
||||
def get_artikel_by_tid(tid) do
|
||||
tid
|
||||
|> String.split(~r/--(?=[0-9A-Za-z])/)
|
||||
|> List.last()
|
||||
|> String.to_integer(36)
|
||||
|> get_artikel!()
|
||||
end
|
||||
|
||||
# for /autoren/
|
||||
|
||||
def list_autoren do
|
||||
Repo.all(Author)
|
||||
end
|
||||
|
||||
def get_autor!(id) do
|
||||
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
|
||||
43
lib/outlook/public/artikel.ex
Normal file
43
lib/outlook/public/artikel.ex
Normal file
@ -0,0 +1,43 @@
|
||||
defmodule Outlook.Public.Artikel do
|
||||
use Ecto.Schema
|
||||
|
||||
alias Outlook.Public.Artikel
|
||||
|
||||
embedded_schema do
|
||||
field :title, :string
|
||||
field :date, :utc_datetime
|
||||
field :public_content, :string
|
||||
field :title_org, :string
|
||||
field :url_org, :string
|
||||
field :date_org, :utc_datetime
|
||||
field :autor_name, :string
|
||||
field :autor_id, :integer
|
||||
field :teaser, :string
|
||||
# field :autor, Autor
|
||||
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/[^\w\s-]/u, "")
|
||||
|> String.replace(~r/(\s|-)+/u, "-")
|
||||
end
|
||||
|
||||
defimpl Phoenix.Param, for: Artikel do
|
||||
def to_param(%{id: id, title: title}) do
|
||||
"#{Artikel.spit_title(title)}--#{Integer.to_string(id, 36) |> String.downcase()}"
|
||||
end
|
||||
end
|
||||
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}})
|
||||
|
||||
@ -191,7 +191,7 @@ defmodule OutlookWeb.CoreComponents do
|
||||
def simple_form(assigns) do
|
||||
~H"""
|
||||
<.form :let={f} for={@for} as={@as} {@rest}>
|
||||
<div class="space-y-8 bg-white mt-10">
|
||||
<div class="space-y-8 bg-transparent mt-10">
|
||||
<%= render_slot(@inner_block, f) %>
|
||||
<div :for={action <- @actions} class="mt-2 flex items-center justify-between gap-6">
|
||||
<%= render_slot(action, f) %>
|
||||
@ -220,8 +220,9 @@ defmodule OutlookWeb.CoreComponents do
|
||||
<button
|
||||
type={@type}
|
||||
class={[
|
||||
"phx-submit-loading:opacity-75 rounded-lg bg-zinc-900 hover:bg-zinc-700 py-2 px-3",
|
||||
"phx-submit-loading:opacity-75 rounded-lg bg-zinc-900 dark:bg-gray-600 hover:bg-zinc-700 py-2 px-3",
|
||||
"text-sm font-semibold leading-6 text-white active:text-white/80",
|
||||
"dark:text-gray-300 dark:active:text-gray/80",
|
||||
@class
|
||||
]}
|
||||
{@rest}
|
||||
@ -281,7 +282,7 @@ defmodule OutlookWeb.CoreComponents do
|
||||
assigns = assign_new(assigns, :checked, fn -> input_equals?(assigns.value, "true") end)
|
||||
|
||||
~H"""
|
||||
<label phx-feedback-for={@name} class="flex items-center gap-4 text-sm leading-6 text-zinc-600">
|
||||
<label phx-feedback-for={@name} class="flex items-center gap-4 text-sm leading-6 text-zinc-600 dark:text-zinc-300">
|
||||
<input type="hidden" name={@name} value="false" />
|
||||
<input
|
||||
type="checkbox"
|
||||
@ -289,7 +290,10 @@ defmodule OutlookWeb.CoreComponents do
|
||||
name={@name}
|
||||
value="true"
|
||||
checked={@checked}
|
||||
class="rounded border-zinc-300 text-zinc-900 focus:ring-zinc-900"
|
||||
class={[
|
||||
"rounded border-zinc-300 dark:border-stone-800 dark:bg-stone-800 text-zinc-900 dark:text-zinc-200",
|
||||
" focus:ring-zinc-900 dark:focus:ring-stone-700 dark:focus:bg-stone-800",
|
||||
]}
|
||||
{@rest}
|
||||
/>
|
||||
<%= @label %>
|
||||
@ -304,7 +308,7 @@ defmodule OutlookWeb.CoreComponents do
|
||||
<select
|
||||
id={@id}
|
||||
name={@name}
|
||||
class="mt-1 block w-full py-2 px-3 border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-zinc-500 focus:border-zinc-500 sm:text-sm"
|
||||
class="mt-1 block w-full py-2 px-3 border border-gray-300 dark:border-gray-700 bg-white dark:bg-stone-900 rounded-md shadow-sm focus:outline-none focus:ring-zinc-500 focus:border-zinc-500 sm:text-sm"
|
||||
multiple={@multiple}
|
||||
{@rest}
|
||||
>
|
||||
@ -328,6 +332,7 @@ defmodule OutlookWeb.CoreComponents do
|
||||
"mt-2 block min-h-[6rem] w-full rounded-lg border-zinc-300 py-[7px] px-[11px]",
|
||||
"text-zinc-900 focus:border-zinc-400 focus:outline-none focus:ring-4 focus:ring-zinc-800/5 sm:text-sm sm:leading-6",
|
||||
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400 phx-no-feedback:focus:ring-zinc-800/5",
|
||||
"dark:border-gray-700 dark:bg-stone-900 dark:text-gray-300",
|
||||
@class
|
||||
]}
|
||||
{@rest}
|
||||
@ -360,7 +365,8 @@ defmodule OutlookWeb.CoreComponents do
|
||||
input_border(@errors),
|
||||
"mt-2 block w-full rounded-lg border-zinc-300 py-[7px] px-[11px]",
|
||||
"text-zinc-900 focus:outline-none focus:ring-4 sm:text-sm sm:leading-6",
|
||||
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400 phx-no-feedback:focus:ring-zinc-800/5"
|
||||
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400 phx-no-feedback:focus:ring-zinc-800/5",
|
||||
"dark:border-gray-700 dark:bg-stone-900 dark:text-gray-300",
|
||||
]}
|
||||
{@rest}
|
||||
/>
|
||||
@ -383,7 +389,7 @@ defmodule OutlookWeb.CoreComponents do
|
||||
|
||||
def label(assigns) do
|
||||
~H"""
|
||||
<label for={@for} class="block text-sm font-semibold leading-6 text-zinc-800">
|
||||
<label for={@for} class="block text-sm font-semibold leading-6 text-zinc-800 dark:text-zinc-400">
|
||||
<%= render_slot(@inner_block) %>
|
||||
</label>
|
||||
"""
|
||||
@ -458,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)}
|
||||
@ -470,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>
|
||||
@ -483,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>
|
||||
@ -23,14 +23,14 @@ defmodule OutlookWeb.PublicComponents do
|
||||
end
|
||||
|
||||
attr :artikel, :any, required: true
|
||||
attr :show_author, :boolean, default: true
|
||||
attr :show_autor, :boolean, default: true
|
||||
|
||||
def artikel(assigns) do
|
||||
~H"""
|
||||
<.link navigate={~p"/artikel/#{@artikel}"}>
|
||||
<div class="my-2 px-2 rounded border-2 border-solid border-gray-300 dark:border-stone-800">
|
||||
<h4 class="font-bold text-stone-800 dark:text-stone-300 py-2"><%= @artikel.title %></h4>
|
||||
<div :if={@show_author}><small><%= @artikel.article.author.name %></small></div>
|
||||
<div :if={@show_autor}><small><%= @artikel.autor_name %></small></div>
|
||||
<div><small><%= @artikel.date |> Calendar.strftime("%d.%m.%Y") %></small></div>
|
||||
<div><%= @artikel.teaser |> tidy_raw %></div>
|
||||
</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 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,19 +1,20 @@
|
||||
defmodule OutlookWeb.ArtikelController do
|
||||
use OutlookWeb, :controller
|
||||
|
||||
alias Outlook.Artikel
|
||||
alias Outlook.Public
|
||||
|
||||
def index(conn, _params) do
|
||||
artikel = Artikel.list_artikel()
|
||||
artikel = Public.list_artikel()
|
||||
render(conn, :index, artikel: artikel, page_title: "Artikel")
|
||||
end
|
||||
|
||||
def show(conn, %{"tid" => tid} = params) do
|
||||
case Artikel.get_artikel_by_tid(tid) do
|
||||
case Public.get_artikel_by_tid(tid) do
|
||||
{:ok, artikel} -> render(conn, :show, artikel: artikel, page_title: artikel.title)
|
||||
{:error, message} -> conn
|
||||
|> put_status(404)
|
||||
|> render(OutlookWeb.ErrorHTML, "404.html")
|
||||
|> put_view(OutlookWeb.ErrorHTML)
|
||||
|> render("404.html")
|
||||
|> halt()
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
<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={"/autoren/#{@artikel.article.author.id}"}><%= @artikel.article.author.name %></.link>
|
||||
— <%= Calendar.strftime(@artikel.article.date, "%d.%m.%Y") %></p>
|
||||
<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.article.url} >
|
||||
<%= @artikel.article.title %>
|
||||
<.link class="hover:text-sky-700" href={@artikel.url_org} >
|
||||
<%= @artikel.title_org %>
|
||||
</.link><br>
|
||||
</div>
|
||||
<div class="my-2">
|
||||
@ -14,4 +14,4 @@
|
||||
|
||||
<div class="article w-full mx-auto max-w-xs"><%= @artikel.public_content |> raw %></div>
|
||||
|
||||
<.back navigate={~p"/autoren/#{@artikel.article.author}"}>Back to Autor</.back>
|
||||
<.back navigate={~p"/autoren/#{@artikel.autor_id}"}>Back to Autor</.back>
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
defmodule OutlookWeb.AutorController do
|
||||
use OutlookWeb, :controller
|
||||
|
||||
alias Outlook.Autoren
|
||||
alias Outlook.Public
|
||||
|
||||
def index(conn, _params) do
|
||||
autoren = Autoren.list_autoren()
|
||||
autoren = Public.list_autoren()
|
||||
render(conn, :index, autoren: autoren, page_title: "Autoren")
|
||||
end
|
||||
|
||||
def show(conn, %{"id" => id}) do
|
||||
autor = Autoren.get_autor!(id)
|
||||
autor = Public.get_autor!(id)
|
||||
# artikel = Autoren.list_artikel(autor)
|
||||
render(conn, :show, autor: autor, page_title: autor.name)
|
||||
end
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
<.header>
|
||||
<%= @autor.name %>
|
||||
<:subtitle><div class="text-lg mb-2"><%= @autor.description %></div></:subtitle>
|
||||
<:subtitle><div class="text-lg mb-2"><%= @autor.description |> tidy_raw %></div></:subtitle>
|
||||
<: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_author={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>
|
||||
|
||||
@ -3,10 +3,19 @@ defmodule OutlookWeb.ViewHelpers do
|
||||
import Phoenix.HTML, only: [raw: 1]
|
||||
|
||||
@doc "Just sanitize tags"
|
||||
def tidy_raw(html) do
|
||||
def tidy_raw(html) when is_binary(html) do
|
||||
html
|
||||
|> Floki.parse_fragment!()
|
||||
|> Floki.raw_html()
|
||||
|> raw
|
||||
end
|
||||
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
|
||||
|
||||
14
mix.lock
14
mix.lock
@ -12,14 +12,14 @@
|
||||
"ecto": {:hex, :ecto, "3.9.4", "3ee68e25dbe0c36f980f1ba5dd41ee0d3eb0873bccae8aeaf1a2647242bffa35", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "de5f988c142a3aa4ec18b85a4ec34a2390b65b24f02385c1144252ff6ff8ee75"},
|
||||
"ecto_psql_extras": {:hex, :ecto_psql_extras, "0.7.10", "e14d400930f401ca9f541b3349212634e44027d7f919bbb71224d7ac0d0e8acd", [:mix], [{:ecto_sql, "~> 3.4", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.15.7 or ~> 0.16.0", [hex: :postgrex, repo: "hexpm", optional: false]}, {:table_rex, "~> 3.1.1", [hex: :table_rex, repo: "hexpm", optional: false]}], "hexpm", "505e8cd81e4f17c090be0f99e92b1b3f0fd915f98e76965130b8ccfb891e7088"},
|
||||
"ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.7.3", "c37fdae1b52d2cc51069713a58c2314877c1ad40800a57efb213f77b078a460d", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "24ada3e3996adbed1fa024ca14995ef2ba3d0d17b678b0f3f2b1f66e6ce2b274"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.7.5", "784cc00f5fa24239067cc04d449437dcc5f59353c44eb08f188b2b146568738a", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "c3d63e8d5c92fa3880d89ecd41de59473fa2e83eeb68148155e25e8b95aa2887"},
|
||||
"esbuild": {:hex, :esbuild, "0.6.1", "a774bfa7b4512a1211bf15880b462be12a4c48ed753a170c68c63b2c95888150", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "569f7409fb5a932211573fc20e2a930a0d5cf3377c5b4f6506c651b1783a1678"},
|
||||
"expo": {:hex, :expo, "0.3.0", "13127c1d5f653b2927f2616a4c9ace5ae372efd67c7c2693b87fd0fdc30c6feb", [:mix], [], "hexpm", "fb3cd4bf012a77bc1608915497dae2ff684a06f0fa633c7afa90c4d72b881823"},
|
||||
"expo": {:hex, :expo, "0.4.0", "bbe4bf455e2eb2ebd2f1e7d83530ce50fb9990eb88fc47855c515bfdf1c6626f", [:mix], [], "hexpm", "a8ed1683ec8b7c7fa53fd7a41b2c6935f539168a6bb0616d7fd6b58a36f3abf2"},
|
||||
"fast_html": {:hex, :fast_html, "2.0.5", "c61760340606c1077ff1f196f17834056cb1dd3d5cb92a9f2cabf28bc6221c3c", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}], "hexpm", "605f4f4829443c14127694ebabb681778712ceecb4470ec32aa31012330e6506"},
|
||||
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
|
||||
"finch": {:hex, :finch, "0.14.0", "619bfdee18fc135190bf590356c4bf5d5f71f916adb12aec94caa3fa9267a4bc", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5459acaf18c4fdb47a8c22fb3baff5d8173106217c8e56c5ba0b93e66501a8dd"},
|
||||
"floki": {:hex, :floki, "0.34.1", "b1f9c413d91140230788b173906065f6f8906bbbf5b3f0d3c626301aeeef44c5", [:mix], [], "hexpm", "cc9b62312a45c1239ca8f65e05377ef8c646f3d7712e5727a9b47c43c946e885"},
|
||||
"gettext": {:hex, :gettext, "0.22.0", "a25d71ec21b1848957d9207b81fd61cb25161688d282d58bdafef74c2270bdc4", [:mix], [{:expo, "~> 0.3.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "cb0675141576f73720c8e49b4f0fd3f2c69f0cd8c218202724d4aebab8c70ace"},
|
||||
"floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"},
|
||||
"gettext": {:hex, :gettext, "0.22.1", "e7942988383c3d9eed4bdc22fc63e712b655ae94a672a27e4900e3d4a2c43581", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "ad105b8dab668ee3f90c0d3d94ba75e9aead27a62495c101d94f2657a190ac5d"},
|
||||
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
|
||||
"heroicons": {:hex, :heroicons, "0.5.2", "a7ae72460ecc4b74a4ba9e72f0b5ac3c6897ad08968258597da11c2b0b210683", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.2", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}], "hexpm", "7ef96f455c1c136c335f1da0f1d7b12c34002c80a224ad96fc0ebf841a6ffef5"},
|
||||
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
|
||||
@ -34,12 +34,12 @@
|
||||
"nimble_options": {:hex, :nimble_options, "0.5.2", "42703307b924880f8c08d97719da7472673391905f528259915782bb346e0a1b", [:mix], [], "hexpm", "4da7f904b915fd71db549bcdc25f8d56f378ef7ae07dc1d372cbe72ba950dce0"},
|
||||
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
|
||||
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
|
||||
"phoenix": {:hex, :phoenix, "1.7.0-rc.2", "8faaff6f699aad2fe6a003c627da65d0864c868a4c10973ff90abfd7286c1f27", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "71abde2f67330c55b625dcc0e42bf76662dbadc7553c4f545c2f3759f40f7487"},
|
||||
"phoenix": {:hex, :phoenix, "1.7.0", "cbed113bdc203e2ced75859011fe7e71eeebb6259cefa54de810d9c7048b5e22", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "8526139d4bd79ec97c5c3c8e69f6cd663597f782756cec874ba7da5429c93e34"},
|
||||
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "3.3.0", "bf451c71ebdaac8d2f40d3b703435e819ccfbb9ff243140ca3bd10c155f134cc", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "272c5c1533499f0132309936c619186480bafcc2246588f99a69ce85095556ef"},
|
||||
"phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
|
||||
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"},
|
||||
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
|
||||
"phoenix_live_view": {:hex, :phoenix_live_view, "0.18.13", "956aed3ffe24b9ecd5e4bde10fdc9673b77f43adf4d1172a6812abad35dbc94c", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9ecbe76c79102565a14e9fe54aac4b086991dbd5e8da7da4d4d6442f4e79147f"},
|
||||
"phoenix_live_view": {:hex, :phoenix_live_view, "0.18.16", "781c6a3ac49e0451ca403848b40807171caea400896fe8ed8e5ddd6106ad5580", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "09e6ae2babe62f74bfcd1e3cac1a9b0e2c262557cc566300a843425c9cb6842a"},
|
||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
|
||||
"phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
|
||||
"plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"},
|
||||
|
||||
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