mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Faux offline messaging: enable/disable
This commit is contained in:
parent
cee1bcc8d1
commit
5d50ea36d0
|
@ -120,15 +120,14 @@ HistoryKeeper::~HistoryKeeper()
|
||||||
delete db;
|
delete db;
|
||||||
}
|
}
|
||||||
|
|
||||||
int HistoryKeeper::addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt)
|
int HistoryKeeper::addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent)
|
||||||
{
|
{
|
||||||
int chat_id = getChatID(chat, ctSingle).first;
|
int chat_id = getChatID(chat, ctSingle).first;
|
||||||
int sender_id = getAliasID(sender);
|
int sender_id = getAliasID(sender);
|
||||||
bool status = sender != Core::getInstance()->getSelfId().publicKey;
|
|
||||||
|
|
||||||
db->exec(QString("INSERT INTO history (timestamp, chat_id, sender, sent_ok, message)") +
|
db->exec(QString("INSERT INTO history (timestamp, chat_id, sender, sent_ok, message)") +
|
||||||
QString("VALUES (%1, %2, %3, %4, '%5');")
|
QString("VALUES (%1, %2, %3, %4, '%5');")
|
||||||
.arg(dt.toMSecsSinceEpoch()).arg(chat_id).arg(sender_id).arg(status).arg(wrapMessage(message)));
|
.arg(dt.toMSecsSinceEpoch()).arg(chat_id).arg(sender_id).arg(isSent).arg(wrapMessage(message)));
|
||||||
|
|
||||||
messageID++;
|
messageID++;
|
||||||
return messageID;
|
return messageID;
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
static bool checkPassword();
|
static bool checkPassword();
|
||||||
static void renameHistory(QString from, QString to);
|
static void renameHistory(QString from, QString to);
|
||||||
|
|
||||||
int addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt);
|
int addChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt, bool isSent);
|
||||||
int addGroupChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt);
|
int addGroupChatEntry(const QString& chat, const QString& message, const QString& sender, const QDateTime &dt);
|
||||||
QList<HistMessage> getChatHistory(ChatType ct, const QString &chat, const QDateTime &time_from, const QDateTime &time_to);
|
QList<HistMessage> getChatHistory(ChatType ct, const QString &chat, const QDateTime &time_from, const QDateTime &time_to);
|
||||||
void markAsSent(int m_id);
|
void markAsSent(int m_id);
|
||||||
|
|
|
@ -121,6 +121,7 @@ void Settings::load()
|
||||||
autoAwayTime = s.value("autoAwayTime", 10).toInt();
|
autoAwayTime = s.value("autoAwayTime", 10).toInt();
|
||||||
checkUpdates = s.value("checkUpdates", false).toBool();
|
checkUpdates = s.value("checkUpdates", false).toBool();
|
||||||
showInFront = s.value("showInFront", false).toBool();
|
showInFront = s.value("showInFront", false).toBool();
|
||||||
|
fauxOfflineMessaging = s.value("fauxOfflineMessaging", false).toBool();
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
s.beginGroup("Widgets");
|
s.beginGroup("Widgets");
|
||||||
|
@ -259,6 +260,7 @@ void Settings::save(QString path)
|
||||||
s.setValue("autoAwayTime", autoAwayTime);
|
s.setValue("autoAwayTime", autoAwayTime);
|
||||||
s.setValue("checkUpdates", checkUpdates);
|
s.setValue("checkUpdates", checkUpdates);
|
||||||
s.setValue("showInFront", showInFront);
|
s.setValue("showInFront", showInFront);
|
||||||
|
s.setValue("fauxOfflineMessaging", fauxOfflineMessaging);
|
||||||
s.endGroup();
|
s.endGroup();
|
||||||
|
|
||||||
s.beginGroup("Widgets");
|
s.beginGroup("Widgets");
|
||||||
|
@ -849,3 +851,13 @@ void Settings::setFriendAlias(const ToxID &id, const QString &alias)
|
||||||
it->alias = alias;
|
it->alias = alias;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Settings::getFauxOfflineMessaging() const
|
||||||
|
{
|
||||||
|
return fauxOfflineMessaging;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::setFauxOfflineMessaging(bool value)
|
||||||
|
{
|
||||||
|
fauxOfflineMessaging = value;
|
||||||
|
}
|
||||||
|
|
|
@ -199,6 +199,9 @@ public:
|
||||||
QString getFriendAlias(const ToxID &id) const;
|
QString getFriendAlias(const ToxID &id) const;
|
||||||
void setFriendAlias(const ToxID &id, const QString &alias);
|
void setFriendAlias(const ToxID &id, const QString &alias);
|
||||||
|
|
||||||
|
bool getFauxOfflineMessaging() const;
|
||||||
|
void setFauxOfflineMessaging(bool value);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void save();
|
void save();
|
||||||
void save(QString path);
|
void save(QString path);
|
||||||
|
@ -218,6 +221,7 @@ private:
|
||||||
int dhtServerId;
|
int dhtServerId;
|
||||||
bool dontShowDhtDialog;
|
bool dontShowDhtDialog;
|
||||||
|
|
||||||
|
bool fauxOfflineMessaging;
|
||||||
bool enableIPv6;
|
bool enableIPv6;
|
||||||
QString translation;
|
QString translation;
|
||||||
static bool makeToxPortable;
|
static bool makeToxPortable;
|
||||||
|
@ -281,6 +285,7 @@ private:
|
||||||
|
|
||||||
QHash<QString, friendProp> friendLst;
|
QHash<QString, friendProp> friendLst;
|
||||||
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
//void dataChanged();
|
//void dataChanged();
|
||||||
void dhtServerListChanged();
|
void dhtServerListChanged();
|
||||||
|
|
|
@ -77,6 +77,7 @@ ChatForm::ChatForm(Friend* chatFriend)
|
||||||
connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle()));
|
connect(volButton, SIGNAL(clicked()), this, SLOT(onVolMuteToggle()));
|
||||||
connect(chatWidget, &ChatAreaWidget::onFileTranfertInterract, this, &ChatForm::onFileTansBtnClicked);
|
connect(chatWidget, &ChatAreaWidget::onFileTranfertInterract, this, &ChatForm::onFileTansBtnClicked);
|
||||||
connect(Core::getInstance(), &Core::fileSendFailed, this, &ChatForm::onFileSendFailed);
|
connect(Core::getInstance(), &Core::fileSendFailed, this, &ChatForm::onFileSendFailed);
|
||||||
|
connect(this, SIGNAL(chatAreaCleared()), this, SLOT(clearReciepts()));
|
||||||
|
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
||||||
|
@ -115,10 +116,10 @@ void ChatForm::onSendTriggered()
|
||||||
if (isAction)
|
if (isAction)
|
||||||
qt_msg_hist = "/me " + qt_msg;
|
qt_msg_hist = "/me " + qt_msg;
|
||||||
|
|
||||||
int id = HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, qt_msg_hist,
|
bool status = !Settings::getInstance().getFauxOfflineMessaging();
|
||||||
Core::getInstance()->getSelfId().publicKey, timestamp);
|
|
||||||
|
|
||||||
qDebug() << "db id:" << id;
|
int id = HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, qt_msg_hist,
|
||||||
|
Core::getInstance()->getSelfId().publicKey, timestamp, status);
|
||||||
|
|
||||||
MessageActionPtr ma = addSelfMessage(msg, isAction, timestamp, false);
|
MessageActionPtr ma = addSelfMessage(msg, isAction, timestamp, false);
|
||||||
|
|
||||||
|
@ -128,7 +129,6 @@ void ChatForm::onSendTriggered()
|
||||||
else
|
else
|
||||||
rec = Core::getInstance()->sendMessage(f->getFriendID(), msg);
|
rec = Core::getInstance()->sendMessage(f->getFriendID(), msg);
|
||||||
|
|
||||||
qDebug() << "receipt:" << rec;
|
|
||||||
registerReceipt(rec, id, ma);
|
registerReceipt(rec, id, ma);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -846,7 +846,6 @@ void ChatForm::registerReceipt(int receipt, int messageID, MessageActionPtr msg)
|
||||||
{
|
{
|
||||||
receipts[receipt] = messageID;
|
receipts[receipt] = messageID;
|
||||||
undeliveredMsgs[messageID] = msg;
|
undeliveredMsgs[messageID] = msg;
|
||||||
qDebug() << "linking: rec" << receipt << "with" << messageID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatForm::dischargeReceipt(int receipt)
|
void ChatForm::dischargeReceipt(int receipt)
|
||||||
|
@ -864,7 +863,6 @@ void ChatForm::dischargeReceipt(int receipt)
|
||||||
undeliveredMsgs.erase(msgIt);
|
undeliveredMsgs.erase(msgIt);
|
||||||
}
|
}
|
||||||
receipts.erase(it);
|
receipts.erase(it);
|
||||||
qDebug() << "receipt" << receipt << "delivered";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,6 +874,9 @@ void ChatForm::clearReciepts()
|
||||||
|
|
||||||
void ChatForm::deliverOfflineMsgs()
|
void ChatForm::deliverOfflineMsgs()
|
||||||
{
|
{
|
||||||
|
if (!Settings::getInstance().getFauxOfflineMessaging())
|
||||||
|
return;
|
||||||
|
|
||||||
QMap<int, MessageActionPtr> msgs = undeliveredMsgs;
|
QMap<int, MessageActionPtr> msgs = undeliveredMsgs;
|
||||||
clearReciepts();
|
clearReciepts();
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,6 @@ public:
|
||||||
void setStatusMessage(QString newMessage);
|
void setStatusMessage(QString newMessage);
|
||||||
|
|
||||||
void dischargeReceipt(int receipt);
|
void dischargeReceipt(int receipt);
|
||||||
void clearReciepts();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sendFile(int32_t friendId, QString, QString, long long);
|
void sendFile(int32_t friendId, QString, QString, long long);
|
||||||
|
@ -52,6 +51,7 @@ signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void deliverOfflineMsgs();
|
void deliverOfflineMsgs();
|
||||||
|
void clearReciepts();
|
||||||
void startFileSend(ToxFile file);
|
void startFileSend(ToxFile file);
|
||||||
void onFileRecvRequest(ToxFile file);
|
void onFileRecvRequest(ToxFile file);
|
||||||
void onAvInvite(int FriendId, int CallId, bool video);
|
void onAvInvite(int FriendId, int CallId, bool video);
|
||||||
|
|
|
@ -305,6 +305,8 @@ void GenericChatForm::clearChatArea(bool notinform)
|
||||||
delete earliestMessage;
|
delete earliestMessage;
|
||||||
earliestMessage = nullptr;
|
earliestMessage = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit chatAreaCleared();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
signals:
|
signals:
|
||||||
void sendMessage(int, QString);
|
void sendMessage(int, QString);
|
||||||
void sendAction(int, QString);
|
void sendAction(int, QString);
|
||||||
|
void chatAreaCleared();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void focusInput();
|
void focusInput();
|
||||||
|
|
|
@ -59,6 +59,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
||||||
bodyUI->autoacceptFiles->setChecked(Settings::getInstance().getAutoSaveEnabled());
|
bodyUI->autoacceptFiles->setChecked(Settings::getInstance().getAutoSaveEnabled());
|
||||||
bodyUI->autoSaveFilesDir->setText(Settings::getInstance().getGlobalAutoAcceptDir());
|
bodyUI->autoSaveFilesDir->setText(Settings::getInstance().getGlobalAutoAcceptDir());
|
||||||
bodyUI->showInFront->setChecked(Settings::getInstance().getShowInFront());
|
bodyUI->showInFront->setChecked(Settings::getInstance().getShowInFront());
|
||||||
|
bodyUI->cbFauxOfflineMessaging->setChecked(Settings::getInstance().getFauxOfflineMessaging());
|
||||||
|
|
||||||
for (auto entry : SmileyPack::listSmileyPacks())
|
for (auto entry : SmileyPack::listSmileyPacks())
|
||||||
{
|
{
|
||||||
|
@ -125,6 +126,7 @@ GeneralForm::GeneralForm(SettingsWidget *myParent) :
|
||||||
connect(bodyUI->proxyAddr, &QLineEdit::editingFinished, this, &GeneralForm::onProxyAddrEdited);
|
connect(bodyUI->proxyAddr, &QLineEdit::editingFinished, this, &GeneralForm::onProxyAddrEdited);
|
||||||
connect(bodyUI->proxyPort, SIGNAL(valueChanged(int)), this, SLOT(onProxyPortEdited(int)));
|
connect(bodyUI->proxyPort, SIGNAL(valueChanged(int)), this, SLOT(onProxyPortEdited(int)));
|
||||||
connect(bodyUI->reconnectButton, &QPushButton::clicked, this, &GeneralForm::onReconnectClicked);
|
connect(bodyUI->reconnectButton, &QPushButton::clicked, this, &GeneralForm::onReconnectClicked);
|
||||||
|
connect(bodyUI->cbFauxOfflineMessaging, &QCheckBox::stateChanged, this, &GeneralForm::onFauxOfflineMessaging);
|
||||||
}
|
}
|
||||||
|
|
||||||
GeneralForm::~GeneralForm()
|
GeneralForm::~GeneralForm()
|
||||||
|
@ -300,3 +302,7 @@ void GeneralForm::onSetShowInFront()
|
||||||
Settings::getInstance().setShowInFront(bodyUI->showInFront->isChecked());
|
Settings::getInstance().setShowInFront(bodyUI->showInFront->isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GeneralForm::onFauxOfflineMessaging()
|
||||||
|
{
|
||||||
|
Settings::getInstance().setFauxOfflineMessaging(bodyUI->cbFauxOfflineMessaging->isChecked());
|
||||||
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ private slots:
|
||||||
void onAutoSaveDirChange();
|
void onAutoSaveDirChange();
|
||||||
void onCheckUpdateChanged();
|
void onCheckUpdateChanged();
|
||||||
void onSetShowInFront();
|
void onSetShowInFront();
|
||||||
|
void onFauxOfflineMessaging();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::GeneralSettings *bodyUI;
|
Ui::GeneralSettings *bodyUI;
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>511</width>
|
<width>511</width>
|
||||||
<height>796</height>
|
<height>698</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,1">
|
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,1">
|
||||||
|
@ -97,41 +97,41 @@
|
||||||
<layout class="QHBoxLayout" name="trayLayout">
|
<layout class="QHBoxLayout" name="trayLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="startInTray">
|
<widget class="QCheckBox" name="startInTray">
|
||||||
<property name="text">
|
|
||||||
<string>Start in tray</string>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Start in tray</string>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="closeToTray">
|
<widget class="QCheckBox" name="closeToTray">
|
||||||
<property name="text">
|
|
||||||
<string>Close to tray</string>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Close to tray</string>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="minimizeToTray">
|
<widget class="QCheckBox" name="minimizeToTray">
|
||||||
<property name="text">
|
|
||||||
<string>Minimize to tray</string>
|
|
||||||
</property>
|
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Minimize to tray</string>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -157,6 +157,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="cbFauxOfflineMessaging">
|
||||||
|
<property name="text">
|
||||||
|
<string>Faux offline messaging</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item alignment="Qt::AlignLeft">
|
<item alignment="Qt::AlignLeft">
|
||||||
|
|
|
@ -52,6 +52,7 @@ void PrivacyForm::onEnableLoggingUpdated()
|
||||||
Settings::getInstance().setEnableLogging(bodyUI->cbKeepHistory->isChecked());
|
Settings::getInstance().setEnableLogging(bodyUI->cbKeepHistory->isChecked());
|
||||||
bodyUI->cbEncryptHistory->setEnabled(bodyUI->cbKeepHistory->isChecked());
|
bodyUI->cbEncryptHistory->setEnabled(bodyUI->cbKeepHistory->isChecked());
|
||||||
HistoryKeeper::getInstance()->resetInstance();
|
HistoryKeeper::getInstance()->resetInstance();
|
||||||
|
Widget::getInstance()->clearAllReceipts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrivacyForm::onTypingNotificationEnabledUpdated()
|
void PrivacyForm::onTypingNotificationEnabledUpdated()
|
||||||
|
|
|
@ -746,9 +746,9 @@ void Widget::onFriendMessageReceived(int friendId, const QString& message, bool
|
||||||
f->getChatForm()->addMessage(f->getToxID(), message, isAction, timestamp, true);
|
f->getChatForm()->addMessage(f->getToxID(), message, isAction, timestamp, true);
|
||||||
|
|
||||||
if (isAction)
|
if (isAction)
|
||||||
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, "/me " + message, f->getToxID().publicKey, timestamp);
|
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, "/me " + message, f->getToxID().publicKey, timestamp, true);
|
||||||
else
|
else
|
||||||
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, message, f->getToxID().publicKey, timestamp);
|
HistoryKeeper::getInstance()->addChatEntry(f->getToxID().publicKey, message, f->getToxID().publicKey, timestamp, true);
|
||||||
|
|
||||||
if (activeChatroomWidget != nullptr)
|
if (activeChatroomWidget != nullptr)
|
||||||
{
|
{
|
||||||
|
@ -773,7 +773,6 @@ void Widget::onReceiptRecieved(int friendId, int receipt)
|
||||||
if (!f)
|
if (!f)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
qDebug() << "Receipt Recieved" << friendId << "receipt" << receipt;
|
|
||||||
f->getChatForm()->dischargeReceipt(receipt);
|
f->getChatForm()->dischargeReceipt(receipt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1143,3 +1142,12 @@ bool Widget::askMsgboxQuestion(const QString& title, const QString& msg)
|
||||||
return QMessageBox::question(this, title, msg) == QMessageBox::StandardButton::Yes;
|
return QMessageBox::question(this, title, msg) == QMessageBox::StandardButton::Yes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Widget::clearAllReceipts()
|
||||||
|
{
|
||||||
|
QList<Friend*> frnds = FriendList::getAllFriends();
|
||||||
|
for (Friend *f : frnds)
|
||||||
|
{
|
||||||
|
f->getChatForm()->clearReciepts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ public:
|
||||||
virtual void closeEvent(QCloseEvent *event);
|
virtual void closeEvent(QCloseEvent *event);
|
||||||
virtual void changeEvent(QEvent *event);
|
virtual void changeEvent(QEvent *event);
|
||||||
|
|
||||||
|
void clearAllReceipts();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void onSettingsClicked();
|
void onSettingsClicked();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user