User dialog group moderation tools

This commit is contained in:
Natsumi
2025-08-23 07:22:30 +12:00
parent af6848e409
commit 4f94582731
10 changed files with 492 additions and 194 deletions
+2
View File
@@ -26,6 +26,7 @@
import WorldDialog from './components/dialogs/WorldDialog/WorldDialog.vue'; import WorldDialog from './components/dialogs/WorldDialog/WorldDialog.vue';
import AvatarDialog from './components/dialogs/AvatarDialog/AvatarDialog.vue'; import AvatarDialog from './components/dialogs/AvatarDialog/AvatarDialog.vue';
import GroupDialog from './components/dialogs/GroupDialog/GroupDialog.vue'; import GroupDialog from './components/dialogs/GroupDialog/GroupDialog.vue';
import GroupMemberModerationDialog from './components/dialogs/GroupDialog/GroupMemberModerationDialog.vue';
import GalleryDialog from './components/dialogs/GalleryDialog.vue'; import GalleryDialog from './components/dialogs/GalleryDialog.vue';
import FullscreenImageDialog from './components/dialogs/FullscreenImageDialog.vue'; import FullscreenImageDialog from './components/dialogs/FullscreenImageDialog.vue';
import PreviousInstancesInfoDialog from './components/dialogs/PreviousInstancesDialog/PreviousInstancesInfoDialog.vue'; import PreviousInstancesInfoDialog from './components/dialogs/PreviousInstancesDialog/PreviousInstancesInfoDialog.vue';
@@ -65,6 +66,7 @@
WorldDialog, WorldDialog,
AvatarDialog, AvatarDialog,
GroupDialog, GroupDialog,
GroupMemberModerationDialog,
GalleryDialog, GalleryDialog,
FullscreenImageDialog, FullscreenImageDialog,
PreviousInstancesInfoDialog, PreviousInstancesInfoDialog,
+2
View File
@@ -46,6 +46,8 @@ doctype html
GroupDialog GroupDialog
GroupMemberModerationDialog
GalleryDialog GalleryDialog
FullscreenImageDialog FullscreenImageDialog
@@ -318,7 +318,10 @@
{{ t('dialog.group.actions.create_post') }} {{ t('dialog.group.actions.create_post') }}
</el-dropdown-item> </el-dropdown-item>
</template> </template>
<el-dropdown-item icon="el-icon-s-operation" command="Moderation Tools"> <el-dropdown-item
:disabled="!hasGroupModerationPermission(groupDialog.ref)"
icon="el-icon-s-operation"
command="Moderation Tools">
{{ t('dialog.group.actions.moderation_tools') }} {{ t('dialog.group.actions.moderation_tools') }}
</el-dropdown-item> </el-dropdown-item>
<template <template
@@ -1152,14 +1155,6 @@
</div> </div>
<!--Nested--> <!--Nested-->
<GroupPostEditDialog :dialog-data.sync="groupPostEditDialog" :selected-gallery-file="selectedGalleryFile" /> <GroupPostEditDialog :dialog-data.sync="groupPostEditDialog" :selected-gallery-file="selectedGalleryFile" />
<GroupMemberModerationDialog
:is-group-members-loading.sync="isGroupMembersLoading"
:group-member-moderation="groupMemberModeration"
@close-dialog="closeMemberModerationDialog"
@group-members-search="groupMembersSearch"
@load-all-group-members="loadAllGroupMembers"
@set-group-member-filter="setGroupMemberFilter"
@set-group-member-sort-order="setGroupMemberSortOrder" />
<InviteGroupDialog /> <InviteGroupDialog />
</safe-dialog> </safe-dialog>
</template> </template>
@@ -1179,6 +1174,7 @@
downloadAndSaveJson, downloadAndSaveJson,
getFaviconUrl, getFaviconUrl,
hasGroupPermission, hasGroupPermission,
hasGroupModerationPermission,
languageClass, languageClass,
openExternalLink, openExternalLink,
refreshInstancePlayerCount, refreshInstancePlayerCount,
@@ -1195,7 +1191,6 @@
useUserStore useUserStore
} from '../../../stores'; } from '../../../stores';
import InviteGroupDialog from '../InviteGroupDialog.vue'; import InviteGroupDialog from '../InviteGroupDialog.vue';
import GroupMemberModerationDialog from './GroupMemberModerationDialog.vue';
import GroupPostEditDialog from './GroupPostEditDialog.vue'; import GroupPostEditDialog from './GroupPostEditDialog.vue';
const { t } = useI18n(); const { t } = useI18n();
@@ -1212,7 +1207,8 @@
setGroupVisibility, setGroupVisibility,
applyGroupMember, applyGroupMember,
handleGroupMember, handleGroupMember,
handleGroupMemberProps handleGroupMemberProps,
showGroupMemberModerationDialog
} = useGroupStore(); } = useGroupStore();
const { lastLocation } = storeToRefs(useLocationStore()); const { lastLocation } = storeToRefs(useLocationStore());
@@ -1245,13 +1241,6 @@
postId: '', postId: '',
groupId: '' groupId: ''
}); });
const groupMemberModeration = reactive({
visible: false,
loading: false,
id: '',
groupRef: {},
auditLogTypes: []
});
let loadMoreGroupMembersParams = ref({ let loadMoreGroupMembersParams = ref({
n: 100, n: 100,
@@ -1292,10 +1281,6 @@
handleGroupRepresentationChange(groupId, false); handleGroupRepresentationChange(groupId, false);
} }
function closeMemberModerationDialog() {
groupMemberModeration.visible = false;
}
function groupMembersSearch() { function groupMembersSearch() {
if (groupMembersSearchTimer.value) { if (groupMembersSearchTimer.value) {
groupMembersSearchPending.value = true; groupMembersSearchPending.value = true;
@@ -1539,28 +1524,6 @@
}); });
} }
function showGroupMemberModerationDialog(groupId) {
if (groupId !== groupDialog.value.id) {
return;
}
const D = groupMemberModeration;
D.id = groupId;
D.groupRef = {};
D.auditLogTypes = [];
groupRequest.getCachedGroup({ groupId }).then((args) => {
D.groupRef = args.ref;
if (hasGroupPermission(D.groupRef, 'group-audit-view')) {
groupRequest.getGroupAuditLogTypes({ groupId }).then((args) => {
if (groupMemberModeration.id !== args.params.groupId) {
return;
}
groupMemberModeration.auditLogTypes = args.json;
});
}
});
D.visible = true;
}
function joinGroup(id) { function joinGroup(id) {
if (!id) { if (!id) {
return null; return null;
@@ -1,12 +1,11 @@
<template> <template>
<safe-dialog <safe-dialog
class="x-dialog" class="x-dialog"
:visible="groupMemberModeration.visible" :visible.sync="groupMemberModeration.visible"
:title="t('dialog.group_member_moderation.header')" :title="t('dialog.group_member_moderation.header')"
append-to-body append-to-body
top="5vh" top="5vh"
width="90vw" width="90vw">
@close="closeDialog">
<div> <div>
<h3>{{ groupMemberModeration.groupRef.name }}</h3> <h3>{{ groupMemberModeration.groupRef.name }}</h3>
<el-tabs type="card" style="height: 100%"> <el-tabs type="card" style="height: 100%">
@@ -33,15 +32,14 @@
:disabled=" :disabled="
Boolean( Boolean(
isGroupMembersLoading || isGroupMembersLoading ||
groupDialog.memberSearch.length || memberSearch.length ||
!hasGroupPermission(groupDialog.ref, 'group-bans-manage') !hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage')
) )
" "
@click.native.stop> @click.native.stop>
<el-button size="mini"> <el-button size="mini">
<span <span
>{{ t(groupDialog.memberSortOrder.name) }} >{{ t(memberSortOrder.name) }} <i class="el-icon-arrow-down el-icon--right"></i
<i class="el-icon-arrow-down el-icon--right"></i
></span> ></span>
</el-button> </el-button>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
@@ -61,15 +59,14 @@
:disabled=" :disabled="
Boolean( Boolean(
isGroupMembersLoading || isGroupMembersLoading ||
groupDialog.memberSearch.length || memberSearch.length ||
!hasGroupPermission(groupDialog.ref, 'group-bans-manage') !hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage')
) )
" "
@click.native.stop> @click.native.stop>
<el-button size="mini"> <el-button size="mini">
<span <span
>{{ t(groupDialog.memberFilter.name) }} >{{ t(memberFilter.name) }} <i class="el-icon-arrow-down el-icon--right"></i
<i class="el-icon-arrow-down el-icon--right"></i
></span> ></span>
</el-button> </el-button>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
@@ -79,7 +76,7 @@
@click.native="setGroupMemberFilter(item)" @click.native="setGroupMemberFilter(item)"
v-text="t(item.name)"></el-dropdown-item> v-text="t(item.name)"></el-dropdown-item>
<el-dropdown-item <el-dropdown-item
v-for="item in groupDialog.ref.roles" v-for="item in groupMemberModeration.groupRef.roles"
:key="item.name" :key="item.name"
@click.native="setGroupMemberFilter(item)" @click.native="setGroupMemberFilter(item)"
><span v-if="!item.defaultRole">{{ t(item.name) }}</span></el-dropdown-item ><span v-if="!item.defaultRole">{{ t(item.name) }}</span></el-dropdown-item
@@ -88,8 +85,8 @@
</el-dropdown> </el-dropdown>
</div> </div>
<el-input <el-input
v-model="groupDialog.memberSearch" v-model="memberSearch"
:disabled="!hasGroupPermission(groupDialog.ref, 'group-bans-manage')" :disabled="!hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage')"
clearable clearable
size="mini" size="mini"
:placeholder="t('dialog.group.members.search')" :placeholder="t('dialog.group.members.search')"
@@ -99,7 +96,10 @@
<el-button size="small" @click="selectAllGroupMembers">{{ <el-button size="small" @click="selectAllGroupMembers">{{
t('dialog.group_member_moderation.select_all') t('dialog.group_member_moderation.select_all')
}}</el-button> }}</el-button>
<data-tables v-bind="groupMemberModerationTable" style="margin-top: 10px"> <data-tables
v-if="groupMemberModerationTable.data.length"
v-bind="groupMemberModerationTable"
style="margin-top: 10px">
<el-table-column width="55" prop="$selected"> <el-table-column width="55" prop="$selected">
<template #default="scope"> <template #default="scope">
<el-button type="text" size="mini" @click.stop> <el-button type="text" size="mini" @click.stop>
@@ -188,7 +188,7 @@
<el-tab-pane <el-tab-pane
:label="t('dialog.group_member_moderation.bans')" :label="t('dialog.group_member_moderation.bans')"
:disabled="!hasGroupPermission(groupDialog.ref, 'group-bans-manage')"> :disabled="!hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage')">
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<el-button <el-button
type="default" type="default"
@@ -303,7 +303,7 @@
<el-tab-pane <el-tab-pane
:label="t('dialog.group_member_moderation.invites')" :label="t('dialog.group_member_moderation.invites')"
:disabled="!hasGroupPermission(groupDialog.ref, 'group-invites-manage')"> :disabled="!hasGroupPermission(groupMemberModeration.groupRef, 'group-invites-manage')">
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<el-button <el-button
type="default" type="default"
@@ -385,7 +385,10 @@
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || progressCurrent ||
!hasGroupPermission(groupDialog.ref, 'group-invites-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-invites-manage'
)
) )
" "
@click="groupMembersDeleteSentInvite" @click="groupMembersDeleteSentInvite"
@@ -464,7 +467,10 @@
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || progressCurrent ||
!hasGroupPermission(groupDialog.ref, 'group-invites-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-invites-manage'
)
) )
" "
@click="groupMembersAcceptInviteRequest" @click="groupMembersAcceptInviteRequest"
@@ -474,7 +480,10 @@
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || progressCurrent ||
!hasGroupPermission(groupDialog.ref, 'group-invites-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-invites-manage'
)
) )
" "
@click="groupMembersRejectInviteRequest" @click="groupMembersRejectInviteRequest"
@@ -484,7 +493,10 @@
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || progressCurrent ||
!hasGroupPermission(groupDialog.ref, 'group-invites-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-invites-manage'
)
) )
" "
@click="groupMembersBlockJoinRequest" @click="groupMembersBlockJoinRequest"
@@ -563,7 +575,10 @@
:disabled=" :disabled="
Boolean( Boolean(
progressCurrent || progressCurrent ||
!hasGroupPermission(groupDialog.ref, 'group-invites-manage') !hasGroupPermission(
groupMemberModeration.groupRef,
'group-invites-manage'
)
) )
" "
@click="groupMembersDeleteBlockedRequest" @click="groupMembersDeleteBlockedRequest"
@@ -576,7 +591,7 @@
<el-tab-pane <el-tab-pane
:label="t('dialog.group_member_moderation.logs')" :label="t('dialog.group_member_moderation.logs')"
:disabled="!hasGroupPermission(groupDialog.ref, 'group-audit-view')"> :disabled="!hasGroupPermission(groupMemberModeration.groupRef, 'group-audit-view')">
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<el-button <el-button
type="default" type="default"
@@ -707,10 +722,13 @@
style="margin-right: 5px; margin-top: 5px" style="margin-right: 5px; margin-top: 5px"
closable closable
@close="deleteSelectedGroupMember(user)"> @close="deleteSelectedGroupMember(user)">
<span <el-tooltip v-if="user.membershipStatus !== 'member'" placement="top">
>{{ user.user?.displayName }} <template #content>
<i v-if="user.membershipStatus !== 'member'" class="el-icon-warning" style="margin-left: 5px"></i <span>{{ t('dialog.group_member_moderation.user_isnt_in_group') }}</span>
></span> </template>
<i class="el-icon el-icon-warning" style="display: inline-block" />
</el-tooltip>
<span v-text="user.user?.displayName || user.userId" style="font-weight: bold; margin-left: 5px"></span>
</el-tag> </el-tag>
<br /> <br />
<br /> <br />
@@ -759,7 +777,7 @@
Boolean( Boolean(
!selectedRoles.length || !selectedRoles.length ||
progressCurrent || progressCurrent ||
!hasGroupPermission(groupDialog.ref, 'group-roles-assign') !hasGroupPermission(groupMemberModeration.groupRef, 'group-roles-assign')
) )
" "
@click="groupMembersAddRoles" @click="groupMembersAddRoles"
@@ -770,29 +788,41 @@
Boolean( Boolean(
!selectedRoles.length || !selectedRoles.length ||
progressCurrent || progressCurrent ||
!hasGroupPermission(groupDialog.ref, 'group-roles-assign') !hasGroupPermission(groupMemberModeration.groupRef, 'group-roles-assign')
) )
" "
@click="groupMembersRemoveRoles" @click="groupMembersRemoveRoles"
>{{ t('dialog.group_member_moderation.remove_roles') }}</el-button >{{ t('dialog.group_member_moderation.remove_roles') }}</el-button
> >
<el-button <el-button
:disabled="Boolean(progressCurrent || !hasGroupPermission(groupDialog.ref, 'group-members-manage'))" :disabled="
Boolean(
progressCurrent || !hasGroupPermission(groupMemberModeration.groupRef, 'group-members-manage')
)
"
@click="groupMembersSaveNote" @click="groupMembersSaveNote"
>{{ t('dialog.group_member_moderation.save_note') }}</el-button >{{ t('dialog.group_member_moderation.save_note') }}</el-button
> >
<el-button <el-button
:disabled="Boolean(progressCurrent || !hasGroupPermission(groupDialog.ref, 'group-members-remove'))" :disabled="
Boolean(
progressCurrent || !hasGroupPermission(groupMemberModeration.groupRef, 'group-members-remove')
)
"
@click="groupMembersKick" @click="groupMembersKick"
>{{ t('dialog.group_member_moderation.kick') }}</el-button >{{ t('dialog.group_member_moderation.kick') }}</el-button
> >
<el-button <el-button
:disabled="Boolean(progressCurrent || !hasGroupPermission(groupDialog.ref, 'group-bans-manage'))" :disabled="
Boolean(progressCurrent || !hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage'))
"
@click="groupMembersBan" @click="groupMembersBan"
>{{ t('dialog.group_member_moderation.ban') }}</el-button >{{ t('dialog.group_member_moderation.ban') }}</el-button
> >
<el-button <el-button
:disabled="Boolean(progressCurrent || !hasGroupPermission(groupDialog.ref, 'group-bans-manage'))" :disabled="
Boolean(progressCurrent || !hasGroupPermission(groupMemberModeration.groupRef, 'group-bans-manage'))
"
@click="groupMembersUnban" @click="groupMembersUnban"
>{{ t('dialog.group_member_moderation.unban') }}</el-button >{{ t('dialog.group_member_moderation.unban') }}</el-button
> >
@@ -814,6 +844,7 @@
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { getCurrentInstance, reactive, ref, watch } from 'vue'; import { getCurrentInstance, reactive, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n-bridge'; import { useI18n } from 'vue-i18n-bridge';
import * as workerTimers from 'worker-timers';
import { groupRequest, userRequest } from '../../../api'; import { groupRequest, userRequest } from '../../../api';
import { groupDialogFilterOptions, groupDialogSortingOptions } from '../../../shared/constants'; import { groupDialogFilterOptions, groupDialogSortingOptions } from '../../../shared/constants';
import { hasGroupPermission, userImage, userImageFull, formatDateFilter } from '../../../shared/utils'; import { hasGroupPermission, userImage, userImageFull, formatDateFilter } from '../../../shared/utils';
@@ -823,8 +854,8 @@
const { randomUserColours } = storeToRefs(useAppearanceSettingsStore()); const { randomUserColours } = storeToRefs(useAppearanceSettingsStore());
const { showUserDialog } = useUserStore(); const { showUserDialog } = useUserStore();
const { currentUser } = storeToRefs(useUserStore()); const { currentUser } = storeToRefs(useUserStore());
const { groupDialog } = storeToRefs(useGroupStore()); const { groupDialog, groupMemberModeration } = storeToRefs(useGroupStore());
const { applyGroupMember, handleGroupMemberProps } = useGroupStore(); const { applyGroupMember, handleGroupMember, handleGroupMemberProps } = useGroupStore();
const { showFullscreenImageDialog } = useGalleryStore(); const { showFullscreenImageDialog } = useGalleryStore();
const { t } = useI18n(); const { t } = useI18n();
const instance = getCurrentInstance(); const instance = getCurrentInstance();
@@ -832,6 +863,28 @@
const selectedUsers = reactive({}); const selectedUsers = reactive({});
const selectedUsersArray = ref([]); const selectedUsersArray = ref([]);
const isGroupMembersLoading = ref(false);
const isGroupMembersDone = ref(false);
const groupMembersSearch = ref('');
const memberFilter = ref({
id: null,
name: 'dialog.group.members.filters.everyone'
});
const memberSortOrder = ref({
id: '',
name: 'dialog.group.members.sorting.joined_at_desc',
value: 'joinedAt:desc'
});
const members = ref([]);
const memberSearch = ref('');
let loadMoreGroupMembersParams = ref({
n: 100,
offset: 0,
groupId: '',
sort: '',
roleId: ''
});
function setSelectedUsers(usersId, user) { function setSelectedUsers(usersId, user) {
if (!user) { if (!user) {
@@ -965,26 +1018,6 @@
deselectInTable(groupBlockedModerationTable.data); deselectInTable(groupBlockedModerationTable.data);
} }
const props = defineProps({
isGroupMembersLoading: {
type: Boolean,
default: false
},
groupMemberModeration: {
type: Object,
required: true
}
});
const emit = defineEmits([
'update:is-group-members-loading',
'close-dialog',
'load-all-group-members',
'set-group-member-sort-order',
'set-group-member-filter',
'group-members-search'
]);
const selectUserId = ref(''); const selectUserId = ref('');
const progressCurrent = ref(0); const progressCurrent = ref(0);
const progressTotal = ref(0); const progressTotal = ref(0);
@@ -994,12 +1027,9 @@
const isGroupLogsExportDialogVisible = ref(false); const isGroupLogsExportDialogVisible = ref(false);
watch( watch(
() => props.groupMemberModeration.visible, () => groupMemberModeration.value.visible,
(newVal) => { (newVal) => {
if (newVal) { if (newVal) {
if (props.groupMemberModeration.id !== groupDialog.value.id) {
return;
}
groupMemberModerationTable.data = []; groupMemberModerationTable.data = [];
groupBansModerationTable.data = []; groupBansModerationTable.data = [];
groupInvitesModerationTable.data = []; groupInvitesModerationTable.data = [];
@@ -1011,62 +1041,17 @@
selectUserId.value = ''; selectUserId.value = '';
selectedRoles.value = []; selectedRoles.value = [];
note.value = ''; note.value = '';
}
}
);
watch( if (groupMemberModeration.value.openWithUserId) {
() => groupDialog.value.members, addGroupMemberToSelection(groupMemberModeration.value.openWithUserId);
(newVal) => { }
if (newVal) {
setGroupMemberModerationTable(newVal);
} }
},
{ immediate: true, deep: true }
);
watch(
() => groupDialog.value.memberSearchResults,
(newVal) => {
if (newVal) {
setGroupMemberModerationTable(newVal);
} }
},
{ immediate: true, deep: true }
); );
// created() // created()
initializePageSize(); initializePageSize();
function loadAllGroupMembers() {
emit('load-all-group-members');
}
function setGroupMemberSortOrder(item) {
emit('set-group-member-sort-order', item);
}
function setGroupMemberFilter(filter) {
emit('set-group-member-filter', filter);
}
function groupMembersSearch() {
emit('group-members-search');
}
function updateIsGroupMembersLoading(value) {
emit('update:is-group-members-loading', value);
}
function closeDialog() {
emit('close-dialog');
}
function setGroupMemberModerationTable(data) {
if (!Array.isArray(data)) {
return;
}
groupMemberModerationTable.data = data.map((member) => ({
...member,
$selected: Boolean(selectedUsers[member.userId])
}));
}
function handleGroupMemberRoleChange(args) { function handleGroupMemberRoleChange(args) {
if (groupDialog.value.id === args.params.groupId) { if (groupDialog.value.id === args.params.groupId) {
groupDialog.value.members.forEach((member) => { groupDialog.value.members.forEach((member) => {
@@ -1079,7 +1064,7 @@
} }
async function groupMembersDeleteSentInvite() { async function groupMembersDeleteSentInvite() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const memberCount = users.length; const memberCount = users.length;
progressTotal.value = memberCount; progressTotal.value = memberCount;
@@ -1130,13 +1115,13 @@
groupBansModerationTable.data = []; groupBansModerationTable.data = [];
const params = { groupId, n: 100, offset: 0 }; const params = { groupId, n: 100, offset: 0 };
const count = 50; // 5000 max const count = 50; // 5000 max
updateIsGroupMembersLoading(true); isGroupMembersLoading.value = true;
const fetchedBans = []; const fetchedBans = [];
try { try {
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const args = await groupRequest.getGroupBans(params); const args = await groupRequest.getGroupBans(params);
if (args && args.json) { if (args && args.json) {
if (props.groupMemberModeration.id !== args.params.groupId) { if (groupMemberModeration.value.id !== args.params.groupId) {
continue; continue;
} }
args.json.forEach((json) => { args.json.forEach((json) => {
@@ -1158,7 +1143,7 @@
type: 'error' type: 'error'
}); });
} finally { } finally {
updateIsGroupMembersLoading(false); isGroupMembersLoading.value = false;
} }
} }
@@ -1170,7 +1155,7 @@
} }
async function groupMembersBan() { async function groupMembersBan() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const memberCount = users.length; const memberCount = users.length;
progressTotal.value = memberCount; progressTotal.value = memberCount;
@@ -1198,7 +1183,7 @@
} }
async function groupMembersUnban() { async function groupMembersUnban() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const memberCount = users.length; const memberCount = users.length;
progressTotal.value = memberCount; progressTotal.value = memberCount;
@@ -1231,7 +1216,7 @@
} }
async function groupMembersKick() { async function groupMembersKick() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const memberCount = users.length; const memberCount = users.length;
progressTotal.value = memberCount; progressTotal.value = memberCount;
@@ -1264,7 +1249,7 @@
} }
async function groupMembersSaveNote() { async function groupMembersSaveNote() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const memberCount = users.length; const memberCount = users.length;
progressTotal.value = memberCount; progressTotal.value = memberCount;
@@ -1299,7 +1284,7 @@
} }
async function groupMembersRemoveRoles() { async function groupMembersRemoveRoles() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const rolesToRemoveSet = new Set(selectedRoles.value); const rolesToRemoveSet = new Set(selectedRoles.value);
const memberCount = users.length; const memberCount = users.length;
@@ -1351,7 +1336,7 @@
} }
async function groupMembersAddRoles() { async function groupMembersAddRoles() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const rolesToAddSet = new Set(selectedRoles.value); const rolesToAddSet = new Set(selectedRoles.value);
const memberCount = users.length; const memberCount = users.length;
@@ -1432,7 +1417,7 @@
} }
async function addGroupMemberToSelection(userId) { async function addGroupMemberToSelection(userId) {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
// fetch member if there is one // fetch member if there is one
// banned members don't have a user object // banned members don't have a user object
let member = {}; let member = {};
@@ -1460,13 +1445,13 @@
params.eventTypes = selectedAuditLogTypes.value; params.eventTypes = selectedAuditLogTypes.value;
} }
const count = 50; // 5000 max const count = 50; // 5000 max
updateIsGroupMembersLoading(true); isGroupMembersLoading.value = true;
try { try {
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const args = await groupRequest.getGroupLogs(params); const args = await groupRequest.getGroupLogs(params);
if (args) { if (args) {
if (props.groupMemberModeration.id !== args.params.groupId) { if (groupMemberModeration.value.id !== args.params.groupId) {
continue; continue;
} }
@@ -1488,12 +1473,12 @@
type: 'error' type: 'error'
}); });
} finally { } finally {
updateIsGroupMembersLoading(false); isGroupMembersLoading.value = false;
} }
} }
async function groupMembersDeleteBlockedRequest() { async function groupMembersDeleteBlockedRequest() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const memberCount = users.length; const memberCount = users.length;
progressTotal.value = memberCount; progressTotal.value = memberCount;
@@ -1533,7 +1518,7 @@
} }
async function groupMembersBlockJoinRequest() { async function groupMembersBlockJoinRequest() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const memberCount = users.length; const memberCount = users.length;
progressTotal.value = memberCount; progressTotal.value = memberCount;
@@ -1569,7 +1554,7 @@
} }
async function groupMembersRejectInviteRequest() { async function groupMembersRejectInviteRequest() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const memberCount = users.length; const memberCount = users.length;
progressTotal.value = memberCount; progressTotal.value = memberCount;
@@ -1606,7 +1591,7 @@
} }
async function groupMembersAcceptInviteRequest() { async function groupMembersAcceptInviteRequest() {
const D = props.groupMemberModeration; const D = groupMemberModeration.value;
const users = [...selectedUsersArray.value]; const users = [...selectedUsersArray.value];
const memberCount = users.length; const memberCount = users.length;
progressTotal.value = memberCount; progressTotal.value = memberCount;
@@ -1657,12 +1642,12 @@
groupBlockedModerationTable.data = []; groupBlockedModerationTable.data = [];
const params = { groupId, n: 100, offset: 0, blocked: true }; const params = { groupId, n: 100, offset: 0, blocked: true };
const count = 50; // 5000 const count = 50; // 5000
updateIsGroupMembersLoading(true); isGroupMembersLoading.value = true;
try { try {
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const args = await groupRequest.getGroupJoinRequests(params); const args = await groupRequest.getGroupJoinRequests(params);
if (props.groupMemberModeration.id !== args.params.groupId) { if (groupMemberModeration.value.id !== args.params.groupId) {
return; return;
} }
const targetTable = args.params.blocked const targetTable = args.params.blocked
@@ -1683,7 +1668,7 @@
type: 'error' type: 'error'
}); });
} finally { } finally {
updateIsGroupMembersLoading(false); isGroupMembersLoading.value = false;
} }
} }
@@ -1691,11 +1676,11 @@
groupJoinRequestsModerationTable.data = []; groupJoinRequestsModerationTable.data = [];
const params = { groupId, n: 100, offset: 0, blocked: false }; const params = { groupId, n: 100, offset: 0, blocked: false };
const count = 50; // 5000 max const count = 50; // 5000 max
updateIsGroupMembersLoading(true); isGroupMembersLoading.value = true;
try { try {
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const args = await groupRequest.getGroupJoinRequests(params); const args = await groupRequest.getGroupJoinRequests(params);
if (props.groupMemberModeration.id !== args.params.groupId) { if (groupMemberModeration.value.id !== args.params.groupId) {
return; return;
} }
const targetTable = args.params.blocked const targetTable = args.params.blocked
@@ -1716,7 +1701,7 @@
type: 'error' type: 'error'
}); });
} finally { } finally {
updateIsGroupMembersLoading(false); isGroupMembersLoading.value = false;
} }
} }
@@ -1724,13 +1709,13 @@
groupInvitesModerationTable.data = []; groupInvitesModerationTable.data = [];
const params = { groupId, n: 100, offset: 0 }; const params = { groupId, n: 100, offset: 0 };
const count = 50; // 5000 max const count = 50; // 5000 max
updateIsGroupMembersLoading(true); isGroupMembersLoading.value = true;
try { try {
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const args = await groupRequest.getGroupInvites(params); const args = await groupRequest.getGroupInvites(params);
if (args) { if (args) {
if (props.groupMemberModeration.id !== args.params.groupId) { if (groupMemberModeration.value.id !== args.params.groupId) {
return; return;
} }
@@ -1743,7 +1728,7 @@
if (args.json.length < params.n) { if (args.json.length < params.n) {
break; break;
} }
if (!props.groupMemberModeration.visible) { if (!groupMemberModeration.value.visible) {
break; break;
} }
} }
@@ -1753,7 +1738,7 @@
type: 'error' type: 'error'
}); });
} finally { } finally {
updateIsGroupMembersLoading(false); isGroupMembersLoading.value = false;
} }
} }
@@ -1789,4 +1774,122 @@
.replace(/\./g, ' ') .replace(/\./g, ' ')
.replace(/\b\w/g, (l) => l.toUpperCase()); .replace(/\b\w/g, (l) => l.toUpperCase());
} }
async function getGroupMembers() {
members.value = [];
isGroupMembersDone.value = false;
loadMoreGroupMembersParams.value = {
sort: '',
roleId: '',
n: 100,
offset: 0,
groupId: groupMemberModeration.value.id
};
if (memberSortOrder.value.value) {
loadMoreGroupMembersParams.value.sort = memberSortOrder.value.value;
}
if (memberFilter.value.id !== null) {
loadMoreGroupMembersParams.value.roleId = memberFilter.value.id;
}
await groupRequest
.getGroupMember({
groupId: groupMemberModeration.value.id,
userId: currentUser.value.id
})
.then((args) => {
args.ref = applyGroupMember(args.json);
if (args.json) {
args.json.user = currentUser.value;
if (memberFilter.value.id === null) {
// when filtered by role don't include self
members.value.push(args.json);
}
}
return args;
});
await loadMoreGroupMembers();
}
async function loadMoreGroupMembers() {
if (isGroupMembersDone.value || isGroupMembersLoading.value) {
return;
}
const params = loadMoreGroupMembersParams.value;
if (params.roleId === '') {
delete params.roleId;
}
memberSearch.value = '';
isGroupMembersLoading.value = true;
await groupRequest
.getGroupMembers(params)
.finally(() => {
isGroupMembersLoading.value = false;
})
.then((args) => {
for (const json of args.json) {
handleGroupMember({
json,
params: {
groupId: args.params.groupId
}
});
}
for (let i = 0; i < args.json.length; i++) {
const member = args.json[i];
if (member.userId === currentUser.value.id) {
if (members.value.length > 0 && members.value[0].userId === currentUser.value.id) {
// remove duplicate and keep sort order
members.value.splice(0, 1);
}
break;
}
}
if (args.json.length < params.n) {
isGroupMembersDone.value = true;
}
members.value = [...members.value, ...args.json];
groupMemberModerationTable.data = members.value.map((member) => ({
...member,
$selected: Boolean(selectedUsers[member.userId])
}));
params.offset += params.n;
return args;
})
.catch((err) => {
isGroupMembersDone.value = true;
throw err;
});
}
async function setGroupMemberSortOrder(sortOrder) {
if (memberSortOrder.value === sortOrder) {
return;
}
memberSortOrder.value = sortOrder;
await getGroupMembers();
}
async function loadAllGroupMembers() {
if (isGroupMembersLoading.value) {
return;
}
await getGroupMembers();
while (groupMemberModeration.value.visible && !isGroupMembersDone.value) {
isGroupMembersLoading.value = true;
await new Promise((resolve) => {
workerTimers.setTimeout(resolve, 1000);
});
isGroupMembersLoading.value = false;
await loadMoreGroupMembers();
}
}
async function setGroupMemberFilter(filter) {
if (memberFilter.value === filter) {
return;
}
memberFilter.value = filter;
await getGroupMembers();
}
</script> </script>
+12 -8
View File
@@ -14,14 +14,12 @@
:placeholder="$t('dialog.invite_to_group.choose_group_placeholder')" :placeholder="$t('dialog.invite_to_group.choose_group_placeholder')"
filterable filterable
:disabled="inviteGroupDialog.loading" :disabled="inviteGroupDialog.loading"
style="margin-top: 15px" style="margin-top: 15px; width: 100%">
@change="isAllowedToInviteToGroup">
<el-option-group <el-option-group
v-if="currentUserGroups.size" :label="$t('dialog.invite_to_group.groups_with_invite_permission')"
:label="$t('dialog.invite_to_group.groups')"
style="width: 410px"> style="width: 410px">
<el-option <el-option
v-for="group in currentUserGroups.values()" v-for="group in groupsWithInvitePermission"
:key="group.id" :key="group.id"
:label="group.name" :label="group.name"
:value="group.id" :value="group.id"
@@ -158,16 +156,16 @@
<el-button <el-button
type="primary" type="primary"
size="small" size="small"
:disabled="inviteGroupDialog.loading || !inviteGroupDialog.userIds.length" :disabled="inviteGroupDialog.loading || !inviteGroupDialog.userIds.length || !inviteGroupDialog.groupId"
@click="sendGroupInvite"> @click="sendGroupInvite">
Invite {{ $t('dialog.invite_to_group.invite') }}
</el-button> </el-button>
</template> </template>
</safe-dialog> </safe-dialog>
</template> </template>
<script setup> <script setup>
import { ref, watch, getCurrentInstance, nextTick } from 'vue'; import { ref, watch, getCurrentInstance, nextTick, computed } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { groupRequest, userRequest } from '../../api'; import { groupRequest, userRequest } from '../../api';
import { adjustDialogZ, hasGroupPermission, userImage, userStatusClass } from '../../shared/utils'; import { adjustDialogZ, hasGroupPermission, userImage, userStatusClass } from '../../shared/utils';
@@ -192,6 +190,12 @@
const inviteGroupDialogRef = ref(null); const inviteGroupDialogRef = ref(null);
const groupsWithInvitePermission = computed(() => {
return Array.from(currentUserGroups.value.values()).filter((group) =>
hasGroupPermission(group, 'group-invites-manage')
);
});
function initDialog() { function initDialog() {
nextTick(() => adjustDialogZ(inviteGroupDialogRef.value.$el)); nextTick(() => adjustDialogZ(inviteGroupDialogRef.value.$el));
const D = inviteGroupDialog.value; const D = inviteGroupDialog.value;
@@ -0,0 +1,120 @@
<template>
<safe-dialog
ref="moderateGroupDialogRef"
:visible.sync="moderateGroupDialog.visible"
:title="$t('dialog.moderate_group.header')"
width="450px"
append-to-body>
<div v-if="moderateGroupDialog.visible">
<div class="x-friend-item" style="cursor: default">
<div class="avatar">
<img v-lazy="userImage(moderateGroupDialog.userObject)" />
</div>
<div class="detail">
<span
v-if="moderateGroupDialog.userObject.id"
class="name"
:style="{ color: moderateGroupDialog.userObject.$userColour }"
v-text="moderateGroupDialog.userObject.displayName"></span>
<span v-else v-text="moderateGroupDialog.userId"></span>
</div>
</div>
<el-select
v-model="moderateGroupDialog.groupId"
clearable
:placeholder="$t('dialog.moderate_group.choose_group_placeholder')"
filterable
style="margin-top: 15px; width: 100%">
<el-option-group
v-if="currentUserGroups.size"
:label="$t('dialog.moderate_group.groups_with_moderation_permission')">
<el-option
v-for="group in groupsWithModerationPermission"
:key="group.id"
:label="group.name"
:value="group.id"
style="height: auto"
class="x-friend-item">
<div class="avatar">
<img v-lazy="group.iconUrl" />
</div>
<div class="detail">
<span class="name" v-text="group.name"></span>
</div>
</el-option>
</el-option-group>
</el-select>
</div>
<template #footer>
<el-button
type="primary"
size="small"
:disabled="!moderateGroupDialog.userId || !moderateGroupDialog.groupId"
@click="
showGroupMemberModerationDialog(moderateGroupDialog.groupId, moderateGroupDialog.userId);
moderateGroupDialog.visible = false;
">
{{ $t('dialog.moderate_group.moderation_tools') }}
</el-button>
</template>
</safe-dialog>
</template>
<script setup>
import { ref, watch, getCurrentInstance, nextTick, computed } from 'vue';
import { storeToRefs } from 'pinia';
import { groupRequest, userRequest } from '../../api';
import {
adjustDialogZ,
hasGroupPermission,
hasGroupModerationPermission,
userImage,
userStatusClass
} from '../../shared/utils';
import { useGroupStore } from '../../stores';
const { currentUserGroups, moderateGroupDialog } = storeToRefs(useGroupStore());
const { applyGroup, showGroupMemberModerationDialog } = useGroupStore();
const { proxy } = getCurrentInstance();
const groupsWithModerationPermission = computed(() => {
return Array.from(currentUserGroups.value.values()).filter((group) => hasGroupModerationPermission(group));
});
watch(
() => {
return moderateGroupDialog.value.visible;
},
(value) => {
if (value) {
initDialog();
}
}
);
const moderateGroupDialogRef = ref(null);
function initDialog() {
nextTick(() => adjustDialogZ(moderateGroupDialogRef.value.$el));
const D = moderateGroupDialog.value;
if (D.groupId) {
groupRequest
.getCachedGroup({
groupId: D.groupId
})
.then((args) => {
D.groupName = args.ref.name;
})
.catch(() => {
D.groupId = '';
});
}
if (D.userId) {
userRequest.getCachedUser({ userId: D.userId }).then((args) => {
D.userObject = args.ref;
});
}
}
</script>
@@ -447,6 +447,9 @@
<el-dropdown-item icon="el-icon-message" command="Invite To Group">{{ <el-dropdown-item icon="el-icon-message" command="Invite To Group">{{
t('dialog.user.actions.invite_to_group') t('dialog.user.actions.invite_to_group')
}}</el-dropdown-item> }}</el-dropdown-item>
<el-dropdown-item icon="el-icon-s-operation" command="Group Moderation">{{
t('dialog.user.actions.group_moderation')
}}</el-dropdown-item>
<!--//- el-dropdown-item(icon="el-icon-thumb" command="Send Boop" :disabled="!currentUser.isBoopingEnabled") {{ t('dialog.user.actions.send_boop') }}--> <!--//- el-dropdown-item(icon="el-icon-thumb" command="Send Boop" :disabled="!currentUser.isBoopingEnabled") {{ t('dialog.user.actions.send_boop') }}-->
<el-dropdown-item icon="el-icon-s-custom" command="Show Avatar Author" divided>{{ <el-dropdown-item icon="el-icon-s-custom" command="Show Avatar Author" divided>{{
t('dialog.user.actions.show_avatar_author') t('dialog.user.actions.show_avatar_author')
@@ -1782,6 +1785,7 @@
<LanguageDialog /> <LanguageDialog />
<BioDialog :bio-dialog="bioDialog" /> <BioDialog :bio-dialog="bioDialog" />
<PronounsDialog :pronouns-dialog="pronounsDialog" /> <PronounsDialog :pronouns-dialog="pronounsDialog" />
<ModerateGroupDialog />
</safe-dialog> </safe-dialog>
</template> </template>
@@ -1855,6 +1859,7 @@
import PronounsDialog from './PronounsDialog.vue'; import PronounsDialog from './PronounsDialog.vue';
import SendInviteRequestDialog from './SendInviteRequestDialog.vue'; import SendInviteRequestDialog from './SendInviteRequestDialog.vue';
import SocialStatusDialog from './SocialStatusDialog.vue'; import SocialStatusDialog from './SocialStatusDialog.vue';
import ModerateGroupDialog from '../ModerateGroupDialog.vue';
const { t } = useI18n(); const { t } = useI18n();
@@ -1880,7 +1885,8 @@
leaveGroup, leaveGroup,
leaveGroupPrompt, leaveGroupPrompt,
setGroupVisibility, setGroupVisibility,
handleGroupList handleGroupList,
showModerateGroupDialog
} = useGroupStore(); } = useGroupStore();
const { currentUserGroups, inviteGroupDialog, inGameGroupOrder } = storeToRefs(useGroupStore()); const { currentUserGroups, inviteGroupDialog, inGameGroupOrder } = storeToRefs(useGroupStore());
const { lastLocation, lastLocationDestination } = storeToRefs(useLocationStore()); const { lastLocation, lastLocationDestination } = storeToRefs(useLocationStore());
@@ -2299,6 +2305,8 @@
showInviteGroupDialog('', D.id); showInviteGroupDialog('', D.id);
// } else if (command === 'Send Boop') { // } else if (command === 'Send Boop') {
// this.showSendBoopDialog(D.id); // this.showSendBoopDialog(D.id);
} else if (command === 'Group Moderation') {
showModerateGroupDialog(D.id);
} else if (command === 'Hide Avatar') { } else if (command === 'Hide Avatar') {
if (D.isHideAvatar) { if (D.isHideAvatar) {
setPlayerModeration(D.id, 0); setPlayerModeration(D.id, 0);
+11 -2
View File
@@ -747,6 +747,7 @@
"request_invite": "Request Invite", "request_invite": "Request Invite",
"request_invite_with_message": "Request Invite With Message", "request_invite_with_message": "Request Invite With Message",
"invite_to_group": "Invite To Group", "invite_to_group": "Invite To Group",
"group_moderation": "Group Moderation",
"send_boop": "Send Boop", "send_boop": "Send Boop",
"manage_gallery_inventory_icon": "Manage VRC+ Images & Inventory", "manage_gallery_inventory_icon": "Manage VRC+ Images & Inventory",
"accept_friend_request": "Accept Friend Request", "accept_friend_request": "Accept Friend Request",
@@ -1407,9 +1408,10 @@
"header": "Invite To Group", "header": "Invite To Group",
"description": "Don't spam invite users, you'll get rate limited.", "description": "Don't spam invite users, you'll get rate limited.",
"choose_group_placeholder": "Choose Group", "choose_group_placeholder": "Choose Group",
"groups": "Groups", "groups_with_invite_permission": "Groups with Invite Permission",
"choose_friends_placeholder": "Choose Friends", "choose_friends_placeholder": "Choose Friends",
"selected_users": "Selected Users" "selected_users": "Selected Users",
"invite": "Invite"
}, },
"note_export": { "note_export": {
"header": "Note Export", "header": "Note Export",
@@ -1600,6 +1602,7 @@
"select_user": "Select User", "select_user": "Select User",
"selected_users": "Selected Users", "selected_users": "Selected Users",
"select_all": "Select All", "select_all": "Select All",
"user_isnt_in_group": "User isn't in group",
"cancel": "Cancel", "cancel": "Cancel",
"choose_roles_placeholder": "Choose Roles", "choose_roles_placeholder": "Choose Roles",
"selected_roles": "Selected Roles", "selected_roles": "Selected Roles",
@@ -1636,6 +1639,12 @@
}, },
"group_calendar": { "group_calendar": {
"header": "Group Calendar" "header": "Group Calendar"
},
"moderate_group": {
"header": "Moderate Group Member",
"choose_group_placeholder": "Choose Group",
"groups_with_moderation_permission": "Groups with Moderation Permission",
"moderation_tools": "Moderation Tools"
} }
}, },
"confirm": { "confirm": {
+21 -1
View File
@@ -20,6 +20,26 @@ function hasGroupPermission(ref, permission) {
return false; return false;
} }
/**
*
* @param {object} group
* @returns {boolean}
*/
function hasGroupModerationPermission(group) {
return (
hasGroupPermission(group, 'group-invites-manage') ||
hasGroupPermission(group, 'group-moderates-manage') ||
hasGroupPermission(group, 'group-audit-view') ||
hasGroupPermission(group, 'group-bans-manage') ||
hasGroupPermission(group, 'group-data-manage') ||
hasGroupPermission(group, 'group-members-manage') ||
hasGroupPermission(group, 'group-members-remove') ||
hasGroupPermission(group, 'group-roles-assign') ||
hasGroupPermission(group, 'group-roles-manage') ||
hasGroupPermission(group, 'group-default-role-manage')
);
}
/** /**
* *
* @param {string} data * @param {string} data
@@ -49,4 +69,4 @@ async function getGroupName(data) {
return groupName; return groupName;
} }
export { hasGroupPermission, getGroupName }; export { hasGroupPermission, hasGroupModerationPermission, getGroupName };
+69 -2
View File
@@ -11,7 +11,11 @@ import { $app } from '../app';
import configRepository from '../service/config'; import configRepository from '../service/config';
import { watchState } from '../service/watchState'; import { watchState } from '../service/watchState';
import { groupDialogFilterOptions } from '../shared/constants/'; import { groupDialogFilterOptions } from '../shared/constants/';
import { replaceBioSymbols, convertFileUrlToImageUrl } from '../shared/utils'; import {
replaceBioSymbols,
convertFileUrlToImageUrl,
hasGroupPermission
} from '../shared/utils';
import { useGameStore } from './game'; import { useGameStore } from './game';
import { useInstanceStore } from './instance'; import { useInstanceStore } from './instance';
import { useUserStore } from './user'; import { useUserStore } from './user';
@@ -62,6 +66,21 @@ export const useGroupStore = defineStore('Group', () => {
userIds: [], userIds: [],
userObject: {} userObject: {}
}, },
moderateGroupDialog: {
visible: false,
groupId: '',
groupName: '',
userId: '',
userObject: {}
},
groupMemberModeration: {
visible: false,
loading: false,
id: '',
groupRef: {},
auditLogTypes: [],
openWithUserId: ''
},
cachedGroups: new Map(), cachedGroups: new Map(),
inGameGroupOrder: [], inGameGroupOrder: [],
groupInstances: [], groupInstances: [],
@@ -89,6 +108,20 @@ export const useGroupStore = defineStore('Group', () => {
} }
}); });
const moderateGroupDialog = computed({
get: () => state.moderateGroupDialog,
set: (value) => {
state.moderateGroupDialog = value;
}
});
const groupMemberModeration = computed({
get: () => state.groupMemberModeration,
set: (value) => {
state.groupMemberModeration = value;
}
});
const cachedGroups = computed({ const cachedGroups = computed({
get: () => state.cachedGroups, get: () => state.cachedGroups,
set: (value) => { set: (value) => {
@@ -122,6 +155,8 @@ export const useGroupStore = defineStore('Group', () => {
(isLoggedIn) => { (isLoggedIn) => {
state.groupDialog.visible = false; state.groupDialog.visible = false;
state.inviteGroupDialog.visible = false; state.inviteGroupDialog.visible = false;
state.moderateGroupDialog.visible = false;
state.groupMemberModeration.visible = false;
state.currentUserGroupsInit = false; state.currentUserGroupsInit = false;
state.cachedGroups.clear(); state.cachedGroups.clear();
state.currentUserGroups.clear(); state.currentUserGroups.clear();
@@ -1023,11 +1058,41 @@ export const useGroupStore = defineStore('Group', () => {
); );
} }
function showModerateGroupDialog(userId) {
const D = state.moderateGroupDialog;
D.userId = userId;
D.userObject = {};
D.visible = true;
}
function showGroupMemberModerationDialog(groupId, userId = '') {
const D = state.groupMemberModeration;
D.id = groupId;
D.openWithUserId = userId;
D.groupRef = {};
D.auditLogTypes = [];
groupRequest.getCachedGroup({ groupId }).then((args) => {
D.groupRef = args.ref;
if (hasGroupPermission(D.groupRef, 'group-audit-view')) {
groupRequest.getGroupAuditLogTypes({ groupId }).then((args) => {
if (D.id !== args.params.groupId) {
return;
}
D.auditLogTypes = args.json;
});
}
});
D.visible = true;
}
return { return {
state, state,
groupDialog, groupDialog,
currentUserGroups, currentUserGroups,
inviteGroupDialog, inviteGroupDialog,
moderateGroupDialog,
groupMemberModeration,
cachedGroups, cachedGroups,
inGameGroupOrder, inGameGroupOrder,
groupInstances, groupInstances,
@@ -1052,6 +1117,8 @@ export const useGroupStore = defineStore('Group', () => {
handleGroupPermissions, handleGroupPermissions,
handleGroupMemberProps, handleGroupMemberProps,
handleGroupList, handleGroupList,
handleGroupRepresented handleGroupRepresented,
showModerateGroupDialog,
showGroupMemberModerationDialog
}; };
}); });