TF-4141 should not show inkwell effect when user drag email into virtual folder
This commit is contained in:
@@ -30,6 +30,8 @@ import 'package:tmail_ui_user/features/mailbox/domain/model/subscribe_request.da
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/get_all_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/refresh_all_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/expand_mode_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_action_required_tab_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_favorite_tab_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/list_mailbox_node_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
|
||||
@@ -672,4 +674,11 @@ abstract class BaseMailboxController extends BaseController
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void autoCreateVirtualFolder(bool isAINeedsActionEnabled) {
|
||||
addFavoriteFolderToMailboxList();
|
||||
if (isAINeedsActionEnabled) {
|
||||
addActionRequiredFolder();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions
|
||||
|
||||
mixin AiScribeMixin {
|
||||
AICapability? getAICapability({Session? session, AccountId? accountId}) {
|
||||
if (PlatformInfo.isMobile) return null;
|
||||
|
||||
if (accountId == null || session == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -17,8 +15,18 @@ mixin AiScribeMixin {
|
||||
return session.getAICapability(accountId);
|
||||
}
|
||||
|
||||
bool isAIScribeEndpointAvailable({Session? session, AccountId? accountId}) {
|
||||
final aiCapability = getAICapability(
|
||||
session: session,
|
||||
accountId: accountId,
|
||||
);
|
||||
return aiCapability?.isScribeEndpointAvailable == true;
|
||||
}
|
||||
|
||||
void injectAIScribeBindings(Session? session, AccountId? accountId) {
|
||||
try {
|
||||
if (PlatformInfo.isMobile) return;
|
||||
|
||||
final aiCapability = getAICapability(
|
||||
session: session,
|
||||
accountId: accountId,
|
||||
|
||||
+5
-4
@@ -9,17 +9,18 @@ import 'package:tmail_ui_user/features/composer/presentation/mixin/text_selectio
|
||||
|
||||
extension HandleAiScribeInComposerExtension on ComposerController {
|
||||
bool get isAIScribeAvailable {
|
||||
final aiCapability = getAICapability(
|
||||
final isAIScribeEndpointAvailable =
|
||||
mailboxDashBoardController.isAIScribeEndpointAvailable(
|
||||
session: mailboxDashBoardController.sessionCurrent,
|
||||
accountId: mailboxDashBoardController.accountId.value,
|
||||
);
|
||||
final isScribeEndpointAvailable =
|
||||
aiCapability?.isScribeEndpointAvailable == true;
|
||||
|
||||
final isAIScribeConfigEnabled =
|
||||
mailboxDashBoardController.cachedAIScribeConfig.value.isEnabled;
|
||||
|
||||
return isAIScribeConfigEnabled && isScribeEndpointAvailable;
|
||||
return isAIScribeConfigEnabled &&
|
||||
isAIScribeEndpointAvailable &&
|
||||
!PlatformInfo.isMobile;
|
||||
}
|
||||
|
||||
Future<String> _getTextOnlyContentInEditor() async {
|
||||
|
||||
@@ -28,7 +28,6 @@ extension SessionExtensions on Session {
|
||||
static final CapabilityIdentifier linagoraContactSupportCapability = CapabilityIdentifier(Uri.parse('com:linagora:params:jmap:contact:support'));
|
||||
static final CapabilityIdentifier linagoraDownloadAllCapability = CapabilityIdentifier(Uri.parse('com:linagora:params:downloadAll'));
|
||||
static final CapabilityIdentifier linagoraSaaSCapability = CapabilityIdentifier(Uri.parse('com:linagora:params:saas'));
|
||||
static final CapabilityIdentifier linagoraAICapability = CapabilityIdentifier(Uri.parse('com:linagora:params:jmap:aibot'));
|
||||
|
||||
static final Map<CapabilityIdentifier, CapabilityProperties Function(Map<String, dynamic>)> customMapCapabilitiesConverter = {
|
||||
linagoraContactSupportCapability: ContactSupportCapability.deserialize,
|
||||
@@ -172,6 +171,10 @@ extension SessionExtensions on Session {
|
||||
|
||||
AICapability? getAICapability(AccountId accountId) {
|
||||
try {
|
||||
if (!AiScribeConstants.aiCapability.isSupported(this, accountId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final aiCapability = getCapabilityProperties<AICapability>(
|
||||
accountId,
|
||||
AiScribeConstants.aiCapability,
|
||||
|
||||
@@ -197,6 +197,9 @@ abstract class BaseMailboxView extends GetWidget<MailboxController>
|
||||
.mailboxDashBoardController
|
||||
.selectedMailbox
|
||||
.value,
|
||||
isDraggingMailbox: controller
|
||||
.mailboxDashBoardController
|
||||
.isDraggingMailbox,
|
||||
isHighlighted: isFolderHighlighted(mailboxNode),
|
||||
onOpenMailboxFolderClick: (mailboxNode) =>
|
||||
mailboxNode != null
|
||||
|
||||
@@ -70,7 +70,6 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_mailbox
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multiple_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_action_required_tab_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_favorite_tab_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/mixin/mailbox_widget_mixin.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
|
||||
@@ -86,7 +85,7 @@ import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/new_ma
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/state/remove_email_drafts_state.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/action/dashboard_action.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_create_new_rule_filter.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart';
|
||||
@@ -265,14 +264,18 @@ class MailboxController extends BaseMailboxController
|
||||
viewState.value.fold(
|
||||
(failure) {
|
||||
if (failure is GetAllMailboxFailure) {
|
||||
autoCreateVirtualFolder();
|
||||
autoCreateVirtualFolder(
|
||||
mailboxDashBoardController.isAINeedsActionEnabled,
|
||||
);
|
||||
mailboxDashBoardController.updateRefreshAllMailboxState(Left(RefreshAllMailboxFailure()));
|
||||
showRetryToast(failure);
|
||||
}
|
||||
},
|
||||
(success) {
|
||||
if (success is GetAllMailboxSuccess) {
|
||||
autoCreateVirtualFolder();
|
||||
autoCreateVirtualFolder(
|
||||
mailboxDashBoardController.isAINeedsActionEnabled,
|
||||
);
|
||||
mailboxDashBoardController.updateRefreshAllMailboxState(Right(RefreshAllMailboxSuccess()));
|
||||
_handleCreateDefaultFolderIfMissing(mailboxDashBoardController.mapDefaultMailboxIdByRole);
|
||||
_handleDataFromNavigationRouter();
|
||||
@@ -281,7 +284,9 @@ class MailboxController extends BaseMailboxController
|
||||
_updateMailboxIdsBlockNotificationToKeychain(success.mailboxList);
|
||||
}
|
||||
} else if (success is CreateDefaultMailboxAllSuccess) {
|
||||
autoCreateVirtualFolder();
|
||||
autoCreateVirtualFolder(
|
||||
mailboxDashBoardController.isAINeedsActionEnabled,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -612,7 +617,9 @@ class MailboxController extends BaseMailboxController
|
||||
if (currentContext != null) {
|
||||
syncAllMailboxWithDisplayName(currentContext!);
|
||||
}
|
||||
autoCreateVirtualFolder();
|
||||
autoCreateVirtualFolder(
|
||||
mailboxDashBoardController.isAINeedsActionEnabled,
|
||||
);
|
||||
_setMapMailbox();
|
||||
_setOutboxMailbox();
|
||||
_selectSelectedMailboxDefault();
|
||||
@@ -1570,11 +1577,4 @@ class MailboxController extends BaseMailboxController
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void autoCreateVirtualFolder() {
|
||||
addFavoriteFolderToMailboxList();
|
||||
if (mailboxDashBoardController.isAINeedsActionEnabled) {
|
||||
addActionRequiredFolder();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ class MailboxItemWidget extends StatefulWidget {
|
||||
final double? itemHeight;
|
||||
final String? iconSelected;
|
||||
final bool isHighlighted;
|
||||
final bool isDraggingMailbox;
|
||||
|
||||
final OnClickExpandMailboxNodeAction? onExpandFolderActionClick;
|
||||
final OnClickOpenMailboxNodeAction? onOpenMailboxFolderClick;
|
||||
@@ -45,6 +46,7 @@ class MailboxItemWidget extends StatefulWidget {
|
||||
required this.mailboxNode,
|
||||
this.mailboxDisplayed = MailboxDisplayed.mailbox,
|
||||
this.isHighlighted = false,
|
||||
this.isDraggingMailbox = false,
|
||||
this.mailboxNodeSelected,
|
||||
this.mailboxActions,
|
||||
this.mailboxIdAlreadySelected,
|
||||
@@ -322,12 +324,19 @@ class _MailboxItemWidgetState extends State<MailboxItemWidget> {
|
||||
widget.mailboxNodeSelected?.id == widget.mailboxNode.item.id;
|
||||
|
||||
Color get backgroundColorItem {
|
||||
if (widget.mailboxDisplayed == MailboxDisplayed.mailbox) {
|
||||
return _isSelected || widget.isHighlighted
|
||||
? AppColor.blue100
|
||||
: Colors.transparent;
|
||||
// Non-mailbox views are always white
|
||||
if (widget.mailboxDisplayed != MailboxDisplayed.mailbox) {
|
||||
return Colors.white;
|
||||
}
|
||||
return Colors.white;
|
||||
|
||||
// Dragging action-required mailboxes must not show highlight
|
||||
if (widget.isDraggingMailbox && widget.mailboxNode.item.isActionRequired) {
|
||||
return AppColor.colorBgDesktop;
|
||||
}
|
||||
|
||||
return (_isSelected || widget.isHighlighted)
|
||||
? AppColor.blue100
|
||||
: Colors.transparent;
|
||||
}
|
||||
|
||||
bool get isFolderModalActive =>
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
import 'package:tmail_ui_user/features/home/domain/extensions/session_extensions.dart';
|
||||
import 'package:scribe/scribe/ai/presentation/utils/ai_scribe_constants.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||
import 'package:tmail_ui_user/main/error/capability_validator.dart';
|
||||
|
||||
extension HandleAiActionExtension on MailboxDashBoardController {
|
||||
extension HandleAiNeedsActionExtension on MailboxDashBoardController {
|
||||
bool get isAiCapabilitySupported {
|
||||
final currentAccountId = accountId.value;
|
||||
final currentSession = sessionCurrent;
|
||||
@@ -11,7 +11,7 @@ extension HandleAiActionExtension on MailboxDashBoardController {
|
||||
return false;
|
||||
}
|
||||
|
||||
return SessionExtensions.linagoraAICapability.isSupported(
|
||||
return AiScribeConstants.aiCapability.isSupported(
|
||||
currentSession,
|
||||
currentAccountId,
|
||||
);
|
||||
@@ -341,6 +341,17 @@ class ManageAccountDashBoardController extends ReloadableController
|
||||
}
|
||||
}
|
||||
|
||||
bool get isAIScribeCapabilityAvailable {
|
||||
if (accountId.value != null && sessionCurrent != null) {
|
||||
return isAIScribeEndpointAvailable(
|
||||
session: sessionCurrent!,
|
||||
accountId: accountId.value!,
|
||||
);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void disableVacationResponder(
|
||||
VacationResponse vacation, {
|
||||
bool isAuto = false,
|
||||
|
||||
@@ -54,6 +54,10 @@ class PreferencesController extends BaseController {
|
||||
return _manageAccountDashBoardController.isAICapabilitySupported;
|
||||
}
|
||||
|
||||
bool get isAIScribeCapabilityAvailable {
|
||||
return _manageAccountDashBoardController.isAIScribeCapabilityAvailable;
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
|
||||
@@ -77,7 +77,7 @@ class PreferencesView extends GetWidget<PreferencesController> with AppLoaderMix
|
||||
(type) =>
|
||||
type.isLocal &&
|
||||
(type != PreferencesOptionType.aiScribe ||
|
||||
controller.isAICapabilitySupported),
|
||||
controller.isAIScribeCapabilityAvailable),
|
||||
),
|
||||
if (settingOption != null &&
|
||||
controller.isAICapabilitySupported)
|
||||
|
||||
@@ -18,7 +18,7 @@ import 'package:tmail_ui_user/features/base/widget/keyboard/keyboard_handler_wra
|
||||
import 'package:tmail_ui_user/features/base/widget/popup_menu/popup_menu_item_action_widget.dart';
|
||||
import 'package:tmail_ui_user/features/base/widget/scrollbar_list_view.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/recent_search.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_receive_time_type.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/email_sort_order_type.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart';
|
||||
|
||||
@@ -58,8 +58,6 @@ import 'package:tmail_ui_user/features/mailbox/domain/usecases/subaddressing_int
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/usecases/subscribe_multiple_mailbox_interactor.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/action/mailbox_ui_action.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_action_required_tab_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/handle_favorite_tab_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/extensions/presentation_mailbox_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_actions.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/presentation/model/mailbox_tree_builder.dart';
|
||||
@@ -69,7 +67,7 @@ import 'package:tmail_ui_user/features/mailbox_creator/domain/usecases/verify_na
|
||||
import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/mailbox_creator_arguments.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_creator/presentation/model/new_mailbox_arguments.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_create_new_rule_filter.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_reactive_obx_variable_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/model/dashboard_routes.dart';
|
||||
@@ -215,11 +213,15 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa
|
||||
super.onDone();
|
||||
viewState.value.fold((failure) {
|
||||
if (failure is GetAllMailboxFailure) {
|
||||
autoCreateVirtualFolder();
|
||||
autoCreateVirtualFolder(
|
||||
dashboardController.isAINeedsActionEnabled,
|
||||
);
|
||||
}
|
||||
}, (success) {
|
||||
if (success is GetAllMailboxSuccess) {
|
||||
autoCreateVirtualFolder();
|
||||
autoCreateVirtualFolder(
|
||||
dashboardController.isAINeedsActionEnabled,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -900,13 +902,6 @@ class SearchMailboxController extends BaseMailboxController with MailboxActionHa
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
}
|
||||
|
||||
void autoCreateVirtualFolder() {
|
||||
addFavoriteFolderToMailboxList();
|
||||
if (dashboardController.isAINeedsActionEnabled) {
|
||||
addActionRequiredFolder();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
textInputSearchController.dispose();
|
||||
|
||||
@@ -20,7 +20,7 @@ import 'package:tmail_ui_user/features/mailbox/domain/state/clear_mailbox_state.
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/state/mark_as_mailbox_read_state.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox/domain/state/move_folder_content_state.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/domain/model/spam_report_state.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_action_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_ai_needs_action_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/handle_open_context_menu_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/extensions/open_and_close_composer_extension.dart';
|
||||
import 'package:tmail_ui_user/features/mailbox_dashboard/presentation/widgets/recover_deleted_message_loading_banner_widget.dart';
|
||||
|
||||
@@ -147,6 +147,11 @@ class MockMailboxDashBoardController extends Mock implements MailboxDashBoardCon
|
||||
|
||||
@override
|
||||
Rx<AIScribeConfig> get cachedAIScribeConfig => AIScribeConfig.initial().obs;
|
||||
|
||||
@override
|
||||
bool isAIScribeEndpointAvailable({Session? session, AccountId? accountId}) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@GenerateNiceMocks([
|
||||
|
||||
+15
-15
@@ -114,19 +114,19 @@ void main() {
|
||||
|
||||
test(
|
||||
'should insert after Starred when role missing but name matches (case-insensitive)',
|
||||
() {
|
||||
nodes = [
|
||||
buildNode('1', name: 'Inbox'),
|
||||
buildNode('2', name: 'STARRED'), // no role
|
||||
buildNode('3', name: 'Trash'),
|
||||
];
|
||||
() {
|
||||
nodes = [
|
||||
buildNode('1', name: 'Inbox'),
|
||||
buildNode('2', name: 'STARRED'), // no role
|
||||
buildNode('3', name: 'Trash'),
|
||||
];
|
||||
|
||||
final newNode = buildNode('4', name: 'Draft');
|
||||
nodes.insertAfterStarredOrInbox(newNode);
|
||||
final newNode = buildNode('4', name: 'Draft');
|
||||
nodes.insertAfterStarredOrInbox(newNode);
|
||||
|
||||
final ids = nodes.mailboxIds.map((id) => id.id.value).toList();
|
||||
expect(ids, ['1', '2', '4', '3']);
|
||||
});
|
||||
final ids = nodes.mailboxIds.map((id) => id.id.value).toList();
|
||||
expect(ids, ['1', '2', '4', '3']);
|
||||
});
|
||||
|
||||
test('should insert after Inbox when Starred not found', () {
|
||||
nodes = [
|
||||
@@ -162,7 +162,7 @@ void main() {
|
||||
];
|
||||
|
||||
final newNode =
|
||||
buildNode('2', name: 'Starred', role: 'favorite'); // duplicate id
|
||||
buildNode('2', name: 'Starred', role: 'favorite'); // duplicate id
|
||||
nodes.insertAfterStarredOrInbox(newNode);
|
||||
|
||||
final ids = nodes.mailboxIds.map((id) => id.id.value).toList();
|
||||
@@ -184,15 +184,15 @@ void main() {
|
||||
|
||||
bool isInbox(MailboxNode node) =>
|
||||
node.item.role?.value == PresentationMailbox.inboxRole ||
|
||||
node.item.name?.name.toLowerCase() == 'inbox';
|
||||
node.item.name?.name.toLowerCase() == 'inbox';
|
||||
|
||||
bool isStarred(MailboxNode node) =>
|
||||
node.item.role?.value == PresentationMailbox.favoriteRole ||
|
||||
node.item.name?.name.toLowerCase() == 'starred';
|
||||
node.item.name?.name.toLowerCase() == 'starred';
|
||||
|
||||
bool isSent(MailboxNode node) =>
|
||||
node.item.role?.value == PresentationMailbox.sentRole ||
|
||||
node.item.name?.name.toLowerCase() == 'sent';
|
||||
node.item.name?.name.toLowerCase() == 'sent';
|
||||
|
||||
test('should insert after first matched priority', () {
|
||||
nodes = [
|
||||
|
||||
Reference in New Issue
Block a user