mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
Added a new page for user request to ConnectFriendWizard.
The page is shown instead of the conclusion page when the user clicks on the certificate link in a message of type user request. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@5432 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
parent
aedac9738a
commit
21e97a47df
@ -449,6 +449,7 @@ void RetroShareLink::clear()
|
||||
{
|
||||
_valid = false;
|
||||
_type = TYPE_UNKNOWN;
|
||||
_subType = 0;
|
||||
_hash = "" ;
|
||||
_size = 0 ;
|
||||
_name = "" ;
|
||||
@ -945,7 +946,7 @@ static void processList(const QStringList &list, const QString &textSingular, co
|
||||
std::cerr << RS_Certificate.toStdString() << std::endl;
|
||||
|
||||
ConnectFriendWizard connectFriendWizard;
|
||||
connectFriendWizard.setCertificate(RS_Certificate);
|
||||
connectFriendWizard.setCertificate(RS_Certificate, (link.subType() == RSLINK_SUBTYPE_CERTIFICATE_USER_REQUEST) ? true : false);
|
||||
connectFriendWizard.exec();
|
||||
needNotifySuccess = false;
|
||||
}
|
||||
|
@ -45,6 +45,8 @@
|
||||
|
||||
#define RSLINK_SCHEME "retroshare"
|
||||
|
||||
#define RSLINK_SUBTYPE_CERTIFICATE_USER_REQUEST 1
|
||||
|
||||
class RetroShareLink
|
||||
{
|
||||
public:
|
||||
@ -80,6 +82,9 @@ class RetroShareLink
|
||||
const QString& location() const { return _location ; }
|
||||
QString title() const;
|
||||
|
||||
unsigned int subType() const { return _subType; }
|
||||
void setSubType(unsigned int subType) { _subType = subType; }
|
||||
|
||||
// get nice name for anchor
|
||||
QString niceName() const;
|
||||
|
||||
@ -126,6 +131,7 @@ class RetroShareLink
|
||||
QString _location ; // location
|
||||
QString _ext_ip_port ;
|
||||
QString _loc_ip_port ;
|
||||
unsigned int _subType; // for general use as sub type for _type (RSLINK_SUBTYPE_...)
|
||||
};
|
||||
|
||||
/// This class handles the copy/paste of links. Every member is static to ensure unicity.
|
||||
|
@ -96,7 +96,7 @@ ConnectFriendWizard::ConnectFriendWizard(QWidget *parent) :
|
||||
ui->rsidRadioButton->hide();
|
||||
}
|
||||
|
||||
void ConnectFriendWizard::setCertificate(const QString &certificate)
|
||||
void ConnectFriendWizard::setCertificate(const QString &certificate, bool friendRequest)
|
||||
{
|
||||
if (certificate.isEmpty()) {
|
||||
setStartId(Page_Intro);
|
||||
@ -110,8 +110,8 @@ void ConnectFriendWizard::setCertificate(const QString &certificate)
|
||||
#ifdef FRIEND_WIZARD_DEBUG
|
||||
std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl;
|
||||
#endif
|
||||
ui->friendCertEdit->setPlainText(certificate);
|
||||
setStartId(Page_Conclusion);
|
||||
mCertificate = certificate.toUtf8().constData();
|
||||
setStartId(friendRequest ? Page_FriendRequest : Page_Conclusion);
|
||||
} else {
|
||||
// error message
|
||||
setField("errorMessage", tr("Certificate Load Failed") + ": " + QString::fromUtf8(error_string.c_str()));
|
||||
@ -124,6 +124,22 @@ ConnectFriendWizard::~ConnectFriendWizard()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
static void fillGroups(ConnectFriendWizard *wizard, QComboBox *comboBox, const QString &groupId)
|
||||
{
|
||||
std::list<RsGroupInfo> groupInfoList;
|
||||
rsPeers->getGroupInfoList(groupInfoList);
|
||||
GroupDefs::sortByName(groupInfoList);
|
||||
comboBox->addItem("", ""); // empty value
|
||||
for (std::list<RsGroupInfo>::iterator groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) {
|
||||
comboBox->addItem(GroupDefs::name(*groupIt), QString::fromStdString(groupIt->id));
|
||||
}
|
||||
|
||||
if (groupId.isEmpty() == false) {
|
||||
comboBox->setCurrentIndex(comboBox->findData(groupId));
|
||||
}
|
||||
QObject::connect(comboBox, SIGNAL(currentIndexChanged(int)), wizard, SLOT(groupCurrentIndexChanged(int)));
|
||||
}
|
||||
|
||||
void ConnectFriendWizard::initializePage(int id)
|
||||
{
|
||||
switch ((Page) id) {
|
||||
@ -253,18 +269,44 @@ void ConnectFriendWizard::initializePage(int id)
|
||||
ui->locationEdit->setText(QString::fromUtf8(peerDetails.location.c_str()));
|
||||
ui->signersEdit->setPlainText(ts);
|
||||
|
||||
std::list<RsGroupInfo> groupInfoList;
|
||||
rsPeers->getGroupInfoList(groupInfoList);
|
||||
GroupDefs::sortByName(groupInfoList);
|
||||
ui->groupComboBox->addItem("", ""); // empty value
|
||||
for (std::list<RsGroupInfo>::iterator groupIt = groupInfoList.begin(); groupIt != groupInfoList.end(); ++groupIt) {
|
||||
ui->groupComboBox->addItem(GroupDefs::name(*groupIt), QString::fromStdString(groupIt->id));
|
||||
fillGroups(this, ui->groupComboBox, groupId);
|
||||
}
|
||||
break;
|
||||
case Page_FriendRequest:
|
||||
{
|
||||
std::cerr << "Friend request page id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl;
|
||||
|
||||
//set the radio button to sign the GPG key
|
||||
if (peerDetails.accept_connection && !peerDetails.ownsign) {
|
||||
//gpg key connection is already accepted, don't propose to accept it again
|
||||
ui->fr_signGPGCheckBox->setChecked(false);
|
||||
ui->fr_acceptNoSignGPGCheckBox->hide();
|
||||
ui->fr_acceptNoSignGPGCheckBox->setChecked(false);
|
||||
}
|
||||
if (!peerDetails.accept_connection && peerDetails.ownsign) {
|
||||
//gpg key is already signed, don't propose to sign it again
|
||||
ui->fr_acceptNoSignGPGCheckBox->setChecked(true);
|
||||
ui->fr_signGPGCheckBox->hide();
|
||||
ui->fr_signGPGCheckBox->setChecked(false);
|
||||
}
|
||||
if (!peerDetails.accept_connection && !peerDetails.ownsign) {
|
||||
ui->fr_acceptNoSignGPGCheckBox->setChecked(true);
|
||||
ui->fr_signGPGCheckBox->show();
|
||||
ui->fr_signGPGCheckBox->setChecked(false);
|
||||
ui->fr_acceptNoSignGPGCheckBox->show();
|
||||
}
|
||||
if (peerDetails.accept_connection && peerDetails.ownsign) {
|
||||
ui->fr_acceptNoSignGPGCheckBox->setChecked(false);
|
||||
ui->fr_acceptNoSignGPGCheckBox->hide();
|
||||
ui->fr_signGPGCheckBox->setChecked(false);
|
||||
ui->fr_signGPGCheckBox->hide();
|
||||
}
|
||||
|
||||
if (groupId.isEmpty() == false) {
|
||||
ui->groupComboBox->setCurrentIndex(ui->groupComboBox->findData(groupId));
|
||||
}
|
||||
connect(ui->groupComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(groupCurrentIndexChanged(int)));
|
||||
ui->fr_nameEdit->setText(QString::fromUtf8(peerDetails.name.c_str()));
|
||||
ui->fr_emailEdit->setText(QString::fromUtf8(peerDetails.email.c_str()));
|
||||
ui->fr_locationEdit->setText(QString::fromUtf8(peerDetails.location.c_str()));
|
||||
|
||||
fillGroups(this, ui->fr_groupComboBox, groupId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -300,6 +342,7 @@ bool ConnectFriendWizard::validateCurrentPage()
|
||||
std::string error_string;
|
||||
|
||||
if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, error_string)) {
|
||||
mCertificate = certstr;
|
||||
#ifdef FRIEND_WIZARD_DEBUG
|
||||
std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl;
|
||||
#endif
|
||||
@ -332,6 +375,7 @@ bool ConnectFriendWizard::validateCurrentPage()
|
||||
|
||||
std::string error_string;
|
||||
if (rsPeers->loadDetailsFromStringCert(certstr, peerDetails, error_string)) {
|
||||
mCertificate = certstr;
|
||||
#ifdef FRIEND_WIZARD_DEBUG
|
||||
std::cerr << "ConnectFriendWizard got id : " << peerDetails.id << "; gpg_id : " << peerDetails.gpg_id << std::endl;
|
||||
#endif
|
||||
@ -384,6 +428,8 @@ bool ConnectFriendWizard::validateCurrentPage()
|
||||
break;
|
||||
case Page_Conclusion:
|
||||
break;
|
||||
case Page_FriendRequest:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -407,6 +453,7 @@ int ConnectFriendWizard::nextId() const
|
||||
case Page_Email:
|
||||
case Page_ErrorMessage:
|
||||
case Page_Conclusion:
|
||||
case Page_FriendRequest:
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -415,19 +462,29 @@ int ConnectFriendWizard::nextId() const
|
||||
|
||||
void ConnectFriendWizard::accept()
|
||||
{
|
||||
bool sign = false;
|
||||
bool accept_connection = false;
|
||||
|
||||
if (hasVisitedPage(Page_Conclusion)) {
|
||||
std::cerr << "ConnectFriendWizard::accept() called with page conclusion visited" << std::endl;
|
||||
|
||||
bool sign = ui->signGPGCheckBox->isChecked();
|
||||
bool accept_connection = ui->acceptNoSignGPGCheckBox->isChecked();
|
||||
sign = ui->signGPGCheckBox->isChecked();
|
||||
accept_connection = ui->acceptNoSignGPGCheckBox->isChecked();
|
||||
} else if (hasVisitedPage(Page_FriendRequest)) {
|
||||
std::cerr << "ConnectFriendWizard::accept() called with page friend request visited" << std::endl;
|
||||
|
||||
if(accept_connection || sign)
|
||||
sign = ui->fr_signGPGCheckBox->isChecked();
|
||||
accept_connection = ui->fr_acceptNoSignGPGCheckBox->isChecked();
|
||||
} else {
|
||||
QDialog::accept();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mCertificate.empty() && (accept_connection || sign))
|
||||
{
|
||||
std::string certstr = ui->friendCertEdit->toPlainText().toUtf8().constData();
|
||||
|
||||
std::string ssl_id, pgp_id ;
|
||||
|
||||
if(!rsPeers->loadCertificateFromString(certstr,ssl_id,pgp_id))
|
||||
if(!rsPeers->loadCertificateFromString(mCertificate,ssl_id,pgp_id))
|
||||
{
|
||||
std::cerr << "ConnectFriendWizard::accept(): cannot load that certificate." << std::endl;
|
||||
return ;
|
||||
@ -470,7 +527,6 @@ void ConnectFriendWizard::accept()
|
||||
}
|
||||
|
||||
rsicontrol->getNotify().notifyListChange(NOTIFY_LIST_NEIGHBOURS,1) ;
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
@ -795,5 +851,8 @@ void ConnectFriendWizard::setGroup(const std::string &id)
|
||||
|
||||
void ConnectFriendWizard::groupCurrentIndexChanged(int index)
|
||||
{
|
||||
groupId = ui->groupComboBox->itemData(index, Qt::UserRole).toString();
|
||||
QComboBox *comboBox = dynamic_cast<QComboBox*>(sender());
|
||||
if (comboBox) {
|
||||
groupId = comboBox->itemData(index, Qt::UserRole).toString();
|
||||
}
|
||||
}
|
||||
|
@ -25,12 +25,12 @@ class ConnectFriendWizard : public QWizard
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Page { Page_Intro, Page_Text, Page_Cert, Page_ErrorMessage, Page_Conclusion, Page_Foff, Page_Rsid, Page_Email };
|
||||
enum Page { Page_Intro, Page_Text, Page_Cert, Page_ErrorMessage, Page_Conclusion, Page_Foff, Page_Rsid, Page_Email, Page_FriendRequest };
|
||||
|
||||
ConnectFriendWizard(QWidget *parent = 0);
|
||||
~ConnectFriendWizard();
|
||||
|
||||
void setCertificate(const QString &certificate);
|
||||
void setCertificate(const QString &certificate, bool friendRequest);
|
||||
|
||||
virtual bool validateCurrentPage();
|
||||
virtual int nextId() const;
|
||||
@ -67,6 +67,7 @@ private slots:
|
||||
private:
|
||||
bool error;
|
||||
RsPeerDetails peerDetails;
|
||||
std::string mCertificate;
|
||||
|
||||
/* TextPage */
|
||||
QTimer *cleanfriendCertTimer;
|
||||
|
@ -516,6 +516,154 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="ConnectFriendPage" name="FriendRequestPage">
|
||||
<property name="title">
|
||||
<string>Friend request</string>
|
||||
</property>
|
||||
<property name="subTitle">
|
||||
<string>Details about the request</string>
|
||||
</property>
|
||||
<attribute name="pageId">
|
||||
<string notr="true">ConnectFriendWizard::Page_FriendRequest</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="fr_label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">
|
||||
border: 2px solid #CCCCCC;
|
||||
border-radius:6px;
|
||||
background: white;
|
||||
</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>You have a friend request .</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="AvatarWidget" name="avatar">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>96</width>
|
||||
<height>96</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>96</width>
|
||||
<height>96</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QGroupBox" name="fr_peerDetailsFrame">
|
||||
<property name="title">
|
||||
<string>Peer details</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="fr_nameLabel">
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="fr_nameEdit">
|
||||
<property name="text">
|
||||
<string notr="true">Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="fr_emailLabel">
|
||||
<property name="text">
|
||||
<string>Email:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="fr_locationLabel">
|
||||
<property name="text">
|
||||
<string>Location:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="fr_locationEdit">
|
||||
<property name="text">
|
||||
<string notr="true">Location</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="fr_emailEdit">
|
||||
<property name="text">
|
||||
<string notr="true">Email</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="fr_optionsFrame">
|
||||
<property name="title">
|
||||
<string>Options</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="fr_groupLabel">
|
||||
<property name="text">
|
||||
<string>Add friend to group:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="fr_groupComboBox"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="fr_signGPGCheckBox">
|
||||
<property name="text">
|
||||
<string>Authenticate friend (Sign GPG Key)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="fr_acceptNoSignGPGCheckBox">
|
||||
<property name="text">
|
||||
<string>Add as friend to connect with</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<spacer name="fr_verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>488</width>
|
||||
<height>118</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="ConnectFriendPage" name="ErrorMessagePage">
|
||||
<property name="title">
|
||||
<string>Sorry, some error appeared</string>
|
||||
@ -687,6 +835,12 @@
|
||||
<header>gui/connect/ConnectFriendWizard.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AvatarWidget</class>
|
||||
<extends>QLabel</extends>
|
||||
<header>gui/common/AvatarWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../images.qrc"/>
|
||||
|
@ -124,10 +124,12 @@ MessageWidget::MessageWidget(bool controlled, QWidget *parent, Qt::WFlags flags)
|
||||
|
||||
isControlled = controlled;
|
||||
isWindow = false;
|
||||
currMsgFlags = 0;
|
||||
|
||||
connect(ui.msgList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(msgfilelistWidgetCostumPopupMenu(QPoint)));
|
||||
connect(ui.expandFilesButton, SIGNAL(clicked()), this, SLOT(togglefileview()));
|
||||
connect(ui.downloadButton, SIGNAL(clicked()), this, SLOT(getallrecommended()));
|
||||
connect(ui.msgText, SIGNAL(anchorClicked(QUrl)), this, SLOT(anchorClicked(QUrl)));
|
||||
|
||||
connect(NotifyQt::getInstance(), SIGNAL(messagesTagsChanged()), this, SLOT(messagesTagsChanged()));
|
||||
connect(NotifyQt::getInstance(), SIGNAL(messagesChanged()), this, SLOT(messagesChanged()));
|
||||
@ -452,6 +454,8 @@ void MessageWidget::fill(const std::string &msgId)
|
||||
|
||||
clearTagLabels();
|
||||
|
||||
currMsgFlags = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -562,6 +566,8 @@ void MessageWidget::fill(const std::string &msgId)
|
||||
ui.filesText->setText(QString("(%1 %2)").arg(msgInfo.count).arg(msgInfo.count == 1 ? tr("File") : tr("Files")));
|
||||
|
||||
showTagLabels();
|
||||
|
||||
currMsgFlags = msgInfo.msgflags;
|
||||
}
|
||||
|
||||
void MessageWidget::remove()
|
||||
@ -690,3 +696,20 @@ void MessageWidget::forward()
|
||||
|
||||
/* window will destroy itself! */
|
||||
}
|
||||
|
||||
void MessageWidget::anchorClicked(const QUrl &url)
|
||||
{
|
||||
RetroShareLink link(url);
|
||||
|
||||
if (link.valid() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (link.type() == RetroShareLink::TYPE_CERTIFICATE && currMsgFlags & RS_MSG_USER_REQUEST) {
|
||||
link.setSubType(RSLINK_SUBTYPE_CERTIFICATE_USER_REQUEST);
|
||||
}
|
||||
|
||||
QList<RetroShareLink> links;
|
||||
links.append(link);
|
||||
RetroShareLink::process(links);
|
||||
}
|
||||
|
@ -76,6 +76,8 @@ private slots:
|
||||
void getcurrentrecommended();
|
||||
void getallrecommended();
|
||||
|
||||
void anchorClicked(const QUrl &url);
|
||||
|
||||
private:
|
||||
void clearTagLabels();
|
||||
void showTagLabels();
|
||||
@ -83,6 +85,7 @@ private:
|
||||
bool isControlled;
|
||||
bool isWindow;
|
||||
std::string currMsgId;
|
||||
unsigned int currMsgFlags;
|
||||
|
||||
QList<QLabel*> tagLabels;
|
||||
|
||||
|
@ -39,13 +39,16 @@
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="LinkTextBrowser" name="msgText">
|
||||
<widget class="QTextBrowser" name="msgText">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
@ -475,13 +478,6 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LinkTextBrowser</class>
|
||||
<extends>QTextBrowser</extends>
|
||||
<header>gui/common/LinkTextBrowser.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../images.qrc"/>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user