Merge branch 'develop' of https://git.pleroma.social/pleroma/pleroma into feature/unrepeats
This commit is contained in:
commit
c5dc7e6e31
|
@ -6,6 +6,9 @@
|
||||||
/uploads
|
/uploads
|
||||||
/test/uploads
|
/test/uploads
|
||||||
|
|
||||||
|
# Prevent committing custom emojis
|
||||||
|
/priv/static/emoji/custom/*
|
||||||
|
|
||||||
# Generated on crash by the VM
|
# Generated on crash by the VM
|
||||||
erl_crash.dump
|
erl_crash.dump
|
||||||
|
|
||||||
|
@ -16,3 +19,6 @@ erl_crash.dump
|
||||||
# secrets files as long as you replace their contents by environment
|
# secrets files as long as you replace their contents by environment
|
||||||
# variables.
|
# variables.
|
||||||
/config/*.secret.exs
|
/config/*.secret.exs
|
||||||
|
|
||||||
|
# Database setup file, some may forget to delete it
|
||||||
|
/config/setup_db.psql
|
||||||
|
|
|
@ -9,6 +9,7 @@ variables:
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
|
- lint
|
||||||
- test
|
- test
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
|
@ -18,6 +19,11 @@ before_script:
|
||||||
- MIX_ENV=test mix ecto.create
|
- MIX_ENV=test mix ecto.create
|
||||||
- MIX_ENV=test mix ecto.migrate
|
- MIX_ENV=test mix ecto.migrate
|
||||||
|
|
||||||
|
lint:
|
||||||
|
stage: lint
|
||||||
|
script:
|
||||||
|
- MIX_ENV=test mix format --check-formatted
|
||||||
|
|
||||||
unit-testing:
|
unit-testing:
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
|
|
|
@ -9,20 +9,6 @@ def run(_) do
|
||||||
name = IO.gets("What is the name of your instance? (e.g. Pleroma/Soykaf): ") |> String.trim()
|
name = IO.gets("What is the name of your instance? (e.g. Pleroma/Soykaf): ") |> String.trim()
|
||||||
email = IO.gets("What's your admin email address: ") |> String.trim()
|
email = IO.gets("What's your admin email address: ") |> String.trim()
|
||||||
|
|
||||||
mediaproxy =
|
|
||||||
IO.gets("Do you want to activate the mediaproxy? (y/N): ")
|
|
||||||
|> String.trim()
|
|
||||||
|> String.downcase()
|
|
||||||
|> String.starts_with?("y")
|
|
||||||
|
|
||||||
proxy_url =
|
|
||||||
if mediaproxy do
|
|
||||||
IO.gets("What is the mediaproxy's URL? (e.g. https://cache.example.com): ")
|
|
||||||
|> String.trim()
|
|
||||||
else
|
|
||||||
"https://cache.example.com"
|
|
||||||
end
|
|
||||||
|
|
||||||
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
|
secret = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
|
||||||
dbpass = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
|
dbpass = :crypto.strong_rand_bytes(64) |> Base.encode64() |> binary_part(0, 64)
|
||||||
|
|
||||||
|
@ -35,8 +21,6 @@ def run(_) do
|
||||||
email: email,
|
email: email,
|
||||||
name: name,
|
name: name,
|
||||||
secret: secret,
|
secret: secret,
|
||||||
mediaproxy: mediaproxy,
|
|
||||||
proxy_url: proxy_url,
|
|
||||||
dbpass: dbpass
|
dbpass: dbpass
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
defmodule Mix.Tasks.RmUser do
|
defmodule Mix.Tasks.RmUser do
|
||||||
use Mix.Task
|
use Mix.Task
|
||||||
import Mix.Ecto
|
import Mix.Ecto
|
||||||
alias Pleroma.User
|
alias Pleroma.{User, Repo}
|
||||||
|
|
||||||
@shortdoc "Permanently delete a user"
|
@shortdoc "Permanently delete a user"
|
||||||
def run([nickname]) do
|
def run([nickname]) do
|
||||||
ensure_started(Repo, [])
|
Mix.Task.run("app.start")
|
||||||
|
|
||||||
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
with %User{local: true} = user <- User.get_by_nickname(nickname) do
|
||||||
user.delete()
|
User.delete(user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,9 +11,9 @@ config :pleroma, :instance,
|
||||||
registrations_open: true
|
registrations_open: true
|
||||||
|
|
||||||
config :pleroma, :media_proxy,
|
config :pleroma, :media_proxy,
|
||||||
enabled: <%= mediaproxy %>,
|
enabled: false,
|
||||||
redirect_on_failure: true,
|
redirect_on_failure: true
|
||||||
base_url: "<%= proxy_url %>"
|
#base_url: "https://cache.pleroma.social"
|
||||||
|
|
||||||
# Configure your database
|
# Configure your database
|
||||||
config :pleroma, Pleroma.Repo,
|
config :pleroma, Pleroma.Repo,
|
||||||
|
|
|
@ -250,6 +250,13 @@ def get_by_nickname(nickname) do
|
||||||
Repo.get_by(User, nickname: nickname)
|
Repo.get_by(User, nickname: nickname)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get_by_nickname_or_email(nickname_or_email) do
|
||||||
|
case user = Repo.get_by(User, nickname: nickname_or_email) do
|
||||||
|
%User{} -> user
|
||||||
|
nil -> Repo.get_by(User, email: nickname_or_email)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_cached_user_info(user) do
|
def get_cached_user_info(user) do
|
||||||
key = "user_info:#{user.id}"
|
key = "user_info:#{user.id}"
|
||||||
Cachex.get!(:user_cache, key, fallback: fn _ -> user_info(user) end)
|
Cachex.get!(:user_cache, key, fallback: fn _ -> user_info(user) end)
|
||||||
|
|
|
@ -61,6 +61,7 @@ def to_for_user_and_mentions(user, mentions, inReplyTo, "direct") do
|
||||||
|
|
||||||
def make_content_html(status, mentions, attachments, tags, no_attachment_links \\ false) do
|
def make_content_html(status, mentions, attachments, tags, no_attachment_links \\ false) do
|
||||||
status
|
status
|
||||||
|
|> String.replace("\r", "")
|
||||||
|> format_input(mentions, tags)
|
|> format_input(mentions, tags)
|
||||||
|> maybe_add_attachments(attachments, no_attachment_links)
|
|> maybe_add_attachments(attachments, no_attachment_links)
|
||||||
end
|
end
|
||||||
|
|
|
@ -700,7 +700,7 @@ defp get_or_make_app() do
|
||||||
end
|
end
|
||||||
|
|
||||||
def login_post(conn, %{"authorization" => %{"name" => name, "password" => password}}) do
|
def login_post(conn, %{"authorization" => %{"name" => name, "password" => password}}) do
|
||||||
with %User{} = user <- User.get_cached_by_nickname(name),
|
with %User{} = user <- User.get_by_nickname_or_email(name),
|
||||||
true <- Pbkdf2.checkpw(password, user.password_hash),
|
true <- Pbkdf2.checkpw(password, user.password_hash),
|
||||||
{:ok, app} <- get_or_make_app(),
|
{:ok, app} <- get_or_make_app(),
|
||||||
{:ok, auth} <- Authorization.create_authorization(app, user),
|
{:ok, auth} <- Authorization.create_authorization(app, user),
|
||||||
|
|
|
@ -29,7 +29,7 @@ def create_authorization(conn, %{
|
||||||
"redirect_uri" => redirect_uri
|
"redirect_uri" => redirect_uri
|
||||||
} = params
|
} = params
|
||||||
}) do
|
}) do
|
||||||
with %User{} = user <- User.get_cached_by_nickname(name),
|
with %User{} = user <- User.get_by_nickname_or_email(name),
|
||||||
true <- Pbkdf2.checkpw(password, user.password_hash),
|
true <- Pbkdf2.checkpw(password, user.password_hash),
|
||||||
%App{} = app <- Repo.get_by(App, client_id: client_id),
|
%App{} = app <- Repo.get_by(App, client_id: client_id),
|
||||||
{:ok, auth} <- Authorization.create_authorization(app, user) do
|
{:ok, auth} <- Authorization.create_authorization(app, user) do
|
||||||
|
|
|
@ -213,6 +213,7 @@ def user_fetcher(username) do
|
||||||
get("/statuses/friends_timeline", TwitterAPI.Controller, :friends_timeline)
|
get("/statuses/friends_timeline", TwitterAPI.Controller, :friends_timeline)
|
||||||
get("/statuses/mentions", TwitterAPI.Controller, :mentions_timeline)
|
get("/statuses/mentions", TwitterAPI.Controller, :mentions_timeline)
|
||||||
get("/statuses/mentions_timeline", TwitterAPI.Controller, :mentions_timeline)
|
get("/statuses/mentions_timeline", TwitterAPI.Controller, :mentions_timeline)
|
||||||
|
get("/qvitter/statuses/notifications", TwitterAPI.Controller, :notifications)
|
||||||
|
|
||||||
post("/statuses/update", TwitterAPI.Controller, :status_update)
|
post("/statuses/update", TwitterAPI.Controller, :status_update)
|
||||||
post("/statuses/retweet/:id", TwitterAPI.Controller, :retweet)
|
post("/statuses/retweet/:id", TwitterAPI.Controller, :retweet)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<h2><%= @error %></h2>
|
<h2><%= @error %></h2>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= form_for @conn, mastodon_api_path(@conn, :login), [as: "authorization"], fn f -> %>
|
<%= form_for @conn, mastodon_api_path(@conn, :login), [as: "authorization"], fn f -> %>
|
||||||
<%= text_input f, :name, placeholder: "Username" %>
|
<%= text_input f, :name, placeholder: "Username or email" %>
|
||||||
<br>
|
<br>
|
||||||
<%= password_input f, :password, placeholder: "Password" %>
|
<%= password_input f, :password, placeholder: "Password" %>
|
||||||
<br>
|
<br>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
|
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
|
||||||
<h2>OAuth Authorization</h2>
|
<h2>OAuth Authorization</h2>
|
||||||
<%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %>
|
<%= form_for @conn, o_auth_path(@conn, :authorize), [as: "authorization"], fn f -> %>
|
||||||
<%= label f, :name, "Name" %>
|
<%= label f, :name, "Name or email" %>
|
||||||
<%= text_input f, :name %>
|
<%= text_input f, :name %>
|
||||||
<br>
|
<br>
|
||||||
<%= label f, :password, "Password" %>
|
<%= label f, :password, "Password" %>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
defmodule Pleroma.Web.TwitterAPI.Controller do
|
defmodule Pleroma.Web.TwitterAPI.Controller do
|
||||||
use Pleroma.Web, :controller
|
use Pleroma.Web, :controller
|
||||||
alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView}
|
alias Pleroma.Web.TwitterAPI.{TwitterAPI, UserView, ActivityView, NotificationView}
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.{Repo, Activity, User}
|
alias Pleroma.{Repo, Activity, User, Notification}
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Ecto.Changeset
|
alias Ecto.Changeset
|
||||||
|
|
||||||
|
@ -119,6 +119,13 @@ def mentions_timeline(%{assigns: %{user: user}} = conn, params) do
|
||||||
|> render(ActivityView, "index.json", %{activities: activities, for: user})
|
|> render(ActivityView, "index.json", %{activities: activities, for: user})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def notifications(%{assigns: %{user: user}} = conn, params) do
|
||||||
|
notifications = Notification.for_user(user, params)
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> render(NotificationView, "notification.json", %{notifications: notifications, for: user})
|
||||||
|
end
|
||||||
|
|
||||||
def follow(%{assigns: %{user: user}} = conn, params) do
|
def follow(%{assigns: %{user: user}} = conn, params) do
|
||||||
case TwitterAPI.follow(user, params) do
|
case TwitterAPI.follow(user, params) do
|
||||||
{:ok, user, followed, _activity} ->
|
{:ok, user, followed, _activity} ->
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
defmodule Pleroma.Web.TwitterAPI.NotificationView do
|
||||||
|
use Pleroma.Web, :view
|
||||||
|
alias Pleroma.{Notification, User}
|
||||||
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
|
alias Pleroma.Web.MediaProxy
|
||||||
|
alias Pleroma.Web.TwitterAPI.UserView
|
||||||
|
alias Pleroma.Web.TwitterAPI.ActivityView
|
||||||
|
|
||||||
|
defp get_user(ap_id, opts) do
|
||||||
|
cond do
|
||||||
|
user = opts[:users][ap_id] ->
|
||||||
|
user
|
||||||
|
|
||||||
|
String.ends_with?(ap_id, "/followers") ->
|
||||||
|
nil
|
||||||
|
|
||||||
|
ap_id == "https://www.w3.org/ns/activitystreams#Public" ->
|
||||||
|
nil
|
||||||
|
|
||||||
|
true ->
|
||||||
|
User.get_cached_by_ap_id(ap_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def render("notification.json", %{notifications: notifications, for: user}) do
|
||||||
|
render_many(
|
||||||
|
notifications,
|
||||||
|
Pleroma.Web.TwitterAPI.NotificationView,
|
||||||
|
"notification.json",
|
||||||
|
for: user
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def render(
|
||||||
|
"notification.json",
|
||||||
|
%{
|
||||||
|
notification: %Notification{
|
||||||
|
id: id,
|
||||||
|
seen: seen,
|
||||||
|
activity: activity,
|
||||||
|
inserted_at: created_at
|
||||||
|
},
|
||||||
|
for: user
|
||||||
|
} = opts
|
||||||
|
) do
|
||||||
|
ntype =
|
||||||
|
case activity.data["type"] do
|
||||||
|
"Create" -> "mention"
|
||||||
|
"Like" -> "like"
|
||||||
|
"Announce" -> "repeat"
|
||||||
|
"Follow" -> "follow"
|
||||||
|
end
|
||||||
|
|
||||||
|
from = get_user(activity.data["actor"], opts)
|
||||||
|
|
||||||
|
%{
|
||||||
|
"id" => id,
|
||||||
|
"ntype" => ntype,
|
||||||
|
"notice" => ActivityView.render("activity.json", %{activity: activity, for: user}),
|
||||||
|
"from_profile" => UserView.render("show.json", %{user: from, for: user}),
|
||||||
|
"is_seen" => if(seen, do: 1, else: 0),
|
||||||
|
"created_at" => created_at |> Utils.format_naive_asctime()
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -1 +1 @@
|
||||||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>Pleroma</title><link rel=stylesheet href=/static/font/css/fontello.css><link rel=stylesheet href=/static/font/css/animation.css><link href=/static/css/app.b96f1ae65bf0fc0f0564dbc7f12febfd.css rel=stylesheet></head><body style="display: none"><div id=app></div><script type=text/javascript src=/static/js/manifest.c0906490430c3def2aa2.js></script><script type=text/javascript src=/static/js/vendor.07fdc75424ae7c00c949.js></script><script type=text/javascript src=/static/js/app.be2883b7ed550f51c41d.js></script></body></html>
|
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>Pleroma</title><link rel=stylesheet href=/static/font/css/fontello.css><link rel=stylesheet href=/static/font/css/animation.css><link href=/static/css/app.6c8da1b0ace79ad8881a0e5e716ec818.css rel=stylesheet></head><body style="display: none"><div id=app></div><script type=text/javascript src=/static/js/manifest.f80ee14f782f05d77e39.js></script><script type=text/javascript src=/static/js/vendor.ef2aee0b2db579c3a86a.js></script><script type=text/javascript src=/static/js/app.64c4246ae54f6439cb69.js></script></body></html>
|
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -107,6 +107,54 @@
|
||||||
"css": "attach",
|
"css": "attach",
|
||||||
"code": 59402,
|
"code": 59402,
|
||||||
"src": "entypo"
|
"src": "entypo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "e15f0d620a7897e2035c18c80142f6d9",
|
||||||
|
"css": "link-ext",
|
||||||
|
"code": 61582,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "381da2c2f7fd51f8de877c044d7f439d",
|
||||||
|
"css": "picture",
|
||||||
|
"code": 59403,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "872d9516df93eb6b776cc4d94bd97dac",
|
||||||
|
"css": "video",
|
||||||
|
"code": 59404,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "399ef63b1e23ab1b761dfbb5591fa4da",
|
||||||
|
"css": "right-open",
|
||||||
|
"code": 59405,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "d870630ff8f81e6de3958ecaeac532f2",
|
||||||
|
"css": "left-open",
|
||||||
|
"code": 59406,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "fe6697b391355dec12f3d86d6d490397",
|
||||||
|
"css": "up-open",
|
||||||
|
"code": 59407,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "9c1376672bb4f1ed616fdd78a23667e9",
|
||||||
|
"css": "comment-empty",
|
||||||
|
"code": 61669,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "cd21cbfb28ad4d903cede582157f65dc",
|
||||||
|
"css": "bell",
|
||||||
|
"code": 59408,
|
||||||
|
"src": "fontawesome"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -229,11 +229,11 @@ body {
|
||||||
}
|
}
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'fontello';
|
font-family: 'fontello';
|
||||||
src: url('./font/fontello.eot?97388161');
|
src: url('./font/fontello.eot?34497073');
|
||||||
src: url('./font/fontello.eot?97388161#iefix') format('embedded-opentype'),
|
src: url('./font/fontello.eot?34497073#iefix') format('embedded-opentype'),
|
||||||
url('./font/fontello.woff?97388161') format('woff'),
|
url('./font/fontello.woff?34497073') format('woff'),
|
||||||
url('./font/fontello.ttf?97388161') format('truetype'),
|
url('./font/fontello.ttf?34497073') format('truetype'),
|
||||||
url('./font/fontello.svg?97388161#fontello') format('svg');
|
url('./font/fontello.svg?34497073#fontello') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
@ -313,11 +313,23 @@ body {
|
||||||
<div class="the-icons span3" title="Code: 0xe808"><i class="demo-icon icon-logout"></i> <span class="i-name">icon-logout</span><span class="i-code">0xe808</span></div>
|
<div class="the-icons span3" title="Code: 0xe808"><i class="demo-icon icon-logout"></i> <span class="i-name">icon-logout</span><span class="i-code">0xe808</span></div>
|
||||||
<div class="the-icons span3" title="Code: 0xe809"><i class="demo-icon icon-down-open"></i> <span class="i-name">icon-down-open</span><span class="i-code">0xe809</span></div>
|
<div class="the-icons span3" title="Code: 0xe809"><i class="demo-icon icon-down-open"></i> <span class="i-name">icon-down-open</span><span class="i-code">0xe809</span></div>
|
||||||
<div class="the-icons span3" title="Code: 0xe80a"><i class="demo-icon icon-attach"></i> <span class="i-name">icon-attach</span><span class="i-code">0xe80a</span></div>
|
<div class="the-icons span3" title="Code: 0xe80a"><i class="demo-icon icon-attach"></i> <span class="i-name">icon-attach</span><span class="i-code">0xe80a</span></div>
|
||||||
<div class="the-icons span3" title="Code: 0xe832"><i class="demo-icon icon-spin3 animate-spin"></i> <span class="i-name">icon-spin3</span><span class="i-code">0xe832</span></div>
|
<div class="the-icons span3" title="Code: 0xe80b"><i class="demo-icon icon-picture"></i> <span class="i-name">icon-picture</span><span class="i-code">0xe80b</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<div class="the-icons span3" title="Code: 0xe80c"><i class="demo-icon icon-video"></i> <span class="i-name">icon-video</span><span class="i-code">0xe80c</span></div>
|
||||||
|
<div class="the-icons span3" title="Code: 0xe80d"><i class="demo-icon icon-right-open"></i> <span class="i-name">icon-right-open</span><span class="i-code">0xe80d</span></div>
|
||||||
|
<div class="the-icons span3" title="Code: 0xe80e"><i class="demo-icon icon-left-open"></i> <span class="i-name">icon-left-open</span><span class="i-code">0xe80e</span></div>
|
||||||
|
<div class="the-icons span3" title="Code: 0xe80f"><i class="demo-icon icon-up-open"></i> <span class="i-name">icon-up-open</span><span class="i-code">0xe80f</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="the-icons span3" title="Code: 0xe810"><i class="demo-icon icon-bell"></i> <span class="i-name">icon-bell</span><span class="i-code">0xe810</span></div>
|
||||||
|
<div class="the-icons span3" title="Code: 0xe832"><i class="demo-icon icon-spin3 animate-spin"></i> <span class="i-name">icon-spin3</span><span class="i-code">0xe832</span></div>
|
||||||
<div class="the-icons span3" title="Code: 0xe834"><i class="demo-icon icon-spin4 animate-spin"></i> <span class="i-name">icon-spin4</span><span class="i-code">0xe834</span></div>
|
<div class="the-icons span3" title="Code: 0xe834"><i class="demo-icon icon-spin4 animate-spin"></i> <span class="i-name">icon-spin4</span><span class="i-code">0xe834</span></div>
|
||||||
|
<div class="the-icons span3" title="Code: 0xf08e"><i class="demo-icon icon-link-ext"></i> <span class="i-name">icon-link-ext</span><span class="i-code">0xf08e</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
<div class="the-icons span3" title="Code: 0xf0c9"><i class="demo-icon icon-menu"></i> <span class="i-name">icon-menu</span><span class="i-code">0xf0c9</span></div>
|
<div class="the-icons span3" title="Code: 0xf0c9"><i class="demo-icon icon-menu"></i> <span class="i-name">icon-menu</span><span class="i-code">0xf0c9</span></div>
|
||||||
|
<div class="the-icons span3" title="Code: 0xf0e5"><i class="demo-icon icon-comment-empty"></i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xf0e5</span></div>
|
||||||
<div class="the-icons span3" title="Code: 0xf112"><i class="demo-icon icon-reply"></i> <span class="i-name">icon-reply</span><span class="i-code">0xf112</span></div>
|
<div class="the-icons span3" title="Code: 0xf112"><i class="demo-icon icon-reply"></i> <span class="i-name">icon-reply</span><span class="i-code">0xf112</span></div>
|
||||||
<div class="the-icons span3" title="Code: 0xf1e5"><i class="demo-icon icon-binoculars"></i> <span class="i-name">icon-binoculars</span><span class="i-code">0xf1e5</span></div>
|
<div class="the-icons span3" title="Code: 0xf1e5"><i class="demo-icon icon-binoculars"></i> <span class="i-name">icon-binoculars</span><span class="i-code">0xf1e5</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Binary file not shown.
|
@ -28,12 +28,28 @@
|
||||||
|
|
||||||
<glyph glyph-name="attach" unicode="" d="M244-140q-102 0-170 72-72 70-74 166t84 190l496 496q80 80 174 54 44-12 79-47t47-79q26-96-54-176l-474-474q-40-40-88-46-48-4-80 28-30 24-27 74t47 92l332 334q24 26 50 0t0-50l-332-332q-44-44-20-70 12-8 24-6 24 4 46 26l474 474q50 50 34 108-16 60-76 76-54 14-108-36l-494-494q-66-76-64-143t52-117q50-48 117-50t141 62l496 494q24 24 50 0 26-22 0-48l-496-496q-82-82-186-82z" horiz-adv-x="939" />
|
<glyph glyph-name="attach" unicode="" d="M244-140q-102 0-170 72-72 70-74 166t84 190l496 496q80 80 174 54 44-12 79-47t47-79q26-96-54-176l-474-474q-40-40-88-46-48-4-80 28-30 24-27 74t47 92l332 334q24 26 50 0t0-50l-332-332q-44-44-20-70 12-8 24-6 24 4 46 26l474 474q50 50 34 108-16 60-76 76-54 14-108-36l-494-494q-66-76-64-143t52-117q50-48 117-50t141 62l496 494q24 24 50 0 26-22 0-48l-496-496q-82-82-186-82z" horiz-adv-x="939" />
|
||||||
|
|
||||||
|
<glyph glyph-name="picture" unicode="" d="M357 529q0-45-31-76t-76-32-76 32-31 76 31 76 76 31 76-31 31-76z m572-215v-250h-786v107l178 179 90-89 285 285z m53 393h-893q-7 0-12-5t-6-13v-678q0-7 6-13t12-5h893q7 0 13 5t5 13v678q0 8-5 13t-13 5z m89-18v-678q0-37-26-63t-63-27h-893q-36 0-63 27t-26 63v678q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1071.4" />
|
||||||
|
|
||||||
|
<glyph glyph-name="video" unicode="" d="M214-43v72q0 14-10 25t-25 10h-72q-14 0-25-10t-11-25v-72q0-14 11-25t25-11h72q14 0 25 11t10 25z m0 214v72q0 14-10 25t-25 11h-72q-14 0-25-11t-11-25v-72q0-14 11-25t25-10h72q14 0 25 10t10 25z m0 215v71q0 15-10 25t-25 11h-72q-14 0-25-11t-11-25v-71q0-15 11-25t25-11h72q14 0 25 11t10 25z m572-429v286q0 14-11 25t-25 11h-429q-14 0-25-11t-10-25v-286q0-14 10-25t25-11h429q15 0 25 11t11 25z m-572 643v71q0 15-10 26t-25 10h-72q-14 0-25-10t-11-26v-71q0-14 11-25t25-11h72q14 0 25 11t10 25z m786-643v72q0 14-11 25t-25 10h-71q-15 0-25-10t-11-25v-72q0-14 11-25t25-11h71q15 0 25 11t11 25z m-214 429v285q0 15-11 26t-25 10h-429q-14 0-25-10t-10-26v-285q0-15 10-25t25-11h429q15 0 25 11t11 25z m214-215v72q0 14-11 25t-25 11h-71q-15 0-25-11t-11-25v-72q0-14 11-25t25-10h71q15 0 25 10t11 25z m0 215v71q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-71q0-15 11-25t25-11h71q15 0 25 11t11 25z m0 214v71q0 15-11 26t-25 10h-71q-15 0-25-10t-11-26v-71q0-14 11-25t25-11h71q15 0 25 11t11 25z m71 89v-750q0-37-26-63t-63-26h-893q-36 0-63 26t-26 63v750q0 37 26 63t63 27h893q37 0 63-27t26-63z" horiz-adv-x="1071.4" />
|
||||||
|
|
||||||
|
<glyph glyph-name="right-open" unicode="" d="M618 361l-414-415q-11-10-25-10t-25 10l-93 93q-11 11-11 25t11 25l296 297-296 296q-11 11-11 25t11 25l93 93q10 11 25 11t25-11l414-414q10-11 10-25t-10-25z" horiz-adv-x="714.3" />
|
||||||
|
|
||||||
|
<glyph glyph-name="left-open" unicode="" d="M654 682l-297-296 297-297q10-10 10-25t-10-25l-93-93q-11-10-25-10t-25 10l-414 415q-11 10-11 25t11 25l414 414q10 11 25 11t25-11l93-93q10-10 10-25t-10-25z" horiz-adv-x="714.3" />
|
||||||
|
|
||||||
|
<glyph glyph-name="up-open" unicode="" d="M939 107l-92-92q-11-10-26-10t-25 10l-296 297-296-297q-11-10-25-10t-25 10l-93 92q-11 11-11 26t11 25l414 414q11 10 25 10t25-10l414-414q11-11 11-25t-11-26z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
|
<glyph glyph-name="bell" unicode="" d="M509-96q0 8-9 8-33 0-57 24t-23 57q0 9-9 9t-9-9q0-41 29-70t69-28q9 0 9 9z m-372 160h726q-149 168-149 465 0 28-13 58t-39 58-67 45-95 17-95-17-67-45-39-58-13-58q0-297-149-465z m827 0q0-29-21-50t-50-21h-250q0-59-42-101t-101-42-101 42-42 101h-250q-29 0-50 21t-21 50q28 24 51 49t47 67 42 89 27 115 11 145q0 84 66 157t171 89q-5 10-5 21 0 23 16 38t38 16 38-16 16-38q0-11-5-21 106-16 171-89t66-157q0-78 11-145t28-115 41-89 48-67 50-49z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
<glyph glyph-name="spin3" unicode="" d="M494 850c-266 0-483-210-494-472-1-19 13-20 13-20l84 0c16 0 19 10 19 18 10 199 176 358 378 358 107 0 205-45 273-118l-58-57c-11-12-11-27 5-31l247-50c21-5 46 11 37 44l-58 227c-2 9-16 22-29 13l-65-60c-89 91-214 148-352 148z m409-508c-16 0-19-10-19-18-10-199-176-358-377-358-108 0-205 45-274 118l59 57c10 12 10 27-5 31l-248 50c-21 5-46-11-37-44l58-227c2-9 16-22 30-13l64 60c89-91 214-148 353-148 265 0 482 210 493 473 1 18-13 19-13 19l-84 0z" horiz-adv-x="1000" />
|
<glyph glyph-name="spin3" unicode="" d="M494 850c-266 0-483-210-494-472-1-19 13-20 13-20l84 0c16 0 19 10 19 18 10 199 176 358 378 358 107 0 205-45 273-118l-58-57c-11-12-11-27 5-31l247-50c21-5 46 11 37 44l-58 227c-2 9-16 22-29 13l-65-60c-89 91-214 148-352 148z m409-508c-16 0-19-10-19-18-10-199-176-358-377-358-108 0-205 45-274 118l59 57c10 12 10 27-5 31l-248 50c-21 5-46-11-37-44l58-227c2-9 16-22 30-13l64 60c89-91 214-148 353-148 265 0 482 210 493 473 1 18-13 19-13 19l-84 0z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
<glyph glyph-name="spin4" unicode="" d="M498 850c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" />
|
<glyph glyph-name="spin4" unicode="" d="M498 850c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" />
|
||||||
|
|
||||||
|
<glyph glyph-name="link-ext" unicode="" d="M786 332v-178q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h393q7 0 12-5t5-13v-36q0-8-5-13t-12-5h-393q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v178q0 8 5 13t13 5h36q8 0 13-5t5-13z m214 482v-285q0-15-11-25t-25-11-25 11l-98 98-364-364q-5-6-13-6t-12 6l-64 64q-6 5-6 12t6 13l364 364-98 98q-11 11-11 25t11 25 25 11h285q15 0 25-11t11-25z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
<glyph glyph-name="menu" unicode="" d="M857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-14-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
|
<glyph glyph-name="menu" unicode="" d="M857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-14-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
|
||||||
|
|
||||||
|
<glyph glyph-name="comment-empty" unicode="" d="M500 636q-114 0-213-39t-157-105-59-142q0-62 40-119t113-98l48-28-15-53q-13-51-39-97 85 36 154 96l24 21 32-3q38-5 72-5 114 0 213 39t157 105 59 142-59 142-157 105-213 39z m500-286q0-97-67-179t-182-130-251-48q-39 0-81 4-110-97-257-135-27-8-63-12h-3q-8 0-15 6t-9 15v1q-2 2 0 6t1 6 2 5l4 5t4 5 4 5q4 5 17 19t20 22 17 22 18 28 15 33 15 42q-88 50-138 123t-51 157q0 97 67 179t182 130 251 48 251-48 182-130 67-179z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
<glyph glyph-name="reply" unicode="" d="M1000 225q0-93-71-252-1-4-6-13t-7-17-7-12q-7-10-16-10-8 0-13 6t-5 14q0 5 1 15t2 13q3 38 3 69 0 56-10 101t-27 77-45 56-59 39-74 24-86 12-98 3h-125v-143q0-14-10-25t-26-11-25 11l-285 286q-11 10-11 25t11 25l285 286q11 10 25 10t26-10 10-25v-143h125q398 0 488-225 30-75 30-186z" horiz-adv-x="1000" />
|
<glyph glyph-name="reply" unicode="" d="M1000 225q0-93-71-252-1-4-6-13t-7-17-7-12q-7-10-16-10-8 0-13 6t-5 14q0 5 1 15t2 13q3 38 3 69 0 56-10 101t-27 77-45 56-59 39-74 24-86 12-98 3h-125v-143q0-14-10-25t-26-11-25 11l-285 286q-11 10-11 25t11 25l285 286q11 10 25 10t26-10 10-25v-143h125q398 0 488-225 30-75 30-186z" horiz-adv-x="1000" />
|
||||||
|
|
||||||
<glyph glyph-name="binoculars" unicode="" d="M393 671v-428q0-15-11-25t-25-11v-321q0-15-10-25t-26-11h-285q-15 0-25 11t-11 25v285l139 488q4 12 17 12h237z m178 0v-392h-142v392h142z m429-500v-285q0-15-11-25t-25-11h-285q-15 0-25 11t-11 25v321q-15 0-25 11t-11 25v428h237q13 0 17-12z m-589 661v-125h-197v125q0 8 5 13t13 5h161q8 0 13-5t5-13z m375 0v-125h-197v125q0 8 5 13t13 5h161q8 0 13-5t5-13z" horiz-adv-x="1000" />
|
<glyph glyph-name="binoculars" unicode="" d="M393 671v-428q0-15-11-25t-25-11v-321q0-15-10-25t-26-11h-285q-15 0-25 11t-11 25v285l139 488q4 12 17 12h237z m178 0v-392h-142v392h142z m429-500v-285q0-15-11-25t-25-11h-285q-15 0-25 11t-11 25v321q-15 0-25 11t-11 25v428h237q13 0 17-12z m-589 661v-125h-197v125q0 8 5 13t13 5h161q8 0 13-5t5-13z m375 0v-125h-197v125q0 8 5 13t13 5h161q8 0 13-5t5-13z" horiz-adv-x="1000" />
|
||||||
|
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2,9 +2,10 @@ defmodule Pleroma.Web.TwitterAPI.ControllerTest do
|
||||||
use Pleroma.Web.ConnCase
|
use Pleroma.Web.ConnCase
|
||||||
alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter
|
alias Pleroma.Web.TwitterAPI.Representers.ActivityRepresenter
|
||||||
alias Pleroma.Builders.{ActivityBuilder, UserBuilder}
|
alias Pleroma.Builders.{ActivityBuilder, UserBuilder}
|
||||||
alias Pleroma.{Repo, Activity, User, Object}
|
alias Pleroma.{Repo, Activity, User, Object, Notification}
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.TwitterAPI.UserView
|
alias Pleroma.Web.TwitterAPI.UserView
|
||||||
|
alias Pleroma.Web.TwitterAPI.NotificationView
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
|
|
||||||
|
@ -247,6 +248,35 @@ test "with credentials", %{conn: conn, user: current_user} do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "GET /api/qvitter/statuses/notifications.json" do
|
||||||
|
setup [:valid_user]
|
||||||
|
|
||||||
|
test "without valid credentials", %{conn: conn} do
|
||||||
|
conn = get(conn, "/api/qvitter/statuses/notifications.json")
|
||||||
|
assert json_response(conn, 403) == %{"error" => "Invalid credentials."}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "with credentials", %{conn: conn, user: current_user} do
|
||||||
|
{:ok, activity} =
|
||||||
|
ActivityBuilder.insert(%{"to" => [current_user.ap_id]}, %{user: current_user})
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> with_credentials(current_user.nickname, "test")
|
||||||
|
|> get("/api/qvitter/statuses/notifications.json")
|
||||||
|
|
||||||
|
response = json_response(conn, 200)
|
||||||
|
|
||||||
|
assert length(response) == 1
|
||||||
|
|
||||||
|
assert response ==
|
||||||
|
NotificationView.render("notification.json", %{
|
||||||
|
notifications: Notification.for_user(current_user),
|
||||||
|
for: current_user
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "GET /statuses/user_timeline.json" do
|
describe "GET /statuses/user_timeline.json" do
|
||||||
setup [:valid_user]
|
setup [:valid_user]
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
defmodule Pleroma.Web.TwitterAPI.NotificationViewTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
alias Pleroma.{User, Notification}
|
||||||
|
alias Pleroma.Web.TwitterAPI.TwitterAPI
|
||||||
|
alias Pleroma.Web.TwitterAPI.NotificationView
|
||||||
|
alias Pleroma.Web.TwitterAPI.UserView
|
||||||
|
alias Pleroma.Web.TwitterAPI.ActivityView
|
||||||
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Builders.UserBuilder
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
setup do
|
||||||
|
user = insert(:user, bio: "<span>Here's some html</span>")
|
||||||
|
[user: user]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "A follow notification" do
|
||||||
|
note_activity = insert(:note_activity)
|
||||||
|
user = User.get_cached_by_ap_id(note_activity.data["actor"])
|
||||||
|
follower = insert(:user)
|
||||||
|
|
||||||
|
{:ok, follower} = User.follow(follower, user)
|
||||||
|
{:ok, activity} = ActivityPub.follow(follower, user)
|
||||||
|
Cachex.set(:user_cache, "user_info:#{user.id}", User.user_info(Repo.get!(User, user.id)))
|
||||||
|
[follow_notif] = Notification.for_user(user)
|
||||||
|
|
||||||
|
represented = %{
|
||||||
|
"created_at" => follow_notif.inserted_at |> Utils.format_naive_asctime(),
|
||||||
|
"from_profile" => UserView.render("show.json", %{user: follower, for: user}),
|
||||||
|
"id" => follow_notif.id,
|
||||||
|
"is_seen" => 0,
|
||||||
|
"notice" => ActivityView.render("activity.json", %{activity: activity, for: user}),
|
||||||
|
"ntype" => "follow"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert represented ==
|
||||||
|
NotificationView.render("notification.json", %{notification: follow_notif, for: user})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "A mention notification" do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} =
|
||||||
|
TwitterAPI.create_status(other_user, %{"status" => "Päivää, @#{user.nickname}"})
|
||||||
|
|
||||||
|
[notification] = Notification.for_user(user)
|
||||||
|
|
||||||
|
represented = %{
|
||||||
|
"created_at" => notification.inserted_at |> Utils.format_naive_asctime(),
|
||||||
|
"from_profile" => UserView.render("show.json", %{user: other_user, for: user}),
|
||||||
|
"id" => notification.id,
|
||||||
|
"is_seen" => 0,
|
||||||
|
"notice" => ActivityView.render("activity.json", %{activity: activity, for: user}),
|
||||||
|
"ntype" => "mention"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert represented ==
|
||||||
|
NotificationView.render("notification.json", %{notification: notification, for: user})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "A retweet notification" do
|
||||||
|
note_activity = insert(:note_activity)
|
||||||
|
user = User.get_cached_by_ap_id(note_activity.data["actor"])
|
||||||
|
repeater = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = TwitterAPI.repeat(repeater, note_activity.id)
|
||||||
|
[notification] = Notification.for_user(user)
|
||||||
|
|
||||||
|
represented = %{
|
||||||
|
"created_at" => notification.inserted_at |> Utils.format_naive_asctime(),
|
||||||
|
"from_profile" => UserView.render("show.json", %{user: repeater, for: user}),
|
||||||
|
"id" => notification.id,
|
||||||
|
"is_seen" => 0,
|
||||||
|
"notice" =>
|
||||||
|
ActivityView.render("activity.json", %{activity: notification.activity, for: user}),
|
||||||
|
"ntype" => "repeat"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert represented ==
|
||||||
|
NotificationView.render("notification.json", %{notification: notification, for: user})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "A like notification" do
|
||||||
|
note_activity = insert(:note_activity)
|
||||||
|
user = User.get_cached_by_ap_id(note_activity.data["actor"])
|
||||||
|
liker = insert(:user)
|
||||||
|
|
||||||
|
{:ok, activity} = TwitterAPI.fav(liker, note_activity.id)
|
||||||
|
[notification] = Notification.for_user(user)
|
||||||
|
|
||||||
|
represented = %{
|
||||||
|
"created_at" => notification.inserted_at |> Utils.format_naive_asctime(),
|
||||||
|
"from_profile" => UserView.render("show.json", %{user: liker, for: user}),
|
||||||
|
"id" => notification.id,
|
||||||
|
"is_seen" => 0,
|
||||||
|
"notice" =>
|
||||||
|
ActivityView.render("activity.json", %{activity: notification.activity, for: user}),
|
||||||
|
"ntype" => "like"
|
||||||
|
}
|
||||||
|
|
||||||
|
assert represented ==
|
||||||
|
NotificationView.render("notification.json", %{notification: notification, for: user})
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue