• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mirego / accent / #842

26 Mar 2026 07:49PM UTC coverage: 76.377% (+0.07%) from 76.303%
#842

push

github

simonprev
v1.29.0

2454 of 3213 relevant lines covered (76.38%)

22.79 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.72
/lib/web/controllers/export_controller.ex
1
defmodule Accent.ExportController do
2
  use Plug.Builder
3

4
  import Canary.Plugs
5

6
  alias Accent.Document
7
  alias Accent.Project
8
  alias Accent.Repo
9
  alias Accent.Scopes.Document, as: DocumentScope
10
  alias Accent.Scopes.Revision, as: RevisionScope
11
  alias Accent.Scopes.Translation, as: Scope
12
  alias Accent.Scopes.Version, as: VersionScope
13
  alias Accent.Translation
14
  alias Accent.Version
15

16
  plug(Plug.Assign, %{canary_action: :export_revision})
17
  plug(:load_and_authorize_resource, model: Project, id_name: "project_id")
18
  plug(Accent.Plugs.AssignRevisionLanguage)
19

20
  plug(:fetch_order)
21
  plug(:fetch_document)
22
  plug(:fetch_version)
23
  plug(:fetch_translations)
24
  plug(:fetch_master_revision)
25
  plug(:fetch_master_translations)
26
  plug(:fetch_rendered_document)
27

28
  plug(:index)
29

30
  @doc """
31
  Export a revision to a file
32

33
  ## Endpoint
34

35
    GET /export
36

37
  ### Required params
38
    - `project_id`
39
    - `language`
40
    - `document_format`
41
    - `document_path`
42

43
  ### Optional params
44
    - `order_by`
45
    - `inline_render`
46
    - `version`
47
    - `filters`
48

49
  ### Response
50

51
    #### Success
52
    `200` - A file containing the rendered document.
53

54
    #### Error
55
    - `404` Unknown revision id.
56
  """
57
  def index(%{query_params: %{"inline_render" => "true"}} = conn, _) do
58
    :telemetry.execute([:accent, :export], %{count: 1}, %{
1✔
59
      format: conn.assigns[:document] && conn.assigns[:document].format
1✔
60
    })
61

62
    conn
63
    |> put_resp_header("content-type", "text/plain")
64
    |> send_resp(:ok, conn.assigns[:document].render)
1✔
65
  end
66

67
  def index(conn, _) do
68
    :telemetry.execute([:accent, :export], %{count: 1}, %{
9✔
69
      format: conn.assigns[:document] && conn.assigns[:document].format
9✔
70
    })
71

72
    file = Path.join([System.tmp_dir(), Accent.Utils.SecureRandom.urlsafe_base64(16)])
9✔
73

74
    :ok = File.write(file, conn.assigns[:document].render)
9✔
75

76
    conn
77
    |> put_resp_header("content-disposition", "inline; filename=\"#{conn.params["document_path"]}\"")
9✔
78
    |> send_file(:ok, file)
9✔
79
  end
80

81
  defp fetch_order(%{params: %{"order_by" => ""}} = conn, _), do: assign(conn, :order, "index")
3✔
82
  defp fetch_order(%{params: %{"order_by" => order}} = conn, _), do: assign(conn, :order, order)
2✔
83
  defp fetch_order(conn, _), do: assign(conn, :order, "index")
7✔
84

85
  defp fetch_translations(
86
         %{assigns: %{document: document, order: order, revision: revision, version: version}} = conn,
87
         _
88
       ) do
89
    filters = parse_filters(conn.params["filters"])
10✔
90

91
    translations =
10✔
92
      Translation
93
      |> Scope.active()
94
      |> Scope.from_document((document && document.id) || :all)
10✔
95
      |> Scope.from_revision(revision.id)
10✔
96
      |> Scope.from_version(version && version.id)
10✔
97
      |> Scope.parse_order(order)
98
      |> Scope.parse_conflicted(filters[:is_conflicted])
