Current section
14 Versions
Jump to
Current section
14 Versions
Compare versions
5
files changed
+94
additions
-5
deletions
| @@ -2,6 +2,13 @@ | |
| 2 2 | |
| 3 3 | ## Unreleased |
| 4 4 | |
| 5 | + ## v0.6.0 |
| 6 | + |
| 7 | + ### `Combo.Conn` |
| 8 | + |
| 9 | + - add `put_previous_url/2`, `get_previous_url/1` for URL tracking |
| 10 | + - add `redirect_back/2` |
| 11 | + |
| 5 12 | ## v0.5.0 |
| 6 13 | |
| 7 14 | ### `Combo` |
| @@ -1,9 +1,9 @@ | |
| 1 1 | {<<"links">>, |
| 2 2 | [{<<"Source">>,<<"https://github.com/combo-lab/combo">>}, |
| 3 3 | {<<"Changelog">>, |
| 4 | - <<"https://github.com/combo-lab/combo/blob/v0.5.1/CHANGELOG.md">>}]}. |
| 4 | + <<"https://github.com/combo-lab/combo/blob/v0.6.0/CHANGELOG.md">>}]}. |
| 5 5 | {<<"name">>,<<"combo">>}. |
| 6 | - {<<"version">>,<<"0.5.1">>}. |
| 6 | + {<<"version">>,<<"0.6.0">>}. |
| 7 7 | {<<"description">>, |
| 8 8 | <<"A web framework, that combines the good parts of modern web development.">>}. |
| 9 9 | {<<"elixir">>,<<"~> 1.18">>}. |
| @@ -11,8 +11,8 @@ defmodule Combo.Conn do | |
| 11 11 | put_private: 3, |
| 12 12 | get_session: 2, |
| 13 13 | put_session: 3, |
| 14 | - get_req_header: 2, |
| 15 14 | delete_session: 2, |
| 15 | + get_req_header: 2, |
| 16 16 | get_resp_header: 2, |
| 17 17 | put_resp_header: 3, |
| 18 18 | merge_resp_headers: 2, |
| @@ -662,6 +662,53 @@ defmodule Combo.Conn do | |
| 662 662 | raise ArgumentError, "the :to option in redirect expects a path but was #{inspect(url)}" |
| 663 663 | end |
| 664 664 | |
| 665 | + @doc """ |
| 666 | + Sends redirect response to the previous location. |
| 667 | + |
| 668 | + It attempts to use path from the following sources in sequence: |
| 669 | + |
| 670 | + 1. the path retrieved from "Referer" request header |
| 671 | + 2. the path retrieved by `get_previous_url/1`. To make it work, you need |
| 672 | + to add `put_previous_url/2` to the pipeline first. |
| 673 | + 3. the path retrieved from `:fallback` option |
| 674 | + 4. the root path |
| 675 | + |
| 676 | + ## Examples |
| 677 | + |
| 678 | + iex> redirect_back(conn) |
| 679 | + |
| 680 | + iex> redirect_back(conn, fallback: ~p"/users") |
| 681 | + |
| 682 | + """ |
| 683 | + def redirect_back(conn, opts \\ []) do |
| 684 | + referrer = |
| 685 | + case get_req_header(conn, "referer") do |
| 686 | + [value] -> value |
| 687 | + _ -> nil |
| 688 | + end |
| 689 | + |
| 690 | + url = |
| 691 | + referrer || |
| 692 | + get_previous_url(conn) || |
| 693 | + Keyword.get(opts, :fallback) || |
| 694 | + root_url(conn) |
| 695 | + |
| 696 | + path = extract_path(url) |
| 697 | + redirect(conn, to: path) |
| 698 | + end |
| 699 | + |
| 700 | + defp root_url(conn) do |
| 701 | + endpoint = endpoint_module!(conn) |
| 702 | + endpoint.url() <> endpoint.path("/") |
| 703 | + end |
| 704 | + |
| 705 | + defp extract_path(url) do |
| 706 | + case URI.parse(url) do |
| 707 | + %URI{path: path, query: nil} -> path |
| 708 | + %URI{path: path, query: query} -> path <> "?" <> query |
| 709 | + end |
| 710 | + end |
| 711 | + |
| 665 712 | @doc """ |
| 666 713 | Sends the given file or binary as a download. |
| 667 714 | |
| @@ -789,6 +836,11 @@ defmodule Combo.Conn do | |
| 789 836 | end |
| 790 837 | end |
| 791 838 | |
| 839 | + defp prefetch?(conn) do |
| 840 | + "prefetch" in get_req_header(conn, "purpose") || |
| 841 | + "prefetch" in get_req_header(conn, "sec-purpose") |
| 842 | + end |
| 843 | + |
| 792 844 | @doc """ |
| 793 845 | Sends JSON response. |
| 794 846 | |
| @@ -1267,6 +1319,36 @@ defmodule Combo.Conn do | |
| 1267 1319 | %{conn | resp_headers: resp_headers} |
| 1268 1320 | end |
| 1269 1321 | |
| 1322 | + ## URL tracking |
| 1323 | + |
| 1324 | + @doc """ |
| 1325 | + Puts current url to the session before sending the response, and it will be |
| 1326 | + available as previous url for subsequence requests. |
| 1327 | + |
| 1328 | + In general, it's added to the pipeline for browser. |
| 1329 | + """ |
| 1330 | + def put_previous_url(conn, _opts) do |
| 1331 | + register_before_send(conn, &put_previous_url/1) |
| 1332 | + end |
| 1333 | + |
| 1334 | + defp put_previous_url(conn) do |
| 1335 | + if conn.method == "GET" && |
| 1336 | + conn.status in 200..299 && |
| 1337 | + !ajax?(conn) && |
| 1338 | + !prefetch?(conn) do |
| 1339 | + put_session(conn, :_previous_url, current_url(conn)) |
| 1340 | + else |
| 1341 | + conn |
| 1342 | + end |
| 1343 | + end |
| 1344 | + |
| 1345 | + @doc """ |
| 1346 | + Gets previous url. |
| 1347 | + """ |
| 1348 | + def get_previous_url(conn) do |
| 1349 | + get_session(conn, :_previous_url) |
| 1350 | + end |
| 1351 | + |
| 1270 1352 | ## URL generation |
| 1271 1353 | |
| 1272 1354 | @doc """ |
| @@ -1,7 +1,7 @@ | |
| 1 1 | defmodule Combo.MixProject do |
| 2 2 | use Mix.Project |
| 3 3 | |
| 4 | - @version "0.5.1" |
| 4 | + @version "0.6.0" |
| 5 5 | @description "A web framework, that combines the good parts of modern web development." |
| 6 6 | @elixir_requirement "~> 1.18" |
| 7 7 | @source_url "https://github.com/combo-lab/combo" |
| @@ -1,6 +1,6 @@ | |
| 1 1 | { |
| 2 2 | "name": "combo", |
| 3 | - "version": "0.5.1", |
| 3 | + "version": "0.6.0", |
| 4 4 | "description": "The JavaScript parts of Combo", |
| 5 5 | "type": "module", |
| 6 6 | "scripts": { |