elastix and elasticsearch binding

This commit is contained in:
byte[] 2019-08-18 21:43:06 -04:00
parent 962c681c8e
commit aee3bbccc4
20 changed files with 585 additions and 19 deletions

View file

@ -9,6 +9,7 @@ use Mix.Config
config :philomena, config :philomena,
ecto_repos: [Philomena.Repo], ecto_repos: [Philomena.Repo],
elasticsearch_url: "http://localhost:9200",
password_pepper: "dn2e0EpZrvBLoxUM3gfQveBhjf0bG/6/bYhrOyq3L3hV9hdo/bimJ+irbDWsuXLP", password_pepper: "dn2e0EpZrvBLoxUM3gfQveBhjf0bG/6/bYhrOyq3L3hV9hdo/bimJ+irbDWsuXLP",
image_url_root: "/img" image_url_root: "/img"
@ -21,6 +22,9 @@ config :philomena, :pow,
config :bcrypt_elixir, config :bcrypt_elixir,
log_rounds: 12 log_rounds: 12
config :elastix,
json_codec: Jason
# Configures the endpoint # Configures the endpoint
config :philomena, PhilomenaWeb.Endpoint, config :philomena, PhilomenaWeb.Endpoint,
url: [host: "localhost"], url: [host: "localhost"],

View file

@ -3,7 +3,6 @@ defmodule Philomena.Comments.Comment do
import Ecto.Changeset import Ecto.Changeset
schema "comments" do schema "comments" do
timestamps() timestamps()
end end

View file

@ -0,0 +1,99 @@
defmodule Philomena.Elasticsearch do
defmacro __using__(opts) do
definition = Keyword.fetch!(opts, :definition)
index_name = Keyword.fetch!(opts, :index_name)
elastic_url = Application.get_env(:philomena, :elasticsearch_url)
quote do
alias Philomena.Repo
import Ecto.Query, warn: false
def create_index! do
Elastix.Index.create(
unquote(elastic_url),
unquote(index_name),
unquote(definition).mapping()
)
end
def delete_index! do
Elastix.Index.delete(unquote(elastic_url), unquote(index_name))
end
def index_document(doc) do
data = unquote(definition).as_json(doc)
Elastix.Document.index(unquote(elastic_url), unquote(index_name), ["_doc"], data.id, data)
end
def reindex(ecto_query, batch_size \\ 1000) do
ids =
ecto_query
|> exclude(:preload)
|> exclude(:order_by)
|> order_by(asc: :id)
|> select([m], m.id)
|> limit(^batch_size)
|> Repo.all()
reindex(ecto_query, batch_size, ids)
end
def reindex(ecto_query, batch_size, []), do: nil
def reindex(ecto_query, batch_size, ids) do
lines =
ecto_query
|> where([m], m.id in ^ids)
|> Repo.all()
|> Enum.flat_map(fn m ->
doc = unquote(definition).as_json(m)
[
%{index: %{_index: unquote(index_name), _type: "_doc", _id: doc.id}},
doc
]
end)
Elastix.Bulk.post(unquote(elastic_url), lines,
index: unquote(index_name),
httpoison_options: [timeout: 30_000]
)
ids =
ecto_query
|> exclude(:preload)
|> exclude(:order_by)
|> order_by(asc: :id)
|> where([m], m.id > ^Enum.max(ids))
|> select([m], m.id)
|> limit(^batch_size)
|> Repo.all()
reindex(ecto_query, batch_size, ids)
end
def search_results(elastic_query) do
{:ok, %{body: results, status_code: 200}} =
Elastix.Search.search(
unquote(elastic_url),
unquote(index_name),
["_doc"],
elastic_query
)
results
end
def search_records(elastic_query, ecto_query \\ __MODULE__) do
results = search_results(elastic_query)
ids = results["hits"]["hits"] |> Enum.map(&String.to_integer(&1["_id"]))
records = ecto_query |> where([m], m.id in ^ids) |> Repo.all()
records |> Enum.sort_by(&Enum.find_index(ids, fn el -> el == &1.id end))
end
end
end
end

104
lib/philomena/galleries.ex Normal file
View file