99
      |> Scope.parse_added_last_sync(filters[:is_added_last_sync], revision.project_id, document && document.id)
10✔
100
      |> Scope.parse_empty(filters[:is_text_empty])
101
      |> Repo.all()
102
      |> Translation.maybe_natural_order_by(order)
103

104
    assign(conn, :translations, translations)
10✔
105
  end
106

107
  defp parse_filters(filters) when is_map(filters) do
108
    %{
×
109
      is_text_empty: if(filters["is_text_empty"] === "true", do: true),
×
110
      is_conflicted: if(filters["is_conflicted"] === "true", do: true),
×
111
      is_added_last_sync: if(filters["is_added_last_sync"] === "true", do: true)
×
112
    }
113
  end
114

115
  defp parse_filters(_), do: %{}
10✔
116

117
  defp fetch_master_revision(%{assigns: %{project: project}} = conn, _) do
118
    revision =
10✔
119
      project
120
      |> Ecto.assoc(:revisions)
121
      |> RevisionScope.master()
122
      |> Repo.one()
123
      |> Repo.preload(:language)
124

125
    assign(conn, :master_revision, revision)
10✔
126
  end
127

128
  defp fetch_master_translations(%{assigns: %{revision: %{master: true}, translations: translations}} = conn, _) do
129
    assign(conn, :master_translations, translations)
10✔
130
  end
131

132
  defp fetch_master_translations(
133
         %{assigns: %{document: document, version: version, master_revision: master_revision}} = conn,
134
         _
135
       ) do
136
    translations =
×
137
      Translation
138
      |> Scope.active()
139
      |> Scope.from_document((document && document.id) || :all)
×
140
      |> Scope.from_revision(master_revision.id)
×
141
      |> Scope.from_version(version && version.id)
×
142
      |> Repo.all()
143

144
    assign(conn, :master_translations, translations)
×
145
  end
146

147
  defp fetch_document(%{params: %{"document_path" => path} = params, assigns: %{project: project}} = conn, _) do
148
    Document
149
    |> DocumentScope.from_project(project.id)
12✔
150
    |> DocumentScope.from_path(path)
151
    |> Repo.one()
152
    |> case do
12✔
153
      document = %Document{} ->
154
        document = Map.put(document, :format, params["document_format"])
11✔
155
        assign(conn, :document, document)
11✔
156

157
      _ ->
158
        Accent.ErrorController.handle_not_found(conn)
1✔
159
    end
160
  end
161

162
  defp fetch_document(conn, _) do
163
    assign(conn, :document, nil)
×
164
  end
165

166
  defp fetch_version(%{params: %{"version" => version_param}, assigns: %{project: project}} = conn, _) do
167
    Version
168
    |> VersionScope.from_project(project.id)
2✔
169
    |> VersionScope.from_tag(version_param)
170
    |> Repo.one()
171
    |> case do
2✔
172
      version = %Version{} ->
173
        assign(conn, :version, version)
1✔
174

175
      _ ->
176
        Accent.ErrorController.handle_not_found(conn)
1✔
177
    end
178
  end
179

180
  defp fetch_version(conn, _), do: assign(conn, :version, nil)
9✔
181

182
  defp fetch_rendered_document(
183
         %{
184
           assigns: %{
185
             master_revision: master_revision,
186
             master_translations: master_translations,
187
             translations: translations,
188
             revision: revision,
189
             document: document
190
           }
191
         } = conn,
192
         _
193
       ) do
194
    document = document || %Document{format: conn.params["document_format"]}
10✔
195

196
    %{render: render} =
10✔
197
      Accent.TranslationsRenderer.render_translations(%{
198
        master_translations: master_translations,
199
        translations: translations,
200
        master_language: Accent.Revision.language(master_revision),
201
        language: Accent.Revision.language(revision),
202
        document: document
203
      })
204

205
    document = Map.put(document, :render, render)
10✔
206

207
    assign(conn, :document, document)
10✔
208
  end
209
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc