Commit 846ce0ca authored by Alex Castaño's avatar Alex Castaño

Merge branch 'release/0.0.7'

parents 0a4da9c1 c691efe1
......@@ -113,6 +113,9 @@ config :moodle_net, :media_proxy,
config :phoenix, :format_encoders, json: Jason
config :phoenix, :json_library, Jason
config :furlex, Furlex.Oembed,
oembed_host: "https://oembed.com"
config :moodle_net, :suggestions,
enabled: false,
third_party_engine:
......
......@@ -13,7 +13,7 @@ services:
depends_on:
- db
db:
image: postgres:11-alpine
image: postgres:9.6.6-alpine
# volumes:
# - "./volumes/postgres:/var/lib/postgresql/data"
# ports:
......
defmodule ActivityPub do
defdelegate new(params), to: ActivityPub.Builder
defdelegate insert(params), to: ActivityPub.SQLEntity
defdelegate insert(entity), to: ActivityPub.SQLEntity
defdelegate insert(entity, repo), to: ActivityPub.SQLEntity
defdelegate update(entity, changes), to: ActivityPub.SQLEntity
defdelegate delete(entity), to: ActivityPub.SQLEntity
defdelegate delete(entity, assocs), to: ActivityPub.SQLEntity
......
......@@ -4,7 +4,7 @@ defmodule ActivityPub.ApplyAction do
alias ActivityPub.SQLEntity
def apply(entity) when not has_type(entity, "Activity"),
do: raise(ArgumentError, "Only an Activity can be applied, received: #{inspect(entity.type)}")
do: raise(ArgumentError, "Action can only be applied on an Activity, but received: #{inspect(entity.type)}")
def apply(activity) when has_type(activity, "Activity") do
with {:ok, activity} <- persist(activity),
......
......@@ -80,14 +80,14 @@ defmodule ActivityPub.Aspect do
# TODO
defp check_field_type!(name, :datetime, _opts) do
raise ArgumentError,
"invalid type :datetime for field #{inspect(name)}. " <>
"You probably meant to choose one between :naive_datetime " <>
"Invalid type :datetime for field #{inspect(name)}. " <>
"You probably meant to choose one of :naive_datetime " <>
"(no time zone information) or :utc_datetime (time zone is set to UTC)"
end
defp check_field_type!(name, {:embed, _}, _opts) do
raise ArgumentError,
"cannot declare field #{inspect(name)} as embed. Use embeds_one/many instead"
"Cannot declare field #{inspect(name)} as embed. Use embeds_one/many instead"
end
defp check_field_type!(name, type, _opts) do
......@@ -100,10 +100,10 @@ defmodule ActivityPub.Aspect do
is_atom(type) and function_exported?(type, :__schema__, 1) ->
raise ArgumentError,
"schema #{inspect(type)} is not a valid type for field #{inspect(name)}."
"Schema #{inspect(type)} is not a valid type for field #{inspect(name)}."
true ->
raise ArgumentError, "invalid or unknown type #{inspect(type)} for field #{inspect(name)}"
raise ArgumentError, "Invalid or unknown type #{inspect(type)} for field #{inspect(name)}"
end
end
......@@ -123,7 +123,7 @@ defmodule ActivityPub.Aspect do
fields = Module.get_attribute(mod, :aspect_struct_fields)
if List.keyfind(fields, name, 0) do
raise ArgumentError, "field/association #{inspect(name)} is already set on aspect"
raise ArgumentError, "Field/association #{inspect(name)} is already set on aspect"
end
Module.put_attribute(mod, :aspect_struct_fields, {name, default})
......
......@@ -108,11 +108,11 @@ defmodule ActivityPub.SQL.Alter do
end
def add(_, relation, _) do
raise ArgumentError, "not valid relation #{inspect(relation)}"
raise ArgumentError, "Not a valid relation #{inspect(relation)}"
end
def remove(_, relation, _) do
raise ArgumentError, "not valid relation #{inspect(relation)}"
raise ArgumentError, "Not a valid relation #{inspect(relation)}"
end
defp insert_all(table_name, subject_key, target_key, subject_ids, target_ids) do
......
......@@ -348,7 +348,7 @@ defmodule ActivityPub.SQL.Query do
do:
raise(
ArgumentError,
"invalid status: #{Entity.status(e)}. Only entities with status :loaded can be preloaded"
"Invalid status: #{Entity.status(e)}. Only entities with status :loaded can be preloaded"
)
# defp print_query(query) do
......
......@@ -25,17 +25,17 @@ defmodule ActivityPub.SQLAspect do
:embedded ->
if Keyword.has_key?(options, :table_name),
do: raise(ArgumentError, "embedded SQLAspect does not need option :table_name")
do: raise(ArgumentError, "Embedded SQLAspect does not need option :table_name")
@table_name nil
@field_name Keyword.get(options, :field_name, aspect.name())
:fields ->
if Keyword.has_key?(options, :table_name),
do: raise(ArgumentError, "fields SQLAspect does not need option :table_name")
do: raise(ArgumentError, "Fields SQLAspect do not need option :table_name")
if Keyword.has_key?(options, :field_name),
do: raise(ArgumentError, "fields SQLAspect does not need option :field_name")
do: raise(ArgumentError, "Fields SQLAspect do not need option :field_name")
@table_name nil
@field_name nil
......
defmodule ActivityPub.SQLEntity do
use Ecto.Schema
alias Ecto.Multi
require ActivityPub.Guards, as: APG
alias ActivityPub.Entity
......@@ -34,18 +33,13 @@ defmodule ActivityPub.SQLEntity do
entity |> Entity.local_id() |> get_by_local_id()
end
def insert(entity) when APG.is_entity(entity) and APG.has_status(entity, :new) do
with {:ok, %{entity: sql_entity}} <- insert_new(entity) do
def insert(entity, repo \\ Repo) when APG.is_entity(entity) and APG.has_status(entity, :new) do
changeset = insert_changeset(entity)
with {:ok, sql_entity} <- repo.insert(changeset) do
{:ok, to_entity(sql_entity)}
end
end
defp insert_new(entity) do
Multi.new()
|> Multi.insert(:entity, insert_changeset(entity))
|> Repo.transaction()
end
defp insert_changeset(entity) when APG.has_status(entity, :new) do
ch =
%__MODULE__{}
......
......@@ -7,7 +7,14 @@ defmodule MoodleNet.Accounts do
alias MoodleNet.Repo
alias Ecto.Multi
alias MoodleNet.Accounts.{User, PasswordAuth, ResetPasswordToken, EmailConfirmationToken}
alias MoodleNet.Accounts.{
User,
PasswordAuth,
ResetPasswordToken,
EmailConfirmationToken,
WhitelistEmail
}
alias MoodleNet.{Mailer, Email}
alias ActivityPub.SQL.Query
......@@ -32,24 +39,17 @@ defmodule MoodleNet.Accounts do
|> Map.delete(:password)
|> Map.delete("password")
with {:ok, actor} <- ActivityPub.new(actor_attrs),
{:ok, actor} <- ActivityPub.insert(actor),
{:ok, ret = %{user: user, email_confirmation_token: token}} <-
register_user_operation(actor, attrs) do
Email.welcome(user, token.token)
|> Mailer.deliver_later()
{:ok, ret}
end
end
defp register_user_operation(actor, attrs) do
password = attrs[:password] || attrs["password"]
ch = User.changeset(actor, attrs)
Multi.new()
|> Multi.run(:actor, fn _, _ -> {:ok, actor} end)
|> Multi.insert(:user, ch)
|> Multi.run(:new_actor, fn _, _ -> ActivityPub.new(actor_attrs) end)
|> Multi.run(:actor, fn repo, %{new_actor: new_actor} ->
ActivityPub.insert(new_actor, repo)
end)
|> Multi.run(:user, fn repo, %{actor: actor} ->
User.changeset(actor, attrs)
|> repo.insert()
end)
|> Multi.run(
:password_auth,
&(PasswordAuth.create_changeset(&2.user.id, password) |> &1.insert())
......@@ -58,6 +58,13 @@ defmodule MoodleNet.Accounts do
:email_confirmation_token,
&(EmailConfirmationToken.build_changeset(&2.user.id) |> &1.insert())
)
|> Multi.run(:email, fn _, %{user: user, email_confirmation_token: token} ->
email =
Email.welcome(user, token.token)
|> Mailer.deliver_later()
{:ok, email}
end)
|> Repo.transaction()
end
......@@ -69,8 +76,14 @@ defmodule MoodleNet.Accounts do
# FIXME this should be a transaction
with {:ok, _icon} <- ActivityPub.update(icon, url: icon_url),
{:ok, _location} <- ActivityPub.update(location, content: location_content) do
ActivityPub.update(actor, changes)
{:ok, _location} <- ActivityPub.update(location, content: location_content),
{:ok, actor} <- ActivityPub.update(actor, changes) do
# FIXME
actor =
ActivityPub.reload(actor)
|> Query.preload_assoc([:icon, :location])
{:ok, actor}
end
end
......@@ -193,4 +206,18 @@ defmodule MoodleNet.Accounts do
_ -> {:error, {:not_found, full_token, "Token"}}
end
end
def add_email_to_whitelist(email) do
%WhitelistEmail{email: email}
|> Repo.insert()
end
def remove_email_from_whitelist(email) do
%WhitelistEmail{email: email}
|> Repo.delete(stale_error_field: :email)
end
def is_email_in_whitelist?(email) do
Repo.get(WhitelistEmail, email) != nil
end
end
......@@ -22,14 +22,30 @@ defmodule MoodleNet.Accounts.User do
|> Ecto.Changeset.validate_required([:actor_id, :email])
|> Ecto.Changeset.unique_constraint(:email)
|> lower_case_email()
|> whitelist_email()
end
defp lower_case_email(%Ecto.Changeset{valid?: false} = ch), do: ch
defp lower_case_email(%Ecto.Changeset{} = ch) do
{_, email} = Ecto.Changeset.fetch_field(ch, :email)
Ecto.Changeset.change(ch, email: String.downcase(email))
end
defp whitelist_email(%Ecto.Changeset{valid?: false} = ch), do: ch
defp whitelist_email(%Ecto.Changeset{} = ch) do
{_, email} = Ecto.Changeset.fetch_field(ch, :email)
if MoodleNet.Accounts.is_email_in_whitelist?(email) do
ch
else
Ecto.Changeset.add_error(ch, :email, "You cannot register with this email address",
validation: "inclusion"
)
end
end
def confirm_email_changeset(%__MODULE__{} = user) do
Ecto.Changeset.change(user, confirmed_at: DateTime.utc_now() |> DateTime.truncate(:second))
end
......
defmodule MoodleNet.Accounts.WhitelistEmail do
use Ecto.Schema
@primary_key false
schema "accounts_whitelist_emails" do
field(:email, :string, primary_key: true)
end
end
......@@ -110,6 +110,7 @@ defmodule MoodleNet.Factory do
def full_user(attrs \\ %{}) do
attrs = attributes(:user, attrs)
Accounts.add_email_to_whitelist(attrs[:email] || attrs["email"])
{:ok, ret} = Accounts.register_user(attrs)
ret
end
......
defmodule MoodleNet.MetadataScraper do
def fetch(url) when is_binary(url) do
with {:ok, data} <- Furlex.unfurl(url) do
{:ok, format_data(data)}
end
end
defp format_data(data) do
%{
title: title(data),
summary: summary(data),
image: image(data),
embed_code: embed_code(data),
language: language(data),
author: author(data),
source: source(data),
resource_type: resource_type(data)
}
end
defp title(data) do
(get(data, :facebook, "title") || get(data, :twitter, "title") || get(data, :oembed, "title") ||
get(data, :other, "title"))
|> only_first()
end
defp summary(data) do
(get(data, :facebook, "description") || get(data, :twitter, "description") ||
get(data, :other, "description"))
|> only_first()
end
defp image(data) do
(get(data, :facebook, "image") || get(data, :twitter, "image") ||
get(data, :other, "thumbnail_url"))
|> only_first()
end
defp embed_code(data) do
(get(data, :facebook, "video:url") || get(data, :facebook, "audio:url") ||
get(data, :twitter, "player") || get(data, :oembed, "html") || get(data, :oembed, "url"))
|> only_first()
end
defp language(data) do
(get(data, :facebook, "locale") || get(data, :other, "language"))
|> only_first()
end
defp author(data) do
(get(data, :facebook, "article:author") || get(data, :twitter, "creator") ||
get(data, :oembed, "author_name") || get(data, :other, "author"))
|> only_first()
end
defp source(data) do
(get(data, :facebook, "site_name") || get(data, :oembed, "provider_name"))
|> only_first()
end
defp resource_type(data) do
(get(data, :facebook, "type") || get(data, :oembed, "type"))
|> only_first()
end
defp get(data, :facebook, label),
do: Map.get(data.facebook, "og:#{label}")
defp get(data, :twitter, label),
do: Map.get(data.twitter, "twitter:#{label}")
defp get(%{oembed: nil}, :oembed, _label), do: nil
defp get(%{oembed: oembed}, :oembed, label),
do: Map.get(oembed, label)
defp get(data, :other, label),
do: Map.get(data.other, label)
defp only_first([head | _]), do: head
defp only_first(arg), do: arg
end
......@@ -11,6 +11,6 @@
<p>
<%= gettext("We'd love your feedback on the sign-up process.") <> " " %>
<a href="https://changemap.co/moodle/moodlenet/task/2727-improve-the-sign-up-process/">
<%= gettext("Click here") %>
<%= gettext("Please comment here") %>
</a><%= " " <> gettext("to tell us anything we can do to improve it!") %>
</p>
......@@ -6,6 +6,5 @@
------------------
<%= gettext("We'd love your feedback on the sign-up process.")%>
https://changemap.co/moodle/moodlenet/task/2727-improve-the-sign-up-process/
<%= gettext("We'd love your feedback on the sign-up process.")%>
<%= gettext("You can do so at:")%> https://changemap.co/moodle/moodlenet/task/2727-improve-the-sign-up-process/
......@@ -71,6 +71,15 @@ defmodule MoodleNetWeb.GraphQL.Errors do
}}
end
def bad_gateway_error() do
{:error,
%{
message: gettext("An error happened connecting with an external server"),
code: :bad_gateway
}
}
end
def invalid_credential_error() do
{:error, %{
code: :unathorized,
......@@ -81,7 +90,7 @@ defmodule MoodleNetWeb.GraphQL.Errors do
def unauthorized_error() do
{:error,
%{
message: gettext("You have to log in to proceed"),
message: gettext("You need to log in first"),
code: :unauthorized
}}
end
......@@ -97,7 +106,7 @@ defmodule MoodleNetWeb.GraphQL.Errors do
def unknown_error(code) do
{:error,
%{
message: gettext("An unknown error happened"),
message: gettext("There was an unknown error"),
code: code
}}
end
......
defmodule MoodleNetWeb.GraphQL.Schema do
use Absinthe.Schema
alias MoodleNetWeb.GraphQL.MoodleNetSchema
alias MoodleNetWeb.GraphQL.{MoodleNetSchema, MiscSchema}
import_types(MoodleNetWeb.GraphQL.Schema.JSON)
import_types(MoodleNetWeb.GraphQL.MoodleNetSchema)
import_types(MoodleNetWeb.GraphQL.MiscSchema)
query do
@desc "Get list of communities"
......@@ -223,5 +224,11 @@ defmodule MoodleNetWeb.GraphQL.Schema do
arg(:token, non_null(:string))
resolve(&MoodleNetSchema.confirm_email/2)
end
@desc "Fetch metadata from webpage"
field :fetch_web_metadata, type: :web_metadata do
arg(:url, non_null(:string))
resolve(&MiscSchema.fetch_web_metadata/2)
end
end
end
defmodule MoodleNetWeb.GraphQL.MiscSchema do
use Absinthe.Schema.Notation
alias MoodleNetWeb.GraphQL.Errors
object :web_metadata do
field(:title, :string)
field(:summary, :string)
field(:image, :string)
field(:embed_code, :string)
field(:language, :string)
field(:author, :string)
field(:source, :string)
field(:resource_type, :string)
end
def fetch_web_metadata(%{url: url}, info) do
with {:ok, actor} <- current_actor(info) do
case MoodleNet.MetadataScraper.fetch(url) do
{:error, _} -> Errors.bad_gateway_error()
ret -> ret
end
end
end
# FIXME repeated code from moodlenetschema
defp current_user(%{context: %{current_user: nil}}), do: Errors.unauthorized_error()
defp current_user(%{context: %{current_user: user}}), do: {:ok, user}
defp current_actor(info) do
case current_user(info) do
{:ok, user} ->
{:ok, user.actor}
ret ->
ret
end
end
end
......@@ -607,7 +607,7 @@ defmodule MoodleNetWeb.GraphQL.MoodleNetSchema do
defp current_actor(info) do
case current_user(info) do
{:ok, user} ->
{:ok, load_actor(user)}
{:ok, user.actor}
ret ->
ret
......
......@@ -4,7 +4,7 @@ defmodule MoodleNet.Mixfile do
def project do
[
app: :moodle_net,
version: "0.0.6",
version: "0.0.7",
elixir: "~> 1.7.4",
elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:phoenix, :gettext] ++ Mix.compilers(),
......@@ -63,6 +63,7 @@ defmodule MoodleNet.Mixfile do
{:absinthe, "~> 1.4"},
{:absinthe_plug, "~> 1.4"},
{:phoenix_integration, git: "https://github.com/alexcastano/phoenix_integration", only: :test},
{:furlex, git: "https://github.com/alexcastano/furlex"},
{:credo, "~> 0.9.3", only: [:dev, :test]},
{:mock, "~> 0.3.1", only: :test},
{:dialyxir, "~> 1.0.0-rc.4", only: [:dev], runtime: false},
......
......@@ -29,6 +29,7 @@
"faker": {:hex, :faker, "0.11.1", "0dcf151bef21cb27e289ae7418fd15c6a278dad676d5996b75d1d309b155c205", [:mix], [], "hexpm"},
"file_system": {:hex, :file_system, "0.2.6", "fd4dc3af89b9ab1dc8ccbcc214a0e60c41f34be251d9307920748a14bf41f1d3", [:mix], [], "hexpm"},
"floki": {:hex, :floki, "0.20.4", "be42ac911fece24b4c72f3b5846774b6e61b83fe685c2fc9d62093277fb3bc86", [:mix], [{:html_entities, "~> 0.4.0", [hex: :html_entities, repo: "hexpm", optional: false]}, {:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
"furlex": {:git, "https://github.com/alexcastano/furlex", "3b77bb7b19f3cee5b2e03d37a997dcec1225d47a", []},
"gettext": {:hex, :gettext, "0.16.1", "e2130b25eebcbe02bb343b119a07ae2c7e28bd4b146c4a154da2ffb2b3507af2", [:mix], [], "hexpm"},
"hackney": {:hex, :hackney, "1.14.3", "b5f6f5dcc4f1fba340762738759209e21914516df6be440d85772542d4a5e412", [:rebar3], [{:certifi, "2.4.2", [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.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"},
"html_entities": {:hex, :html_entities, "0.4.0", "f2fee876858cf6aaa9db608820a3209e45a087c5177332799592142b50e89a6b", [:mix], [], "hexpm"},
......
......@@ -20,11 +20,6 @@ msgstr ""
msgid "Alternatively, copy and paste this link into your browser:"
msgstr ""
#, elixir-format
#: lib/moodle_net_web/email/templates/welcome.html.eex:14
msgid "Click here"
msgstr ""
#, elixir-format
#: lib/moodle_net/email.ex:16
msgid "Did you forget your MoodleNet password?"
......@@ -108,11 +103,6 @@ msgstr ""
msgid "Activity"
msgstr ""
#, elixir-format
#: lib/moodle_net_web/graph_ql/errors.ex:100
msgid "An unknown error happened"
msgstr ""
#, elixir-format
#: lib/moodle_net_web/graph_ql/errors.ex:77
msgid "Invalid credentials"
......@@ -128,13 +118,28 @@ msgstr ""
msgid "You are not authorized to perform this action"
msgstr ""
#, elixir-format
#: lib/moodle_net_web/graph_ql/errors.ex:84
msgid "You have to log in to proceed"
msgstr ""
#, elixir-format
#: lib/moodle_net_web/graph_ql/errors.ex:57
#: lib/moodle_net_web/graph_ql/errors.ex:64
msgid "not found"
msgstr ""
#, elixir-format
#: lib/moodle_net_web/email/templates/welcome.html.eex:14
msgid "Please comment here"
msgstr ""
#, elixir-format
#: lib/moodle_net_web/graph_ql/errors.ex:100
msgid "There was an unknown error"
msgstr ""
#, elixir-format
#: lib/moodle_net_web/email/templates/welcome.text.eex:10
msgid "You can do so at:"
msgstr ""
#, elixir-format
#: lib/moodle_net_web/graph_ql/errors.ex:84
msgid "You need to log in first"
msgstr ""
defmodule MoodleNet.Repo.Migrations.WhitelistEmails do
use Ecto.Migration
def change do
create table(:accounts_whitelist_emails, primary_key: false) do
add :email, :citext, null: false, primary_key: true
end
end
end
......@@ -26,7 +26,7 @@ defmodule ActivityPub.AspectTest do
# Errors
test "field name clash" do
assert_raise ArgumentError, "field/association :name is already set on aspect", fn ->
assert_raise ArgumentError, "Field/association :name is already set on this aspect", fn ->
defmodule AspectFieldNameClash do
use ActivityPub.Aspect, persistence: :any
......@@ -39,7 +39,7 @@ defmodule ActivityPub.AspectTest do
end
test "invalid field type" do
assert_raise ArgumentError, "invalid or unknown type {:apa} for field :name", fn ->
assert_raise ArgumentError, "Invalid or unknown type {:apa} for field :name", fn ->
defmodule AspectInvalidFieldType do
use ActivityPub.Aspect, persistence: :any
......@@ -49,7 +49,7 @@ defmodule ActivityPub.AspectTest do
end
end
assert_raise ArgumentError, "invalid or unknown type OMG for field :name", fn ->
assert_raise ArgumentError, "Invalid or unknown type OMG for field :name", fn ->
defmodule AspectInvalidFieldType do
use ActivityPub.Aspect, persistence: :any
......
......@@ -87,7 +87,7 @@ defmodule ActivityPub.SQLEntityTest do
}
assert {:ok, entity} = ActivityPub.new(map)
assert {:error, _, %Ecto.Changeset{} = ch, _} = SQLEntity.insert(entity)
assert {:error, %Ecto.Changeset{} = ch} = SQLEntity.insert(entity)
assert [%{status: _}] = errors_on(ch)[:attributed_to]
end
end
......
......@@ -13,6 +13,7 @@ defmodule MoodleNet.AccountsTest do
|> Map.put("icon", icon_attrs)
|> Map.put("extra_field", "extra")
Accounts.add_email_to_whitelist(attrs["email"])
assert {:ok, ret} = Accounts.register_user(attrs)
assert attrs["email"] == ret.user.email
assert ret.actor
......@@ -26,10 +27,12 @@ defmodule MoodleNet.AccountsTest do
test "fails with invalid password values" do
attrs = Factory.attributes(:user) |> Map.delete("password")
Accounts.add_email_to_whitelist(attrs["email"])
assert {:error, _, ch, _} = Accounts.register_user(attrs)
assert "can't be blank" in errors_on(ch).password
attrs = Factory.attributes(:user) |> Map.put("password", "short")
Accounts.add_email_to_whitelist(attrs["email"])
assert {:error, _, ch, _} = Accounts.register_user(attrs)
assert "should be at least 6 character(s)" in errors_on(ch).password
end
......@@ -40,6 +43,7 @@ defmodule MoodleNet.AccountsTest do
assert "can't be blank" in errors_on(ch).email
attrs = Factory.attributes(:user) |> Map.put("email", "not_an_email")
Accounts.add_email_to_whitelist(attrs["email"])
assert {:error, _, ch, _} = Accounts.register_user(attrs)
assert "has invalid format" in errors_on(ch).email
end
......@@ -48,6 +52,7 @@ defmodule MoodleNet.AccountsTest do
attrs = Factory.attributes(:user)
email = attrs["email"]
attrs = Map.put(attrs, "email", String.upcase(attrs["email"]))
Accounts.add_email_to_whitelist(attrs["email"])
assert {:ok, ret} = Accounts.register_user(attrs)
assert ret.user.email == email
end
......@@ -149,4 +154,16 @@ defmodule MoodleNet.AccountsTest do
assert {:error, {:not_found, _, "Token"}} = Accounts.confirm_email(token <> "1")
end
end
describe "whitelist" do
test "works" do
email = Faker.Internet.safe_email()
refute Accounts.is_email_in_whitelist?(email)
assert {:ok, _} = Accounts.add_email_to_whitelist(email)
assert Accounts.is_email_in_whitelist?(email)
assert {:ok, _} = Accounts.remove_email_from_whitelist(email)
refute Accounts.is_email_in_whitelist?(email)
assert {:error, _} = Accounts.remove_email_from_whitelist(email)
end
end
end
defmodule MoodleNet.MetadataScraperTest do
use MoodleNet.DataCase, async: true
alias MoodleNet.MetadataScraper, as: Subject
@tag :external
test "works" do
# FIXME Not a very good test but it is better than nothing
url = "https://www.youtube.com/watch?v=RYihwKty83A"
assert {:ok, data} = Subject.fetch(url)
assert data.author == "Jaime Altozano"
assert data.embed_code == "https://www.youtube.com/embed/RYihwKty83A"
assert data.image == "https://i.ytimg.com/vi/RYihwKty83A/maxresdefault.jpg"
assert data.language == nil