mirror of
https://github.com/philomena-dev/philomena.git
synced 2025-02-01 03:46:44 +01:00
add interactions
This commit is contained in:
parent
6513fb39b8
commit
d60c6ccb06
14 changed files with 409 additions and 273 deletions
|
@ -5,9 +5,9 @@
|
||||||
import { fetchJson } from './utils/requests';
|
import { fetchJson } from './utils/requests';
|
||||||
|
|
||||||
const endpoints = {
|
const endpoints = {
|
||||||
fave: `${window.booru.apiEndpoint}interactions/fave`,
|
vote(imageId) { return `/images/${imageId}/vote` },
|
||||||
vote: `${window.booru.apiEndpoint}interactions/vote`,
|
fave(imageId) { return `/images/${imageId}/fave` },
|
||||||
hide: `${window.booru.apiEndpoint}interactions/hide`,
|
hide(imageId) { return `/images/${imageId}/hide` },
|
||||||
};
|
};
|
||||||
|
|
||||||
const spoilerDownvoteMsg =
|
const spoilerDownvoteMsg =
|
||||||
|
@ -22,10 +22,8 @@ function onImage(id, selector, cb) {
|
||||||
function setScore(imageId, data) {
|
function setScore(imageId, data) {
|
||||||
onImage(imageId, '.score',
|
onImage(imageId, '.score',
|
||||||
el => el.textContent = data.score);
|
el => el.textContent = data.score);
|
||||||
onImage(imageId, '.votes',
|
|
||||||
el => el.textContent = data.votes);
|
|
||||||
onImage(imageId, '.favorites',
|
onImage(imageId, '.favorites',
|
||||||
el => el.textContent = data.favourites);
|
el => el.textContent = data.faves);
|
||||||
onImage(imageId, '.upvotes',
|
onImage(imageId, '.upvotes',
|
||||||
el => el.textContent = data.upvotes);
|
el => el.textContent = data.upvotes);
|
||||||
onImage(imageId, '.downvotes',
|
onImage(imageId, '.downvotes',
|
||||||
|
@ -73,10 +71,8 @@ function resetHidden(imageId) {
|
||||||
el => el.classList.remove('active'));
|
el => el.classList.remove('active'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function interact(type, imageId, value) {
|
function interact(type, imageId, method, data = {}) {
|
||||||
return fetchJson('PUT', endpoints[type], {
|
return fetchJson(method, endpoints[type](imageId), data)
|
||||||
class: 'Image', id: imageId, value
|
|
||||||
})
|
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(res => setScore(imageId, res));
|
.then(res => setScore(imageId, res));
|
||||||
}
|
}
|
||||||
|
@ -129,37 +125,37 @@ const targets = {
|
||||||
|
|
||||||
/* Active-state targets first */
|
/* Active-state targets first */
|
||||||
'.interaction--upvote.active'(imageId) {
|
'.interaction--upvote.active'(imageId) {
|
||||||
interact('vote', imageId, 'false')
|
interact('vote', imageId, 'DELETE')
|
||||||
.then(() => resetVoted(imageId));
|
.then(() => resetVoted(imageId));
|
||||||
},
|
},
|
||||||
'.interaction--downvote.active'(imageId) {
|
'.interaction--downvote.active'(imageId) {
|
||||||
interact('vote', imageId, 'false')
|
interact('vote', imageId, 'DELETE')
|
||||||
.then(() => resetVoted(imageId));
|
.then(() => resetVoted(imageId));
|
||||||
},
|
},
|
||||||
'.interaction--fave.active'(imageId) {
|
'.interaction--fave.active'(imageId) {
|
||||||
interact('fave', imageId, 'false')
|
interact('fave', imageId, 'DELETE')
|
||||||
.then(() => resetFaved(imageId));
|
.then(() => resetFaved(imageId));
|
||||||
},
|
},
|
||||||
'.interaction--hide.active'(imageId) {
|
'.interaction--hide.active'(imageId) {
|
||||||
interact('hide', imageId, 'false')
|
interact('hide', imageId, 'DELETE')
|
||||||
.then(() => resetHidden(imageId));
|
.then(() => resetHidden(imageId));
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Inactive targets */
|
/* Inactive targets */
|
||||||
'.interaction--upvote:not(.active)'(imageId) {
|
'.interaction--upvote:not(.active)'(imageId) {
|
||||||
interact('vote', imageId, 'up')
|
interact('vote', imageId, 'POST', { up: true })
|
||||||
.then(() => { resetVoted(imageId); showUpvoted(imageId); });
|
.then(() => { resetVoted(imageId); showUpvoted(imageId); });
|
||||||
},
|
},
|
||||||
'.interaction--downvote:not(.active)'(imageId) {
|
'.interaction--downvote:not(.active)'(imageId) {
|
||||||
interact('vote', imageId, 'down')
|
interact('vote', imageId, 'POST', { up: false })
|
||||||
.then(() => { resetVoted(imageId); showDownvoted(imageId); });
|
.then(() => { resetVoted(imageId); showDownvoted(imageId); });
|
||||||
},
|
},
|
||||||
'.interaction--fave:not(.active)'(imageId) {
|
'.interaction--fave:not(.active)'(imageId) {
|
||||||
interact('fave', imageId, 'true')
|
interact('fave', imageId, 'POST')
|
||||||
.then(() => { resetVoted(imageId); showFaved(imageId); showUpvoted(imageId); });
|
.then(() => { resetVoted(imageId); showFaved(imageId); showUpvoted(imageId); });
|
||||||
},
|
},
|
||||||
'.interaction--hide:not(.active)'(imageId) {
|
'.interaction--hide:not(.active)'(imageId) {
|
||||||
interact('hide', imageId, 'true')
|
interact('hide', imageId, 'POST')
|
||||||
.then(() => { showHidden(imageId); });
|
.then(() => { showHidden(imageId); });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -4,101 +4,51 @@ defmodule Philomena.ImageFaves do
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import Ecto.Query, warn: false
|
import Ecto.Query, warn: false
|
||||||
alias Philomena.Repo
|
alias Ecto.Multi
|
||||||
|
|
||||||
|
alias Philomena.Images.Image
|
||||||
alias Philomena.ImageFaves.ImageFave
|
alias Philomena.ImageFaves.ImageFave
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Returns the list of image_faves.
|
Creates a image_hide.
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> list_image_faves()
|
|
||||||
[%ImageFave{}, ...]
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def list_image_faves do
|
def create_fave_transaction(image, user) do
|
||||||
Repo.all(ImageFave)
|
fave =
|
||||||
end
|
%ImageFave{image_id: image.id, user_id: user.id}
|
||||||
|
|> ImageFave.changeset(%{})
|
||||||
|
|
||||||
@doc """
|
image_query =
|
||||||
Gets a single image_fave.
|
Image
|
||||||
|
|> where(id: ^image.id)
|
||||||
|
|
||||||
Raises `Ecto.NoResultsError` if the Image fave does not exist.
|
Multi.new
|
||||||
|
|> Multi.insert(:fave, fave)
|
||||||
## Examples
|
|> Multi.update_all(:inc_faves_count, image_query, inc: [faves_count: 1])
|
||||||
|
|
||||||
iex> get_image_fave!(123)
|
|
||||||
%ImageFave{}
|
|
||||||
|
|
||||||
iex> get_image_fave!(456)
|
|
||||||
** (Ecto.NoResultsError)
|
|
||||||
|
|
||||||
"""
|
|
||||||
def get_image_fave!(id), do: Repo.get!(ImageFave, id)
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Creates a image_fave.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> create_image_fave(%{field: value})
|
|
||||||
{:ok, %ImageFave{}}
|
|
||||||
|
|
||||||
iex> create_image_fave(%{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
|
||||||
def create_image_fave(attrs \\ %{}) do
|
|
||||||
%ImageFave{}
|
|
||||||
|> ImageFave.changeset(attrs)
|
|
||||||
|> Repo.insert()
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Updates a image_fave.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> update_image_fave(image_fave, %{field: new_value})
|
|
||||||
{:ok, %ImageFave{}}
|
|
||||||
|
|
||||||
iex> update_image_fave(image_fave, %{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
|
||||||
def update_image_fave(%ImageFave{} = image_fave, attrs) do
|
|
||||||
image_fave
|
|
||||||
|> ImageFave.changeset(attrs)
|
|
||||||
|> Repo.update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Deletes a ImageFave.
|
Deletes a ImageFave.
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> delete_image_fave(image_fave)
|
|
||||||
{:ok, %ImageFave{}}
|
|
||||||
|
|
||||||
iex> delete_image_fave(image_fave)
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def delete_image_fave(%ImageFave{} = image_fave) do
|
def delete_fave_transaction(image, user) do
|
||||||
Repo.delete(image_fave)
|
fave_query =
|
||||||
end
|
ImageFave
|
||||||
|
|> where(image_id: ^image.id)
|
||||||
|
|> where(user_id: ^user.id)
|
||||||
|
|
||||||
@doc """
|
image_query =
|
||||||
Returns an `%Ecto.Changeset{}` for tracking image_fave changes.
|
Image
|
||||||
|
|> where(id: ^image.id)
|
||||||
|
|
||||||
## Examples
|
Multi.new
|
||||||
|
|> Multi.delete_all(:unfave, fave_query)
|
||||||
|
|> Multi.run(:dec_faves_count, fn repo, %{unfave: {faves, nil}} ->
|
||||||
|
{count, nil} =
|
||||||
|
image_query
|
||||||
|
|> repo.update_all(inc: [faves_count: -faves])
|
||||||
|
|
||||||
iex> change_image_fave(image_fave)
|
{:ok, count}
|
||||||
%Ecto.Changeset{source: %ImageFave{}}
|
end)
|
||||||
|
|
||||||
"""
|
|
||||||
def change_image_fave(%ImageFave{} = image_fave) do
|
|
||||||
ImageFave.changeset(image_fave, %{})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,101 +4,51 @@ defmodule Philomena.ImageHides do
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import Ecto.Query, warn: false
|
import Ecto.Query, warn: false
|
||||||
alias Philomena.Repo
|
alias Ecto.Multi
|
||||||
|
|
||||||
|
alias Philomena.Images.Image
|
||||||
alias Philomena.ImageHides.ImageHide
|
alias Philomena.ImageHides.ImageHide
|
||||||
|
|
||||||
@doc """
|
|
||||||
Returns the list of image_hides.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> list_image_hides()
|
|
||||||
[%ImageHide{}, ...]
|
|
||||||
|
|
||||||
"""
|
|
||||||
def list_image_hides do
|
|
||||||
Repo.all(ImageHide)
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Gets a single image_hide.
|
|
||||||
|
|
||||||
Raises `Ecto.NoResultsError` if the Image hide does not exist.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> get_image_hide!(123)
|
|
||||||
%ImageHide{}
|
|
||||||
|
|
||||||
iex> get_image_hide!(456)
|
|
||||||
** (Ecto.NoResultsError)
|
|
||||||
|
|
||||||
"""
|
|
||||||
def get_image_hide!(id), do: Repo.get!(ImageHide, id)
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Creates a image_hide.
|
Creates a image_hide.
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> create_image_hide(%{field: value})
|
|
||||||
{:ok, %ImageHide{}}
|
|
||||||
|
|
||||||
iex> create_image_hide(%{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def create_image_hide(attrs \\ %{}) do
|
def create_hide_transaction(image, user) do
|
||||||
%ImageHide{}
|
hide =
|
||||||
|> ImageHide.changeset(attrs)
|
%ImageHide{image_id: image.id, user_id: user.id}
|
||||||
|> Repo.insert()
|
|> ImageHide.changeset(%{})
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
image_query =
|
||||||
Updates a image_hide.
|
Image
|
||||||
|
|> where(id: ^image.id)
|
||||||
|
|
||||||
## Examples
|
Multi.new
|
||||||
|
|> Multi.insert(:hide, hide)
|
||||||
iex> update_image_hide(image_hide, %{field: new_value})
|
|> Multi.update_all(:inc_hides_count, image_query, inc: [hides_count: 1])
|
||||||
{:ok, %ImageHide{}}
|
|
||||||
|
|
||||||
iex> update_image_hide(image_hide, %{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
|
||||||
def update_image_hide(%ImageHide{} = image_hide, attrs) do
|
|
||||||
image_hide
|
|
||||||
|> ImageHide.changeset(attrs)
|
|
||||||
|> Repo.update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Deletes a ImageHide.
|
Deletes a ImageHide.
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> delete_image_hide(image_hide)
|
|
||||||
{:ok, %ImageHide{}}
|
|
||||||
|
|
||||||
iex> delete_image_hide(image_hide)
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def delete_image_hide(%ImageHide{} = image_hide) do
|
def delete_hide_transaction(image, user) do
|
||||||
Repo.delete(image_hide)
|
hide_query =
|
||||||
end
|
ImageHide
|
||||||
|
|> where(image_id: ^image.id)
|
||||||
|
|> where(user_id: ^user.id)
|
||||||
|
|
||||||
@doc """
|
image_query =
|
||||||
Returns an `%Ecto.Changeset{}` for tracking image_hide changes.
|
Image
|
||||||
|
|> where(id: ^image.id)
|
||||||
|
|
||||||
## Examples
|
Multi.new
|
||||||
|
|> Multi.delete_all(:unhide, hide_query)
|
||||||
|
|> Multi.run(:dec_hides_count, fn repo, %{unhide: {hides, nil}} ->
|
||||||
|
{count, nil} =
|
||||||
|
image_query
|
||||||
|
|> repo.update_all(inc: [hides_count: -hides])
|
||||||
|
|
||||||
iex> change_image_hide(image_hide)
|
{:ok, count}
|
||||||
%Ecto.Changeset{source: %ImageHide{}}
|
end)
|
||||||
|
|
||||||
"""
|
|
||||||
def change_image_hide(%ImageHide{} = image_hide) do
|
|
||||||
ImageHide.changeset(image_hide, %{})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,101 +4,62 @@ defmodule Philomena.ImageVotes do
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import Ecto.Query, warn: false
|
import Ecto.Query, warn: false
|
||||||
alias Philomena.Repo
|
alias Ecto.Multi
|
||||||
|
|
||||||
|
alias Philomena.Images.Image
|
||||||
alias Philomena.ImageVotes.ImageVote
|
alias Philomena.ImageVotes.ImageVote
|
||||||
|
|
||||||
@doc """
|
|
||||||
Returns the list of image_votes.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> list_image_votes()
|
|
||||||
[%ImageVote{}, ...]
|
|
||||||
|
|
||||||
"""
|
|
||||||
def list_image_votes do
|
|
||||||
Repo.all(ImageVote)
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Gets a single image_vote.
|
|
||||||
|
|
||||||
Raises `Ecto.NoResultsError` if the Image vote does not exist.
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> get_image_vote!(123)
|
|
||||||
%ImageVote{}
|
|
||||||
|
|
||||||
iex> get_image_vote!(456)
|
|
||||||
** (Ecto.NoResultsError)
|
|
||||||
|
|
||||||
"""
|
|
||||||
def get_image_vote!(id), do: Repo.get!(ImageVote, id)
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Creates a image_vote.
|
Creates a image_vote.
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> create_image_vote(%{field: value})
|
|
||||||
{:ok, %ImageVote{}}
|
|
||||||
|
|
||||||
iex> create_image_vote(%{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def create_image_vote(attrs \\ %{}) do
|
def create_vote_transaction(image, user, up) do
|
||||||
%ImageVote{}
|
vote =
|
||||||
|> ImageVote.changeset(attrs)
|
%ImageVote{image_id: image.id, user_id: user.id, up: up}
|
||||||
|> Repo.insert()
|
|> ImageVote.changeset(%{})
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
image_query =
|
||||||
Updates a image_vote.
|
Image
|
||||||
|
|> where(id: ^image.id)
|
||||||
|
|
||||||
## Examples
|
upvotes = if up, do: 1, else: 0
|
||||||
|
downvotes = if up, do: 0, else: 1
|
||||||
|
|
||||||
iex> update_image_vote(image_vote, %{field: new_value})
|
Multi.new
|
||||||
{:ok, %ImageVote{}}
|
|> Multi.insert(:vote, vote)
|
||||||
|
|> Multi.update_all(:inc_vote_count, image_query, inc: [upvotes_count: upvotes, downvotes_count: downvotes, score: upvotes - downvotes])
|
||||||
iex> update_image_vote(image_vote, %{field: bad_value})
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
|
||||||
def update_image_vote(%ImageVote{} = image_vote, attrs) do
|
|
||||||
image_vote
|
|
||||||
|> ImageVote.changeset(attrs)
|
|
||||||
|> Repo.update()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Deletes a ImageVote.
|
Deletes a ImageVote.
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
iex> delete_image_vote(image_vote)
|
|
||||||
{:ok, %ImageVote{}}
|
|
||||||
|
|
||||||
iex> delete_image_vote(image_vote)
|
|
||||||
{:error, %Ecto.Changeset{}}
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def delete_image_vote(%ImageVote{} = image_vote) do
|
def delete_vote_transaction(image, user) do
|
||||||
Repo.delete(image_vote)
|
upvote_query =
|
||||||
end
|
ImageVote
|
||||||
|
|> where(image_id: ^image.id)
|
||||||
|
|> where(user_id: ^user.id)
|
||||||
|
|> where(up: true)
|
||||||
|
|
||||||
@doc """
|
downvote_query =
|
||||||
Returns an `%Ecto.Changeset{}` for tracking image_vote changes.
|
ImageVote
|
||||||
|
|> where(image_id: ^image.id)
|
||||||
|
|> where(user_id: ^user.id)
|
||||||
|
|> where(up: false)
|
||||||
|
|
||||||
## Examples
|
image_query =
|
||||||
|
Image
|
||||||
|
|> where(id: ^image.id)
|
||||||
|
|
||||||
iex> change_image_vote(image_vote)
|
Multi.new
|
||||||
%Ecto.Changeset{source: %ImageVote{}}
|
|> Multi.delete_all(:unupvote, upvote_query)
|
||||||
|
|> Multi.delete_all(:undownvote, downvote_query)
|
||||||
|
|> Multi.run(:dec_votes_count, fn repo, %{unupvote: {upvotes, nil}, undownvote: {downvotes, nil}} ->
|
||||||
|
{count, nil} =
|
||||||
|
image_query
|
||||||
|
|> repo.update_all(inc: [upvotes_count: -upvotes, downvotes_count: -downvotes, score: downvotes - upvotes])
|
||||||
|
|
||||||
"""
|
{:ok, count}
|
||||||
def change_image_vote(%ImageVote{} = image_vote) do
|
end)
|
||||||
ImageVote.changeset(image_vote, %{})
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,6 +104,22 @@ defmodule Philomena.Images do
|
||||||
Image.changeset(image, %{})
|
Image.changeset(image, %{})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reindex_image(%Image{} = image) do
|
||||||
|
spawn fn ->
|
||||||
|
Image
|
||||||
|
|> preload(^indexing_preloads())
|
||||||
|
|> where(id: ^image.id)
|
||||||
|
|> Repo.one()
|
||||||
|
|> Image.index_document()
|
||||||
|
end
|
||||||
|
|
||||||
|
image
|
||||||
|
end
|
||||||
|
|
||||||
|
def indexing_preloads do
|
||||||
|
[:user, :favers, :downvoters, :upvoters, :hiders, :deleter, :gallery_interactions, tags: [:aliases, :aliased_tag]]
|
||||||
|
end
|
||||||
|
|
||||||
alias Philomena.Images.Subscription
|
alias Philomena.Images.Subscription
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
|
|
@ -83,4 +83,13 @@ defmodule Philomena.Images.Image do
|
||||||
|> cast(attrs, [])
|
|> cast(attrs, [])
|
||||||
|> validate_required([])
|
|> validate_required([])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def interaction_data(image) do
|
||||||
|
%{
|
||||||
|
score: image.score,
|
||||||
|
faves: image.faves_count,
|
||||||
|
upvotes: image.upvotes_count,
|
||||||
|
downvotes: image.downvotes_count
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
60
lib/philomena/interactions.ex
Normal file
60
lib/philomena/interactions.ex
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
defmodule Philomena.Interactions do
|
||||||
|
import Ecto.Query
|
||||||
|
|
||||||
|
alias Philomena.ImageHides.ImageHide
|
||||||
|
alias Philomena.ImageFaves.ImageFave
|
||||||
|
alias Philomena.ImageVotes.ImageVote
|
||||||
|
alias Philomena.Repo
|
||||||
|
|
||||||
|
def user_interactions(_images, nil),
|
||||||
|
do: []
|
||||||
|
|
||||||
|
def user_interactions(images, user) do
|
||||||
|
ids =
|
||||||
|
images
|
||||||
|
|> Enum.flat_map(fn
|
||||||
|
nil -> []
|
||||||
|
%{id: id} -> [id]
|
||||||
|
enum -> Enum.map(enum, & &1.id)
|
||||||
|
end)
|
||||||
|
|> Enum.uniq()
|
||||||
|
|
||||||
|
hide_interactions =
|
||||||
|
ImageHide
|
||||||
|
|> select([h], %{image_id: h.image_id, user_id: h.user_id, interaction_type: ^"hidden", value: ^""})
|
||||||
|
|> where([h], h.image_id in ^ids)
|
||||||
|
|> where(user_id: ^user.id)
|
||||||
|
|
||||||
|
fave_interactions =
|
||||||
|
ImageFave
|
||||||
|
|> select([f], %{image_id: f.image_id, user_id: f.user_id, interaction_type: ^"faved", value: ^""})
|
||||||
|
|> where([f], f.image_id in ^ids)
|
||||||
|
|> where(user_id: ^user.id)
|
||||||
|
|
||||||
|
upvote_interactions =
|
||||||
|
ImageVote
|
||||||
|
|> select([v], %{image_id: v.image_id, user_id: v.user_id, interaction_type: ^"voted", value: ^"up"})
|
||||||
|
|> where([v], v.image_id in ^ids)
|
||||||
|
|> where(user_id: ^user.id, up: true)
|
||||||
|
|
||||||
|
downvote_interactions =
|
||||||
|
ImageVote
|
||||||
|
|> select([v], %{image_id: v.image_id, user_id: v.user_id, interaction_type: ^"voted", value: ^"down"})
|
||||||
|
|> where([v], v.image_id in ^ids)
|
||||||
|
|> where(user_id: ^user.id, up: false)
|
||||||
|
|
||||||
|
[
|
||||||
|
hide_interactions,
|
||||||
|
fave_interactions,
|
||||||
|
upvote_interactions,
|
||||||
|
downvote_interactions
|
||||||
|
]
|
||||||
|
|> union_all_queries()
|
||||||
|
|> Repo.all()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp union_all_queries([query]),
|
||||||
|
do: query
|
||||||
|
defp union_all_queries([query | rest]),
|
||||||
|
do: query |> union_all(^union_all_queries(rest))
|
||||||
|
end
|
|
@ -1,7 +1,9 @@
|
||||||
defmodule PhilomenaWeb.ActivityController do
|
defmodule PhilomenaWeb.ActivityController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
alias Philomena.{Images, Images.Image, Images.Feature, Comments.Comment, Channels.Channel, Topics.Topic, Forums.Forum}
|
alias Philomena.{Images.Image, ImageFeatures.ImageFeature, Comments.Comment, Channels.Channel, Topics.Topic, Forums.Forum}
|
||||||
|
alias Philomena.Interactions
|
||||||
|
alias Philomena.Images
|
||||||
alias Philomena.Repo
|
alias Philomena.Repo
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
@ -15,8 +17,11 @@ defmodule PhilomenaWeb.ActivityController do
|
||||||
%{
|
%{
|
||||||
query: %{
|
query: %{
|
||||||
bool: %{
|
bool: %{
|
||||||
must_not: filter,
|
must: image_query,
|
||||||
must: image_query
|
must_not: [
|
||||||
|
filter,
|
||||||
|
%{term: %{hidden_from_users: true}}
|
||||||
|
],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sort: %{created_at: :desc}
|
sort: %{created_at: :desc}
|
||||||
|
@ -30,8 +35,11 @@ defmodule PhilomenaWeb.ActivityController do
|
||||||
%{
|
%{
|
||||||
query: %{
|
query: %{
|
||||||
bool: %{
|
bool: %{
|
||||||
must_not: filter,
|
must: %{range: %{first_seen_at: %{gt: "now-3d"}}},
|
||||||
must: %{range: %{first_seen_at: %{gt: "now-3d"}}}
|
must_not: [
|
||||||
|
filter,
|
||||||
|
%{term: %{hidden_from_users: true}}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sort: [%{score: :desc}, %{first_seen_at: :desc}]
|
sort: [%{score: :desc}, %{first_seen_at: :desc}]
|
||||||
|
@ -67,8 +75,11 @@ defmodule PhilomenaWeb.ActivityController do
|
||||||
%{
|
%{
|
||||||
query: %{
|
query: %{
|
||||||
bool: %{
|
bool: %{
|
||||||
must_not: filter,
|
must: watched_query,
|
||||||
must: watched_query
|
must_not: [
|
||||||
|
filter,
|
||||||
|
%{term: %{hidden_from_users: true}}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
sort: %{created_at: :desc}
|
sort: %{created_at: :desc}
|
||||||
|
@ -80,7 +91,7 @@ defmodule PhilomenaWeb.ActivityController do
|
||||||
|
|
||||||
featured_image =
|
featured_image =
|
||||||
Image
|
Image
|
||||||
|> join(:inner, [i], f in Feature, on: [image_id: i.id])
|
|> join(:inner, [i], f in ImageFeature, on: [image_id: i.id])
|
||||||
|> order_by([i, f], desc: f.created_at)
|
|> order_by([i, f], desc: f.created_at)
|
||||||
|> limit(1)
|
|> limit(1)
|
||||||
|> preload([:tags])
|
|> preload([:tags])
|
||||||
|
@ -105,6 +116,12 @@ defmodule PhilomenaWeb.ActivityController do
|
||||||
|> limit(6)
|
|> limit(6)
|
||||||
|> Repo.all()
|
|> Repo.all()
|
||||||
|
|
||||||
|
interactions =
|
||||||
|
Interactions.user_interactions(
|
||||||
|
[images, top_scoring, watched, featured_image],
|
||||||
|
user
|
||||||
|
)
|
||||||
|
|
||||||
render(
|
render(
|
||||||
conn,
|
conn,
|
||||||
"index.html",
|
"index.html",
|
||||||
|
@ -114,7 +131,8 @@ defmodule PhilomenaWeb.ActivityController do
|
||||||
watched: watched,
|
watched: watched,
|
||||||
featured_image: featured_image,
|
featured_image: featured_image,
|
||||||
streams: streams,
|
streams: streams,
|
||||||
topics: topics
|
topics: topics,
|
||||||
|
interactions: interactions
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
60
lib/philomena_web/controllers/image/fave_controller.ex
Normal file
60
lib/philomena_web/controllers/image/fave_controller.ex
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
defmodule PhilomenaWeb.Image.FaveController do
|
||||||
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
|
alias Philomena.{Images, Images.Image}
|
||||||
|
alias Philomena.{ImageFaves, ImageVotes}
|
||||||
|
alias Philomena.Repo
|
||||||
|
alias Ecto.Multi
|
||||||
|
|
||||||
|
plug PhilomenaWeb.Plugs.FilterBannedUsers
|
||||||
|
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
|
||||||
|
|
||||||
|
def create(conn, _params) do
|
||||||
|
user = conn.assigns.current_user
|
||||||
|
image = conn.assigns.image
|
||||||
|
|
||||||
|
Multi.append(
|
||||||
|
ImageFaves.delete_fave_transaction(image, user),
|
||||||
|
ImageFaves.create_fave_transaction(image, user)
|
||||||
|
)
|
||||||
|
|> Multi.append(ImageVotes.delete_vote_transaction(image, user))
|
||||||
|
|> Multi.append(ImageVotes.create_vote_transaction(image, user, true))
|
||||||
|
|> Repo.transaction()
|
||||||
|
|> case do
|
||||||
|
{:ok, _result} ->
|
||||||
|
image =
|
||||||
|
Images.get_image!(image.id)
|
||||||
|
|> Images.reindex_image()
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> json(Image.interaction_data(image))
|
||||||
|
|
||||||
|
_error ->
|
||||||
|
conn
|
||||||
|
|> Plug.Conn.put_status(409)
|
||||||
|
|> json(%{})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, _params) do
|
||||||
|
user = conn.assigns.current_user
|
||||||
|
image = conn.assigns.image
|
||||||
|
|
||||||
|
ImageFaves.delete_fave_transaction(image, user)
|
||||||
|
|> Repo.transaction()
|
||||||
|
|> case do
|
||||||
|
{:ok, _result} ->
|
||||||
|
image =
|
||||||
|
Images.get_image!(image.id)
|
||||||
|
|> Images.reindex_image()
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> json(Image.interaction_data(image))
|
||||||
|
|
||||||
|
_error ->
|
||||||
|
conn
|
||||||
|
|> Plug.Conn.put_status(409)
|
||||||
|
|> json(%{})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
58
lib/philomena_web/controllers/image/hide_controller.ex
Normal file
58
lib/philomena_web/controllers/image/hide_controller.ex
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
defmodule PhilomenaWeb.Image.HideController do
|
||||||
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
|
alias Philomena.{Images, Images.Image}
|
||||||
|
alias Philomena.ImageHides
|
||||||
|
alias Philomena.Repo
|
||||||
|
alias Ecto.Multi
|
||||||
|
|
||||||
|
plug PhilomenaWeb.Plugs.FilterBannedUsers
|
||||||
|
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
|
||||||
|
|
||||||
|
def create(conn, _params) do
|
||||||
|
user = conn.assigns.current_user
|
||||||
|
image = conn.assigns.image
|
||||||
|
|
||||||
|
Multi.append(
|
||||||
|
ImageHides.delete_hide_transaction(image, user),
|
||||||
|
ImageHides.create_hide_transaction(image, user)
|
||||||
|
)
|
||||||
|
|> Repo.transaction()
|
||||||
|
|> case do
|
||||||
|
{:ok, _result} ->
|
||||||
|
image =
|
||||||
|
Images.get_image!(image.id)
|
||||||
|
|> Images.reindex_image()
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> json(Image.interaction_data(image))
|
||||||
|
|
||||||
|
_error ->
|
||||||
|
conn
|
||||||
|
|> Plug.Conn.put_status(409)
|
||||||
|
|> json(%{})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def delete(conn, _params) do
|
||||||
|
user = conn.assigns.current_user
|
||||||
|
image = conn.assigns.image
|
||||||
|
|
||||||
|
ImageHides.delete_hide_transaction(image, user)
|
||||||
|
|> Repo.transaction()
|
||||||
|
|> case do
|
||||||
|
{:ok, _result} ->
|
||||||
|
image =
|
||||||
|
Images.get_image!(image.id)
|
||||||
|
|> Images.reindex_image()
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> json(Image.interaction_data(image))
|
||||||
|
|
||||||
|
_error ->
|
||||||
|
conn
|
||||||
|
|> Plug.Conn.put_status(409)
|
||||||
|
|> json(%{})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,18 +1,58 @@
|
||||||
defmodule PhilomenaWeb.Image.VoteController do
|
defmodule PhilomenaWeb.Image.VoteController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
alias Philomena.Images.Image
|
alias Philomena.{Images, Images.Image}
|
||||||
# alias Philomena.Repo
|
alias Philomena.ImageVotes
|
||||||
# alias Ecto.Multi
|
alias Philomena.Repo
|
||||||
|
alias Ecto.Multi
|
||||||
|
|
||||||
plug PhilomenaWeb.Plugs.FilterBannedUsers
|
plug PhilomenaWeb.Plugs.FilterBannedUsers
|
||||||
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
|
plug :load_and_authorize_resource, model: Image, id_name: "image_id", persisted: true
|
||||||
|
|
||||||
def create(conn, _params) do
|
def create(conn, params) do
|
||||||
|
user = conn.assigns.current_user
|
||||||
|
image = conn.assigns.image
|
||||||
|
|
||||||
|
Multi.append(
|
||||||
|
ImageVotes.delete_vote_transaction(image, user),
|
||||||
|
ImageVotes.create_vote_transaction(image, user, params["up"] == true)
|
||||||
|
)
|
||||||
|
|> Repo.transaction()
|
||||||
|
|> case do
|
||||||
|
{:ok, _result} ->
|
||||||
|
image =
|
||||||
|
Images.get_image!(image.id)
|
||||||
|
|> Images.reindex_image()
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|
|> json(Image.interaction_data(image))
|
||||||
|
|
||||||
|
_error ->
|
||||||
|
conn
|
||||||
|
|> Plug.Conn.put_status(409)
|
||||||
|
|> json(%{})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete(conn, _params) do
|
def delete(conn, _params) do
|
||||||
|
user = conn.assigns.current_user
|
||||||
|
image = conn.assigns.image
|
||||||
|
|
||||||
|
ImageVotes.delete_vote_transaction(image, user)
|
||||||
|
|> Repo.transaction()
|
||||||
|
|> case do
|
||||||
|
{:ok, _result} ->
|
||||||
|
image =
|
||||||
|
Images.get_image!(image.id)
|
||||||
|
|> Images.reindex_image()
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|
|> json(Image.interaction_data(image))
|
||||||
|
|
||||||
|
_error ->
|
||||||
|
conn
|
||||||
|
|> Plug.Conn.put_status(409)
|
||||||
|
|> json(%{})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -2,6 +2,7 @@ defmodule PhilomenaWeb.ImageController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
alias Philomena.{Images.Image, Comments.Comment, Textile.Renderer}
|
alias Philomena.{Images.Image, Comments.Comment, Textile.Renderer}
|
||||||
|
alias Philomena.Interactions
|
||||||
alias Philomena.Repo
|
alias Philomena.Repo
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
|
@ -20,13 +21,18 @@ defmodule PhilomenaWeb.ImageController do
|
||||||
Image |> preload([:tags, :user])
|
Image |> preload([:tags, :user])
|
||||||
)
|
)
|
||||||
|
|
||||||
render(conn, "index.html", images: images)
|
interactions =
|
||||||
|
Interactions.user_interactions(images, conn.assigns.current_user)
|
||||||
|
|
||||||
|
render(conn, "index.html", images: images, interactions: interactions)
|
||||||
end
|
end
|
||||||
|
|
||||||
def show(conn, %{"id" => _id}) do
|
def show(conn, %{"id" => _id}) do
|
||||||
|
image = conn.assigns.image
|
||||||
|
|
||||||
comments =
|
comments =
|
||||||
Comment
|
Comment
|
||||||
|> where(image_id: ^conn.assigns.image.id)
|
|> where(image_id: ^image.id)
|
||||||
|> preload([:image, user: [awards: :badge]])
|
|> preload([:image, user: [awards: :badge]])
|
||||||
|> order_by(desc: :created_at)
|
|> order_by(desc: :created_at)
|
||||||
|> limit(25)
|
|> limit(25)
|
||||||
|
@ -40,9 +46,12 @@ defmodule PhilomenaWeb.ImageController do
|
||||||
%{comments | entries: Enum.zip(comments.entries, rendered)}
|
%{comments | entries: Enum.zip(comments.entries, rendered)}
|
||||||
|
|
||||||
description =
|
description =
|
||||||
%{body: conn.assigns.image.description}
|
%{body: image.description}
|
||||||
|> Renderer.render_one()
|
|> Renderer.render_one()
|
||||||
|
|
||||||
render(conn, "show.html", image: conn.assigns.image, comments: comments, description: description)
|
interactions =
|
||||||
|
Interactions.user_interactions([image], conn.assigns.current_user)
|
||||||
|
|
||||||
|
render(conn, "show.html", image: image, comments: comments, description: description, interactions: interactions)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,13 +2,14 @@ defmodule PhilomenaWeb.SearchController do
|
||||||
use PhilomenaWeb, :controller
|
use PhilomenaWeb, :controller
|
||||||
|
|
||||||
alias Philomena.Images.{Image, Query}
|
alias Philomena.Images.{Image, Query}
|
||||||
|
alias Philomena.Interactions
|
||||||
alias Pow.Plug
|
alias Pow.Plug
|
||||||
|
|
||||||
import Ecto.Query
|
import Ecto.Query
|
||||||
|
|
||||||
def index(conn, params) do
|
def index(conn, params) do
|
||||||
filter = conn.assigns[:compiled_filter]
|
filter = conn.assigns.compiled_filter
|
||||||
user = conn |> Plug.current_user()
|
user = conn.assigns.current_user
|
||||||
|
|
||||||
with {:ok, query} <- Query.compile(user, params["q"]) do
|
with {:ok, query} <- Query.compile(user, params["q"]) do
|
||||||
images =
|
images =
|
||||||
|
@ -21,8 +22,11 @@ defmodule PhilomenaWeb.SearchController do
|
||||||
Image |> preload(:tags)
|
Image |> preload(:tags)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
interactions =
|
||||||
|
Interactions.user_interactions(images, user)
|
||||||
|
|
||||||
conn
|
conn
|
||||||
|> render("index.html", images: images, search_query: params["q"])
|
|> render("index.html", images: images, search_query: params["q"], interactions: interactions)
|
||||||
else
|
else
|
||||||
{:error, msg} ->
|
{:error, msg} ->
|
||||||
conn
|
conn
|
||||||
|
|
|
@ -54,6 +54,11 @@ defmodule PhilomenaWeb.Router do
|
||||||
|
|
||||||
resources "/notifications", NotificationController, only: [:index, :delete]
|
resources "/notifications", NotificationController, only: [:index, :delete]
|
||||||
resources "/conversations", ConversationController, only: [:index, :show]
|
resources "/conversations", ConversationController, only: [:index, :show]
|
||||||
|
resources "/images", ImageController, only: [] do
|
||||||
|
resources "/vote", Image.VoteController, only: [:create, :delete], singleton: true
|
||||||
|
resources "/fave", Image.FaveController, only: [:create, :delete], singleton: true
|
||||||
|
resources "/hide", Image.HideController, only: [:create, :delete], singleton: true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
scope "/", PhilomenaWeb do
|
scope "/", PhilomenaWeb do
|
||||||
|
|
Loading…
Reference in a new issue