am c3ceed68
: Fix ui notifications on folder list changes.
* commit 'c3ceed68948ef6720ae7b861955b4d341f331643': Fix ui notifications on folder list changes.
This commit is contained in:
commit
d9521a3f9d
@ -131,6 +131,12 @@ public class Mailbox extends EmailContent implements MailboxColumns, Parcelable
|
|||||||
};
|
};
|
||||||
private static final int MAILBOX_DISPLAY_NAME_COLUMN = 0;
|
private static final int MAILBOX_DISPLAY_NAME_COLUMN = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Projection to use when reading {@link MailboxColumns#ACCOUNT_KEY} for a mailbox.
|
||||||
|
*/
|
||||||
|
private static final String[] ACCOUNT_KEY_PROJECTION = { MailboxColumns.ACCOUNT_KEY };
|
||||||
|
private static final int ACCOUNT_KEY_PROJECTION_ACCOUNT_KEY_COLUMN = 0;
|
||||||
|
|
||||||
public static final long NO_MAILBOX = -1;
|
public static final long NO_MAILBOX = -1;
|
||||||
|
|
||||||
// Sentinel values for the mSyncInterval field of both Mailbox records
|
// Sentinel values for the mSyncInterval field of both Mailbox records
|
||||||
@ -760,4 +766,18 @@ public class Mailbox extends EmailContent implements MailboxColumns, Parcelable
|
|||||||
OUTBOX_PLUS_SYNCING_AND_ACCOUNT_SELECTION,
|
OUTBOX_PLUS_SYNCING_AND_ACCOUNT_SELECTION,
|
||||||
new String[] { Long.toString(accountId) }, null);
|
new String[] { Long.toString(accountId) }, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the account id for a mailbox.
|
||||||
|
* @param context The {@link Context}.
|
||||||
|
* @param mailboxId The id of the mailbox we're interested in, as a {@link String}.
|
||||||
|
* @return The account id for the mailbox, or {@link Account#NO_ACCOUNT} if the mailbox doesn't
|
||||||
|
* exist.
|
||||||
|
*/
|
||||||
|
public static long getAccountIdForMailbox(final Context context, final String mailboxId) {
|
||||||
|
return Utility.getFirstRowLong(context,
|
||||||
|
Mailbox.CONTENT_URI.buildUpon().appendEncodedPath(mailboxId).build(),
|
||||||
|
ACCOUNT_KEY_PROJECTION, null, null, null,
|
||||||
|
ACCOUNT_KEY_PROJECTION_ACCOUNT_KEY_COLUMN, Account.NO_ACCOUNT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -577,13 +577,20 @@ public class EmailProvider extends ContentProvider {
|
|||||||
db.execSQL(UPDATED_MESSAGE_DELETE + id);
|
db.execSQL(UPDATED_MESSAGE_DELETE + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final long accountId;
|
||||||
|
if (match == MAILBOX_ID) {
|
||||||
|
accountId = Mailbox.getAccountIdForMailbox(context, id);
|
||||||
|
} else {
|
||||||
|
accountId = Account.NO_ACCOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
result = db.delete(tableName, whereWithId(id, selection), selectionArgs);
|
result = db.delete(tableName, whereWithId(id, selection), selectionArgs);
|
||||||
|
|
||||||
if (match == ACCOUNT_ID) {
|
if (match == ACCOUNT_ID) {
|
||||||
notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, id);
|
notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, id);
|
||||||
resolver.notifyChange(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null);
|
resolver.notifyChange(UIPROVIDER_ALL_ACCOUNTS_NOTIFIER, null);
|
||||||
} else if (match == MAILBOX_ID) {
|
} else if (match == MAILBOX_ID) {
|
||||||
notifyUIFolder(id, null);
|
notifyUIFolder(id, accountId);
|
||||||
} else if (match == ATTACHMENT_ID) {
|
} else if (match == ATTACHMENT_ID) {
|
||||||
notifyUI(UIPROVIDER_ATTACHMENT_NOTIFIER, id);
|
notifyUI(UIPROVIDER_ATTACHMENT_NOTIFIER, id);
|
||||||
}
|
}
|
||||||
@ -684,26 +691,30 @@ public class EmailProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These URIs are used for specific UI notifications. We don't use EmailContent.CONTENT_URI
|
||||||
|
// as the base because that gets spammed.
|
||||||
|
private static final String UI_NOTIFICATION_AUTHORITY =
|
||||||
|
EmailContent.EMAIL_PACKAGE_NAME + ".uinotifications";
|
||||||
private static final Uri UIPROVIDER_CONVERSATION_NOTIFIER =
|
private static final Uri UIPROVIDER_CONVERSATION_NOTIFIER =
|
||||||
Uri.parse("content://" + UIProvider.AUTHORITY + "/uimessages");
|
Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uimessages");
|
||||||
private static final Uri UIPROVIDER_FOLDER_NOTIFIER =
|
private static final Uri UIPROVIDER_FOLDER_NOTIFIER =
|
||||||
Uri.parse("content://" + UIProvider.AUTHORITY + "/uifolder");
|
Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uifolder");
|
||||||
private static final Uri UIPROVIDER_FOLDERLIST_NOTIFIER =
|
private static final Uri UIPROVIDER_FOLDERLIST_NOTIFIER =
|
||||||
Uri.parse("content://" + UIProvider.AUTHORITY + "/uifolders");
|
Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uifolders");
|
||||||
private static final Uri UIPROVIDER_ACCOUNT_NOTIFIER =
|
private static final Uri UIPROVIDER_ACCOUNT_NOTIFIER =
|
||||||
Uri.parse("content://" + UIProvider.AUTHORITY + "/uiaccount");
|
Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uiaccount");
|
||||||
public static final Uri UIPROVIDER_SETTINGS_NOTIFIER =
|
public static final Uri UIPROVIDER_SETTINGS_NOTIFIER =
|
||||||
Uri.parse("content://" + UIProvider.AUTHORITY + "/uisettings");
|
Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uisettings");
|
||||||
private static final Uri UIPROVIDER_ATTACHMENT_NOTIFIER =
|
private static final Uri UIPROVIDER_ATTACHMENT_NOTIFIER =
|
||||||
Uri.parse("content://" + UIProvider.AUTHORITY + "/uiattachment");
|
Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uiattachment");
|
||||||
private static final Uri UIPROVIDER_ATTACHMENTS_NOTIFIER =
|
private static final Uri UIPROVIDER_ATTACHMENTS_NOTIFIER =
|
||||||
Uri.parse("content://" + UIProvider.AUTHORITY + "/uiattachments");
|
Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uiattachments");
|
||||||
public static final Uri UIPROVIDER_ALL_ACCOUNTS_NOTIFIER =
|
public static final Uri UIPROVIDER_ALL_ACCOUNTS_NOTIFIER =
|
||||||
Uri.parse("content://" + UIProvider.AUTHORITY + "/uiaccts");
|
Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uiaccts");
|
||||||
private static final Uri UIPROVIDER_MESSAGE_NOTIFIER =
|
private static final Uri UIPROVIDER_MESSAGE_NOTIFIER =
|
||||||
Uri.parse("content://" + UIProvider.AUTHORITY + "/uimessage");
|
Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uimessage");
|
||||||
private static final Uri UIPROVIDER_RECENT_FOLDERS_NOTIFIER =
|
private static final Uri UIPROVIDER_RECENT_FOLDERS_NOTIFIER =
|
||||||
Uri.parse("content://" + UIProvider.AUTHORITY + "/uirecentfolders");
|
Uri.parse("content://" + UI_NOTIFICATION_AUTHORITY + "/uirecentfolders");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Uri insert(Uri uri, ContentValues values) {
|
public Uri insert(Uri uri, ContentValues values) {
|
||||||
@ -744,25 +755,25 @@ public class EmailProvider extends ContentProvider {
|
|||||||
resultUri = ContentUris.withAppendedId(uri, longId);
|
resultUri = ContentUris.withAppendedId(uri, longId);
|
||||||
switch(match) {
|
switch(match) {
|
||||||
case MESSAGE:
|
case MESSAGE:
|
||||||
|
final long mailboxId = values.getAsLong(Message.MAILBOX_KEY);
|
||||||
if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) {
|
if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) {
|
||||||
notifyUIConversationMailbox(values.getAsLong(Message.MAILBOX_KEY));
|
notifyUIConversationMailbox(mailboxId);
|
||||||
}
|
}
|
||||||
|
notifyUIFolder(mailboxId, values.getAsLong(Message.ACCOUNT_KEY));
|
||||||
break;
|
break;
|
||||||
case MAILBOX:
|
case MAILBOX:
|
||||||
if (values.containsKey(MailboxColumns.TYPE)) {
|
if (values.containsKey(MailboxColumns.TYPE)) {
|
||||||
// Only notify for special mailbox types
|
if (values.getAsInteger(MailboxColumns.TYPE) <
|
||||||
int type = values.getAsInteger(MailboxColumns.TYPE);
|
Mailbox.TYPE_NOT_EMAIL) {
|
||||||
if (type != Mailbox.TYPE_INBOX && type != Mailbox.TYPE_OUTBOX &&
|
// Notify the account when a new mailbox is added
|
||||||
type != Mailbox.TYPE_DRAFTS && type != Mailbox.TYPE_SENT &&
|
final Long accountId =
|
||||||
type != Mailbox.TYPE_TRASH && type != Mailbox.TYPE_SEARCH) {
|
values.getAsLong(MailboxColumns.ACCOUNT_KEY);
|
||||||
break;
|
if (accountId != null && accountId.longValue() > 0) {
|
||||||
|
notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, accountId);
|
||||||
|
notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Notify the account when a new mailbox is added
|
|
||||||
Long accountId = values.getAsLong(MailboxColumns.ACCOUNT_KEY);
|
|
||||||
if (accountId != null && accountId.longValue() > 0) {
|
|
||||||
notifyUI(UIPROVIDER_ACCOUNT_NOTIFIER, accountId);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case ACCOUNT:
|
case ACCOUNT:
|
||||||
updateAccountSyncInterval(longId, values);
|
updateAccountSyncInterval(longId, values);
|
||||||
@ -1438,27 +1449,19 @@ public class EmailProvider extends ContentProvider {
|
|||||||
case QUICK_RESPONSE_ID:
|
case QUICK_RESPONSE_ID:
|
||||||
case POLICY_ID:
|
case POLICY_ID:
|
||||||
id = uri.getPathSegments().get(1);
|
id = uri.getPathSegments().get(1);
|
||||||
try {
|
if (match == SYNCED_MESSAGE_ID) {
|
||||||
if (match == SYNCED_MESSAGE_ID) {
|
// For synced messages, first copy the old message to the updated table
|
||||||
// For synced messages, first copy the old message to the updated table
|
// Note the insert or ignore semantics, guaranteeing that only the first
|
||||||
// Note the insert or ignore semantics, guaranteeing that only the first
|
// update will be reflected in the updated message table; therefore this
|
||||||
// update will be reflected in the updated message table; therefore this
|
// row will always have the "original" data
|
||||||
// row will always have the "original" data
|
db.execSQL(UPDATED_MESSAGE_INSERT + id);
|
||||||
db.execSQL(UPDATED_MESSAGE_INSERT + id);
|
} else if (match == MESSAGE_ID) {
|
||||||
} else if (match == MESSAGE_ID) {
|
db.execSQL(UPDATED_MESSAGE_DELETE + id);
|
||||||
db.execSQL(UPDATED_MESSAGE_DELETE + id);
|
|
||||||
}
|
|
||||||
result = db.update(tableName, values, whereWithId(id, selection),
|
|
||||||
selectionArgs);
|
|
||||||
} catch (SQLiteException e) {
|
|
||||||
// Null out values (so they aren't cached) and re-throw
|
|
||||||
values = null;
|
|
||||||
throw e;
|
|
||||||
}
|
}
|
||||||
|
result = db.update(tableName, values, whereWithId(id, selection),
|
||||||
|
selectionArgs);
|
||||||
if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) {
|
if (match == MESSAGE_ID || match == SYNCED_MESSAGE_ID) {
|
||||||
if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) {
|
handleMessageUpdateNotifications(uri, id, values);
|
||||||
notifyUIConversation(uri);
|
|
||||||
}
|
|
||||||
} else if (match == ATTACHMENT_ID) {
|
} else if (match == ATTACHMENT_ID) {
|
||||||
long attId = Integer.parseInt(id);
|
long attId = Integer.parseInt(id);
|
||||||
if (values.containsKey(Attachment.FLAGS)) {
|
if (values.containsKey(Attachment.FLAGS)) {
|
||||||
@ -1477,9 +1480,8 @@ public class EmailProvider extends ContentProvider {
|
|||||||
notifyUI(UIPROVIDER_ATTACHMENTS_NOTIFIER, att.mMessageKey);
|
notifyUI(UIPROVIDER_ATTACHMENTS_NOTIFIER, att.mMessageKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (match == MAILBOX_ID && values.containsKey(Mailbox.UI_SYNC_STATUS)) {
|
} else if (match == MAILBOX_ID) {
|
||||||
// TODO: should this notify on keys other than sync status?
|
notifyUIFolder(id, Mailbox.getAccountIdForMailbox(context, id));
|
||||||
notifyUIFolder(id, null);
|
|
||||||
} else if (match == ACCOUNT_ID) {
|
} else if (match == ACCOUNT_ID) {
|
||||||
updateAccountSyncInterval(Long.parseLong(id), values);
|
updateAccountSyncInterval(Long.parseLong(id), values);
|
||||||
// Notify individual account and "all accounts"
|
// Notify individual account and "all accounts"
|
||||||
@ -3055,8 +3057,10 @@ public class EmailProvider extends ContentProvider {
|
|||||||
row = getVirtualMailboxRow(acctId, Mailbox.TYPE_UNREAD);
|
row = getVirtualMailboxRow(acctId, Mailbox.TYPE_UNREAD);
|
||||||
mc.addRow(row);
|
mc.addRow(row);
|
||||||
|
|
||||||
mc.setNotificationUri(context.getContentResolver(), uri);
|
final Uri notifyUri =
|
||||||
c.setNotificationUri(context.getContentResolver(), uri);
|
UIPROVIDER_FOLDERLIST_NOTIFIER.buildUpon().appendEncodedPath(id).build();
|
||||||
|
mc.setNotificationUri(context.getContentResolver(), notifyUri);
|
||||||
|
c.setNotificationUri(context.getContentResolver(), notifyUri);
|
||||||
Cursor[] cursors = new Cursor[] {mc, c};
|
Cursor[] cursors = new Cursor[] {mc, c};
|
||||||
return new MergeCursor(cursors);
|
return new MergeCursor(cursors);
|
||||||
}
|
}
|
||||||
@ -3436,8 +3440,11 @@ public class EmailProvider extends ContentProvider {
|
|||||||
Uri notifyUri = null;
|
Uri notifyUri = null;
|
||||||
switch(match) {
|
switch(match) {
|
||||||
case UI_ALL_FOLDERS:
|
case UI_ALL_FOLDERS:
|
||||||
|
// TODO: Should this just do uiFolders()?
|
||||||
c = db.rawQuery(genQueryAccountAllMailboxes(uiProjection), new String[] {id});
|
c = db.rawQuery(genQueryAccountAllMailboxes(uiProjection), new String[] {id});
|
||||||
c = getFolderListCursor(db, c, uiProjection);
|
c = getFolderListCursor(db, c, uiProjection);
|
||||||
|
notifyUri =
|
||||||
|
UIPROVIDER_FOLDERLIST_NOTIFIER.buildUpon().appendEncodedPath(id).build();
|
||||||
break;
|
break;
|
||||||
case UI_RECENT_FOLDERS:
|
case UI_RECENT_FOLDERS:
|
||||||
c = db.rawQuery(genQueryRecentMailboxes(uiProjection), new String[] {id});
|
c = db.rawQuery(genQueryRecentMailboxes(uiProjection), new String[] {id});
|
||||||
@ -3446,6 +3453,11 @@ public class EmailProvider extends ContentProvider {
|
|||||||
case UI_SUBFOLDERS:
|
case UI_SUBFOLDERS:
|
||||||
c = db.rawQuery(genQuerySubfolders(uiProjection), new String[] {id});
|
c = db.rawQuery(genQuerySubfolders(uiProjection), new String[] {id});
|
||||||
c = getFolderListCursor(db, c, uiProjection);
|
c = getFolderListCursor(db, c, uiProjection);
|
||||||
|
// Get notifications for any folder changes on this account. This is broader than
|
||||||
|
// we need but otherwise we'd need for every folder change to notify on all relevant
|
||||||
|
// subtrees. For now we opt for simplicity.
|
||||||
|
final long accountId = Mailbox.getAccountIdForMailbox(context, id);
|
||||||
|
notifyUri = ContentUris.withAppendedId(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId);
|
||||||
break;
|
break;
|
||||||
case UI_MESSAGES:
|
case UI_MESSAGES:
|
||||||
long mailboxId = Long.parseLong(id);
|
long mailboxId = Long.parseLong(id);
|
||||||
@ -4117,9 +4129,48 @@ public class EmailProvider extends ContentProvider {
|
|||||||
.build();
|
.build();
|
||||||
addToSequence(uri, op);
|
addToSequence(uri, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
return update(ourUri, ourValues, null, null);
|
return update(ourUri, ourValues, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Projection for use with getting mailbox & account keys for a message.
|
||||||
|
*/
|
||||||
|
private static final String[] MESSAGE_KEYS_PROJECTION =
|
||||||
|
{ MessageColumns.MAILBOX_KEY, MessageColumns.ACCOUNT_KEY };
|
||||||
|
private static final int MESSAGE_KEYS_MAILBOX_KEY_COLUMN = 0;
|
||||||
|
private static final int MESSAGE_KEYS_ACCOUNT_KEY_COLUMN = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify necessary UI components in response to a message update.
|
||||||
|
* @param uri The {@link Uri} for this message update.
|
||||||
|
* @param messageId The id of the message that's been updated.
|
||||||
|
* @param values The {@link ContentValues} that were updated in the message.
|
||||||
|
*/
|
||||||
|
private void handleMessageUpdateNotifications(final Uri uri, final String messageId,
|
||||||
|
final ContentValues values) {
|
||||||
|
if (!uri.getBooleanQueryParameter(IS_UIPROVIDER, false)) {
|
||||||
|
notifyUIConversation(uri);
|
||||||
|
}
|
||||||
|
// TODO: Ideally, also test that the values actually changed.
|
||||||
|
if (values.containsKey(MessageColumns.FLAG_READ) ||
|
||||||
|
values.containsKey(MessageColumns.MAILBOX_KEY)) {
|
||||||
|
final Cursor c = query(
|
||||||
|
Message.CONTENT_URI.buildUpon().appendEncodedPath(messageId).build(),
|
||||||
|
MESSAGE_KEYS_PROJECTION, null, null, null);
|
||||||
|
if (c != null) {
|
||||||
|
try {
|
||||||
|
if (c.moveToFirst()) {
|
||||||
|
notifyUIFolder(c.getLong(MESSAGE_KEYS_MAILBOX_KEY_COLUMN),
|
||||||
|
c.getLong(MESSAGE_KEYS_ACCOUNT_KEY_COLUMN));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static final String PICKER_UI_ACCOUNT = "picker_ui_account";
|
public static final String PICKER_UI_ACCOUNT = "picker_ui_account";
|
||||||
public static final String PICKER_MAILBOX_TYPE = "picker_mailbox_type";
|
public static final String PICKER_MAILBOX_TYPE = "picker_mailbox_type";
|
||||||
public static final String PICKER_MESSAGE_ID = "picker_message_id";
|
public static final String PICKER_MESSAGE_ID = "picker_message_id";
|
||||||
@ -4248,30 +4299,18 @@ public class EmailProvider extends ContentProvider {
|
|||||||
* Notify about a folder update. Because folder changes can affect the conversation cursor's
|
* Notify about a folder update. Because folder changes can affect the conversation cursor's
|
||||||
* extras, the conversation must also be notified here.
|
* extras, the conversation must also be notified here.
|
||||||
* @param folderId the folder id to be notified
|
* @param folderId the folder id to be notified
|
||||||
* @param accountId the account id to be notified (for folder list notification); if null, then
|
* @param accountId the account id to be notified (for folder list notification).
|
||||||
* lookup the accountId from the folder.
|
|
||||||
*/
|
*/
|
||||||
private void notifyUIFolder(String folderId, String accountId) {
|
private void notifyUIFolder(final String folderId, final long accountId) {
|
||||||
notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, folderId);
|
notifyUI(UIPROVIDER_CONVERSATION_NOTIFIER, folderId);
|
||||||
notifyUI(UIPROVIDER_FOLDER_NOTIFIER, folderId);
|
notifyUI(UIPROVIDER_FOLDER_NOTIFIER, folderId);
|
||||||
if (accountId == null) {
|
if (accountId != Account.NO_ACCOUNT) {
|
||||||
try {
|
|
||||||
final Mailbox mailbox = Mailbox.restoreMailboxWithId(getContext(),
|
|
||||||
Long.parseLong(folderId));
|
|
||||||
if (mailbox != null) {
|
|
||||||
accountId = Long.toString(mailbox.mAccountKey);
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
// Bad folderId, so we can't lookup account.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (accountId != null) {
|
|
||||||
notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId);
|
notifyUI(UIPROVIDER_FOLDERLIST_NOTIFIER, accountId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyUIFolder(long folderId, long accountId) {
|
private void notifyUIFolder(final long folderId, final long accountId) {
|
||||||
notifyUIFolder(Long.toString(folderId), Long.toString(accountId));
|
notifyUIFolder(Long.toString(folderId), accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyUI(Uri uri, String id) {
|
private void notifyUI(Uri uri, String id) {
|
||||||
|
Loading…
Reference in New Issue
Block a user