@ -0,0 +1,104 @@
defmodule Philomena.Galleries do
@moduledoc """
The Galleries context.
"""
import Ecto.Query, warn: false
alias Philomena.Repo
alias Philomena.Galleries.Gallery
@doc """
Returns the list of galleries.
## Examples
iex> list_galleries()
[%Gallery{}, ...]
"""
def list_galleries do
Repo.all(Gallery)
end
@doc """
Gets a single gallery.
Raises `Ecto.NoResultsError` if the Gallery does not exist.
## Examples
iex> get_gallery!(123)
%Gallery{}
iex> get_gallery!(456)
** (Ecto.NoResultsError)
"""
def get_gallery!(id), do: Repo.get!(Gallery, id)
@doc """
Creates a gallery.
## Examples
iex> create_gallery(%{field: value})
{:ok, %Gallery{}}
iex> create_gallery(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_gallery(attrs \\ %{}) do
%Gallery{}
|> Gallery.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a gallery.
## Examples
iex> update_gallery(gallery, %{field: new_value})
{:ok, %Gallery{}}
iex> update_gallery(gallery, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_gallery(%Gallery{} = gallery, attrs) do
gallery
|> Gallery.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a Gallery.
## Examples
iex> delete_gallery(gallery)
{:ok, %Gallery{}}
iex> delete_gallery(gallery)
{:error, %Ecto.Changeset{}}
"""
def delete_gallery(%Gallery{} = gallery) do
Repo.delete(gallery)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking gallery changes.
## Examples
iex> change_gallery(gallery)
%Ecto.Changeset{source: %Gallery{}}
"""
def change_gallery(%Gallery{} = gallery) do
Gallery.changeset(gallery, %{})
end
end

View file

@ -0,0 +1,24 @@
defmodule Philomena.Galleries.Gallery do
use Ecto.Schema
import Ecto.Changeset
schema "galleries" do
belongs_to :thumbnail, Philomena.Images.Image, source: :thumbnail_id
belongs_to :creator, Philomena.Users.User, source: :creator_id
field :title, :string
field :spoiler_warning, :string
field :description, :string
field :image_count, :integer
field :order_position_asc, :boolean
timestamps(inserted_at: :created_at)
end
@doc false
def changeset(gallery, attrs) do
gallery
|> cast(attrs, [])
|> validate_required([])
end
end

View file

@ -0,0 +1,18 @@
defmodule Philomena.Galleries.Interaction do
use Ecto.Schema
import Ecto.Changeset
schema "gallery_interactions" do
belongs_to :gallery, Philomena.Galleries.Gallery
belongs_to :image, Philomena.Images.Image
field :position, :integer
end
@doc false
def changeset(interaction, attrs) do
interaction
|> cast(attrs, [])
|> validate_required([])
end
end

View file

@ -0,0 +1,147 @@
defmodule Philomena.Images.Elasticsearch do
def mapping do
%{
settings: %{
index: %{
number_of_shards: 5,
max_result_window: 10_000_000
}
},
mappings: %{
_doc: %{
_all: %{enabled: false},
dynamic: false,
properties: %{
anonymous: %{type: "boolean"},
aspect_ratio: %{type: "float"},
comment_count: %{type: "integer"},
commenters: %{type: "keyword"},
created_at: %{type: "date"},
deleted_by_user: %{type: "keyword"},
deleted_by_user_id: %{type: "keyword"},
deletion_reason: %{type: "text", analyzer: "snowball"},
description: %{type: "text", analyzer: "snowball"},
downvoter_ids: %{type: "keyword"},
downvoters: %{type: "keyword"},
downvotes: %{type: "integer"},
faves: %{type: "integer"},
favourited_by_user_ids: %{type: "keyword"},
favourited_by_users: %{type: "keyword"},
file_name: %{type: "keyword"},
fingerprint: %{type: "keyword"},
first_seen_at: %{type: "date"},
height: %{type: "integer"},
hidden_by_user_ids: %{type: "keyword"},
hidden_by_users: %{type: "keyword"},
hidden_from_users: %{type: "keyword"},
id: %{type: "integer"},
ip: %{type: "ip"},
mime_type: %{type: "keyword"},
orig_sha512_hash: %{type: "keyword"},
original_format: %{type: "keyword"},
score: %{type: "integer"},
sha512_hash: %{type: "keyword"},
source_url: %{type: "keyword"},
tag_count: %{type: "integer"},
tag_ids: %{type: "keyword"},
tags: %{type: "text", analyzer: "keyword"},
true_uploader: %{type: "keyword"},
true_uploader_id: %{type: "keyword"},
updated_at: %{type: "date"},
uploader: %{type: "keyword"},
uploader_id: %{type: "keyword"},
upvoter_ids: %{type: "keyword"},
upvoters: %{type: "keyword"},
upvotes: %{type: "integer"},
user_id: %{type: "keyword"},
width: %{type: "integer"},
wilson_score: %{type: "float"},
galleries: %{
type: "nested",
properties: %{
id: %{type: "integer"},
position: %{type: "integer"}
}
},
namespaced_tags: %{
properties: %{
name: %{type: "keyword"},
name_in_namespace: %{type: "keyword"},
namespace: %{type: "keyword"}
}
}
}
}
}
}
end
def as_json(image) do
%{
id: image.id,
upvotes: image.upvotes_count,
downvotes: image.downvotes_count,
score: image.score,
faves: image.faves_count,
comment_count: image.comments_count,
width: image.image_width,
height: image.image_height,
tag_count: length(image.tags),
aspect_ratio: image.image_aspect_ratio,
wilson_score: wilson_score(image),
created_at: image.created_at,
updated_at: image.updated_at,
first_seen_at: image.first_seen_at,
ip: image.ip |> to_string,
tag_ids: image.tags |> Enum.map(& &1.id),
mime_type: image.image_mime_type,
uploader: if(!!image.user and !image.anonymous, do: String.downcase(image.user.name)),
true_uploader: if(!!image.user, do: String.downcase(image.user.name)),
source_url: image.source_url |> to_string |> String.downcase(),
file_name: image.image_name,
original_format: image.image_format,
fingerprint: image.fingerprint,
uploader_id: if(!!image.user_id and !image.anonymous, do: image.user_id),
true_uploader_id: image.user_id,
orig_sha512_hash: image.image_orig_sha512_hash,
sha512_hash: image.image_sha512_hash,
hidden_from_users: image.hidden_from_users,
anonymous: image.anonymous,
description: image.description,
deletion_reason: image.deletion_reason,
favourited_by_user_ids: image.favers |> Enum.map(& &1.id),
hidden_by_user_ids: image.hiders |> Enum.map(& &1.id),
upvoter_ids: image.upvoters |> Enum.map(& &1.id),
downvoter_ids: image.downvoters |> Enum.map(& &1.id),
deleted_by_user_id: image.deleter_id,
galleries:
image.gallery_interactions |> Enum.map(&%{id: &1.gallery_id, position: &1.position}),
namespaced_tags: %{
name: image.tags |> Enum.flat_map(&([&1] ++ &1.aliases)) |> Enum.map(& &1.name)
},
favourited_by_users: image.favers |> Enum.map(&String.downcase(&1.name)),
hidden_by_users: image.hiders |> Enum.map(&String.downcase(&1.name)),
upvoters: image.upvoters |> Enum.map(&String.downcase(&1.name)),
downvoters: image.downvoters |> Enum.map(&String.downcase(&1.name)),
deleted_by_user: if(!!image.deleter, do: image.deleter.name)
}
end
def wilson_score(%{upvotes_count: upvotes, downvotes_count: downvotes})
when upvotes > 0 or downvotes > 0 do
# Population size
n = (upvotes + downvotes) / 1
# Success proportion
p_hat = upvotes / n
# z and z^2 values for CI upper 99.5%
z = 2.57583
z2 = 6.634900189
(p_hat + z2 / (2 * n) - z * :math.sqrt((p_hat * (1 - p_hat) + z2 / (4 * n)) / n)) /
(1 + z2 / n)
end
def wilson_score(_), do: 0
end

View file

@ -0,0 +1,19 @@
defmodule Philomena.Images.Fave do
use Ecto.Schema
import Ecto.Changeset
@primary_key false
schema "image_faves" do
belongs_to :user, Philomena.Users.User, primary_key: true
belongs_to :image, Philomena.Images.Image, primary_key: true
timestamps(inserted_at: :created_at, updated_at: false)
end
@doc false
def changeset(fave, attrs) do
fave
|> cast(attrs, [])
|> validate_required([])
end
end

View file

@ -0,0 +1,19 @@
defmodule Philomena.Images.Hide do
use Ecto.Schema
import Ecto.Changeset
@primary_key false
schema "image_hides" do
belongs_to :user, Philomena.Users.User, primary_key: true
belongs_to :image, Philomena.Images.Image, primary_key: true
timestamps(inserted_at: :created_at, updated_at: false)
end
@doc false
def changeset(hide, attrs) do
hide
|> cast(attrs, [])
|> validate_required([])
end
end

View file

@ -1,11 +1,26 @@
defmodule Philomena.Images.Image do defmodule Philomena.Images.Image do
use Ecto.Schema use Ecto.Schema
use Philomena.Elasticsearch,
definition: Philomena.Images.Elasticsearch,
index_name: "images"
import Ecto.Changeset import Ecto.Changeset
schema "images" do schema "images" do
belongs_to :user, Philomena.Users.User belongs_to :user, Philomena.Users.User
belongs_to :deleter, Philomena.Users.User, source: :deleted_by_id belongs_to :deleter, Philomena.Users.User, source: :deleted_by_id
many_to_many :tags, Philomena.Tags.Tag, join_through: "image_taggings" has_many :upvotes, Philomena.Images.Vote, where: [up: true]
has_many :downvotes, Philomena.Images.Vote, where: [up: false]
has_many :faves, Philomena.Images.Fave
has_many :hides, Philomena.Images.Hide
has_many :taggings, Philomena.Images.Tagging
has_many :gallery_interactions, Philomena.Galleries.Interaction
has_many :tags, through: [:taggings, :tag]
has_many :upvoters, through: [:upvotes, :user]
has_many :downvoters, through: [:downvotes, :user]
has_many :favers, through: [:faves, :user]
has_many :hiders, through: [:hides, :user]
field :image, :string field :image, :string
field :image_name, :string field :image_name, :string

View file

@ -0,0 +1,18 @@
defmodule Philomena.Images.Tagging do
use Ecto.Schema
import Ecto.Changeset
@primary_key false
schema "image_taggings" do
belongs_to :image, Philomena.Images.Image, primary_key: true
belongs_to :tag, Philomena.Tags.Tag, primary_key: true
end
@doc false
def changeset(tagging, attrs) do
tagging
|> cast(attrs, [])
|> validate_required([])
end
end

View file

@ -0,0 +1,20 @@
defmodule Philomena.Images.Vote do
use Ecto.Schema
import Ecto.Changeset
@primary_key false
schema "image_votes" do
belongs_to :user, Philomena.Users.User, primary_key: true
belongs_to :image, Philomena.Images.Image, primary_key: true
field :up, :boolean
timestamps(inserted_at: :created_at, updated_at: false)
end
@doc false
def changeset(vote, attrs) do
vote
|> cast(attrs, [])
|> validate_required([])
end
end

View file

@ -3,6 +3,9 @@ defmodule Philomena.Tags.Tag do
import Ecto.Changeset import Ecto.Changeset
schema "tags" do schema "tags" do
belongs_to :aliased_tag, Philomena.Tags.Tag, source: :aliased_tag_id
has_many :aliases, Philomena.Tags.Tag, foreign_key: :aliased_tag_id
field :slug, :string field :slug, :string
field :name, :string field :name, :string
field :category, :string field :category, :string

View file

@ -26,7 +26,8 @@ defmodule PhilomenaWeb.AppView do
months = abs(div(days, 30)) months = abs(div(days, 30))
years = abs(div(days, 365)) years = abs(div(days, 365))
words = cond do words =
cond do
seconds < 45 -> String.replace(@time_strings[:seconds], "%d", to_string(seconds)) seconds < 45 -> String.replace(@time_strings[:seconds], "%d", to_string(seconds))
seconds < 90 -> String.replace(@time_strings[:minute], "%d", to_string(1)) seconds < 90 -> String.replace(@time_strings[:minute], "%d", to_string(1))
minutes < 45 -> String.replace(@time_strings[:minutes], "%d", to_string(minutes)) minutes < 45 -> String.replace(@time_strings[:minutes], "%d", to_string(minutes))

View file

@ -48,7 +48,8 @@ defmodule Philomena.MixProject do
{:pow, "~> 1.0.11"}, {:pow, "~> 1.0.11"},
{:bcrypt_elixir, "~> 2.0"}, {:bcrypt_elixir, "~> 2.0"},
{:pot, "~> 0.10.1"}, {:pot, "~> 0.10.1"},
{:secure_compare, "~> 0.1.0"} {:secure_compare, "~> 0.1.0"},
{:elastix, "~> 0.7.1"}
] ]
end end

View file

@ -1,5 +1,6 @@
%{ %{
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.0.3", "64e0792d5b5064391927bf3b8e436994cafd18ca2d2b76dea5c76e0adcf66b7c", [:make, :mix], [{:comeonin, "~> 5.1", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"}, "bcrypt_elixir": {:hex, :bcrypt_elixir, "2.0.3", "64e0792d5b5064391927bf3b8e436994cafd18ca2d2b76dea5c76e0adcf66b7c", [:make, :mix], [{:comeonin, "~> 5.1", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"certifi": {:hex, :certifi, "2.5.1", "867ce347f7c7d78563450a18a6a28a8090331e77fa02380b4a21962a65d36ee5", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"},
"comeonin": {:hex, :comeonin, "5.1.2", "fbbbbbfcf0f0e9900c0336d16c8d462edf838ba1759577e29cc5fbd7c28a4540", [:mix], [], "hexpm"}, "comeonin": {:hex, :comeonin, "5.1.2", "fbbbbbfcf0f0e9900c0336d16c8d462edf838ba1759577e29cc5fbd7c28a4540", [:mix], [], "hexpm"},
"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"}, "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, "cowboy": {:hex, :cowboy, "2.6.3", "99aa50e94e685557cad82e704457336a453d4abcb77839ad22dbe71f311fcc06", [:rebar3], [{:cowlib, "~> 2.7.3", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"},
@ -9,12 +10,19 @@
"ecto": {:hex, :ecto, "3.1.7", "fa21d06ef56cdc2fdaa62574e8c3ba34a2751d44ea34c30bc65f0728421043e5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"}, "ecto": {:hex, :ecto, "3.1.7", "fa21d06ef56cdc2fdaa62574e8c3ba34a2751d44ea34c30bc65f0728421043e5", [:mix], [{:decimal, "~> 1.6", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm"},
"ecto_network": {:hex, :ecto_network, "1.1.0", "7062004b9324ff13e50c02dab84877f8a55e06db9eabbf2d04bda21da6fc6e8a", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm"}, "ecto_network": {:hex, :ecto_network, "1.1.0", "7062004b9324ff13e50c02dab84877f8a55e06db9eabbf2d04bda21da6fc6e8a", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm"},
"ecto_sql": {:hex, :ecto_sql, "3.1.6", "1e80e30d16138a729c717f73dcb938590bcdb3a4502f3012414d0cbb261045d8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0 or ~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "ecto_sql": {:hex, :ecto_sql, "3.1.6", "1e80e30d16138a729c717f73dcb938590bcdb3a4502f3012414d0cbb261045d8", [:mix], [{:db_connection, "~> 2.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.1.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.9.1", [hex: :mariaex, repo: "hexpm", optional: true]}, {:myxql, "~> 0.2.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.14.0 or ~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
"elastix": {:hex, :elastix, "0.7.1", "8e199a764a0bc018e0a97afeea950a8069b988867d87f8d25ae121d8b3288612", [:mix], [{:httpoison, "~> 1.4", [hex: :httpoison, repo: "hexpm", optional: false]}, {:poison, "~> 3.1", [hex: :poison, repo: "hexpm", optional: true]}, {:retry, "~> 0.8", [hex: :retry, repo: "hexpm", optional: false]}], "hexpm"},
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm"}, "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm"},
"file_system": {:hex, :file_system, "0.2.7", "e6f7f155970975789f26e77b8b8d8ab084c59844d8ecfaf58cbda31c494d14aa", [:mix], [], "hexpm"}, "file_system": {:hex, :file_system, "0.2.7", "e6f7f155970975789f26e77b8b8d8ab084c59844d8ecfaf58cbda31c494d14aa", [:mix], [], "hexpm"},
"gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"}, "gettext": {:hex, :gettext, "0.17.0", "abe21542c831887a2b16f4c94556db9c421ab301aee417b7c4fbde7fbdbe01ec", [:mix], [], "hexpm"},
"hackney": {:hex, :hackney, "1.15.1", "9f8f471c844b8ce395f7b6d8398139e26ddca9ebc171a8b91342ee15a19963f4", [:rebar3], [{:certifi, "2.5.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"httpoison": {:hex, :httpoison, "1.5.1", "0f55b5b673b03c5c327dac7015a67cb571b99b631acc0bc1b0b98dcd6b9f2104", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"},
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"}, "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm"},
"neotoma": {:hex, :neotoma, "1.7.3", "d8bd5404b73273989946e4f4f6d529e5c2088f5fa1ca790b4dbe81f4be408e61", [:rebar], [], "hexpm"}, "neotoma": {:hex, :neotoma, "1.7.3", "d8bd5404b73273989946e4f4f6d529e5c2088f5fa1ca790b4dbe81f4be408e61", [:rebar], [], "hexpm"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"},
"pbkdf2": {:hex, :pbkdf2, "2.0.0", "11c23279fded5c0027ab3996cfae77805521d7ef4babde2bd7ec04a9086cf499", [:rebar3], [], "hexpm"}, "pbkdf2": {:hex, :pbkdf2, "2.0.0", "11c23279fded5c0027ab3996cfae77805521d7ef4babde2bd7ec04a9086cf499", [:rebar3], [], "hexpm"},
"phoenix": {:hex, :phoenix, "1.4.9", "746d098e10741c334d88143d3c94cab1756435f94387a63441792e66ec0ee974", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix": {:hex, :phoenix, "1.4.9", "746d098e10741c334d88143d3c94cab1756435f94387a63441792e66ec0ee974", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.0.0", "c43117a136e7399ea04ecaac73f8f23ee0ffe3e07acfcb8062fe5f4c9f0f6531", [:mix], [{:ecto, "~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.9", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
@ -29,7 +37,10 @@
"pot": {:hex, :pot, "0.10.1", "af7dc220fd45478719b821fb4c1222975132516478483213507f95026298d8ab", [:rebar3], [], "hexpm"}, "pot": {:hex, :pot, "0.10.1", "af7dc220fd45478719b821fb4c1222975132516478483213507f95026298d8ab", [:rebar3], [], "hexpm"},
"pow": {:hex, :pow, "1.0.11", "f5ef721ac17d2bf8f9dd92f5d40fa0b96512d24b91a26603147754034e3a6101", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.3.0 or ~> 1.4.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 2.0.0 and <= 3.0.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, ">= 1.5.0 and < 2.0.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm"}, "pow": {:hex, :pow, "1.0.11", "f5ef721ac17d2bf8f9dd92f5d40fa0b96512d24b91a26603147754034e3a6101", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.3.0 or ~> 1.4.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 2.0.0 and <= 3.0.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, ">= 1.5.0 and < 2.0.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"}, "ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm"},
"retry": {:hex, :retry, "0.13.0", "bb9b2713f70f39337837852337ad280c77662574f4fb852a8386c269f3d734c4", [:mix], [], "hexpm"},
"secure_compare": {:hex, :secure_compare, "0.1.0", "01b3c93c8edb696e8a5b38397ed48e10958c8a5ec740606656445bcbec0aadb8", [:mix], [], "hexpm"}, "secure_compare": {:hex, :secure_compare, "0.1.0", "01b3c93c8edb696e8a5b38397ed48e10958c8a5ec740606656445bcbec0aadb8", [:mix], [], "hexpm"},
"slime": {:hex, :slime, "1.2.0", "d46ede53c96b743dfdd23821268dc9b01f04ffea65d9d57c4e3d9200b162df02", [:mix], [{:neotoma, "~> 1.7", [hex: :neotoma, repo: "hexpm", optional: false]}], "hexpm"}, "slime": {:hex, :slime, "1.2.0", "d46ede53c96b743dfdd23821268dc9b01f04ffea65d9d57c4e3d9200b162df02", [:mix], [{:neotoma, "~> 1.7", [hex: :neotoma, repo: "hexpm", optional: false]}], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"},
"telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"}, "telemetry": {:hex, :telemetry, "0.4.0", "8339bee3fa8b91cb84d14c2935f8ecf399ccd87301ad6da6b71c09553834b2ab", [:rebar3], [], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"},
} }

View file

@ -0,0 +1,62 @@
defmodule Philomena.GalleriesTest do
use Philomena.DataCase
alias Philomena.Galleries
describe "galleries" do
alias Philomena.Galleries.Gallery
@valid_attrs %{}
@update_attrs %{}
@invalid_attrs %{}
def gallery_fixture(attrs \\ %{}) do
{:ok, gallery} =
attrs
|> Enum.into(@valid_attrs)
|> Galleries.create_gallery()
gallery
end
test "list_galleries/0 returns all galleries" do
gallery = gallery_fixture()
assert Galleries.list_galleries() == [gallery]
end
test "get_gallery!/1 returns the gallery with given id" do
gallery = gallery_fixture()
assert Galleries.get_gallery!(gallery.id) == gallery
end
test "create_gallery/1 with valid data creates a gallery" do
assert {:ok, %Gallery{} = gallery} = Galleries.create_gallery(@valid_attrs)
end
test "create_gallery/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Galleries.create_gallery(@invalid_attrs)
end
test "update_gallery/2 with valid data updates the gallery" do
gallery = gallery_fixture()
assert {:ok, %Gallery{} = gallery} = Galleries.update_gallery(gallery, @update_attrs)
end
test "update_gallery/2 with invalid data returns error changeset" do
gallery = gallery_fixture()
assert {:error, %Ecto.Changeset{}} = Galleries.update_gallery(gallery, @invalid_attrs)
assert gallery == Galleries.get_gallery!(gallery.id)
end
test "delete_gallery/1 deletes the gallery" do
gallery = gallery_fixture()
assert {:ok, %Gallery{}} = Galleries.delete_gallery(gallery)
assert_raise Ecto.NoResultsError, fn -> Galleries.get_gallery!(gallery.id) end
end
test "change_gallery/1 returns a gallery changeset" do
gallery = gallery_fixture()
assert %Ecto.Changeset{} = Galleries.change_gallery(gallery)
end
end
end

View file

@ -75,6 +75,7 @@ defmodule PhilomenaWeb.CommentControllerTest do
test "deletes chosen comment", %{conn: conn, comment: comment} do test "deletes chosen comment", %{conn: conn, comment: comment} do
conn = delete(conn, Routes.comment_path(conn, :delete, comment)) conn = delete(conn, Routes.comment_path(conn, :delete, comment))
assert redirected_to(conn) == Routes.comment_path(conn, :index) assert redirected_to(conn) == Routes.comment_path(conn, :index)
assert_error_sent 404, fn -> assert_error_sent 404, fn ->
get(conn, Routes.comment_path(conn, :show, comment)) get(conn, Routes.comment_path(conn, :show, comment))
end end

View file

@ -75,6 +75,7 @@ defmodule PhilomenaWeb.TagControllerTest do
test "deletes chosen tag", %{conn: conn, tag: tag} do test "deletes chosen tag", %{conn: conn, tag: tag} do
conn = delete(conn, Routes.tag_path(conn, :delete, tag)) conn = delete(conn, Routes.tag_path(conn, :delete, tag))
assert redirected_to(conn) == Routes.tag_path(conn, :index) assert redirected_to(conn) == Routes.tag_path(conn, :index)
assert_error_sent 404, fn -> assert_error_sent 404, fn ->
get(conn, Routes.tag_path(conn, :show, tag)) get(conn, Routes.tag_path(conn, :show, tag))
end end

View file

@ -24,9 +24,9 @@ fi
# Necessary for apt and elasticsearch to succeed # Necessary for apt and elasticsearch to succeed
install_packages apt-transport-https default-jre-headless install_packages apt-transport-https default-jre-headless
if [ ! -f /etc/apt/sources.list.d/elasticsearch-7.x.list ]; then if [ ! -f /etc/apt/sources.list.d/elasticsearch-6.x.list ]; then
add_key https://packages.elastic.co/GPG-KEY-elasticsearch add_key https://packages.elastic.co/GPG-KEY-elasticsearch
echo "deb https://artifacts.elastic.co/packages/7.x/apt stable main" > /etc/apt/sources.list.d/elasticsearch-7.x.list echo "deb https://artifacts.elastic.co/packages/6.x/apt stable main" > /etc/apt/sources.list.d/elasticsearch-6.x.list
fi fi
if [ ! -f /etc/apt/sources.list.d/pgdg.list ]; then if [ ! -f /etc/apt/sources.list.d/pgdg.list ]; then