-
-
-
- All Organizations
-
- {process.env.IMPOSE_HARD_CAP !== 'true' && (
+
+
+
+ All Organizations
+
+ {process.env.IMPOSE_HARD_CAP !== "true" &&
+ (window.user_invite_only === "true" ||
+ process.env.USER_INVITE_ONLY === "true"
+ ? data?.vettedUserStatus.vetted === true
+ : true) && (
}
style={{ borderRadius: 4 }}
onClick={() => {
analyticsLogger.logEvent("ACTION_NEW_ORG");
- this.openOrganizationModal();
+ openOrganizationModal();
}}
type="primary"
>
@@ -118,35 +119,32 @@ class OrganizationIndex extends Component {
)}
-
-
+
+
-
-
-
-
-
-
- >
- );
- }
-}
+
-export default OrganizationIndex;
+
+
+
+
+ >
+ );
+};
diff --git a/assets/js/graphql/users.js b/assets/js/graphql/users.js
new file mode 100644
index 000000000..69235090f
--- /dev/null
+++ b/assets/js/graphql/users.js
@@ -0,0 +1,9 @@
+import { gql } from "@apollo/client";
+
+export const GET_VETTED_USER_STATUS = gql`
+ query VettedUserStatusQuery($email: String!) {
+ vettedUserStatus(email: $email) {
+ vetted
+ }
+ }
+`;
diff --git a/lib/console/auth/auth.ex b/lib/console/auth/auth.ex
index b0db18355..ff6d355d9 100644
--- a/lib/console/auth/auth.ex
+++ b/lib/console/auth/auth.ex
@@ -16,13 +16,18 @@ defmodule Console.Auth do
end
def get_user_by_id_and_email(user_id, email) do
+ user = get_user_by_email(email)
+ vetted = if is_nil(user) do nil else user.vetted end
+
case get_user_by_id(user_id) do
- %{super: is_super} -> get_user_data_map(user_id, email, is_super)
- _ -> get_user_data_map(user_id, email)
+ %{super: is_super} ->
+ vetted = if is_super == true do true else vetted end
+ get_user_data_map(user_id, email, vetted, is_super)
+ _ -> get_user_data_map(user_id, email, vetted)
end
end
- defp get_user_data_map(user_id, user_email, super_user \\ false) do
- %User{id: user_id, super: super_user, email: user_email}
+ defp get_user_data_map(user_id, user_email, vetted, super_user \\ false) do
+ %User{id: user_id, super: super_user, email: user_email, vetted: vetted}
end
end
diff --git a/lib/console/auth/user.ex b/lib/console/auth/user.ex
index 27843bb3c..857745f8f 100644
--- a/lib/console/auth/user.ex
+++ b/lib/console/auth/user.ex
@@ -13,6 +13,7 @@ defmodule Console.Auth.User do
field :confirmed_at, :naive_datetime
field :last_2fa_skipped_at, :naive_datetime
field :super, :boolean
+ field :vetted, :boolean
has_many :memberships, Console.Organizations.Membership
has_many :api_keys, Console.ApiKeys.ApiKey
diff --git a/lib/console/auth/user_resolver.ex b/lib/console/auth/user_resolver.ex
new file mode 100644
index 000000000..3c7e03ae0
--- /dev/null
+++ b/lib/console/auth/user_resolver.ex
@@ -0,0 +1,12 @@
+defmodule Console.Users.UserResolver do
+ alias Console.Auth
+
+ def get_vetted_user_status(%{email: email}, %{context: %{current_organization: _}}) do
+ user = Auth.get_user_by_email(email)
+ if not is_nil(user) and (user.vetted == true or user.super == true) do
+ {:ok, %{vetted: true}}
+ else
+ {:ok, %{vetted: false}}
+ end
+ end
+end
\ No newline at end of file
diff --git a/lib/console_web/controllers/organization_controller.ex b/lib/console_web/controllers/organization_controller.ex
index 882cd62fc..55bc3cd02 100644
--- a/lib/console_web/controllers/organization_controller.ex
+++ b/lib/console_web/controllers/organization_controller.ex
@@ -36,38 +36,42 @@ defmodule ConsoleWeb.OrganizationController do
end
def create(conn, %{"organization" => %{ "name" => organization_name, "from" => _ } }) do
- with {:ok, %Organization{} = organization} <-
- Organizations.create_organization(conn.assigns.current_user, %{ "name" => organization_name }) do
- organizations = Organizations.get_organizations(conn.assigns.current_user)
- membership = Organizations.get_membership!(conn.assigns.current_user, organization)
- membership_info = %{id: organization.id, name: organization.name, role: membership.role}
-
- Task.Supervisor.async_nolink(ConsoleWeb.TaskSupervisor, fn ->
- OrgIps.create_org_ip(%{
- "address" => ConsoleWeb.IPFilter.get_ip(conn),
- "email" => membership.email,
- "organization_id" => organization.id,
- "organization_name" => organization.name,
- "banned" => false
- })
- end)
+ if Application.get_env(:console, :user_invite_only) == true and not conn.assigns.current_user.vetted do
+ {:error, :forbidden, "Please contact #{if Application.get_env(:console, :self_hosted) == true do "the admin" else "our sales team" end} to add organizations."}
+ else
+ with {:ok, %Organization{} = organization} <-
+ Organizations.create_organization(conn.assigns.current_user, %{ "name" => organization_name }) do
+ organizations = Organizations.get_organizations(conn.assigns.current_user)
+ membership = Organizations.get_membership!(conn.assigns.current_user, organization)
+ membership_info = %{id: organization.id, name: organization.name, role: membership.role}
+
+ Task.Supervisor.async_nolink(ConsoleWeb.TaskSupervisor, fn ->
+ OrgIps.create_org_ip(%{
+ "address" => ConsoleWeb.IPFilter.get_ip(conn),
+ "email" => membership.email,
+ "organization_id" => organization.id,
+ "organization_name" => organization.name,
+ "banned" => false
+ })
+ end)
- case Enum.count(organizations) do
- 1 ->
- initial_dc = String.to_integer(System.get_env("INITIAL_ORG_GIFTED_DC") || "10000")
- if initial_dc > 0 do
- Organizations.update_organization(organization, %{ "dc_balance" => initial_dc, "dc_balance_nonce" => 1, "received_free_dc" => true })
- end
+ case Enum.count(organizations) do
+ 1 ->
+ initial_dc = String.to_integer(System.get_env("INITIAL_ORG_GIFTED_DC") || "10000")
+ if initial_dc > 0 do
+ Organizations.update_organization(organization, %{ "dc_balance" => initial_dc, "dc_balance_nonce" => 1, "received_free_dc" => true })
+ end
- render(conn, "show.json", organization: membership_info)
- _ ->
- ConsoleWeb.Endpoint.broadcast("graphql:topbar_orgs", "graphql:topbar_orgs:#{conn.assigns.current_user.id}:organization_list_update", %{})
- ConsoleWeb.Endpoint.broadcast("graphql:orgs_index_table", "graphql:orgs_index_table:#{conn.assigns.current_user.id}:organization_list_update", %{})
+ render(conn, "show.json", organization: membership_info)
+ _ ->
+ ConsoleWeb.Endpoint.broadcast("graphql:topbar_orgs", "graphql:topbar_orgs:#{conn.assigns.current_user.id}:organization_list_update", %{})
+ ConsoleWeb.Endpoint.broadcast("graphql:orgs_index_table", "graphql:orgs_index_table:#{conn.assigns.current_user.id}:organization_list_update", %{})
- conn
- |> put_status(:created)
- |> put_resp_header("message", "Organization #{organization.name} added successfully")
- |> render("show.json", organization: membership_info)
+ conn
+ |> put_status(:created)
+ |> put_resp_header("message", "Organization #{organization.name} added successfully")
+ |> render("show.json", organization: membership_info)
+ end
end
end
end
diff --git a/lib/console_web/schema/schema.ex b/lib/console_web/schema/schema.ex
index 7faa34b21..a8e37fde8 100644
--- a/lib/console_web/schema/schema.ex
+++ b/lib/console_web/schema/schema.ex
@@ -152,6 +152,10 @@ defmodule ConsoleWeb.Schema do
field :labels, list_of(:label)
end
+ object :vetted_user_status do
+ field :vetted, :boolean
+ end
+
object :group do
field :id, :id
field :name, :string
@@ -607,5 +611,10 @@ defmodule ConsoleWeb.Schema do
paginated field :dc_purchases, :paginated_dc_purchases do
resolve(&Console.DcPurchases.DcPurchaseResolver.paginate/2)
end
+
+ field :vetted_user_status, :vetted_user_status do
+ arg :email, :string
+ resolve &Console.Users.UserResolver.get_vetted_user_status/2
+ end
end
end
diff --git a/priv/repo/migrations/20220708223548_user_vetted_attribute.exs b/priv/repo/migrations/20220708223548_user_vetted_attribute.exs
new file mode 100644
index 000000000..a15b31b18
--- /dev/null
+++ b/priv/repo/migrations/20220708223548_user_vetted_attribute.exs
@@ -0,0 +1,9 @@
+defmodule Console.Repo.Migrations.UserVettedAttribute do
+ use Ecto.Migration
+
+ def change do
+ alter table(:users) do
+ add :vetted, :boolean, default: false, null: false
+ end
+ end
+end