user list for moderation of pending users - #877
This commit is contained in:
@@ -332,6 +332,11 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
|
|||||||
description: "Filter users by current signed-in IP address"
|
description: "Filter users by current signed-in IP address"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
arg(:pending_user, :boolean,
|
||||||
|
default_value: false,
|
||||||
|
description: "Filter users by pending or not"
|
||||||
|
)
|
||||||
|
|
||||||
arg(:page, :integer, default_value: 1, description: "The page in the paginated users list")
|
arg(:page, :integer, default_value: 1, description: "The page in the paginated users list")
|
||||||
arg(:limit, :integer, default_value: 10, description: "The limit of users per page")
|
arg(:limit, :integer, default_value: 10, description: "The limit of users per page")
|
||||||
|
|
||||||
|
|||||||
@@ -290,6 +290,7 @@ defmodule Mobilizon.Users do
|
|||||||
@spec list_users(Keyword.t()) :: Page.t(User.t())
|
@spec list_users(Keyword.t()) :: Page.t(User.t())
|
||||||
def list_users(options) do
|
def list_users(options) do
|
||||||
User
|
User
|
||||||
|
|> filter_by_pending(Keyword.get(options, :pending_user))
|
||||||
|> filter_by_email(Keyword.get(options, :email))
|
|> filter_by_email(Keyword.get(options, :email))
|
||||||
|> filter_by_ip(Keyword.get(options, :current_sign_in_ip))
|
|> filter_by_ip(Keyword.get(options, :current_sign_in_ip))
|
||||||
|> sort(Keyword.get(options, :sort), Keyword.get(options, :direction))
|
|> sort(Keyword.get(options, :sort), Keyword.get(options, :direction))
|
||||||
@@ -534,6 +535,11 @@ defmodule Mobilizon.Users do
|
|||||||
where(User, [u], u.id == ^user_id)
|
where(User, [u], u.id == ^user_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@spec filter_by_pending(Ecto.Queryable.t(), Boolean.t() | nil) :: Ecto.Query.t()
|
||||||
|
defp filter_by_pending(query, nil), do: query
|
||||||
|
defp filter_by_pending(query, true), do: where(query, [q], q.role == :pending)
|
||||||
|
defp filter_by_pending(query, false), do: where(query, [q], q.role != :pending)
|
||||||
|
|
||||||
@spec filter_by_email(Ecto.Queryable.t(), String.t() | nil) :: Ecto.Query.t()
|
@spec filter_by_email(Ecto.Queryable.t(), String.t() | nil) :: Ecto.Query.t()
|
||||||
defp filter_by_email(query, nil), do: query
|
defp filter_by_email(query, nil), do: query
|
||||||
defp filter_by_email(query, ""), do: query
|
defp filter_by_email(query, ""), do: query
|
||||||
|
|||||||
@@ -271,6 +271,7 @@ export const LIST_USERS = gql`
|
|||||||
query ListUsers(
|
query ListUsers(
|
||||||
$email: String
|
$email: String
|
||||||
$currentSignInIp: String
|
$currentSignInIp: String
|
||||||
|
$pendingUser: Boolean
|
||||||
$page: Int
|
$page: Int
|
||||||
$limit: Int
|
$limit: Int
|
||||||
$sort: SortableUserField
|
$sort: SortableUserField
|
||||||
@@ -279,6 +280,7 @@ export const LIST_USERS = gql`
|
|||||||
users(
|
users(
|
||||||
email: $email
|
email: $email
|
||||||
currentSignInIp: $currentSignInIp
|
currentSignInIp: $currentSignInIp
|
||||||
|
pendingUser: $pendingUser
|
||||||
page: $page
|
page: $page
|
||||||
limit: $limit
|
limit: $limit
|
||||||
sort: $sort
|
sort: $sort
|
||||||
|
|||||||
@@ -854,7 +854,7 @@
|
|||||||
"Open user menu": "Open user menu",
|
"Open user menu": "Open user menu",
|
||||||
"Opened reports": "Opened reports",
|
"Opened reports": "Opened reports",
|
||||||
"Open": "Open",
|
"Open": "Open",
|
||||||
"Options":"Options",
|
"Options": "Options",
|
||||||
"Or": "Or",
|
"Or": "Or",
|
||||||
"Ordered list": "Ordered list",
|
"Ordered list": "Ordered list",
|
||||||
"Organized": "Organized",
|
"Organized": "Organized",
|
||||||
@@ -1374,6 +1374,7 @@
|
|||||||
"User suspended and report resolved": "User suspended and report resolved",
|
"User suspended and report resolved": "User suspended and report resolved",
|
||||||
"Username": "Username",
|
"Username": "Username",
|
||||||
"Users": "Users",
|
"Users": "Users",
|
||||||
|
"Users pending for moderation": "Users pending for moderation",
|
||||||
"Validating account": "Validating account",
|
"Validating account": "Validating account",
|
||||||
"Validating email": "Validating email",
|
"Validating email": "Validating email",
|
||||||
"Video Conference": "Video Conference",
|
"Video Conference": "Video Conference",
|
||||||
|
|||||||
@@ -10,8 +10,13 @@
|
|||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
<div v-if="users">
|
<div v-if="users">
|
||||||
<form @submit.prevent="activateFilters">
|
<form>
|
||||||
<o-field class="mb-5" grouped group-multiline>
|
<o-field class="mb-5" grouped group-multiline>
|
||||||
|
<p class="control mb-3 m-auto" v-if="registrationsModeration">
|
||||||
|
<o-checkbox v-model="pendingFieldValue">{{
|
||||||
|
$t("Users pending for moderation")
|
||||||
|
}}</o-checkbox>
|
||||||
|
</p>
|
||||||
<o-field :label="$t('Email')" expanded>
|
<o-field :label="$t('Email')" expanded>
|
||||||
<o-input trap-focus icon="email" v-model="emailFilterFieldValue" />
|
<o-input trap-focus icon="email" v-model="emailFilterFieldValue" />
|
||||||
</o-field>
|
</o-field>
|
||||||
@@ -19,7 +24,7 @@
|
|||||||
<o-input icon="web" v-model="ipFilterFieldValue" />
|
<o-input icon="web" v-model="ipFilterFieldValue" />
|
||||||
</o-field>
|
</o-field>
|
||||||
<p class="control self-end mb-0">
|
<p class="control self-end mb-0">
|
||||||
<o-button variant="primary" native-type="submit">{{
|
<o-button variant="primary" @click="filterUsers">{{
|
||||||
$t("Filter")
|
$t("Filter")
|
||||||
}}</o-button>
|
}}</o-button>
|
||||||
</p>
|
</p>
|
||||||
@@ -112,17 +117,29 @@ import { useI18n } from "vue-i18n";
|
|||||||
import { useHead } from "@/utils/head";
|
import { useHead } from "@/utils/head";
|
||||||
import { integerTransformer, useRouteQuery } from "vue-use-route-query";
|
import { integerTransformer, useRouteQuery } from "vue-use-route-query";
|
||||||
import { formatDateTimeString } from "@/filters/datetime";
|
import { formatDateTimeString } from "@/filters/datetime";
|
||||||
|
import { useRegistrationConfig } from "@/composition/apollo/config";
|
||||||
|
|
||||||
|
const { registrationsModeration } = useRegistrationConfig();
|
||||||
|
|
||||||
const USERS_PER_PAGE = 10;
|
const USERS_PER_PAGE = 10;
|
||||||
|
|
||||||
const emailFilter = useRouteQuery("emailFilter", "");
|
const emailFilter = useRouteQuery("emailFilter", "");
|
||||||
const ipFilter = useRouteQuery("ipFilter", "");
|
const ipFilter = useRouteQuery("ipFilter", "");
|
||||||
|
const pendingFilter = useRouteQuery("pendingFilter", "true");
|
||||||
const page = useRouteQuery("page", 1, integerTransformer);
|
const page = useRouteQuery("page", 1, integerTransformer);
|
||||||
|
|
||||||
const languagesCodes = computed((): string[] => {
|
const languagesCodes = computed((): string[] => {
|
||||||
return (users.value?.elements ?? []).map((user: IUser) => user.locale);
|
return (users.value?.elements ?? []).map((user: IUser) => user.locale);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const pendingFilterBuilder = computed(() => {
|
||||||
|
if (registrationsModeration.value) {
|
||||||
|
return pendingFilter.value == "true";
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const {
|
const {
|
||||||
result: usersResult,
|
result: usersResult,
|
||||||
fetchMore,
|
fetchMore,
|
||||||
@@ -130,6 +147,7 @@ const {
|
|||||||
} = useQuery<{ users: Paginate<IUser> }>(LIST_USERS, () => ({
|
} = useQuery<{ users: Paginate<IUser> }>(LIST_USERS, () => ({
|
||||||
email: emailFilter.value,
|
email: emailFilter.value,
|
||||||
currentSignInIp: ipFilter.value,
|
currentSignInIp: ipFilter.value,
|
||||||
|
pendingUser: pendingFilterBuilder.value,
|
||||||
page: page.value,
|
page: page.value,
|
||||||
limit: USERS_PER_PAGE,
|
limit: USERS_PER_PAGE,
|
||||||
}));
|
}));
|
||||||
@@ -156,6 +174,7 @@ useHead({
|
|||||||
|
|
||||||
const emailFilterFieldValue = ref(emailFilter.value);
|
const emailFilterFieldValue = ref(emailFilter.value);
|
||||||
const ipFilterFieldValue = ref(ipFilter.value);
|
const ipFilterFieldValue = ref(ipFilter.value);
|
||||||
|
const pendingFieldValue = ref(pendingFilter.value == "true");
|
||||||
|
|
||||||
const getLanguageNameForCode = (code: string): string => {
|
const getLanguageNameForCode = (code: string): string => {
|
||||||
return (
|
return (
|
||||||
@@ -171,20 +190,31 @@ const onPageChange = async (newPage: number): Promise<void> => {
|
|||||||
variables: {
|
variables: {
|
||||||
email: emailFilter.value,
|
email: emailFilter.value,
|
||||||
currentSignInIp: ipFilter.value,
|
currentSignInIp: ipFilter.value,
|
||||||
|
pendingUser: pendingFilterBuilder.value,
|
||||||
page: page.value,
|
page: page.value,
|
||||||
limit: USERS_PER_PAGE,
|
limit: USERS_PER_PAGE,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const activateFilters = (): void => {
|
const filterUsers = async (): void => {
|
||||||
emailFilter.value = emailFilterFieldValue.value;
|
emailFilter.value = emailFilterFieldValue.value;
|
||||||
ipFilter.value = ipFilterFieldValue.value;
|
ipFilter.value = ipFilterFieldValue.value;
|
||||||
|
if (registrationsModeration.value) {
|
||||||
|
if (pendingFieldValue.value) {
|
||||||
|
pendingFilter.value = "true";
|
||||||
|
} else {
|
||||||
|
pendingFilter.value = "false";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pendingFilter.value = "";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const resetFilters = (): void => {
|
const resetFilters = (): void => {
|
||||||
emailFilterFieldValue.value = "";
|
emailFilterFieldValue.value = "";
|
||||||
ipFilterFieldValue.value = "";
|
ipFilterFieldValue.value = "";
|
||||||
|
pendingFieldValue.value = true;
|
||||||
activateFilters();
|
activateFilters();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
|
|||||||
query ListUsers(
|
query ListUsers(
|
||||||
$email: String
|
$email: String
|
||||||
$currentSignInIp: String
|
$currentSignInIp: String
|
||||||
|
$pendingUser: Boolean
|
||||||
$page: Int
|
$page: Int
|
||||||
$limit: Int
|
$limit: Int
|
||||||
$sort: SortableUserField
|
$sort: SortableUserField
|
||||||
@@ -46,6 +47,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
|
|||||||
users(
|
users(
|
||||||
email: $email
|
email: $email
|
||||||
currentSignInIp: $currentSignInIp
|
currentSignInIp: $currentSignInIp
|
||||||
|
pendingUser: $pendingUser
|
||||||
page: $page
|
page: $page
|
||||||
limit: $limit
|
limit: $limit
|
||||||
sort: $sort
|
sort: $sort
|
||||||
@@ -246,6 +248,7 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
|
|||||||
user = insert(:user, email: "riri@example.com", role: :moderator)
|
user = insert(:user, email: "riri@example.com", role: :moderator)
|
||||||
insert(:user, email: "fifi@example.com")
|
insert(:user, email: "fifi@example.com")
|
||||||
insert(:user, email: "loulou@example.com")
|
insert(:user, email: "loulou@example.com")
|
||||||
|
insert(:user, email: "picsous@example.com", role: :pending)
|
||||||
|
|
||||||
res =
|
res =
|
||||||
conn
|
conn
|
||||||
@@ -259,6 +262,25 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
|
|||||||
assert res["data"]["users"]["total"] == 3
|
assert res["data"]["users"]["total"] == 3
|
||||||
assert res["data"]["users"]["elements"] |> length == 3
|
assert res["data"]["users"]["elements"] |> length == 3
|
||||||
|
|
||||||
|
assert res["data"]["users"]["elements"]
|
||||||
|
|> Enum.map(& &1["email"]) == [
|
||||||
|
"loulou@example.com",
|
||||||
|
"fifi@example.com",
|
||||||
|
"riri@example.com"
|
||||||
|
]
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> AbsintheHelpers.graphql_query(
|
||||||
|
query: @list_users_query,
|
||||||
|
variables: %{pendingUser: false}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] == nil
|
||||||
|
assert res["data"]["users"]["total"] == 3
|
||||||
|
assert res["data"]["users"]["elements"] |> length == 3
|
||||||
|
|
||||||
assert res["data"]["users"]["elements"]
|
assert res["data"]["users"]["elements"]
|
||||||
|> Enum.map(& &1["email"]) == [
|
|> Enum.map(& &1["email"]) == [
|
||||||
"loulou@example.com",
|
"loulou@example.com",
|
||||||
@@ -297,6 +319,22 @@ defmodule Mobilizon.GraphQL.Resolvers.UserTest do
|
|||||||
assert res["data"]["users"]["elements"] |> Enum.map(& &1["email"]) == [
|
assert res["data"]["users"]["elements"] |> Enum.map(& &1["email"]) == [
|
||||||
"riri@example.com"
|
"riri@example.com"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
res =
|
||||||
|
conn
|
||||||
|
|> auth_conn(user)
|
||||||
|
|> AbsintheHelpers.graphql_query(
|
||||||
|
query: @list_users_query,
|
||||||
|
variables: %{pendingUser: true}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert res["errors"] == nil
|
||||||
|
assert res["data"]["users"]["total"] == 1
|
||||||
|
assert res["data"]["users"]["elements"] |> length == 1
|
||||||
|
|
||||||
|
assert res["data"]["users"]["elements"] |> Enum.map(& &1["email"]) == [
|
||||||
|
"picsous@example.com"
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "list_users/3 allows filtering the list of users by email", %{conn: conn} do
|
test "list_users/3 allows filtering the list of users by email", %{conn: conn} do
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`UsersView > Show simple list 1`] = `
|
exports[`UsersView > Show list with moderation 1`] = `
|
||||||
"<div data-v-01123d3b="">
|
"<div data-v-01123d3b="">
|
||||||
<breadcrumbs-nav data-v-01123d3b="" links="[object Object],[object Object]"></breadcrumbs-nav>
|
<breadcrumbs-nav data-v-01123d3b="" links="[object Object],[object Object]"></breadcrumbs-nav>
|
||||||
<div data-v-01123d3b="">
|
<div data-v-01123d3b="">
|
||||||
@@ -9,6 +9,7 @@ exports[`UsersView > Show simple list 1`] = `
|
|||||||
<!---->
|
<!---->
|
||||||
<div class="o-field__body">
|
<div class="o-field__body">
|
||||||
<div class="o-field o-field--grouped-multiline o-field--grouped">
|
<div class="o-field o-field--grouped-multiline o-field--grouped">
|
||||||
|
<p data-v-01123d3b="" class="control mb-3 m-auto"><label data-v-01123d3b="" class="o-chk o-chk--checked" data-oruga="checkbox" role="checkbox" aria-checked="true"><input type="checkbox" data-oruga-input="checkbox" class="o-chk__input o-chk__input--checked" autocomplete="off" true-value="true" false-value="false"><span class="o-chk__label">Users pending for moderation</span></label></p>
|
||||||
<div data-v-01123d3b="" data-oruga="field" class="o-field" expanded=""><label class="o-field__label" for="">Email</label>
|
<div data-v-01123d3b="" data-oruga="field" class="o-field" expanded=""><label class="o-field__label" for="">Email</label>
|
||||||
<div class="o-field__body">
|
<div class="o-field__body">
|
||||||
<div class="o-field o-field--addons">
|
<div class="o-field o-field--addons">
|
||||||
@@ -31,7 +32,121 @@ exports[`UsersView > Show simple list 1`] = `
|
|||||||
</div>
|
</div>
|
||||||
<!---->
|
<!---->
|
||||||
</div>
|
</div>
|
||||||
<p data-v-01123d3b="" class="control self-end mb-0"><button data-v-01123d3b="" type="submit" class="o-btn o-btn--primary" role="button" data-oruga="button"><span class="o-btn__wrapper"><!----><span class="o-btn__label">Filter</span>
|
<p data-v-01123d3b="" class="control self-end mb-0"><button data-v-01123d3b="" type="button" class="o-btn o-btn--primary" role="button" data-oruga="button"><span class="o-btn__wrapper"><!----><span class="o-btn__label">Filter</span>
|
||||||
|
<!----></span>
|
||||||
|
</button></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div data-v-01123d3b="" class="o-table__root" data-oruga="table">
|
||||||
|
<div style="display: none;"><span data-v-01123d3b="" data-id="1" data-oruga="table-column"> <!----></span><span data-v-01123d3b="" data-id="2" data-oruga="table-column">Email <!----></span><span data-v-01123d3b="" data-id="3" data-oruga="table-column" centered="true">Last seen on <!----></span><span data-v-01123d3b="" data-id="4" data-oruga="table-column" centered="true">Language <!----></span></div>
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
<div class="o-table__wrapper">
|
||||||
|
<table class="o-table">
|
||||||
|
<!---->
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
<th class="o-table__th" style="width: 40px;" draggable="false"><span> <span class="o-table__th__sort-icon" style="display: none;"><span class="o-icon o-icon--small" data-oruga="icon"><i class="mdi mdi-arrow-up"></i></span></span></span></th>
|
||||||
|
<th class="o-table__th" draggable="false"><span>Email <span class="o-table__th__sort-icon" style="display: none;"><span class="o-icon o-icon--small" data-oruga="icon"><i class="mdi mdi-arrow-up"></i></span></span></span></th>
|
||||||
|
<th class="o-table__th" draggable="false"><span>Last seen on <span class="o-table__th__sort-icon" style="display: none;"><span class="o-icon o-icon--small" data-oruga="icon"><i class="mdi mdi-arrow-up"></i></span></span></span></th>
|
||||||
|
<th class="o-table__th" draggable="false"><span>Language <span class="o-table__th__sort-icon" style="display: none;"><span class="o-icon o-icon--small" data-oruga="icon"><i class="mdi mdi-arrow-up"></i></span></span></span></th>
|
||||||
|
<!---->
|
||||||
|
</tr>
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr class="" draggable="false">
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
<td class="o-table__td" style="width: 40px;">6</td>
|
||||||
|
<td class="o-table__td" data-label="Email"><a data-v-01123d3b="" href="/settings/admin/users/6" class="">truc@mobilizon.test</a></td>
|
||||||
|
<td class="o-table__td" data-label="Last seen on"><time data-v-01123d3b="">Thursday, January 1, 1970 at 1:00 AM</time></td>
|
||||||
|
<td class="o-table__td" data-label="Language">English</td>
|
||||||
|
<!---->
|
||||||
|
</tr>
|
||||||
|
<transition-stub name="slide" appear="false" persisted="false" css="true">
|
||||||
|
<!---->
|
||||||
|
</transition-stub>
|
||||||
|
<!---->
|
||||||
|
<tr class="" draggable="false">
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
<td class="o-table__td" style="width: 40px;">1</td>
|
||||||
|
<td class="o-table__td" data-label="Email"><a data-v-01123d3b="" href="/settings/admin/users/1" class="">admin@mobilizon.test</a></td>
|
||||||
|
<td class="o-table__td" data-label="Last seen on"><time data-v-01123d3b="" datetime="2025-09-11T16:10:03Z">Thursday, September 11, 2025 at 6:10 PM</time></td>
|
||||||
|
<td class="o-table__td" data-label="Language">English</td>
|
||||||
|
<!---->
|
||||||
|
</tr>
|
||||||
|
<transition-stub name="slide" appear="false" persisted="false" css="true">
|
||||||
|
<!---->
|
||||||
|
</transition-stub>
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
</tbody>
|
||||||
|
<!---->
|
||||||
|
</table>
|
||||||
|
<transition-stub name="fade" appear="false" persisted="false" css="true">
|
||||||
|
<!---->
|
||||||
|
</transition-stub>
|
||||||
|
</div>
|
||||||
|
<div class="o-table__pagination" per-page="10" total="2" rounded="false" size="small" simple="false" aria-next-label="Next page" aria-previous-label="Previous page" aria-page-label="Page" aria-current-label="Current page">
|
||||||
|
<div></div>
|
||||||
|
<div>
|
||||||
|
<nav class="o-pag o-pag--right o-pag--small" data-oruga="pagination"><button role="button" tabindex="0" class="o-pag__link o-pag__previous o-pag__link--disabled" aria-label="Previous page" aria-current="false"><span class="o-icon" data-oruga="icon" aria-hidden="true"><i class="mdi mdi-chevron-left mdi-24px"></i></span></button><button role="button" tabindex="0" class="o-pag__link o-pag__next o-pag__link--disabled" aria-label="Next page" aria-current="false"><span class="o-icon" data-oruga="icon" aria-hidden="true"><i class="mdi mdi-chevron-right mdi-24px"></i></span></button>
|
||||||
|
<ul class="o-pag__list">
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
<li class="o-pag__item"><button role="button" tabindex="0" class="o-pag__link o-pag__link--current" aria-label="Current page, Page 1." aria-current="true">1</button></li>
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`UsersView > Show simple list 1`] = `
|
||||||
|
"<div data-v-01123d3b="">
|
||||||
|
<breadcrumbs-nav data-v-01123d3b="" links="[object Object],[object Object]"></breadcrumbs-nav>
|
||||||
|
<div data-v-01123d3b="">
|
||||||
|
<form data-v-01123d3b="">
|
||||||
|
<div data-v-01123d3b="" data-oruga="field" class="o-field mb-5">
|
||||||
|
<!---->
|
||||||
|
<div class="o-field__body">
|
||||||
|
<div class="o-field o-field--grouped-multiline o-field--grouped">
|
||||||
|
<!--v-if-->
|
||||||
|
<div data-v-01123d3b="" data-oruga="field" class="o-field" expanded=""><label class="o-field__label" for="">Email</label>
|
||||||
|
<div class="o-field__body">
|
||||||
|
<div class="o-field o-field--addons">
|
||||||
|
<div data-v-01123d3b="" data-oruga="input" class="o-input__wrapper"><input trap-focus="" id="" data-oruga-input="text" type="text" class="o-input o-input--iconspace-left" autocomplete="off"><span class="o-icon o-input__icon-left" data-oruga="icon"><i class="mdi mdi-email mdi-24px"></i></span>
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
<div data-v-01123d3b="" data-oruga="field" class="o-field" expanded=""><label class="o-field__label" for="">IP Address</label>
|
||||||
|
<div class="o-field__body">
|
||||||
|
<div class="o-field o-field--addons">
|
||||||
|
<div data-v-01123d3b="" data-oruga="input" class="o-input__wrapper"><input id="" data-oruga-input="text" type="text" class="o-input o-input--iconspace-left" autocomplete="off"><span class="o-icon o-input__icon-left" data-oruga="icon"><i class="mdi mdi-web mdi-24px"></i></span>
|
||||||
|
<!---->
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!---->
|
||||||
|
</div>
|
||||||
|
<p data-v-01123d3b="" class="control self-end mb-0"><button data-v-01123d3b="" type="button" class="o-btn o-btn--primary" role="button" data-oruga="button"><span class="o-btn__wrapper"><!----><span class="o-btn__label">Filter</span>
|
||||||
<!----></span>
|
<!----></span>
|
||||||
</button></p>
|
</button></p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { createRouter, createWebHistory, Router } from "vue-router";
|
|||||||
import { routes } from "@/router";
|
import { routes } from "@/router";
|
||||||
import { Oruga } from "@oruga-ui/oruga-next";
|
import { Oruga } from "@oruga-ui/oruga-next";
|
||||||
import { htmlRemoveId } from "../../common";
|
import { htmlRemoveId } from "../../common";
|
||||||
|
import { CONFIG } from "@/graphql/config";
|
||||||
|
|
||||||
let router: Router;
|
let router: Router;
|
||||||
|
|
||||||
@@ -103,15 +104,23 @@ const listUsersMock = {
|
|||||||
|
|
||||||
config.global.plugins.push(Oruga);
|
config.global.plugins.push(Oruga);
|
||||||
|
|
||||||
const generateWrapper = (currentUsersMock = listUsersMock) => {
|
const generateWrapper = (currentModeration = false) => {
|
||||||
mockClient = createMockClient({
|
mockClient = createMockClient({
|
||||||
cache,
|
cache,
|
||||||
resolvers: buildCurrentUserResolver(cache),
|
resolvers: buildCurrentUserResolver(cache),
|
||||||
});
|
});
|
||||||
requestHandlers = {
|
requestHandlers = {
|
||||||
|
config: vi.fn().mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
config: {
|
||||||
|
registrationsModeration: currentModeration,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
languagecode: vi.fn().mockResolvedValue(languageCodeMock),
|
languagecode: vi.fn().mockResolvedValue(languageCodeMock),
|
||||||
list_users: vi.fn().mockResolvedValue(currentUsersMock),
|
list_users: vi.fn().mockResolvedValue(listUsersMock),
|
||||||
};
|
};
|
||||||
|
mockClient.setRequestHandler(CONFIG, requestHandlers.config);
|
||||||
mockClient.setRequestHandler(LANGUAGES_CODES, requestHandlers.languagecode);
|
mockClient.setRequestHandler(LANGUAGES_CODES, requestHandlers.languagecode);
|
||||||
mockClient.setRequestHandler(LIST_USERS, requestHandlers.list_users);
|
mockClient.setRequestHandler(LIST_USERS, requestHandlers.list_users);
|
||||||
|
|
||||||
@@ -145,6 +154,44 @@ describe("UsersView", () => {
|
|||||||
expect(wrapper.exists()).toBe(true);
|
expect(wrapper.exists()).toBe(true);
|
||||||
expect(requestHandlers.languagecode).toHaveBeenCalled();
|
expect(requestHandlers.languagecode).toHaveBeenCalled();
|
||||||
expect(requestHandlers.list_users).toHaveBeenCalled();
|
expect(requestHandlers.list_users).toHaveBeenCalled();
|
||||||
|
expect(requestHandlers.list_users).toHaveBeenCalledWith({
|
||||||
|
currentSignInIp: "",
|
||||||
|
email: "",
|
||||||
|
limit: 10,
|
||||||
|
page: 1,
|
||||||
|
pendingUser: false,
|
||||||
|
});
|
||||||
expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
|
expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Show list with moderation", async () => {
|
||||||
|
const wrapper = generateWrapper(true);
|
||||||
|
await wrapper.vm.$nextTick();
|
||||||
|
await flushPromises();
|
||||||
|
expect(wrapper.exists()).toBe(true);
|
||||||
|
expect(requestHandlers.languagecode).toHaveBeenCalledTimes(0);
|
||||||
|
expect(requestHandlers.list_users).toHaveBeenCalledTimes(1);
|
||||||
|
expect(requestHandlers.list_users).toHaveBeenCalledWith({
|
||||||
|
currentSignInIp: "",
|
||||||
|
email: "",
|
||||||
|
limit: 10,
|
||||||
|
page: 1,
|
||||||
|
pendingUser: true,
|
||||||
|
});
|
||||||
|
expect(htmlRemoveId(wrapper.html())).toMatchSnapshot();
|
||||||
|
|
||||||
|
wrapper.vm.pendingFieldValue = false;
|
||||||
|
//wrapper.find('input[type="checkbox"]').trigger("change");
|
||||||
|
wrapper.find('input[type="text"]').setValue("@email.tld");
|
||||||
|
wrapper.find('button[type="button"]').trigger("click");
|
||||||
|
await flushPromises();
|
||||||
|
expect(requestHandlers.list_users).toHaveBeenCalledTimes(3);
|
||||||
|
expect(requestHandlers.list_users).toHaveBeenNthCalledWith(3, {
|
||||||
|
currentSignInIp: "",
|
||||||
|
email: "@email.tld",
|
||||||
|
limit: 10,
|
||||||
|
page: 1,
|
||||||
|
pendingUser: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user