[Adminitration] Allow registrations: 3 modes = "close", "allowed", "moderate" - #877

This commit is contained in:
Laurent GAY
2025-09-03 21:07:33 +02:00
parent 8f8aa0ffbe
commit 3e4899c8e4
28 changed files with 526 additions and 19 deletions

View File

@@ -17,6 +17,7 @@ config :mobilizon, :instance,
description: "Change this to a proper description of your instance", description: "Change this to a proper description of your instance",
hostname: "localhost", hostname: "localhost",
registrations_open: false, registrations_open: false,
registrations_moderation: false,
registration_email_allowlist: [], registration_email_allowlist: [],
registration_email_denylist: [], registration_email_denylist: [],
disable_database_login: false, disable_database_login: false,

View File

@@ -82,6 +82,8 @@ config :mobilizon, :instance,
email_from: System.get_env("MOBILIZON_INSTANCE_EMAIL"), email_from: System.get_env("MOBILIZON_INSTANCE_EMAIL"),
email_reply_to: System.get_env("MOBILIZON_INSTANCE_EMAIL"), email_reply_to: System.get_env("MOBILIZON_INSTANCE_EMAIL"),
registrations_open: System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_OPEN") == "true", registrations_open: System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_OPEN") == "true",
registrations_moderation:
System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_MODERATION", "false") == "true",
groups: true groups: true
config :mobilizon, Mobilizon.Web.Auth.Guardian, config :mobilizon, Mobilizon.Web.Auth.Guardian,

View File

@@ -54,6 +54,8 @@ config :mobilizon, :instance,
), ),
hostname: System.get_env("MOBILIZON_INSTANCE_HOST", "mobilizon.lan"), hostname: System.get_env("MOBILIZON_INSTANCE_HOST", "mobilizon.lan"),
registrations_open: System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_OPEN", "false") == "true", registrations_open: System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_OPEN", "false") == "true",
registrations_moderation:
System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_MODERATION", "false") == "true",
registration_email_allowlist: registration_email_allowlist:
System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_EMAIL_ALLOWLIST", "") System.get_env("MOBILIZON_INSTANCE_REGISTRATIONS_EMAIL_ALLOWLIST", "")
|> String.split(",", trim: true), |> String.split(",", trim: true),

View File

@@ -34,6 +34,7 @@ config :mobilizon, :instance,
description: "E2E is safety", description: "E2E is safety",
hostname: "mobilizon1.com", hostname: "mobilizon1.com",
registrations_open: true, registrations_open: true,
registrations_moderation: false,
registration_email_denylist: ["gmail.com", "deny@tcit.fr"], registration_email_denylist: ["gmail.com", "deny@tcit.fr"],
demo: false, demo: false,
default_language: "en", default_language: "en",

View File

@@ -3,6 +3,7 @@ import Config
config :mobilizon, :instance, config :mobilizon, :instance,
name: "Test instance", name: "Test instance",
registrations_open: true, registrations_open: true,
registrations_moderation: false,
duration_of_long_event: 0 duration_of_long_event: 0
# We don't run a server during test. If one is required, # We don't run a server during test. If one is required,

View File

@@ -90,6 +90,7 @@ defmodule Mobilizon.GraphQL.Resolvers.Config do
%{ %{
name: Config.instance_name(), name: Config.instance_name(),
registrations_open: Config.instance_registrations_open?(), registrations_open: Config.instance_registrations_open?(),
registrations_moderation: Config.instance_registrations_moderation?(),
registrations_allowlist: Config.instance_registrations_allowlist?(), registrations_allowlist: Config.instance_registrations_allowlist?(),
contact: Config.contact(), contact: Config.contact(),
demo_mode: Config.instance_demo_mode?(), demo_mode: Config.instance_demo_mode?(),

View File

@@ -153,6 +153,11 @@ defmodule Mobilizon.GraphQL.Schema.AdminType do
field(:instance_privacy_policy_url, :string, description: "The instance's privacy policy URL") field(:instance_privacy_policy_url, :string, description: "The instance's privacy policy URL")
field(:instance_rules, :string, description: "The instance's rules") field(:instance_rules, :string, description: "The instance's rules")
field(:registrations_open, :boolean, description: "Whether the registrations are opened") field(:registrations_open, :boolean, description: "Whether the registrations are opened")
field(:registrations_moderation, :boolean,
description: "Whether the registrations want moderation"
)
field(:instance_languages, list_of(:string), description: "The instance's languages") field(:instance_languages, list_of(:string), description: "The instance's languages")
end end
@@ -464,6 +469,11 @@ defmodule Mobilizon.GraphQL.Schema.AdminType do
arg(:instance_privacy_policy_url, :string, description: "The instance's privacy policy URL") arg(:instance_privacy_policy_url, :string, description: "The instance's privacy policy URL")
arg(:instance_rules, :string, description: "The instance's rules") arg(:instance_rules, :string, description: "The instance's rules")
arg(:registrations_open, :boolean, description: "Whether the registrations are opened") arg(:registrations_open, :boolean, description: "Whether the registrations are opened")
arg(:registrations_moderation, :boolean,
description: "Whether the registrations want moderation"
)
arg(:instance_languages, list_of(:string), description: "The instance's languages") arg(:instance_languages, list_of(:string), description: "The instance's languages")
middleware(Rajska.QueryAuthorization, permit: :administrator) middleware(Rajska.QueryAuthorization, permit: :administrator)
resolve(&Admin.save_settings/3) resolve(&Admin.save_settings/3)

View File

@@ -26,6 +26,10 @@ defmodule Mobilizon.GraphQL.Schema.ConfigType do
field(:registrations_open, :boolean, description: "Whether the registrations are opened") field(:registrations_open, :boolean, description: "Whether the registrations are opened")
field(:registrations_moderation, :boolean,
description: "Whether the registrations want moderation"
)
field(:registrations_allowlist, :boolean, field(:registrations_allowlist, :boolean,
description: "Whether the registration are on an allowlist" description: "Whether the registration are on an allowlist"
) )

View File

@@ -15,6 +15,7 @@ defmodule Mobilizon.Config do
description: String.t(), description: String.t(),
hostname: String.t(), hostname: String.t(),
registrations_open: boolean(), registrations_open: boolean(),
registrations_moderation: boolean(),
languages: list(String.t()), languages: list(String.t()),
default_language: String.t(), default_language: String.t(),
registration_email_allowlist: list(String.t()), registration_email_allowlist: list(String.t()),
@@ -154,6 +155,17 @@ defmodule Mobilizon.Config do
) )
) )
@spec instance_registrations_moderation? :: boolean
def instance_registrations_moderation?,
do:
to_boolean(
config_cached_value(
"instance",
"registrations_moderation",
instance_config()[:registrations_moderation]
)
)
@spec instance_languages :: list(String.t()) @spec instance_languages :: list(String.t())
def instance_languages, def instance_languages,
do: do:
@@ -451,6 +463,7 @@ defmodule Mobilizon.Config do
instance_name: instance_name(), instance_name: instance_name(),
instance_slogan: instance_slogan(), instance_slogan: instance_slogan(),
registrations_open: instance_registrations_open?(), registrations_open: instance_registrations_open?(),
registrations_moderation: instance_registrations_moderation?(),
contact: contact(), contact: contact(),
primary_color: primary_color(), primary_color: primary_color(),
secondary_color: secondary_color(), secondary_color: secondary_color(),

