From e864b38ec69be2342bcbaf24c1f2719e49a37d23 Mon Sep 17 00:00:00 2001
From: Chocobozzz <me@florianbigard.com>
Date: Fri, 22 Mar 2019 10:53:38 +0100
Subject: [PATCH] Add config endpoint

---
 config/config.exs                             |  2 +-
 js/src/graphql/config.ts                      | 40 +++++++++++++++++++
 js/src/types/config.model.ts                  |  7 ++++
 lib/mobilizon/common-config.ex                |  7 ++++
 lib/mobilizon/users/user.ex                   |  9 +----
 lib/mobilizon_web/resolvers/config.ex         | 14 +++++++
 lib/mobilizon_web/resolvers/user.ex           | 13 +++++-
 lib/mobilizon_web/schema.ex                   |  2 +
 lib/mobilizon_web/schema/config.ex            | 23 +++++++++++
 .../resolvers/config_resolver_test.exs        | 25 ++++++++++++
 .../resolvers/user_resolver_test.exs          | 26 +++++++++++-
 11 files changed, 157 insertions(+), 11 deletions(-)
 create mode 100644 js/src/graphql/config.ts
 create mode 100644 js/src/types/config.model.ts
 create mode 100644 lib/mobilizon/common-config.ex
 create mode 100644 lib/mobilizon_web/resolvers/config.ex
 create mode 100644 lib/mobilizon_web/schema/config.ex
 create mode 100644 test/mobilizon_web/resolvers/config_resolver_test.exs

diff --git a/config/config.exs b/config/config.exs
index cb708b25e..97bf5c466 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -12,7 +12,7 @@ config :mobilizon,
 config :mobilizon, :instance,
   name: System.get_env("MOBILIZON_INSTANCE_NAME") || "Localhost",
   version: "1.0.0-dev",
