Current section

37 Versions

Jump to

Compare versions

32 files changed
+612 additions
-294 deletions
  @@ -64,9 +64,9 @@
64 64 <tr><td><h4>Caveats</h4></td></tr>
65 65 <tr>
66 66 <td>
67 - Thesis is currently considered <em>Alpha-quality</em>, but is in production on several
68 - websites, including <a href="https://infinite.red">Infinite Red</a>. The API is unstable and
69 - changing but we are committed to providing a clear upgrade path and documentation.
67 + Thesis is currently considered <em>Beta-quality</em>, but is in production on several
68 + websites, including <a href="https://infinite.red">Infinite Red</a>. The API is
69 + largely stable and we are committed to providing a clear upgrade path and documentation.
70 70 </td>
71 71 </tr>
72 72 </table>
  @@ -83,7 +83,7 @@
83 83
84 84 ```elixir
85 85 def deps do
86 - [{:thesis, "~> 0.0.30"}]
86 + [{:thesis, "~> 0.1.0"}]
87 87 end
88 88
89 89 def application do
  @@ -150,6 +150,30 @@ becomes...
150 150 </p>
151 151 <% end %>
152 152 ```
153 +
154 + ### Custom HTML Editor
155 + Don't like the MediumEditor? Write your own custom editor implementing the common editor interface.
156 +
157 + ```
158 + class MyCustomEditor {
159 + constructor (opts) {
160 + this.onChange = opts.onChange
161 + }
162 + enable () {} // Setup Editor
163 + disable () {} // Teardown Editor
164 + content (editor) {} // Return content
165 + set (name, data) {} // Set content
166 + }
167 + ```
168 +
169 + For more detail checkout [HtmlEditor](web/static/js/content_types/html_editor.js) or [this gist](https://gist.github.com/ryanlntn/ac346d361d9e10a8f1888bf59cea0e37) implementing a custom editor using [Trumbowyg](https://alex-d.github.io/Trumbowyg/).
170 +
171 + To enable, add this in your config/config.exs file:
172 +
173 + ```elixir
174 + config :thesis,
175 + html_editor: "MyCustomEditor"
176 + ```
153 177 <br/>
154 178
155 179 ---
  @@ -458,7 +482,7 @@ websites. Please help us improve!
458 482 1. Fork it
459 483 2. Create your feature branch (`git checkout -b my-new-feature`)
460 484 3. Commit your changes (`git commit -am 'Add some feature'`)
461 - 4. Run `brunch watch -p` during development
485 + 4. Run `npm run webpack` during development
462 486 5. Use the `apps/example` Phoenix app to manually test your feature
463 487 6. Write tests for your new feature
464 488 7. Run `./bin/ci` in the root directory to ensure that Thesis tests pass.
  @@ -6,7 +6,7 @@ For automatic setup, see `README.md`.
6 6
7 7 ```elixir
8 8 def deps do
9 - [{:thesis, "~> 0.0.30"}]
9 + [{:thesis, "~> 0.1.0"}]
10 10 end
11 11
12 12 def application do
  @@ -2,15 +2,16 @@
2 2 {<<"build_tools">>,[<<"mix">>]}.
3 3 {<<"description">>,
4 4 <<"Thesis is a lightweight bolt-on content editing system\nfor Phoenix websites.">>}.
5 - {<<"elixir">>,<<"~> 1.2">>}.
5 + {<<"elixir">>,<<">= 1.4.0">>}.
6 6 {<<"files">>,
7 7 [<<"lib/mix/tasks/thesis.install.ex">>,<<"lib/mix/utils.ex">>,
8 8 <<"lib/thesis.ex">>,<<"lib/thesis/api_controller.ex">>,
9 9 <<"lib/thesis/auth.ex">>,<<"lib/thesis/config.ex">>,
10 - <<"lib/thesis/controller.ex">>,<<"lib/thesis/models/file.ex">>,
11 - <<"lib/thesis/models/page.ex">>,<<"lib/thesis/models/page_content.ex">>,
12 - <<"lib/thesis/render.ex">>,<<"lib/thesis/router.ex">>,
13 - <<"lib/thesis/stores/ecto_store.ex">>,<<"lib/thesis/stores/store.ex">>,
10 + <<"lib/thesis/controller.ex">>,<<"lib/thesis/models/backup.ex">>,
11 + <<"lib/thesis/models/file.ex">>,<<"lib/thesis/models/page.ex">>,
12 + <<"lib/thesis/models/page_content.ex">>,<<"lib/thesis/render.ex">>,
13 + <<"lib/thesis/router.ex">>,<<"lib/thesis/stores/ecto_store.ex">>,
14 + <<"lib/thesis/stores/store.ex">>,
14 15 <<"lib/thesis/uploaders/repo_uploader.ex">>,
15 16 <<"lib/thesis/uploaders/s3_uploader.ex">>,
16 17 <<"lib/thesis/uploaders/uploader.ex">>,<<"lib/thesis/utilities.ex">>,
  @@ -20,6 +21,7 @@
20 21 <<"priv/templates/thesis.install/add_meta_to_thesis_page_contents.exs">>,
21 22 <<"priv/templates/thesis.install/add_template_and_redirect_url_to_thesis_pages.exs">>,
22 23 <<"priv/templates/thesis.install/change_content_default_for_page_content.exs">>,
24 + <<"priv/templates/thesis.install/create_thesis_backups_table.exs">>,
23 25 <<"priv/templates/thesis.install/create_thesis_files_table.exs">>,
24 26 <<"priv/templates/thesis.install/create_thesis_tables.exs">>,
25 27 <<"priv/templates/thesis.install/thesis_auth.exs">>,
  @@ -124,8 +126,8 @@
124 126 <<"web/static/js/components/cancel_button.js">>,
125 127 <<"web/static/js/components/delete_button.js">>,
126 128 <<"web/static/js/components/edit_button.js">>,
127 - <<"web/static/js/components/import_export_button.js">>,
128 - <<"web/static/js/components/import_export_tray.js">>,
129 + <<"web/static/js/components/import_export_restore_button.js">>,
130 + <<"web/static/js/components/import_export_restore_tray.js">>,
129 131 <<"web/static/js/components/save_button.js">>,
130 132 <<"web/static/js/components/settings_button.js">>,
131 133 <<"web/static/js/components/settings_tray.js">>,
  @@ -142,39 +144,51 @@
142 144 <<"README_INSTALL.md">>,<<"LICENSE.md">>,<<"package.json">>]}.
143 145 {<<"licenses">>,[<<"MIT">>]}.
144 146 {<<"links">>,
145 - [{<<"Docs">>,<<"https://hexdocs.pm/thesis/0.0.30/api-reference.html">>},
147 + [{<<"Docs">>,<<"https://hexdocs.pm/thesis/0.1.0/api-reference.html">>},
146 148 {<<"GitHub">>,<<"https://github.com/infinitered/thesis-phoenix">>}]}.
147 149 {<<"maintainers">>,
148 150 [<<"Jamon Holmgren">>,<<"Yulian Glukhenko">>,<<"Ken Miller">>,
149 151 <<"Daniel Berkompas">>]}.
150 152 {<<"name">>,<<"thesis">>}.
151 153 {<<"requirements">>,
152 - [[{<<"app">>,<<"phoenix">>},
153 - {<<"name">>,<<"phoenix">>},
154 + [[{<<"app">>,<<"lz_string">>},
155 + {<<"name">>,<<"lz_string">>},
154 156 {<<"optional">>,false},
155 - {<<"requirement">>,<<">= 1.0.0">>}],
156 - [{<<"app">>,<<"phoenix_html">>},
157 - {<<"name">>,<<"phoenix_html">>},
158 - {<<"optional">>,false},
159 - {<<"requirement">>,<<">= 2.0.0">>}],
160 - [{<<"app">>,<<"ecto">>},
161 - {<<"name">>,<<"ecto">>},
162 - {<<"optional">>,false},
163 - {<<"requirement">>,<<">= 2.0.0">>}],
164 - [{<<"app">>,<<"plug">>},
165 - {<<"name">>,<<"plug">>},
166 - {<<"optional">>,false},
167 - {<<"requirement">>,<<">= 1.0.0">>}],
157 + {<<"repository">>,<<"hexpm">>},
158 + {<<"requirement">>,<<"~> 0.0.7">>}],
168 159 [{<<"app">>,<<"poison">>},
169 160 {<<"name">>,<<"poison">>},
170 161 {<<"optional">>,false},
162 + {<<"repository">>,<<"hexpm">>},
171 163 {<<"requirement">>,<<">= 1.0.0">>}],
172 164 [{<<"app">>,<<"httpoison">>},
173 165 {<<"name">>,<<"httpoison">>},
174 166 {<<"optional">>,false},
167 + {<<"repository">>,<<"hexpm">>},
175 168 {<<"requirement">>,<<"~> 0.11.0">>}],
169 + [{<<"app">>,<<"ecto">>},
170 + {<<"name">>,<<"ecto">>},
171 + {<<"optional">>,false},
172 + {<<"repository">>,<<"hexpm">>},
173 + {<<"requirement">>,<<">= 2.0.0">>}],
176 174 [{<<"app">>,<<"html_sanitize_ex">>},
177 175 {<<"name">>,<<"html_sanitize_ex">>},
178 176 {<<"optional">>,false},
179 - {<<"requirement">>,<<">= 1.0.1">>}]]}.
180 - {<<"version">>,<<"0.0.30">>}.
177 + {<<"repository">>,<<"hexpm">>},
178 + {<<"requirement">>,<<">= 1.3.0">>}],
179 + [{<<"app">>,<<"plug">>},
180 + {<<"name">>,<<"plug">>},
181 + {<<"optional">>,false},
182 + {<<"repository">>,<<"hexpm">>},
183 + {<<"requirement">>,<<">= 1.0.0">>}],
184 + [{<<"app">>,<<"phoenix_html">>},
185 + {<<"name">>,<<"phoenix_html">>},
186 + {<<"optional">>,false},
187 + {<<"repository">>,<<"hexpm">>},
188 + {<<"requirement">>,<<">= 2.0.0">>}],
189 + [{<<"app">>,<<"phoenix">>},
190 + {<<"name">>,<<"phoenix">>},
191 + {<<"optional">>,false},
192 + {<<"repository">>,<<"hexpm">>},
193 + {<<"requirement">>,<<">= 1.2.0">>}]]}.
194 + {<<"version">>,<<"0.1.0">>}.
  @@ -8,7 +8,8 @@ defmodule Mix.Tasks.Thesis.Install do
8 8 "add_indexes_to_tables",
9 9 "add_template_and_redirect_url_to_thesis_pages",
10 10 "change_content_default_for_page_content",
11 - "create_thesis_files_table"
11 + "create_thesis_files_table",
12 + "create_thesis_backups_table"
12 13 ]
13 14 @template_files [
14 15 {"priv/templates/thesis.install/thesis_auth.exs", "lib/thesis_auth.ex"}
  @@ -30,9 +31,9 @@ defmodule Mix.Tasks.Thesis.Install do
30 31
31 32 @doc false
32 33 def run(_args) do
33 - thesis_templates
34 - thesis_config
35 - thesis_web
34 + thesis_templates()
35 + thesis_config()
36 + thesis_web()
36 37
37 38 status_msg("done",
38 39 "Now run #{IO.ANSI.blue}mix ecto.migrate#{IO.ANSI.reset} to ensure your database is up to date.")
  @@ -58,7 +59,7 @@ defmodule Mix.Tasks.Thesis.Install do
58 59 dest_file_path = Path.join [File.cwd! | ~w(config config.exs)]
59 60 dest_file_path
60 61 |> File.read!()
61 - |> insert_thesis
62 + |> insert_thesis()
62 63 |> overwrite_file(dest_file_path)
63 64 end
64 65
  @@ -128,7 +129,7 @@ defmodule Mix.Tasks.Thesis.Install do
128 129 end
129 130
130 131 defp migration_tuple({filename, i}) do
131 - ts = String.to_integer(timestamp) + i
132 + ts = String.to_integer(timestamp()) + i
132 133 {"priv/templates/thesis.install/#{filename}.exs", "priv/repo/migrations/#{ts}_#{filename}.exs"}
133 134 end
134 135 end
  @@ -3,22 +3,43 @@ defmodule Thesis.ApiController do
3 3
4 4 use Phoenix.Controller
5 5 import Thesis.Config
6 - alias Thesis.Utilities
6 + alias Thesis.{Utilities, Backup}
7 7
8 8 plug :ensure_authorized! when not action in [:show_file]
9 9
10 10 def assets(conn, _params), do: conn
11 11
12 12 def update(conn, %{"contents" => contents, "page" => page}) do
13 - :ok = store.update(page, contents)
13 + {:ok, _page} = store().update(page, contents)
14 14 json conn, %{}
15 15 end
16 16
17 17 def delete(conn, %{"path" => path}) do
18 - :ok = store.delete(%{"slug" => path})
18 + {:ok, _page} = store().delete(%{"slug" => path})
19 19 json conn, %{}
20 20 end
21 21
22 + def backups_for_page(conn, %{"page_slug" => page_slug}) do
23 + backups =
24 + page_slug
25 + |> store().backups()
26 + |> Enum.map(&Backup.with_pretty_datetime/1)
27 + |> Enum.map(fn b ->
28 + %{
29 + id: b.id,
30 + page_revision: b.page_revision,
31 + inserted_at: b.inserted_at,
32 + pretty_date: b.pretty_date
33 + } end
34 + )
35 + json conn, backups
36 + end
37 +
38 + def restore(conn, %{"backup_id" => backup_id}) do
39 + backup = store().restore(String.to_integer(backup_id))
40 + json conn, %{revision: backup.page_json}
41 + end
42 +
22 43 def import_file(conn, %{"image_url" => ""}), do: json conn, %{path: ""}
23 44 def import_file(conn, %{"image_url" => image_url}) do
24 45 image = HTTPoison.get!(image_url)
  @@ -37,12 +58,12 @@ defmodule Thesis.ApiController do
37 58 def upload_file(conn, _), do: json conn, %{path: ""}
38 59
39 60 def show_file(conn, %{"slug" => slug}) do
40 - file = store.file(slug)
61 + file = store().file(slug)
41 62 do_show_file(conn, file)
42 63 end
43 64
44 65 defp do_upload_file(conn, file) do
45 - case uploader.upload(file) do
66 + case uploader().upload(file) do
46 67 {:ok, path} -> json conn, %{path: path}
47 68 {:error, _} -> json conn, %{path: ""}
48 69 end
  @@ -61,7 +82,7 @@ defmodule Thesis.ApiController do
61 82 end
62 83
63 84 defp ensure_authorized!(conn, _params) do
64 - if auth.page_is_editable?(conn), do: conn, else: put_unauthorized(conn)
85 + if auth().page_is_editable?(conn), do: conn, else: put_unauthorized(conn)
65 86 end
66 87
67 88 defp put_unauthorized(conn) do
  @@ -69,4 +90,6 @@ defmodule Thesis.ApiController do
69 90 |> put_status(:unauthorized)
70 91 |> halt
71 92 end
93 +
94 +
72 95 end
Loading more files…