View File

@@ -53,6 +53,7 @@ defmodule Mobilizon.Web.NodeInfoController do
outbound: ["atom1.0"] outbound: ["atom1.0"]
}, },
openRegistrations: Config.instance_registrations_open?(), openRegistrations: Config.instance_registrations_open?(),
moderationRegistrations: Config.instance_registrations_moderation?(),
usage: %{ usage: %{
users: %{ users: %{
total: Statistics.get_cached_value(:local_users) total: Statistics.get_cached_value(:local_users)

View File

@@ -193,6 +193,9 @@ type Config {
"Whether the registrations are opened" "Whether the registrations are opened"
registrationsOpen: Boolean registrationsOpen: Boolean
"Whether the registrations want moderation"
registrationsModeration: Boolean
"Whether the registration are on an allowlist" "Whether the registration are on an allowlist"
registrationsAllowlist: Boolean registrationsAllowlist: Boolean
@@ -1929,6 +1932,9 @@ type RootMutationType {
"Whether the registrations are opened" "Whether the registrations are opened"
registrationsOpen: Boolean registrationsOpen: Boolean
"Whether the registrations want moderation"
registrationsModeration: Boolean
"The instance's languages" "The instance's languages"
instanceLanguages: [String] instanceLanguages: [String]
): AdminSettings ): AdminSettings
@@ -3761,6 +3767,9 @@ type AdminSettings {
"Whether the registrations are opened" "Whether the registrations are opened"
registrationsOpen: Boolean registrationsOpen: Boolean
"Whether the registrations want moderation"
registrationsModeration: Boolean
"The instance's languages" "The instance's languages"
instanceLanguages: [String] instanceLanguages: [String]
} }

View File

@@ -229,13 +229,19 @@ export function useRegistrationConfig() {
const { result, error, loading, onResult } = useQuery<{ const { result, error, loading, onResult } = useQuery<{
config: Pick< config: Pick<
IConfig, IConfig,
"registrationsOpen" | "registrationsAllowlist" | "auth" | "registrationsOpen"
| "registrationsModeration"
| "registrationsAllowlist"
| "auth"
>; >;
}>(CONFIG); }>(CONFIG);
const registrationsOpen = computed( const registrationsOpen = computed(
() => result.value?.config?.registrationsOpen () => result.value?.config?.registrationsOpen
); );
const registrationsModeration = computed(
() => result.value?.config?.registrationsModeration
);
const registrationsAllowlist = computed( const registrationsAllowlist = computed(
() => result.value?.config?.registrationsAllowlist () => result.value?.config?.registrationsAllowlist
); );
@@ -244,6 +250,7 @@ export function useRegistrationConfig() {
); );
return { return {
registrationsOpen, registrationsOpen,
registrationsModeration,
registrationsAllowlist, registrationsAllowlist,
databaseLogin, databaseLogin,
error, error,

View File

@@ -225,6 +225,7 @@ export const ADMIN_SETTINGS_FRAGMENT = gql`
instancePrivacyPolicyUrl instancePrivacyPolicyUrl
instanceRules instanceRules
registrationsOpen registrationsOpen
registrationsModeration
instanceLanguages instanceLanguages
} }
`; `;
@@ -258,6 +259,7 @@ export const SAVE_ADMIN_SETTINGS = gql`
$instancePrivacyPolicyUrl: String $instancePrivacyPolicyUrl: String
$instanceRules: String $instanceRules: String
$registrationsOpen: Boolean $registrationsOpen: Boolean
$registrationsModeration: Boolean
$instanceLanguages: [String] $instanceLanguages: [String]
) { ) {
saveAdminSettings( saveAdminSettings(
@@ -279,6 +281,7 @@ export const SAVE_ADMIN_SETTINGS = gql`
instancePrivacyPolicyUrl: $instancePrivacyPolicyUrl instancePrivacyPolicyUrl: $instancePrivacyPolicyUrl
instanceRules: $instanceRules instanceRules: $instanceRules
registrationsOpen: $registrationsOpen registrationsOpen: $registrationsOpen
registrationsModeration: $registrationsModeration
instanceLanguages: $instanceLanguages instanceLanguages: $instanceLanguages
) { ) {
...adminSettingsFragment ...adminSettingsFragment

View File

@@ -11,6 +11,7 @@ export const CONFIG = gql`
version version
federating federating
registrationsOpen registrationsOpen
registrationsModeration
registrationsAllowlist registrationsAllowlist
demoMode demoMode
longEvents longEvents
@@ -205,6 +206,7 @@ export const ABOUT = gql`
contact contact
languages languages
registrationsOpen registrationsOpen
registrationsModeration
registrationsAllowlist registrationsAllowlist
anonymous { anonymous {
participation { participation {

View File

@@ -975,6 +975,7 @@
"Registration is allowed, anyone can register.": "Registration is allowed, anyone can register.", "Registration is allowed, anyone can register.": "Registration is allowed, anyone can register.",
"Registration is closed.": "Registration is closed.", "Registration is closed.": "Registration is closed.",
"Registration is currently closed.": "Registration is currently closed.", "Registration is currently closed.": "Registration is currently closed.",
"Registration is moderated, new user must be validated.": "Registration is moderated, new user must be validated.",
"Registrations": "Registrations", "Registrations": "Registrations",
"Registrations are restricted by allowlisting.": "Registrations are restricted by allowlisting.", "Registrations are restricted by allowlisting.": "Registrations are restricted by allowlisting.",
"Reject": "Reject", "Reject": "Reject",

View File

@@ -39,5 +39,6 @@ export interface IAdminSettings {
instancePrivacyPolicyUrl: string | null; instancePrivacyPolicyUrl: string | null;
instanceRules: string; instanceRules: string;
registrationsOpen: boolean; registrationsOpen: boolean;
registrationsModeration: boolean;
instanceLanguages: string[]; instanceLanguages: string[];
} }

View File

@@ -43,6 +43,7 @@ export interface IConfig {
secondaryColor: string; secondaryColor: string;
registrationsOpen: boolean; registrationsOpen: boolean;
registrationsModeration: boolean;
registrationsAllowlist: boolean; registrationsAllowlist: boolean;
demoMode: boolean; demoMode: boolean;
longEvents: boolean; longEvents: boolean;

View File

@@ -11,6 +11,12 @@ export enum InstancePrivacyType {
CUSTOM = "CUSTOM", CUSTOM = "CUSTOM",
} }
export enum registrationsModeType {
CLOSE = "CLOSE",
OPEN = "OPEN",
MODERATED = "MODERATED",
}
export enum ICurrentUserRole { export enum ICurrentUserRole {
USER = "USER", USER = "USER",
MODERATOR = "MODERATOR", MODERATOR = "MODERATOR",

View File

@@ -123,17 +123,36 @@
</div> </div>
--> -->
<o-field :label="t('Allow registrations')"> <o-field :label="t('Allow registrations')">
<o-switch v-model="settingsToWrite.registrationsOpen"> <fieldset>
<p <o-field>
class="prose dark:prose-invert" <o-radio
v-if="settingsToWrite.registrationsOpen" v-model="registrationsMode"
name="registrationsModeType"
:native-value="registrationsModeType.CLOSE"
>{{ t("Registration is closed.") }}</o-radio
> >
{{ t("Registration is allowed, anyone can register.") }} </o-field>
</p> <o-field>
<p class="prose dark:prose-invert" v-else> <o-radio
{{ t("Registration is closed.") }} v-model="registrationsMode"
</p> name="registrationsModeType"
</o-switch> :native-value="registrationsModeType.OPEN"
>{{
t("Registration is allowed, anyone can register.")
}}</o-radio
>
</o-field>
<o-field>
<o-radio
v-model="registrationsMode"
name="registrationsModeType"
:native-value="registrationsModeType.MODERATED"
>{{
t("Registration is moderated, new user must be validated.")
}}</o-radio
>
</o-field>
</fieldset>
</o-field> </o-field>
<div class="field flex flex-col"> <div class="field flex flex-col">
<label class="" for="instance-languages">{{ <label class="" for="instance-languages">{{
@@ -447,7 +466,11 @@ import {
SAVE_ADMIN_SETTINGS, SAVE_ADMIN_SETTINGS,
LANGUAGES, LANGUAGES,
} from "@/graphql/admin"; } from "@/graphql/admin";
import { InstancePrivacyType, InstanceTermsType } from "@/types/enums"; import {
InstancePrivacyType,
InstanceTermsType,
registrationsModeType,
} from "@/types/enums";
import { IAdminSettings, ILanguage } from "@/types/admin.model"; import { IAdminSettings, ILanguage } from "@/types/admin.model";
import RouteName from "@/router/name"; import RouteName from "@/router/name";
import { useMutation, useQuery } from "@vue/apollo-composable"; import { useMutation, useQuery } from "@vue/apollo-composable";
@@ -485,6 +508,7 @@ const defaultAdminSettings: IAdminSettings = {
instancePrivacyPolicyUrl: null, instancePrivacyPolicyUrl: null,
instanceRules: "", instanceRules: "",
registrationsOpen: false, registrationsOpen: false,
registrationsModeration: false,
instanceLanguages: [], instanceLanguages: [],
}; };
@@ -533,6 +557,32 @@ watch(adminSettings, () => {
const filteredLanguages = ref<string[]>([]); const filteredLanguages = ref<string[]>([]);
const registrationsMode = computed({
get() {
if (settingsToWrite.value.registrationsOpen == true) {
if (settingsToWrite.value.registrationsModeration == true) {
return registrationsModeType.MODERATED;
} else {
return registrationsModeType.OPEN;
}
} else {
return registrationsModeType.CLOSE;
}
},
set(newMode: string) {
if (newMode == registrationsModeType.OPEN) {
settingsToWrite.value.registrationsOpen = true;
settingsToWrite.value.registrationsModeration = false;
} else if (newMode == registrationsModeType.MODERATED) {
settingsToWrite.value.registrationsOpen = true;
settingsToWrite.value.registrationsModeration = true;
} else {
settingsToWrite.value.registrationsOpen = false;
settingsToWrite.value.registrationsModeration = false;
}
},
});
const instanceLanguages = computed({ const instanceLanguages = computed({
get() { get() {
const languageCodes = [...(adminSettings.value?.instanceLanguages ?? [])]; const languageCodes = [...(adminSettings.value?.instanceLanguages ?? [])];

View File

@@ -212,7 +212,11 @@ const EventParticipationCard = defineAsyncComponent(
const { result: aboutConfigResult } = useQuery<{ const { result: aboutConfigResult } = useQuery<{
config: Pick< config: Pick<
IConfig, IConfig,
"name" | "description" | "slogan" | "registrationsOpen" | "name"
| "description"
| "slogan"
| "registrationsOpen"
| "registrationsModeration"
>; >;
}>(CONFIG); }>(CONFIG);

View File

@@ -162,7 +162,10 @@ const apollo = useApolloClient();
const configQuery = useQuery<{ const configQuery = useQuery<{
config: Pick< config: Pick<
IConfig, IConfig,
"auth" | "registrationsOpen" | "registrationsAllowlist" | "auth"
| "registrationsOpen"
| "registrationsModeration"
| "registrationsAllowlist"
>; >;
}>(CONFIG); }>(CONFIG);

View File

@@ -333,6 +333,7 @@ defmodule Mobilizon.GraphQL.Resolvers.AdminTest do
instancePrivacyPolicyUrl instancePrivacyPolicyUrl
instanceRules instanceRules
registrationsOpen registrationsOpen
registrationsModeration
} }
""" """
@@ -365,13 +366,17 @@ defmodule Mobilizon.GraphQL.Resolvers.AdminTest do
assert res["data"]["adminSettings"]["registrationsOpen"] == assert res["data"]["adminSettings"]["registrationsOpen"] ==
Application.get_env(:mobilizon, :instance)[:registrations_open] Application.get_env(:mobilizon, :instance)[:registrations_open]
assert res["data"]["adminSettings"]["registrationsModeration"] ==
Application.get_env(:mobilizon, :instance)[:registrations_moderation]
end end
@instance_name "My Awesome Instance" @instance_name "My Awesome Instance"
test "from DB", %{conn: conn} do test "from DB 1", %{conn: conn} do
admin = insert(:user, role: :administrator) admin = insert(:user, role: :administrator)
insert(:admin_setting, group: "instance", name: "instance_name", value: @instance_name) insert(:admin_setting, group: "instance", name: "instance_name", value: @instance_name)
insert(:admin_setting, group: "instance", name: "registrations_open", value: "false") insert(:admin_setting, group: "instance", name: "registrations_open", value: "false")
insert(:admin_setting, group: "instance", name: "registrations_moderation", value: "false")
res = res =
conn conn
@@ -381,6 +386,43 @@ defmodule Mobilizon.GraphQL.Resolvers.AdminTest do
assert res["data"]["adminSettings"]["instanceName"] == @instance_name assert res["data"]["adminSettings"]["instanceName"] == @instance_name
assert res["data"]["adminSettings"]["registrationsOpen"] == false assert res["data"]["adminSettings"]["registrationsOpen"] == false
assert res["data"]["adminSettings"]["registrationsModeration"] == false
end
@instance_name "My Awesome Instance"
test "from DB 2", %{conn: conn} do
admin = insert(:user, role: :administrator)
insert(:admin_setting, group: "instance", name: "instance_name", value: @instance_name)
insert(:admin_setting, group: "instance", name: "registrations_open", value: "true")
insert(:admin_setting, group: "instance", name: "registrations_moderation", value: "false")
res =
conn
|> auth_conn(admin)
|> AbsintheHelpers.graphql_query(query: @admin_settings_query)
assert res["data"]["adminSettings"]["instanceName"] == @instance_name
assert res["data"]["adminSettings"]["registrationsOpen"] == true
assert res["data"]["adminSettings"]["registrationsModeration"] == false
end
@instance_name "My Awesome Instance"
test "from DB 3", %{conn: conn} do
admin = insert(:user, role: :administrator)
insert(:admin_setting, group: "instance", name: "instance_name", value: @instance_name)
insert(:admin_setting, group: "instance", name: "registrations_open", value: "true")
insert(:admin_setting, group: "instance", name: "registrations_moderation", value: "true")
res =
conn
|> auth_conn(admin)
|> AbsintheHelpers.graphql_query(query: @admin_settings_query)
assert res["data"]["adminSettings"]["instanceName"] == @instance_name
assert res["data"]["adminSettings"]["registrationsOpen"] == true
assert res["data"]["adminSettings"]["registrationsModeration"] == true
end end
test "unless user isn't admin", %{conn: conn} do test "unless user isn't admin", %{conn: conn} do
@@ -416,6 +458,7 @@ defmodule Mobilizon.GraphQL.Resolvers.AdminTest do
$instancePrivacyPolicyUrl: String $instancePrivacyPolicyUrl: String
$instanceRules: String $instanceRules: String
$registrationsOpen: Boolean $registrationsOpen: Boolean
$registrationsModeration: Boolean
) { ) {
saveAdminSettings( saveAdminSettings(
instanceName: $instanceName instanceName: $instanceName
@@ -430,6 +473,7 @@ defmodule Mobilizon.GraphQL.Resolvers.AdminTest do
instancePrivacyPolicyUrl: $instancePrivacyPolicyUrl instancePrivacyPolicyUrl: $instancePrivacyPolicyUrl
instanceRules: $instanceRules instanceRules: $instanceRules
registrationsOpen: $registrationsOpen registrationsOpen: $registrationsOpen
registrationsModeration: $registrationsModeration
) { ) {
...adminSettingsFragment ...adminSettingsFragment
} }
@@ -453,16 +497,24 @@ defmodule Mobilizon.GraphQL.Resolvers.AdminTest do
assert res["data"]["adminSettings"]["registrationsOpen"] == assert res["data"]["adminSettings"]["registrationsOpen"] ==
Application.get_env(:mobilizon, :instance)[:registrations_open] Application.get_env(:mobilizon, :instance)[:registrations_open]
assert res["data"]["adminSettings"]["registrationsModeration"] ==
Application.get_env(:mobilizon, :instance)[:registrations_moderation]
res = res =
conn conn
|> auth_conn(admin) |> auth_conn(admin)
|> AbsintheHelpers.graphql_query( |> AbsintheHelpers.graphql_query(
query: @update_instance_admin_settings_mutation, query: @update_instance_admin_settings_mutation,
variables: %{"instanceName" => @new_instance_name, "registrationsOpen" => false} variables: %{
"instanceName" => @new_instance_name,
"registrationsOpen" => false,
"registrationsModeration" => false
}
) )
assert res["data"]["saveAdminSettings"]["instanceName"] == @new_instance_name assert res["data"]["saveAdminSettings"]["instanceName"] == @new_instance_name
assert res["data"]["saveAdminSettings"]["registrationsOpen"] == false assert res["data"]["saveAdminSettings"]["registrationsOpen"] == false
assert res["data"]["saveAdminSettings"]["registrationsModeration"] == false
assert %Actor{name: @new_instance_name} = Relay.get_actor() assert %Actor{name: @new_instance_name} = Relay.get_actor()
end end
@@ -475,7 +527,11 @@ defmodule Mobilizon.GraphQL.Resolvers.AdminTest do
|> auth_conn(user) |> auth_conn(user)
|> AbsintheHelpers.graphql_query( |> AbsintheHelpers.graphql_query(
query: @update_instance_admin_settings_mutation, query: @update_instance_admin_settings_mutation,
variables: %{"instanceName" => @new_instance_name, "registrationsOpen" => false} variables: %{
"instanceName" => @new_instance_name,
"registrationsOpen" => false,
"registrationsModeration" => false
}
) )
assert hd(res["errors"])["message"] == assert hd(res["errors"])["message"] ==

View File

@@ -11,6 +11,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
Mobilizon.Config.clear_config_cache() Mobilizon.Config.clear_config_cache()
Config.put([:instance, :name], "Test instance") Config.put([:instance, :name], "Test instance")
Config.put([:instance, :registrations_open], true) Config.put([:instance, :registrations_open], true)
Config.put([:instance, :registrations_moderation], true)
Config.put([:instance, :demo], false) Config.put([:instance, :demo], false)
Config.put([:instance, :duration_of_long_event], 0) Config.put([:instance, :duration_of_long_event], 0)
@@ -26,6 +27,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
config { config {
name, name,
registrationsOpen registrationsOpen
registrationsModeration
anonymous { anonymous {
participation { participation {
allowed, allowed,
@@ -48,6 +50,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
assert res["data"]["config"]["name"] == "Test instance" assert res["data"]["config"]["name"] == "Test instance"
assert res["data"]["config"]["registrationsOpen"] == true assert res["data"]["config"]["registrationsOpen"] == true
assert res["data"]["config"]["registrationsModeration"] == true
assert res["data"]["config"]["anonymous"]["participation"]["validation"]["email"]["enabled"] == assert res["data"]["config"]["anonymous"]["participation"]["validation"]["email"]["enabled"] ==
true true
@@ -65,6 +68,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
Mobilizon.Config.clear_config_cache() Mobilizon.Config.clear_config_cache()
Config.put([:instance, :name], "Test instance") Config.put([:instance, :name], "Test instance")
Config.put([:instance, :registrations_open], true) Config.put([:instance, :registrations_open], true)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :demo], false) Config.put([:instance, :demo], false)
Config.put([:instance, :duration_of_long_event], 0) Config.put([:instance, :duration_of_long_event], 0)
@@ -80,6 +84,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
config { config {
name, name,
registrationsOpen, registrationsOpen,
registrationsModeration
registrations_allowlist, registrations_allowlist,
contact, contact,
demo_mode, demo_mode,
@@ -102,6 +107,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
assert res["data"]["config"]["name"] == "Test instance" assert res["data"]["config"]["name"] == "Test instance"
assert res["data"]["config"]["registrationsOpen"] == true assert res["data"]["config"]["registrationsOpen"] == true
assert res["data"]["config"]["registrationsModeration"] == false
assert res["data"]["config"]["registrations_allowlist"] == false assert res["data"]["config"]["registrations_allowlist"] == false
assert res["data"]["config"]["contact"] == nil assert res["data"]["config"]["contact"] == nil
assert res["data"]["config"]["demo_mode"] == false assert res["data"]["config"]["demo_mode"] == false
@@ -126,6 +132,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
Mobilizon.Config.clear_config_cache() Mobilizon.Config.clear_config_cache()
Config.put([:instance, :name], "My instance") Config.put([:instance, :name], "My instance")
Config.put([:instance, :registrations_open], false) Config.put([:instance, :registrations_open], false)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :demo], true) Config.put([:instance, :demo], true)
Config.put([:instance, :duration_of_long_event], 30) Config.put([:instance, :duration_of_long_event], 30)
Config.put([:instance, :description], "My description") Config.put([:instance, :description], "My description")
@@ -136,6 +143,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
config { config {
name, name,
registrationsOpen, registrationsOpen,
registrationsModeration
demo_mode, demo_mode,
long_events, long_events,
description, description,
@@ -150,6 +158,7 @@ defmodule Mobilizon.GraphQL.Resolvers.ConfigTest do
assert res["data"]["config"]["name"] == "My instance" assert res["data"]["config"]["name"] == "My instance"
assert res["data"]["config"]["registrationsOpen"] == false assert res["data"]["config"]["registrationsOpen"] == false
assert res["data"]["config"]["registrationsModeration"] == false
assert res["data"]["config"]["demo_mode"] == true assert res["data"]["config"]["demo_mode"] == true
assert res["data"]["config"]["long_events"] == true assert res["data"]["config"]["long_events"] == true
assert res["data"]["config"]["description"] == "My description" assert res["data"]["config"]["description"] == "My description"

View File

@@ -406,6 +406,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
test "create_user/3 doesn't allow registration when registration is closed", %{conn: conn} do test "create_user/3 doesn't allow registration when registration is closed", %{conn: conn} do
Config.put([:instance, :registrations_open], false) Config.put([:instance, :registrations_open], false)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :registration_email_allowlist], []) Config.put([:instance, :registration_email_allowlist], [])
res = res =
@@ -417,12 +418,14 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
assert hd(res["errors"])["message"] == "Registrations are not open" assert hd(res["errors"])["message"] == "Registrations are not open"
Config.put([:instance, :registrations_open], true) Config.put([:instance, :registrations_open], true)
Config.put([:instance, :registrations_moderation], false)
end end
test "create_user/3 doesn't allow registration when user email is not on the allowlist", %{ test "create_user/3 doesn't allow registration when user email is not on the allowlist", %{
conn: conn conn: conn
} do } do
Config.put([:instance, :registrations_open], false) Config.put([:instance, :registrations_open], false)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :registration_email_allowlist], ["random.org"]) Config.put([:instance, :registration_email_allowlist], ["random.org"])
res = res =
@@ -434,6 +437,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
assert hd(res["errors"])["message"] == "Your email is not on the allowlist" assert hd(res["errors"])["message"] == "Your email is not on the allowlist"
Config.put([:instance, :registrations_open], true) Config.put([:instance, :registrations_open], true)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :registration_email_allowlist], []) Config.put([:instance, :registration_email_allowlist], [])
end end
@@ -441,6 +445,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
conn: conn conn: conn
} do } do
Config.put([:instance, :registrations_open], false) Config.put([:instance, :registrations_open], false)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :registration_email_allowlist], ["demo.tld"]) Config.put([:instance, :registration_email_allowlist], ["demo.tld"])
res = res =
@@ -453,11 +458,13 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
refute res["errors"] refute res["errors"]
assert res["data"]["createUser"]["email"] == @user_creation.email assert res["data"]["createUser"]["email"] == @user_creation.email
Config.put([:instance, :registrations_open], true) Config.put([:instance, :registrations_open], true)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :registration_email_allowlist], []) Config.put([:instance, :registration_email_allowlist], [])
end end
test "create_user/3 allows registration when user email is on the allowlist", %{conn: conn} do test "create_user/3 allows registration when user email is on the allowlist", %{conn: conn} do
Config.put([:instance, :registrations_open], false) Config.put([:instance, :registrations_open], false)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :registration_email_allowlist], [@user_creation.email]) Config.put([:instance, :registration_email_allowlist], [@user_creation.email])
res = res =
@@ -470,6 +477,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
refute res["errors"] refute res["errors"]
assert res["data"]["createUser"]["email"] == @user_creation.email assert res["data"]["createUser"]["email"] == @user_creation.email
Config.put([:instance, :registrations_open], true) Config.put([:instance, :registrations_open], true)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :registration_email_allowlist], []) Config.put([:instance, :registration_email_allowlist], [])
end end
@@ -489,6 +497,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
"Your e-mail has been denied registration or uses a disallowed e-mail provider" "Your e-mail has been denied registration or uses a disallowed e-mail provider"
Config.put([:instance, :registrations_open], true) Config.put([:instance, :registrations_open], true)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :registration_email_denylist], []) Config.put([:instance, :registration_email_denylist], [])
end end
@@ -508,6 +517,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
"Your e-mail has been denied registration or uses a disallowed e-mail provider" "Your e-mail has been denied registration or uses a disallowed e-mail provider"
Config.put([:instance, :registrations_open], true) Config.put([:instance, :registrations_open], true)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :registration_email_denylist], []) Config.put([:instance, :registration_email_denylist], [])
end end
@@ -528,6 +538,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
"Your e-mail has been denied registration or uses a disallowed e-mail provider" "Your e-mail has been denied registration or uses a disallowed e-mail provider"
Config.put([:instance, :registrations_open], true) Config.put([:instance, :registrations_open], true)
Config.put([:instance, :registrations_moderation], false)
Config.put([:instance, :registration_email_denylist], []) Config.put([:instance, :registration_email_denylist], [])
end end

View File

@@ -42,6 +42,7 @@ defmodule Mobilizon.Web.NodeInfoControllerTest do
"nodeDescription" => Config.instance_description() "nodeDescription" => Config.instance_description()
}, },
"openRegistrations" => Config.instance_registrations_open?(), "openRegistrations" => Config.instance_registrations_open?(),
"moderationRegistrations" => Config.instance_registrations_moderation?(),
"protocols" => ["activitypub"], "protocols" => ["activitypub"],
"services" => %{"inbound" => [], "outbound" => ["atom1.0"]}, "services" => %{"inbound" => [], "outbound" => ["atom1.0"]},
"software" => %{ "software" => %{

View File

@@ -0,0 +1,129 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`SettingsView > Show and save settings 1`] = `
"<div data-v-a8bb2abf="">
<breadcrumbs-nav data-v-a8bb2abf="" links="[object Object],[object Object]"></breadcrumbs-nav>
<section data-v-a8bb2abf="">
<form data-v-a8bb2abf="">
<o-field data-v-a8bb2abf="" label="Instance Name" label-for="instance-name">
<o-input data-v-a8bb2abf="" modelvalue="Mobilizon.test" id="instance-name" expanded=""></o-input>
</o-field>
<div data-v-a8bb2abf="" class="field flex flex-col"><label data-v-a8bb2abf="" class="" for="instance-description">Instance Short Description</label><small data-v-a8bb2abf="">Displayed on homepage and meta tags. Describe what Mobilizon is and what makes this instance special in a single paragraph.</small>
<o-input data-v-a8bb2abf="" type="textarea" modelvalue="Welcome to Mobilizon" rows="2" id="instance-description"></o-input>
</div>
<div data-v-a8bb2abf="" class="field flex flex-col"><label data-v-a8bb2abf="" class="" for="instance-slogan">Instance Slogan</label><small data-v-a8bb2abf="">A short tagline for your instance homepage. Defaults to "Gather ⋅ Organize ⋅ Mobilize"</small>
<o-input data-v-a8bb2abf="" modelvalue="Long life to Mobilizon" placeholder="Gather ⋅ Organize ⋅ Mobilize" id="instance-slogan"></o-input>
</div>
<div data-v-a8bb2abf="" class="field flex flex-col"><label data-v-a8bb2abf="" class="" for="instance-contact">Contact</label><small data-v-a8bb2abf="">Can be an email or a link, or just plain text.</small>
<o-input data-v-a8bb2abf="" modelvalue="info@mobilizon.test" id="instance-contact"></o-input>
</div><label data-v-a8bb2abf="" class="field flex flex-col">
<p data-v-a8bb2abf="">Logo</p><small data-v-a8bb2abf="">Logo of the instance. Defaults to the upstream Mobilizon logo.</small>
<picture-upload-stub data-v-a8bb2abf="" textfallback="Logo" accept="image/gif,image/png,image/jpeg,image/webp" maxsize="10485760"></picture-upload-stub>
</label><label data-v-a8bb2abf="" class="field flex flex-col">
<p data-v-a8bb2abf="">Favicon</p><small data-v-a8bb2abf="">Browser tab icon and PWA icon of the instance. Defaults to the upstream Mobilizon icon.</small>
<picture-upload-stub data-v-a8bb2abf="" textfallback="Favicon" accept="image/gif,image/png,image/jpeg,image/webp" maxsize="10485760"></picture-upload-stub>
</label><label data-v-a8bb2abf="" class="field flex flex-col">
<p data-v-a8bb2abf="">Default Picture</p><small data-v-a8bb2abf="">Default picture when an event or group doesn't have one.</small>
<picture-upload-stub data-v-a8bb2abf="" textfallback="Default Picture" accept="image/gif,image/png,image/jpeg,image/webp" maxsize="10485760"></picture-upload-stub>
</label>
<!-- piece of code to manage instance colors
<div class="field flex flex-col">
<label class="" for="primary-color">{{ t("Primary Color") }}</label>
<o-input
type="color"
v-model="settingsToWrite.primaryColor"
id="primary-color"
/>
</div>
<div class="field flex flex-col">
<label class="" for="secondary-color">{{
t("Secondary Color")
}}</label>
<o-input
type="color"
v-model="settingsToWrite.secondaryColor"
id="secondary-color"
/>
</div>
-->
<o-field data-v-a8bb2abf="" label="Allow registrations">
<fieldset data-v-a8bb2abf="">
<o-field data-v-a8bb2abf="">
<o-radio data-v-a8bb2abf="" modelvalue="OPEN" name="registrationsModeType" native-value="CLOSE">Registration is closed.</o-radio>
</o-field>
<o-field data-v-a8bb2abf="">
<o-radio data-v-a8bb2abf="" modelvalue="OPEN" name="registrationsModeType" native-value="OPEN">Registration is allowed, anyone can register.</o-radio>
</o-field>
<o-field data-v-a8bb2abf="">
<o-radio data-v-a8bb2abf="" modelvalue="OPEN" name="registrationsModeType" native-value="MODERATED">Registration is moderated, new user must be validated.</o-radio>
</o-field>
</fieldset>
</o-field>
<div data-v-a8bb2abf="" class="field flex flex-col"><label data-v-a8bb2abf="" class="" for="instance-languages">Instance languages</label><small data-v-a8bb2abf="">Main languages you/your moderators speak</small>
<o-taginput data-v-a8bb2abf="" modelvalue="" data="" allow-autocomplete="" open-on-focus="true" field="name" icon="label" placeholder="Select languages" id="instance-languages"></o-taginput>
</div>
<div data-v-a8bb2abf="" class="field flex flex-col"><label data-v-a8bb2abf="" class="" for="instance-long-description">Instance Long Description</label><small data-v-a8bb2abf="">A place to explain who you are and the things that set your instance apart. You can use HTML tags.</small>
<o-input data-v-a8bb2abf="" type="textarea" modelvalue="Mobilizon instance." rows="4" id="instance-long-description"></o-input>
</div>
<div data-v-a8bb2abf="" class="field flex flex-col"><label data-v-a8bb2abf="" class="" for="instance-rules">Instance Rules</label><small data-v-a8bb2abf="">A place for your code of conduct, rules or guidelines. You can use HTML tags.</small>
<o-input data-v-a8bb2abf="" type="textarea" id="instance-rules"></o-input>
</div>
<o-field data-v-a8bb2abf="" label="Instance Terms Source">
<div data-v-a8bb2abf="" class="">
<div data-v-a8bb2abf="" class="">
<fieldset data-v-a8bb2abf="">
<legend data-v-a8bb2abf="">Choose the source of the instance's Terms</legend>
<o-field data-v-a8bb2abf="">
<o-radio data-v-a8bb2abf="" modelvalue="DEFAULT" name="instanceTermsType" native-value="DEFAULT">Default Mobilizon terms</o-radio>
</o-field>
<o-field data-v-a8bb2abf="">
<o-radio data-v-a8bb2abf="" modelvalue="DEFAULT" name="instanceTermsType" native-value="URL">Custom URL</o-radio>
</o-field>
<o-field data-v-a8bb2abf="">
<o-radio data-v-a8bb2abf="" modelvalue="DEFAULT" name="instanceTermsType" native-value="CUSTOM">Custom text</o-radio>
</o-field>
</fieldset>
</div>
<div data-v-a8bb2abf="" class="">
<o-notification data-v-a8bb2abf="" class="bg-slate-700"><b data-v-a8bb2abf="">Default</b>
<i18n-t-stub data-v-a8bb2abf="" tag="p" keypath="The {default_terms} will be used. They will be translated in the user's language." scope="parent" class="prose dark:prose-invert"></i18n-t-stub><b data-v-a8bb2abf="">NOTE! The default terms have not been checked over by a lawyer and thus are unlikely to provide full legal protection for all situations for an instance admin using them. They are also not specific to all countries and jurisdictions. If you are unsure, please check with a lawyer.</b>
</o-notification>
<!--v-if-->
<!--v-if-->
</div>
</div>
</o-field>
<!--v-if-->
<!--v-if-->
<o-field data-v-a8bb2abf="" label="Instance Privacy Policy Source">
<div data-v-a8bb2abf="" class="">
<div data-v-a8bb2abf="" class="">
<fieldset data-v-a8bb2abf="">
<legend data-v-a8bb2abf="">Choose the source of the instance's Privacy Policy</legend>
<o-field data-v-a8bb2abf="">
<o-radio data-v-a8bb2abf="" modelvalue="DEFAULT" name="instancePrivacyType" native-value="DEFAULT">Default Mobilizon privacy policy</o-radio>
</o-field>
<o-field data-v-a8bb2abf="">
<o-radio data-v-a8bb2abf="" modelvalue="DEFAULT" name="instancePrivacyType" native-value="URL">Custom URL</o-radio>
</o-field>
<o-field data-v-a8bb2abf="">
<o-radio data-v-a8bb2abf="" modelvalue="DEFAULT" name="instancePrivacyType" native-value="CUSTOM">Custom text</o-radio>
</o-field>
</fieldset>
</div>
<div data-v-a8bb2abf="" class="">
<div data-v-a8bb2abf="" class="notification"><b data-v-a8bb2abf="">Default</b>
<i18n-t-stub data-v-a8bb2abf="" tag="p" keypath="The {default_privacy_policy} will be used. They will be translated in the user's language." scope="parent" class="prose dark:prose-invert"></i18n-t-stub>
</div>
<!--v-if-->
<!--v-if-->
</div>
</div>
</o-field>
<!--v-if-->
<!--v-if-->
<o-button data-v-a8bb2abf="" native-type="submit" variant="primary">Save</o-button>
</form>
</section>
</div>"
`;

View File

@@ -0,0 +1,176 @@
import { describe, it, expect, vi } from "vitest";
import { DefaultApolloClient } from "@vue/apollo-composable";
import { shallowMount } from "@vue/test-utils";
import buildCurrentUserResolver from "@/apollo/user";
import flushPromises from "flush-promises";
import { cache } from "@/apollo/memory";
import {
createMockClient,
MockApolloClient,
RequestHandler,
} from "mock-apollo-client";
import SettingsView from "@/views/Admin/SettingsView.vue";
import { nullMock } from "../../common";
import { CONFIG } from "@/graphql/config";
import {
ADMIN_SETTINGS,
SAVE_ADMIN_SETTINGS,
LANGUAGES,
} from "@/graphql/admin";
let mockClient: MockApolloClient | null;
let requestHandlers: Record<string, RequestHandler>;
const languageMock = {
data: {
languages: [
{
__typename: "Language",
code: "es",
name: "Spanish",
},
{
__typename: "Language",
code: "fr-FR",
name: "Français",
},
{
__typename: "Language",
code: "en-EN",
name: "English",
},
],
},
};
const settingMock = {
data: {
adminSettings: {
__typename: "AdminSettings",
contact: "info@mobilizon.test",
defaultPicture: null,
instanceDescription: "Welcome to Mobilizon",
instanceFavicon: null,
instanceLanguages: ["fr"],
instanceLogo: null,
instanceLongDescription: "Mobilizon instance.",
instanceName: "Mobilizon.test",
instancePrivacyPolicy: '<p class="message-body">Privacy policy</p>',
instancePrivacyPolicyType: "DEFAULT",
instancePrivacyPolicyUrl: null,
instanceRules: null,
instanceSlogan: "Long life to Mobilizon",
instanceTerms: '<p class="message-body">Rulls and terms</p>',
instanceTermsType: "DEFAULT",
instanceTermsUrl: null,
primaryColor: null,
registrationsOpen: true,
registrationsModeration: false,
secondaryColor: null,
},
},
};
const generateWrapper = () => {
mockClient = createMockClient({
cache,
resolvers: buildCurrentUserResolver(cache),
});
requestHandlers = {
config: vi.fn().mockResolvedValue(nullMock),
settings: vi.fn().mockResolvedValue(settingMock),
save_settings: vi.fn().mockResolvedValue(nullMock),
languages: vi.fn().mockResolvedValue(languageMock),
};
mockClient.setRequestHandler(CONFIG, requestHandlers.config);
mockClient.setRequestHandler(ADMIN_SETTINGS, requestHandlers.settings);
mockClient.setRequestHandler(
SAVE_ADMIN_SETTINGS,
requestHandlers.save_settings
);
mockClient.setRequestHandler(LANGUAGES, requestHandlers.languages);
return shallowMount(SettingsView, {
props: {},
global: {
provide: {
[DefaultApolloClient]: mockClient,
},
},
});
};
describe("SettingsView", () => {
it("Show and save settings", async () => {
const wrapper = generateWrapper();
await wrapper.vm.$nextTick();
await flushPromises();
expect(wrapper.exists()).toBe(true);
expect(requestHandlers.config).toHaveBeenCalled();
expect(requestHandlers.languages).toHaveBeenCalled();
expect(requestHandlers.settings).toHaveBeenCalled();
expect(requestHandlers.save_settings).toHaveBeenCalledTimes(0);
expect(wrapper.html()).toMatchSnapshot();
expect(wrapper.find("#instance-description").attributes("modelvalue")).toBe(
"Welcome to Mobilizon"
);
expect(wrapper.find("#instance-contact").attributes("modelvalue")).toBe(
"info@mobilizon.test"
);
const radiolist1 = wrapper
.findAll('o-radio[name="registrationsModeType"]')
.filter(
(radio) =>
radio.attributes("modelvalue") == radio.attributes("native-value")
);
expect(radiolist1.length).toBe(1);
expect(radiolist1[0].text()).toBe(
"Registration is allowed, anyone can register."
);
wrapper.vm.settingsToWrite.instanceDescription = "Best Mobilizon";
wrapper.vm.settingsToWrite.contact = "some@email.tld";
wrapper.vm.settingsToWrite.registrationsOpen = false;
await wrapper.vm.$nextTick();
expect(wrapper.find("#instance-description").attributes("modelvalue")).toBe(
"Best Mobilizon"
);
expect(wrapper.find("#instance-contact").attributes("modelvalue")).toBe(
"some@email.tld"
);
const radiolist2 = wrapper
.findAll('o-radio[name="registrationsModeType"]')
.filter(
(radio) =>
radio.attributes("modelvalue") == radio.attributes("native-value")
);
expect(radiolist2.length).toBe(1);
expect(radiolist2[0].text()).toBe("Registration is closed.");
wrapper.find("form").trigger("submit");
expect(requestHandlers.save_settings).toHaveBeenCalledTimes(1);
expect(requestHandlers.save_settings).toBeCalledWith({
...settingMock.data.adminSettings,
contact: "some@email.tld",
instanceDescription: "Best Mobilizon",
registrationsOpen: false,
defaultPicture: {},
instanceFavicon: {},
instanceLogo: {},
});
wrapper.vm.settingsToWrite.registrationsOpen = true;
wrapper.vm.settingsToWrite.registrationsModeration = true;
await wrapper.vm.$nextTick();
const radiolist3 = wrapper
.findAll('o-radio[name="registrationsModeType"]')
.filter(
(radio) =>
radio.attributes("modelvalue") == radio.attributes("native-value")
);
expect(radiolist3.length).toBe(1);
expect(radiolist3[0].text()).toBe(
"Registration is moderated, new user must be validated."
);
});
});

View File

@@ -87,6 +87,7 @@ export const configMock = {
name: "Mobilizon", name: "Mobilizon",
registrationsAllowlist: false, registrationsAllowlist: false,
registrationsOpen: true, registrationsOpen: true,
registrationsModeration: false,
resourceProviders: [ resourceProviders: [
{ {
__typename: "ResourceProvider", __typename: "ResourceProvider",
@@ -139,6 +140,7 @@ export const loginMock = {
oauthProviders: [], oauthProviders: [],
}, },
registrationsOpen: true, registrationsOpen: true,
registrationsModeration: false,
}, },
}, },
}; };