-  registrations_open: true
+  registrations_open: System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_OPEN") || true
 
 config :mime, :types, %{
   "application/activity+json" => ["activity-json"],
diff --git a/js/src/graphql/config.ts b/js/src/graphql/config.ts
new file mode 100644
index 000000000..07a16aba0
--- /dev/null
+++ b/js/src/graphql/config.ts
@@ -0,0 +1,40 @@
+import gql from 'graphql-tag';
+
+export const CREATE_USER = gql`
+mutation CreateUser($email: String!, $password: String!) {
+  createUser(email: $email, password: $password) {
+    email,
+    confirmationSentAt
+  }
+}
+`;
+
+export const VALIDATE_USER = gql`
+mutation ValidateUser($token: String!) {
+  validateUser(token: $token) {
+    token,
+    user {
+      id,
+      email,
+      defaultActor {
+        id
+      }
+    }
+  }
+}
+`;
+
+export const CURRENT_USER_CLIENT = gql`
+query {
+  currentUser @client {
+    id,
+    email
+  }
+}
+`;
+
+export const UPDATE_CURRENT_USER_CLIENT = gql`
+mutation UpdateCurrentUser($id: Int!, $email: String!) {
+  updateCurrentUser(id: $id, email: $email) @client
+}
+`;
diff --git a/js/src/types/config.model.ts b/js/src/types/config.model.ts
new file mode 100644
index 000000000..d3d3335e8
--- /dev/null
+++ b/js/src/types/config.model.ts
@@ -0,0 +1,7 @@
+import { ICurrentUser } from '@/types/current-user.model';
+
+export interface ILogin {
+  user: ICurrentUser,
+
+  token: string,
+}
diff --git a/lib/mobilizon/common-config.ex b/lib/mobilizon/common-config.ex
new file mode 100644
index 000000000..d713c0187
--- /dev/null
+++ b/lib/mobilizon/common-config.ex
@@ -0,0 +1,7 @@
+defmodule Mobilizon.CommonConfig do
+  def registrations_open?(), do: instance_config() |> get_in([:registrations_open])
+
+  def instance_name(), do: instance_config() |> get_in([:name])
+
+  defp instance_config(), do: Application.get_env(:mobilizon, :instance)
+end
diff --git a/lib/mobilizon/users/user.ex b/lib/mobilizon/users/user.ex
index d1bdae752..cd31a29f4 100644
--- a/lib/mobilizon/users/user.ex
+++ b/lib/mobilizon/users/user.ex
@@ -146,13 +146,8 @@ defmodule Mobilizon.Users.User do
     end
   end
 
-  def is_confirmed(%User{confirmed_at: nil} = _user) do
-    {:error, :unconfirmed}
-  end
-
-  def is_confirmed(%User{} = user) do
-    {:ok, user}
-  end
+  def is_confirmed(%User{confirmed_at: nil} = _user), do: {:error, :unconfirmed}
+  def is_confirmed(%User{} = user), do: {:ok, user}
 
   def owns_actor(%User{actors: actors}, actor_id) do
     case Enum.find(actors, fn a -> a.id == actor_id end) do
diff --git a/lib/mobilizon_web/resolvers/config.ex b/lib/mobilizon_web/resolvers/config.ex
new file mode 100644
index 000000000..931403c99
--- /dev/null
+++ b/lib/mobilizon_web/resolvers/config.ex
@@ -0,0 +1,14 @@
+defmodule MobilizonWeb.Resolvers.Config do
+  @moduledoc """
+  Handles the config-related GraphQL calls
+  """
+  require Logger
+  import Mobilizon.CommonConfig
+
+  @doc """
+  Get config
+  """
+  def get_config(_parent, _params, _context) do
+    {:ok, %{name: instance_name(), registrations_open: registrations_open?()}}
+  end
+end
diff --git a/lib/mobilizon_web/resolvers/user.ex b/lib/mobilizon_web/resolvers/user.ex
index 974568196..fed884d19 100644
--- a/lib/mobilizon_web/resolvers/user.ex
+++ b/lib/mobilizon_web/resolvers/user.ex
@@ -3,6 +3,7 @@ defmodule MobilizonWeb.Resolvers.User do
   Handles the user-related GraphQL calls
   """
   alias Mobilizon.Actors.Actor
+  alias Mobilizon.CommonConfig
   alias Mobilizon.Users.User
   alias Mobilizon.{Actors, Users}
   alias Mobilizon.Service.Users.{ResetPassword, Activation}
@@ -64,15 +65,23 @@ defmodule MobilizonWeb.Resolvers.User do
   end
 
   @doc """
-  Register an user :
+  Register an user:
+    - check registrations are enabled
     - create the user
     - send a validation email to the user
   """
   @spec create_user(any(), map(), any()) :: tuple()
   def create_user(_parent, args, _resolution) do
-    with {:ok, %User{} = user} <- Users.register(args) do
+    with {:registrations_open, true} <- {:registrations_open, CommonConfig.registrations_open?()},
+         {:ok, %User{} = user} <- Users.register(args) do
       Activation.send_confirmation_email(user)
       {:ok, user}
+    else
+      {:registrations_open, false} ->
+        {:error, "Registrations are not enabled"}
+
+      err ->
+        err
     end
   end
 
diff --git a/lib/mobilizon_web/schema.ex b/lib/mobilizon_web/schema.ex
index 0373b80ce..4a8f868cf 100644
--- a/lib/mobilizon_web/schema.ex
+++ b/lib/mobilizon_web/schema.ex
@@ -18,6 +18,7 @@ defmodule MobilizonWeb.Schema do
   import_types(MobilizonWeb.Schema.Actors.PersonType)
   import_types(MobilizonWeb.Schema.Actors.GroupType)
   import_types(MobilizonWeb.Schema.CommentType)
+  import_types(MobilizonWeb.Schema.ConfigType)
 
   alias MobilizonWeb.Resolvers
 
@@ -133,6 +134,7 @@ defmodule MobilizonWeb.Schema do
     import_fields(:participant_queries)
     import_fields(:tag_queries)
     import_fields(:address_queries)
+    import_fields(:config_queries)
   end
 
   @desc """
diff --git a/lib/mobilizon_web/schema/config.ex b/lib/mobilizon_web/schema/config.ex
new file mode 100644
index 000000000..ea7e9259e
--- /dev/null
+++ b/lib/mobilizon_web/schema/config.ex
@@ -0,0 +1,23 @@
+defmodule MobilizonWeb.Schema.ConfigType do
+  @moduledoc """
+  Schema representation for User
+  """
+  use Absinthe.Schema.Notation
+
+  alias MobilizonWeb.Resolvers.Config
+
+  @desc "A config object"
+  object :config do
+    # Instance name
+    field(:name, :string)
+
+    field(:registrations_open, :boolean)
+  end
+
+  object :config_queries do
+    @desc "Get the instance config"
+    field :config, :config do
+      resolve(&Config.get_config/3)
+    end
+  end
+end
diff --git a/test/mobilizon_web/resolvers/config_resolver_test.exs b/test/mobilizon_web/resolvers/config_resolver_test.exs
new file mode 100644
index 000000000..bdbbc0b91
--- /dev/null
+++ b/test/mobilizon_web/resolvers/config_resolver_test.exs
@@ -0,0 +1,25 @@
+defmodule MobilizonWeb.Resolvers.ConfigResolverTest do
+  alias MobilizonWeb.AbsintheHelpers
+  use MobilizonWeb.ConnCase
+  use Bamboo.Test
+
+  describe "Resolver: Get config" do
+    test "get_config/3 returns the instance config", context do
+      query = """
+      {
+        config {
+            name,
+            registrationsOpen
+        }
+      }
+      """
+
+      res =
+        context.conn
+        |> get("/api", AbsintheHelpers.query_skeleton(query, "config"))
+
+      assert json_response(res, 200)["data"]["config"]["name"] == "Localhost"
+      assert json_response(res, 200)["data"]["config"]["registrationsOpen"] == true
+    end
+  end
+end
diff --git a/test/mobilizon_web/resolvers/user_resolver_test.exs b/test/mobilizon_web/resolvers/user_resolver_test.exs
index ffd47e4cd..5db02f088 100644
--- a/test/mobilizon_web/resolvers/user_resolver_test.exs
+++ b/test/mobilizon_web/resolvers/user_resolver_test.exs
@@ -1,11 +1,12 @@
 defmodule MobilizonWeb.Resolvers.UserResolverTest do
   use MobilizonWeb.ConnCase
-  alias Mobilizon.{Actors, Users}
+  alias Mobilizon.{Actors, Users, CommonConfig}
   alias Mobilizon.Actors.Actor
   alias Mobilizon.Users.User
   alias MobilizonWeb.AbsintheHelpers
   alias Mobilizon.Service.Users.ResetPassword
   import Mobilizon.Factory
+  import Mock
   use Bamboo.Test
 
   @valid_actor_params %{email: "test@test.tld", password: "testest", username: "test"}
@@ -389,6 +390,29 @@ defmodule MobilizonWeb.Resolvers.UserResolverTest do
       assert hd(json_response(res, 200)["errors"])["message"] ==
                "Email doesn't fit required format"
     end
+
+    test "test create_user/3 doesn't create a user when registration is disabled", context do
+      with_mock CommonConfig, registrations_open?: fn -> false end do
+        mutation = """
+            mutation {
+              createUser(
+                    email: "#{@user_creation.email}",
+                    password: "#{@user_creation.password}",
+                ) {
+                  id,
+                  email
+                }
+              }
+        """
+
+        res =
+          context.conn
+          |> post("/api", AbsintheHelpers.mutation_skeleton(mutation))
+
+        assert hd(json_response(res, 200)["errors"])["message"] ==
+                 "Registrations are not enabled"
+      end
+    end
   end
 
   describe "Resolver: Validate an user" do
-- 
GitLab