M assets/css/_svgs.scss => assets/css/_svgs.scss +6 -1
@@ 13,4 13,9 @@
// icon for to-read links
@function later($color) {
@return inline-svg("<?xml version='1.0' encoding='UTF-8'?><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='#{$color}'><path d='M12,2C6.477,2,2,6.477,2,12c0,5.523,4.477,10,10,10s10-4.477,10-10C22,6.477,17.523,2,12,2z M14.586,16l-3.293-3.293 C11.105,12.519,11,12.265,11,12V7c0-0.552,0.448-1,1-1h0c0.552,0,1,0.448,1,1v4.586l3,3c0.39,0.39,0.39,1.024,0,1.414l0,0 C15.61,16.39,14.976,16.39,14.586,16z'/></svg>")
-}>
\ No newline at end of file
+}
+
+// icon for rss feed
+@function rss($color) {
+ @return inline-svg("<?xml version='1.0' encoding='UTF-8'?><svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256' fill='#{$color}'><circle cx='68' cy='189' r='24'></circle><path d='M160 213h-34a82 82 0 0 0 -82 -82v-34a116 116 0 0 1 116 116z'></path><path d='M184 213A140 140 0 0 0 44 73 V 38a175 175 0 0 1 175 175z'></path></svg>")
+}
M assets/css/app.scss => assets/css/app.scss +39 -5
@@ 365,6 365,7 @@ nav {
& > div.breadcrumbs {
display: inline-flex;
flex-grow: 0;
+ flex-wrap: wrap;
& > a.brand {
color: $foreground;
@@ 546,7 547,37 @@ div#content, div#controls {
content: ", ";
}
}
+ }
+
+ & div.explore {
+ & > ul {
+ align-items: baseline;
+ display: inline-flex;
+ flex-direction: row;
+ font-size: $font-small;
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+
+ & > li {
+ align-items: baseline;
+ display: inline-flex;
+ list-style: none outside none;
+
+ & > a {
+ text-transform: lowercase;
+ }
+
+ &:not(:first-child) {
+ margin-left: $spacing-tiny;
+ }
+ &:not(:first-child)::before {
+ content: "\00B7";
+ margin-right: $spacing-tiny;
+ }
+ }
+ }
}
}
@@ 906,11 937,14 @@ div.pagination {
}
}
-a.feed-link > svg {
- display: inline;
- height: 1.1em;
- vertical-align: bottom;
- width: 1.1em;
+a.feed-link {
+ &::before {
+ content: rss($near-black);
+ display: inline-block;
+ vertical-align: middle;
+ width: $font-normal;
+ margin-right: 0.5 * $spacing-tiny;
+ }
}
details {
M lib/linkhut/links.ex => lib/linkhut/links.ex +42 -1
@@ 204,7 204,11 @@ defmodule Linkhut.Links do
datetime = DateTime.add(DateTime.now!("Etc/UTC"), -days, :day)
links()
- |> join(:inner, [l, _], u in assoc(l, :user))
+ |> join(:inner, [l], u in assoc(l, :user))
+ |> join(:left, [l], latest in subquery(latest()),
+ on: l.url == latest.url and l.inserted_at == latest.inserted_at
+ )
+ |> where([l, _, _, latest], l.url == latest.url and l.inserted_at == latest.inserted_at)
|> where(is_private: false)
|> where(is_unread: false)
|> where([l], l.inserted_at >= ^datetime)
@@ 213,6 217,27 @@ defmodule Linkhut.Links do
end
@doc """
+ Returns the most popular public links
+ """
+ def popular(popularity \\ 3) do
+ links()
+ |> join(:inner, [l, _], u in assoc(l, :user))
+ |> join(:left, [l, _, _], earliest in subquery(earliest()),
+ on: l.url == earliest.url and l.inserted_at == earliest.inserted_at
+ )
+ |> where([l, s], s.savers > 1)
+ |> where([l, _, _, latest], l.url == latest.url and l.inserted_at == latest.inserted_at)
+ |> where(is_private: false)
+ |> where(is_unread: false)
+ |> where(
+ [l, s, _, latest],
+ s.savers > ^popularity and l.url == latest.url and l.inserted_at == latest.inserted_at
+ )
+ |> order_by([l, s, _, _], desc: s.savers, desc: l.inserted_at)
+ |> preload([_, _, u], user: u)
+ end
+
+ @doc """
Returns the unread links for a user
"""
def unread(user_id) do
@@ 254,4 279,20 @@ defmodule Linkhut.Links do
}
)
end
+
+ defp earliest() do
+ Link
+ |> where(is_private: false)
+ |> where(is_unread: false)
+ |> group_by([x], x.url)
+ |> select([x], %{url: x.url, inserted_at: min(x.inserted_at)})
+ end
+
+ defp latest() do
+ Link
+ |> where(is_private: false)
+ |> where(is_unread: false)
+ |> group_by([x], x.url)
+ |> select([x], %{url: x.url, inserted_at: max(x.inserted_at)})
+ end
end
M lib/linkhut/links/link.ex => lib/linkhut/links/link.ex +19 -4
@@ 49,15 49,30 @@ defmodule Linkhut.Links.Link do
defp update_tags(changeset) do
case get_change(changeset, :tags) do
- nil -> changeset
- tags -> if Enum.any?(tags, &Tags.is_unread?/1), do: force_change(changeset, :is_unread, true), else: changeset
+ nil ->
+ changeset
+
+ tags ->
+ if Enum.any?(tags, &Tags.is_unread?/1),
+ do: force_change(changeset, :is_unread, true),
+ else: changeset
end
end
defp dedupe_tags(changeset) do
case get_change(changeset, :tags) do
- nil -> changeset
- tags -> force_change(changeset, :tags, Enum.uniq_by(tags, &(if Tags.is_unread?(&1), do: Tags.unread, else: String.downcase(&1))))
+ nil ->
+ changeset
+
+ tags ->
+ force_change(
+ changeset,
+ :tags,
+ Enum.uniq_by(
+ tags,
+ &if(Tags.is_unread?(&1), do: Tags.unread(), else: String.downcase(&1))
+ )
+ )
end
end
M lib/linkhut_web/controllers/link_controller.ex => lib/linkhut_web/controllers/link_controller.ex +17 -9
@@ 114,7 114,7 @@ defmodule LinkhutWeb.LinkController do
cond do
has_query?(params) -> query(conn, context(params), Map.get(params, "query"), page(params))
has_filters?(params) -> filter(conn, context(params), page(params))
- true -> recent(conn, page(params))
+ true -> explore(conn, view(params), page(params))
end
end
@@ 125,22 125,26 @@ defmodule LinkhutWeb.LinkController do
conn
|> render("index.html",
- links: realize_query(links_query, page),
- tags: Tags.for_query(links_query, limit: @related_tags_limit),
- query: "",
- context: context(params),
- title: :unread
+ links: realize_query(links_query, page),
+ tags: Tags.for_query(links_query, limit: @related_tags_limit),
+ query: "",
+ context: context(params),
+ title: :unread
)
end
- defp recent(conn, page) do
+ defp explore(conn, view, page) do
context =
case conn.assigns[:current_user] do
nil -> %Context{}
current_user -> %Context{visible_as: current_user.username}
end
- links_query = Links.recent()
+ links_query =
+ case view do
+ :recent -> Links.recent()
+ :popular -> Links.popular()
+ end
conn
|> render(:index,
@@ 148,7 152,7 @@ defmodule LinkhutWeb.LinkController do
tags: Tags.for_query(links_query, limit: @related_tags_limit),
query: "",
context: context,
- title: :recent
+ title: view
)
end
@@ 235,4 239,8 @@ defmodule LinkhutWeb.LinkController do
defp page(%{"p" => page}), do: page
defp page(_), do: 1
+
+ defp view(%{"v" => "recent"}), do: :recent
+ defp view(%{"v" => "popular"}), do: :popular
+ defp view(_), do: :recent
end
M lib/linkhut_web/templates/layout/_context.html.heex => lib/linkhut_web/templates/layout/_context.html.heex +1 -1
@@ 24,7 24,7 @@
<ul class="tags">
<%= for tag <- @context.tagged_with do %>
<li><a href={Routes.tags_path(@conn, :show, [tag])}><%= tag %></a></li>
- <% end %>
+ <% end %>
</ul>
<% end %>
<% _ -> %>
M lib/linkhut_web/templates/layout/_session.html.heex => lib/linkhut_web/templates/layout/_session.html.heex +4 -2
@@ 3,12 3,14 @@
<li>
<span>Logged in as <%= link(@current_user.username, to: Routes.user_path(@conn, :show, @current_user.username)) %></span>
<%= if @unread_count > 0 do %>
- <ul class="quicklinks"><li><%= link("Unread", to: Routes.unread_path(@conn, :unread), title: gettext("%{count} unread links", count: @unread_count), data: [count: @unread_count]) %></li></ul>
+ <ul class="quicklinks">
+ <li><%= link("Unread", to: Routes.unread_path(@conn, :unread), title: gettext("%{count} unread links", count: @unread_count), data: [count: @unread_count]) %></li>
+ </ul>
<% end %>
</li>
<li><%= link("Settings", to: Routes.profile_path(@conn, :show)) %></li>
<li>
- <%# Using a form instead of a link, since the route for signing out requires making a DELETE call and we don't want to rely on JS being activated %>
+
<%= form_for :nil, Routes.session_path(@conn, :delete), [method: :delete, itemprop: "signout"], fn _f -> %>
<%= submit("Log out") %>
<% end %>
M lib/linkhut_web/templates/link/_bookmark.html.heex => lib/linkhut_web/templates/link/_bookmark.html.heex +77 -73
@@ 1,83 1,87 @@
<div class="bookmark-card">
-<div class="bookmark">
- <div data-posted-on={@link.inserted_at} data-savers={@link.savers} class="title">
- <h4><a class="taggedlink" href={@link.url}><%= @link.title %></a></h4>
- <%= if @link.is_private do %>
- <span class="no-css-label"><%= gettext("Private") %></span>
- <% end %>
- <%= if @context.url == nil and not (@link.is_private or @link.is_unread) and @link.savers > 1 do %>
- <a class="savers" data-count={@link.savers} data-label={gettext("people")} href={Routes.bookmark_path(@conn, :show, @link.url)}></a>
- <% end %>
- </div>
- <div class="full-url">
- <a rel="nofollow" href={@link.url}><%= @link.url %></a>
- </div>
- <div class="description">
- <%= sanitize(Earmark.as_html!(@link.notes, pure_links: false)) %>
- </div>
- <div class="ownership">
- <%= unless @logged_in? && @link.user_id == @current_user.id do %>
+ <div class="bookmark">
+ <div data-posted-on={@link.inserted_at} data-savers={@link.savers} class="title">
+ <h4><a class="taggedlink" href={@link.url}><%= @link.title %></a></h4>
+ <%= if @link.is_private do %>
+ <span class="no-css-label"><%= gettext("Private") %></span>
+ <% end %>
+ <%= if @context.url == nil and not (@link.is_private or @link.is_unread) and @link.savers > 1 do %>
+ <a class="savers" data-count={@link.savers} data-label={gettext("people")} href={Routes.bookmark_path(@conn, :show, @link.url)}></a>
+ <% end %>
+ </div>
+ <div class="full-url">
+ <a rel="nofollow" href={@link.url}><%= @link.url %></a>
+ </div>
+ <div class="description">
+ <%= sanitize(Earmark.as_html!(@link.notes, pure_links: false)) %>
+ </div>
+ <div class="ownership">
+ <%= unless @logged_in? && @link.user_id == @current_user.id do %>
+ <span>
+ <%= gettext("by") %> <a href={current_path(@conn, username: @link.user.username)}><%= @link.user.username %></a>
+ </span>
+ <% end %>
<span>
- <%= gettext("by") %> <a href={current_path(@conn, username: @link.user.username)}><%= @link.user.username %></a>
- </span>
- <% end %>
- <span>
- <%= Timex.format!(@link.inserted_at, "{relative}", :relative) %>
- </span>
- <%= if @context.url == nil and not (@link.is_private or @link.is_unread) and @link.savers > 1 do %>
- <span class="savers">
- <%= gettext("saved") %> <a href={Routes.bookmark_path(@conn, :show, @link.url)}><%= @link.savers %></a> <%= ngettext("time", "times", @link.savers) %>
+ <%= Timex.format!(@link.inserted_at, "{relative}", :relative) %>
</span>
- <% end %>
- </div>
- <div class="meta">
- <div class="tags">
- <h5 class="label"><%= gettext("Tags:") %></h5>
- <ul class="tags" data-label={gettext("tags")}>
- <%= for tag <- @link.tags do %>
- <li>
- <a href={current_path(@conn, tag: tag)}><%= tag %></a>
- </li>
- <% end %>
- </ul>
+ <%= if @context.url == nil and not (@link.is_private or @link.is_unread) and @link.savers > 1 do %>
+ <span class="savers">
+ <%= gettext("saved") %> <a href={Routes.bookmark_path(@conn, :show, @link.url)}><%= @link.savers %></a> <%= ngettext("time", "times", @link.savers) %>
+ </span>
+ <% end %>
</div>
- <%= if @logged_in? do %>
- <div class="actions">
- <h5 class="label"><%= gettext("Actions:") %></h5>
- <ul class="actions">
- <%= if !assigns[:hide_actions] do %>
- <%= if @link.user_id == @current_user.id do %>
- <li>
- <a href={Routes.link_path(@conn, :edit, url: @link.url)}><%= gettext("edit") %></a>
- </li>
- <li>
- <a href={Routes.link_path(@conn, :delete, url: @link.url)}><%= gettext("delete") %></a>
- </li>
- <%= if @link.is_unread do %>
- <li>
- <%= form_for :mark_as_read, Routes.link_path(@conn, :update), [method: :put], fn _ -> %>
- <%= hidden_input(:link, :url, value: @link.url) %>
- <%= hidden_input(:link, :is_unread, value: false) %>
- <%= submit(gettext("mark as read")) %>
- <% end %>
- </li>
- <% end %>
- <% else %>
- <li>
- <a href={Routes.link_path(@conn, :new, url: @link.url, title: @link.title, notes: @link.notes, tags: @link.tags)}><%= gettext("copy to mine") %></a>
- </li>
- <% end %>
+ <div class="meta">
+ <div class="tags">
+ <h5 class="label"><%= gettext("Tags:") %></h5>
+ <ul class="tags" data-label={gettext("tags")}>
+ <%= for tag <- @link.tags do %>
+ <li>
+ <a href={current_path(@conn, tag: tag)}><%= tag %></a>
+ </li>
<% end %>
</ul>
</div>
- <% end %>
+ <%= if @logged_in? do %>
+ <div class="actions">
+ <h5 class="label"><%= gettext("Actions:") %></h5>
+ <ul class="actions">
+ <%= if !assigns[:hide_actions] do %>
+ <%= if @link.user_id == @current_user.id do %>
+ <li>
+ <a href={Routes.link_path(@conn, :edit, url: @link.url)}><%= gettext("edit") %></a>
+ </li>
+ <li>
+ <a href={Routes.link_path(@conn, :delete, url: @link.url)}><%= gettext("delete") %></a>
+ </li>
+ <%= if @link.is_unread do %>
+ <li>
+ <%= form_for :mark_as_read, Routes.link_path(@conn, :update), [method: :put], fn _ -> %>
+ <%= hidden_input(:link, :url, value: @link.url) %>
+ <%= hidden_input(:link, :is_unread, value: false) %>
+ <%= submit(gettext("mark as read")) %>
+ <% end %>
+ </li>
+ <% end %>
+ <% else %>
+ <li>
+ <a href={Routes.link_path(@conn, :new, url: @link.url, title: @link.title, notes: @link.notes, tags: @link.tags)}><%= gettext("copy to mine") %></a>
+ </li>
+ <% end %>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+ </div>
</div>
-</div>
-<%= if @link.is_private or @link.is_unread do %>
-<div class="icons">
- <%= if @link.is_private do %><span data-icon-type="private" title={gettext("private")}></span><% end %>
- <%= if @link.is_unread do %><span data-icon-type="unread" title={gettext("unread")}></span><% end %>
-</div>
-<% end %>
+ <%= if @link.is_private or @link.is_unread do %>
+ <div class="icons">
+ <%= if @link.is_private do %>
+ <span data-icon-type="private" title={gettext("private")}></span>
+ <% end %>
+ <%= if @link.is_unread do %>
+ <span data-icon-type="unread" title={gettext("unread")}></span>
+ <% end %>
+ </div>
+ <% end %>
</div>
<hr />
M => +42 -43
@@ 5,49 5,48 @@
<span class="no-css-label"><%= gettext("Previous") %></span>
</a>
<% end %>
<% pages = ceil(@page.count/LinkhutWeb.LinkController.links_per_page) %>
<%= cond do %>
<% pages <= 1 -> %>
<%# noop %>
<% pages <= 7 -> %>
<%= for p <- 1..pages do %>
<a class={if p == @page.page, do: "active"} href={current_path(@conn, page: p)}>
<span><%= p %></span>
</a>
<% end %>
<% @page.page <= 3 or @page.page >= (pages-2) -> %>
<%= for p <- 1..3 do %>
<a class={if p == @page.page, do: "active"} href={current_path(@conn, page: p)}>
<span><%= p %></span>
</a>
<% end %>
<span>
<span>…</span>
</span>
<%= for p <- (pages-2)..pages do %>
<a class={if p == @page.page, do: "active"} href={current_path(@conn, page: p)}>
<span><%= p %></span>
</a>
<% end %>
<% true -> %>
<a href={current_path(@conn, page: 1)}>
<span>1</span>
</a>
<span>
<span>…</span>
</span>
<%= for p <- (@page.page-1)..(@page.page+1) do %>
<a class={if p == @page.page, do: "active"} href={current_path(@conn, page: p)}>
<span><%= p %></span>
</a>
<% end %>
<span>
<span>…</span>
</span>
<a href={current_path(@conn, page: pages)}>
<span><%= pages %></span>
</a>
<% end %>
<% pages = ceil(@page.count / LinkhutWeb.LinkController.links_per_page()) %>
<%= cond do %>
<% pages <= 1 -> %>
<% pages <= 7 -> %>
<%= for p <- 1..pages do %>
<a class={if p == @page.page, do: "active"} href={current_path(@conn, page: p)}>
<span><%= p %></span>
</a>
<% end %>
<% @page.page <= 3 or @page.page >= (pages-2) -> %>
<%= for p <- 1..3 do %>
<a class={if p == @page.page, do: "active"} href={current_path(@conn, page: p)}>
<span><%= p %></span>
</a>
<% end %>
<span>
<span>…</span>
</span>
<%= for p <- (pages-2)..pages do %>
<a class={if p == @page.page, do: "active"} href={current_path(@conn, page: p)}>
<span><%= p %></span>
</a>
<% end %>
<% true -> %>
<a href={current_path(@conn, page: 1)}>
<span>1</span>
</a>
<span>
<span>…</span>
</span>
<%= for p <- (@page.page-1)..(@page.page+1) do %>
<a class={if p == @page.page, do: "active"} href={current_path(@conn, page: p)}>
<span><%= p %></span>
</a>
<% end %>
<span>
<span>…</span>
</span>
<a href={current_path(@conn, page: pages)}>
<span><%= pages %></span>
</a>
<% end %>
<%= if @page.has_next do %>
<a href={current_path(@conn, page: @page.next_page)}>
<span class="no-css-label"><%= gettext("Next") %></span>
M lib/linkhut_web/templates/link/_side-pannel.html.heex => lib/linkhut_web/templates/link/_side-pannel.html.heex +11 -9
@@ 7,7 7,7 @@
<% end %>
<%= if length(@tags) > 0 do %>
<section>
- <h5><%= gettext("tags") %></h5>
+ <h5><%= gettext("Tags") %></h5>
<ul class="tag-cloud">
<%= for %{tag: tag, count: count} <- @tags do %>
<li><a href={current_path(@conn, tag: tag)} data-count={count}><%= tag %></a></li>
@@ 16,15 16,17 @@
</section>
<% end %>
<section>
+ <div class="explore">
+ <h5><%= gettext("Explore") %></h5>
+ <ul>
+ <li><a href={Routes.link_path(@conn, :show, v: "recent")}><%= gettext("Recent") %></a></li>
+ <li><a href={Routes.link_path(@conn, :show, v: "popular")}><%= gettext("Popular") %></a></li>
+ </ul>
+ </div>
+ </section>
+ <section>
<h5>
- <a class="feed-link" href={feed_path(@conn)}>
- <svg data-icon="rss-feed" width="16" height="16" viewBox="0 0 256 256">
- <circle cx="68" cy="189" r="24" />
- <path d="M160 213h-34a82 82 0 0 0 -82 -82v-34a116 116 0 0 1 116 116z" />
- <path d="M184 213A140 140 0 0 0 44 73 V 38a175 175 0 0 1 175 175z" />
- </svg>
- <%= gettext("RSS feed") %>
- </a>
+ <a class="feed-link" href={feed_path(@conn)}><%= gettext("RSS feed") %></a>
</h5>
</section>
</aside>
M lib/linkhut_web/templates/link/delete.html.heex => lib/linkhut_web/templates/link/delete.html.heex +1 -1
@@ 11,7 11,7 @@
<%= sanitize(Earmark.as_html!(@link.notes, pure_links: false)) %>
</div>
</div>
- <hr>
+ <hr />
<%= form_for @changeset, Routes.link_path(@conn, :delete), fn f -> %>
<fieldset>
<%= hidden_input(f, :url) %>
M lib/linkhut_web/templates/settings/oauth/authorization/new.html.heex => lib/linkhut_web/templates/settings/oauth/authorization/new.html.heex +1 -2
@@ 5,8 5,7 @@
<strong><%= @client.name %></strong> would like access to your linkhut account.
</p>
<p>
- <strong><%= @client.name %></strong>
- is a third-party application operated by <strong><%= @client.owner.username %></strong>. You may revoke this access at any time.
+ <strong><%= @client.name %></strong> is a third-party application operated by <strong><%= @client.owner.username %></strong>. You may revoke this access at any time.
</p>
They would like permission to access the following resources on your account:
<ul>
M lib/linkhut_web/views/link_view.ex => lib/linkhut_web/views/link_view.ex +25 -6
@@ 31,7 31,11 @@ defmodule LinkhutWeb.LinkView do
def current_path(conn, opts)
def current_path(%Plug.Conn{query_params: params} = conn, username: username) do
- current_path(conn, %Context{Map.drop(context(conn), [:url]) | from: Accounts.get_user(username)}, Map.drop(params, ["p"]))
+ current_path(
+ conn,
+ %Context{Map.drop(context(conn), [:url]) | from: Accounts.get_user(username)},
+ Map.drop(params, ["p"])
+ )
end
def current_path(%Plug.Conn{query_params: params} = conn, url: url) do
@@ 135,20 139,35 @@ defmodule LinkhutWeb.LinkView do
defp title(%Context{} = context) do
case context do
- %{from: user, url: url, tagged_with: tags} when not is_nil(user) and is_binary(url) and tags != [] ->
- LinkhutWeb.Gettext.gettext("Bookmarks for url: %{url} by linkhut user: %{user} tagged with: %{tags}", url: url, tags: Enum.join(tags, ","), user: user.username)
+ %{from: user, url: url, tagged_with: tags}
+ when not is_nil(user) and is_binary(url) and tags != [] ->
+ LinkhutWeb.Gettext.gettext(
+ "Bookmarks for url: %{url} by linkhut user: %{user} tagged with: %{tags}",
+ url: url,
+ tags: Enum.join(tags, ","),
+ user: user.username
+ )
%{from: user, url: url} when not is_nil(user) and is_binary(url) ->
- LinkhutWeb.Gettext.gettext("Bookmarks for url: %{url} by linkhut user: %{user}", url: url, user: user.username)
+ LinkhutWeb.Gettext.gettext("Bookmarks for url: %{url} by linkhut user: %{user}",
+ url: url,
+ user: user.username
+ )
%{url: url, tagged_with: tags} when is_binary(url) and tags != [] ->
- LinkhutWeb.Gettext.gettext("Bookmarks for url: %{url} tagged with: %{tags}", url: url, tags: Enum.join(tags, ","))
+ LinkhutWeb.Gettext.gettext("Bookmarks for url: %{url} tagged with: %{tags}",
+ url: url,
+ tags: Enum.join(tags, ",")
+ )
%{url: url} when is_binary(url) ->
LinkhutWeb.Gettext.gettext("Bookmarks for url: %{url}", url: url)
%{from: user, tagged_with: tags} when not is_nil(user) and tags != [] ->
- LinkhutWeb.Gettext.gettext("Bookmarks by linkhut user: %{user} tagged with: %{tags}", tags: Enum.join(tags, ","), user: user.username)
+ LinkhutWeb.Gettext.gettext("Bookmarks by linkhut user: %{user} tagged with: %{tags}",
+ tags: Enum.join(tags, ","),
+ user: user.username
+ )
%{from: user} when not is_nil(user) ->
LinkhutWeb.Gettext.gettext("Bookmarks by linkhut user: %{user}", user: user.username)
M priv/repo/migrations/20221214091713_add_is_unread_to_links.exs => priv/repo/migrations/20221214091713_add_is_unread_to_links.exs +8 -4
@@ 9,14 9,18 @@ defmodule Linkhut.Repo.Migrations.AddIsUnreadToLinks do
create index(:links, [:is_unread])
- if (direction() == :up) do
+ if direction() == :up do
flush()
execute(&execute_up/0)
end
end
-
- defp execute_up, do: from(l in Linkhut.Links.Link, where: fragment("lower(tags::text)::text[] && ARRAY['unread','toread']"), update: [set: [is_unread: true]]) |> Linkhut.Repo.update_all([])
-
+ defp execute_up do
+ from(l in Linkhut.Links.Link,
+ where: fragment("lower(tags::text)::text[] && ARRAY['unread','toread']"),
+ update: [set: [is_unread: true]]
+ )
+ |> Linkhut.Repo.update_all([])
+ end
end