[Adminitration] Allow registrations: 3 modes = "close", "allowed", "moderate" - #877
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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?(),
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -1698,4 +1699,4 @@
|
|||||||
"{user}'s follow request was accepted": "{user}'s follow request was accepted",
|
"{user}'s follow request was accepted": "{user}'s follow request was accepted",
|
||||||
"{user}'s follow request was rejected": "{user}'s follow request was rejected",
|
"{user}'s follow request was rejected": "{user}'s follow request was rejected",
|
||||||
"\u00a9 The OpenStreetMap Contributors": "\u00a9 The OpenStreetMap Contributors"
|
"\u00a9 The OpenStreetMap Contributors": "\u00a9 The OpenStreetMap Contributors"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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"
|
||||||
{{ t("Registration is allowed, anyone can register.") }}
|
:native-value="registrationsModeType.CLOSE"
|
||||||
</p>
|
>{{ t("Registration is closed.") }}</o-radio
|
||||||
<p class="prose dark:prose-invert" v-else>
|
>
|
||||||
{{ t("Registration is closed.") }}
|
</o-field>
|
||||||
</p>
|
<o-field>
|
||||||
</o-switch>
|
<o-radio
|
||||||
|
v-model="registrationsMode"
|
||||||
|
name="registrationsModeType"
|
||||||
|
: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 ?? [])];
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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"] ==
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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" => %{
|
||||||
|
|||||||
@@ -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>"
|
||||||
|
`;
|
||||||
176
tests/unit/specs/components/admin/settings.spec.ts
Normal file
176
tests/unit/specs/components/admin/settings.spec.ts
Normal 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."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -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,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user