mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-06 14:29:54 +08:00
KateVi: skip Ctrl+X as well as Ctrl+C
This commit is contained in:
parent
52d389a5e7
commit
8be34ade30
@ -1 +1 @@
|
|||||||
Subproject commit f38624d8b342da710dca7b5e6efb229a99032420
|
Subproject commit b3af91647d64f91eb031b4c0a3ce5d1e656fae08
|
@ -6,14 +6,13 @@
|
|||||||
|
|
||||||
#include <utils/utils.h>
|
#include <utils/utils.h>
|
||||||
#include <utils/pathutils.h>
|
#include <utils/pathutils.h>
|
||||||
#include "githubimagehost.h"
|
|
||||||
|
|
||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
|
|
||||||
const QString GiteeImageHost::c_apiUrl = "https://gitee.com/api/v5";
|
const QString GiteeImageHost::c_apiUrl = "https://gitee.com/api/v5";
|
||||||
|
|
||||||
GiteeImageHost::GiteeImageHost(QObject *p_parent)
|
GiteeImageHost::GiteeImageHost(QObject *p_parent)
|
||||||
: ImageHost(p_parent)
|
: RepoImageHost(p_parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,23 +43,6 @@ void GiteeImageHost::setConfig(const QJsonObject &p_jobj)
|
|||||||
m_imageUrlPrefix = QString("https://gitee.com/%1/%2/raw/").arg(m_userName, m_repoName);
|
m_imageUrlPrefix = QString("https://gitee.com/%1/%2/raw/").arg(m_userName, m_repoName);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GiteeImageHost::testConfig(const QJsonObject &p_jobj, QString &p_msg)
|
|
||||||
{
|
|
||||||
p_msg.clear();
|
|
||||||
|
|
||||||
QString token, userName, repoName;
|
|
||||||
parseConfig(p_jobj, token, userName, repoName);
|
|
||||||
|
|
||||||
if (token.isEmpty() || userName.isEmpty() || repoName.isEmpty()) {
|
|
||||||
p_msg = tr("PersonalAccessToken/UserName/RepositoryName should not be empty.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto reply = getRepoInfo(token, userName, repoName);
|
|
||||||
p_msg = QString::fromUtf8(reply.m_data);
|
|
||||||
return reply.m_error == QNetworkReply::NoError;
|
|
||||||
}
|
|
||||||
|
|
||||||
vte::NetworkAccess::RawHeaderPairs GiteeImageHost::prepareCommonHeaders()
|
vte::NetworkAccess::RawHeaderPairs GiteeImageHost::prepareCommonHeaders()
|
||||||
{
|
{
|
||||||
vte::NetworkAccess::RawHeaderPairs rawHeader;
|
vte::NetworkAccess::RawHeaderPairs rawHeader;
|
||||||
@ -86,16 +68,6 @@ vte::NetworkReply GiteeImageHost::getRepoInfo(const QString &p_token, const QStr
|
|||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GiteeImageHost::parseConfig(const QJsonObject &p_jobj,
|
|
||||||
QString &p_token,
|
|
||||||
QString &p_userName,
|
|
||||||
QString &p_repoName)
|
|
||||||
{
|
|
||||||
p_token = p_jobj[QStringLiteral("personal_access_token")].toString();
|
|
||||||
p_userName = p_jobj[QStringLiteral("user_name")].toString();
|
|
||||||
p_repoName = p_jobj[QStringLiteral("repository_name")].toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isEmptyResponse(const QByteArray &p_data)
|
static bool isEmptyResponse(const QByteArray &p_data)
|
||||||
{
|
{
|
||||||
return p_data == QByteArray("[]");
|
return p_data == QByteArray("[]");
|
||||||
@ -168,7 +140,7 @@ bool GiteeImageHost::remove(const QString &p_url, QString &p_msg)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto resourcePath = GitHubImageHost::fetchResourcePath(m_imageUrlPrefix, p_url);
|
const auto resourcePath = fetchResourcePath(m_imageUrlPrefix, p_url);
|
||||||
|
|
||||||
auto rawHeader = prepareCommonHeaders();
|
auto rawHeader = prepareCommonHeaders();
|
||||||
const auto urlStr = QString("%1/repos/%2/%3/contents/%4").arg(c_apiUrl, m_userName, m_repoName, resourcePath);
|
const auto urlStr = QString("%1/repos/%2/%3/contents/%4").arg(c_apiUrl, m_userName, m_repoName, resourcePath);
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
#ifndef GITEEIMAGEHOST_H
|
#ifndef GITEEIMAGEHOST_H
|
||||||
#define GITEEIMAGEHOST_H
|
#define GITEEIMAGEHOST_H
|
||||||
|
|
||||||
#include "imagehost.h"
|
#include "repoimagehost.h"
|
||||||
|
|
||||||
#include <vtextedit/networkutils.h>
|
|
||||||
|
|
||||||
namespace vnotex
|
namespace vnotex
|
||||||
{
|
{
|
||||||
class GiteeImageHost : public ImageHost
|
class GiteeImageHost : public RepoImageHost
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@ -21,8 +19,6 @@ namespace vnotex
|
|||||||
|
|
||||||
void setConfig(const QJsonObject &p_jobj) Q_DECL_OVERRIDE;
|
void setConfig(const QJsonObject &p_jobj) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
bool testConfig(const QJsonObject &p_jobj, QString &p_msg) Q_DECL_OVERRIDE;
|
|
||||||
|
|
||||||
QString create(const QByteArray &p_data, const QString &p_path, QString &p_msg) Q_DECL_OVERRIDE;
|
QString create(const QByteArray &p_data, const QString &p_path, QString &p_msg) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
bool remove(const QString &p_url, QString &p_msg) Q_DECL_OVERRIDE;
|
bool remove(const QString &p_url, QString &p_msg) Q_DECL_OVERRIDE;
|
||||||
@ -30,13 +26,7 @@ namespace vnotex
|
|||||||
bool ownsUrl(const QString &p_url) const Q_DECL_OVERRIDE;
|
bool ownsUrl(const QString &p_url) const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Used to test.
|
vte::NetworkReply getRepoInfo(const QString &p_token, const QString &p_userName, const QString &p_repoName) const Q_DECL_OVERRIDE;
|
||||||
vte::NetworkReply getRepoInfo(const QString &p_token, const QString &p_userName, const QString &p_repoName) const;
|
|
||||||
|
|
||||||
static void parseConfig(const QJsonObject &p_jobj,
|
|
||||||
QString &p_token,
|
|
||||||
QString &p_userName,
|
|
||||||
QString &p_repoName);
|
|
||||||
|
|
||||||
static vte::NetworkAccess::RawHeaderPairs prepareCommonHeaders();
|
static vte::NetworkAccess::RawHeaderPairs prepareCommonHeaders();
|
||||||
|
|
||||||
|
@ -7,14 +7,13 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
|
||||||
#include <utils/utils.h>
|
#include <utils/utils.h>
|
||||||
#include <utils/webutils.h>
|
|
||||||
|
|
||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
|
|
||||||
const QString GitHubImageHost::c_apiUrl = "https://api.github.com";
|
const QString GitHubImageHost::c_apiUrl = "https://api.github.com";
|
||||||
|
|
||||||
GitHubImageHost::GitHubImageHost(QObject *p_parent)
|
GitHubImageHost::GitHubImageHost(QObject *p_parent)
|
||||||
: ImageHost(p_parent)
|
: RepoImageHost(p_parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,23 +44,6 @@ void GitHubImageHost::setConfig(const QJsonObject &p_jobj)
|
|||||||
m_imageUrlPrefix = QString("https://raw.githubusercontent.com/%1/%2/").arg(m_userName, m_repoName);
|
m_imageUrlPrefix = QString("https://raw.githubusercontent.com/%1/%2/").arg(m_userName, m_repoName);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GitHubImageHost::testConfig(const QJsonObject &p_jobj, QString &p_msg)
|
|
||||||
{
|
|
||||||
p_msg.clear();
|
|
||||||
|
|
||||||
QString token, userName, repoName;
|
|
||||||
parseConfig(p_jobj, token, userName, repoName);
|
|
||||||
|
|
||||||
if (token.isEmpty() || userName.isEmpty() || repoName.isEmpty()) {
|
|
||||||
p_msg = tr("PersonalAccessToken/UserName/RepositoryName should not be empty.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto reply = getRepoInfo(token, userName, repoName);
|
|
||||||
p_msg = QString::fromUtf8(reply.m_data);
|
|
||||||
return reply.m_error == QNetworkReply::NoError;
|
|
||||||
}
|
|
||||||
|
|
||||||
QPair<QByteArray, QByteArray> GitHubImageHost::authorizationHeader(const QString &p_token)
|
QPair<QByteArray, QByteArray> GitHubImageHost::authorizationHeader(const QString &p_token)
|
||||||
{
|
{
|
||||||
auto token = "token " + p_token;
|
auto token = "token " + p_token;
|
||||||
@ -89,16 +71,6 @@ vte::NetworkReply GitHubImageHost::getRepoInfo(const QString &p_token, const QSt
|
|||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GitHubImageHost::parseConfig(const QJsonObject &p_jobj,
|
|
||||||
QString &p_token,
|
|
||||||
QString &p_userName,
|
|
||||||
QString &p_repoName)
|
|
||||||
{
|
|
||||||
p_token = p_jobj[QStringLiteral("personal_access_token")].toString();
|
|
||||||
p_userName = p_jobj[QStringLiteral("user_name")].toString();
|
|
||||||
p_repoName = p_jobj[QStringLiteral("repository_name")].toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString GitHubImageHost::create(const QByteArray &p_data, const QString &p_path, QString &p_msg)
|
QString GitHubImageHost::create(const QByteArray &p_data, const QString &p_path, QString &p_msg)
|
||||||
{
|
{
|
||||||
QString destUrl;
|
QString destUrl;
|
||||||
@ -153,15 +125,6 @@ bool GitHubImageHost::ownsUrl(const QString &p_url) const
|
|||||||
return p_url.startsWith(m_imageUrlPrefix);
|
return p_url.startsWith(m_imageUrlPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GitHubImageHost::fetchResourcePath(const QString &p_prefix, const QString &p_url)
|
|
||||||
{
|
|
||||||
auto resourcePath = p_url.mid(p_prefix.size());
|
|
||||||
// Skip the branch name.
|
|
||||||
resourcePath = resourcePath.mid(resourcePath.indexOf(QLatin1Char('/')) + 1);
|
|
||||||
resourcePath = WebUtils::purifyUrl(resourcePath);
|
|
||||||
return resourcePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GitHubImageHost::remove(const QString &p_url, QString &p_msg)
|
bool GitHubImageHost::remove(const QString &p_url, QString &p_msg)
|
||||||
{
|
{
|
||||||
Q_ASSERT(ownsUrl(p_url));
|
Q_ASSERT(ownsUrl(p_url));
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
#ifndef GITHUBIMAGEHOST_H
|
#ifndef GITHUBIMAGEHOST_H
|
||||||
#define GITHUBIMAGEHOST_H
|
#define GITHUBIMAGEHOST_H
|
||||||
|
|
||||||
#include "imagehost.h"
|
#include "repoimagehost.h"
|
||||||
|
|
||||||
#include <vtextedit/networkutils.h>
|
|
||||||
|
|
||||||
namespace vnotex
|
namespace vnotex
|
||||||
{
|
{
|
||||||
class GitHubImageHost : public ImageHost
|
class GitHubImageHost : public RepoImageHost
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
@ -21,16 +19,12 @@ namespace vnotex
|
|||||||
|
|
||||||
void setConfig(const QJsonObject &p_jobj) Q_DECL_OVERRIDE;
|
void setConfig(const QJsonObject &p_jobj) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
bool testConfig(const QJsonObject &p_jobj, QString &p_msg) Q_DECL_OVERRIDE;
|
|
||||||
|
|
||||||
QString create(const QByteArray &p_data, const QString &p_path, QString &p_msg) Q_DECL_OVERRIDE;
|
QString create(const QByteArray &p_data, const QString &p_path, QString &p_msg) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
bool remove(const QString &p_url, QString &p_msg) Q_DECL_OVERRIDE;
|
bool remove(const QString &p_url, QString &p_msg) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
bool ownsUrl(const QString &p_url) const Q_DECL_OVERRIDE;
|
bool ownsUrl(const QString &p_url) const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
static QString fetchResourcePath(const QString &p_prefix, const QString &p_url);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QString m_personalAccessToken;
|
QString m_personalAccessToken;
|
||||||
|
|
||||||
@ -41,13 +35,7 @@ namespace vnotex
|
|||||||
QString m_imageUrlPrefix;
|
QString m_imageUrlPrefix;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Used to test.
|
vte::NetworkReply getRepoInfo(const QString &p_token, const QString &p_userName, const QString &p_repoName) const Q_DECL_OVERRIDE;
|
||||||
vte::NetworkReply getRepoInfo(const QString &p_token, const QString &p_userName, const QString &p_repoName) const;
|
|
||||||
|
|
||||||
static void parseConfig(const QJsonObject &p_jobj,
|
|
||||||
QString &p_token,
|
|
||||||
QString &p_userName,
|
|
||||||
QString &p_repoName);
|
|
||||||
|
|
||||||
static QPair<QByteArray, QByteArray> authorizationHeader(const QString &p_token);
|
static QPair<QByteArray, QByteArray> authorizationHeader(const QString &p_token);
|
||||||
|
|
||||||
|
@ -5,12 +5,14 @@ HEADERS += \
|
|||||||
$$PWD/githubimagehost.h \
|
$$PWD/githubimagehost.h \
|
||||||
$$PWD/imagehost.h \
|
$$PWD/imagehost.h \
|
||||||
$$PWD/imagehostmgr.h \
|
$$PWD/imagehostmgr.h \
|
||||||
$$PWD/imagehostutils.h
|
$$PWD/imagehostutils.h \
|
||||||
|
$$PWD/repoimagehost.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/giteeimagehost.cpp \
|
$$PWD/giteeimagehost.cpp \
|
||||||
$$PWD/githubimagehost.cpp \
|
$$PWD/githubimagehost.cpp \
|
||||||
$$PWD/imagehost.cpp \
|
$$PWD/imagehost.cpp \
|
||||||
$$PWD/imagehostmgr.cpp \
|
$$PWD/imagehostmgr.cpp \
|
||||||
$$PWD/imagehostutils.cpp
|
$$PWD/imagehostutils.cpp \
|
||||||
|
$$PWD/repoimagehost.cpp
|
||||||
|
|
||||||
|
62
src/imagehost/repoimagehost.cpp
Normal file
62
src/imagehost/repoimagehost.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#include "repoimagehost.h"
|
||||||
|
|
||||||
|
#include <utils/webutils.h>
|
||||||
|
#include <utils/utils.h>
|
||||||
|
|
||||||
|
using namespace vnotex;
|
||||||
|
|
||||||
|
RepoImageHost::RepoImageHost(QObject *p_parent)
|
||||||
|
: ImageHost(p_parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RepoImageHost::testConfig(const QJsonObject &p_jobj, QString &p_msg)
|
||||||
|
{
|
||||||
|
p_msg.clear();
|
||||||
|
|
||||||
|
QString token, userName, repoName;
|
||||||
|
parseConfig(p_jobj, token, userName, repoName);
|
||||||
|
|
||||||
|
if (token.isEmpty() || userName.isEmpty() || repoName.isEmpty()) {
|
||||||
|
p_msg = tr("PersonalAccessToken/UserName/RepositoryName should not be empty.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto reply = getRepoInfo(token, userName, repoName);
|
||||||
|
p_msg = QString::fromUtf8(reply.m_data);
|
||||||
|
|
||||||
|
if (reply.m_error != QNetworkReply::NoError) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto replyObj = Utils::fromJsonString(reply.m_data);
|
||||||
|
if (replyObj.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (replyObj[QStringLiteral("private")].toBool()) {
|
||||||
|
p_msg = tr("Private repository is not supported.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RepoImageHost::parseConfig(const QJsonObject &p_jobj,
|
||||||
|
QString &p_token,
|
||||||
|
QString &p_userName,
|
||||||
|
QString &p_repoName)
|
||||||
|
{
|
||||||
|
p_token = p_jobj[QStringLiteral("personal_access_token")].toString();
|
||||||
|
p_userName = p_jobj[QStringLiteral("user_name")].toString();
|
||||||
|
p_repoName = p_jobj[QStringLiteral("repository_name")].toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString RepoImageHost::fetchResourcePath(const QString &p_prefix, const QString &p_url)
|
||||||
|
{
|
||||||
|
auto resourcePath = p_url.mid(p_prefix.size());
|
||||||
|
// Skip the branch name.
|
||||||
|
resourcePath = resourcePath.mid(resourcePath.indexOf(QLatin1Char('/')) + 1);
|
||||||
|
resourcePath = WebUtils::purifyUrl(resourcePath);
|
||||||
|
return resourcePath;
|
||||||
|
}
|
31
src/imagehost/repoimagehost.h
Normal file
31
src/imagehost/repoimagehost.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#ifndef REPOIMAGEHOST_H
|
||||||
|
#define REPOIMAGEHOST_H
|
||||||
|
|
||||||
|
#include "imagehost.h"
|
||||||
|
|
||||||
|
#include <vtextedit/networkutils.h>
|
||||||
|
|
||||||
|
namespace vnotex
|
||||||
|
{
|
||||||
|
class RepoImageHost : public ImageHost
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit RepoImageHost(QObject *p_parent);
|
||||||
|
|
||||||
|
bool testConfig(const QJsonObject &p_jobj, QString &p_msg) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void parseConfig(const QJsonObject &p_jobj,
|
||||||
|
QString &p_token,
|
||||||
|
QString &p_userName,
|
||||||
|
QString &p_repoName);
|
||||||
|
|
||||||
|
// Used to test.
|
||||||
|
virtual vte::NetworkReply getRepoInfo(const QString &p_token, const QString &p_userName, const QString &p_repoName) const = 0;
|
||||||
|
|
||||||
|
static QString fetchResourcePath(const QString &p_prefix, const QString &p_url);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // REPOIMAGEHOST_H
|
@ -1,10 +1,10 @@
|
|||||||
#include "filesearchengine.h"
|
#include "filesearchengine.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QMimeDatabase>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "searchresultitem.h"
|
#include "searchresultitem.h"
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
using namespace vnotex;
|
using namespace vnotex;
|
||||||
|
|
||||||
@ -26,7 +26,6 @@ void FileSearchEngineWorker::run()
|
|||||||
{
|
{
|
||||||
const int c_batchSize = 100;
|
const int c_batchSize = 100;
|
||||||
|
|
||||||
QMimeDatabase mimeDatabase;
|
|
||||||
m_state = SearchState::Busy;
|
m_state = SearchState::Busy;
|
||||||
|
|
||||||
m_results.clear();
|
m_results.clear();
|
||||||
@ -37,8 +36,7 @@ void FileSearchEngineWorker::run()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QMimeType mimeType = mimeDatabase.mimeTypeForFile(item.m_filePath);
|
if (!FileUtils::isText(item.m_filePath)) {
|
||||||
if (mimeType.isValid() && !mimeType.inherits(QStringLiteral("text/plain"))) {
|
|
||||||
appendError(tr("Skip binary file (%1)").arg(item.m_filePath));
|
appendError(tr("Skip binary file (%1)").arg(item.m_filePath));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@ void ViPage::setupUI()
|
|||||||
auto mainLayout = WidgetsFactory::createFormLayout(this);
|
auto mainLayout = WidgetsFactory::createFormLayout(this);
|
||||||
|
|
||||||
{
|
{
|
||||||
const QString label(tr("Control-C to copy"));
|
const QString label(tr("Ctrl+C/X to copy/cut"));
|
||||||
m_controlCToCopyCheckBox = WidgetsFactory::createCheckBox(label, this);
|
m_controlCToCopyCheckBox = WidgetsFactory::createCheckBox(label, this);
|
||||||
m_controlCToCopyCheckBox->setToolTip(tr("Use Control-C to copy text"));
|
m_controlCToCopyCheckBox->setToolTip(tr("Use Ctrl+C/X to copy/cut text"));
|
||||||
mainLayout->addRow(m_controlCToCopyCheckBox);
|
mainLayout->addRow(m_controlCToCopyCheckBox);
|
||||||
addSearchItem(label, m_controlCToCopyCheckBox->toolTip(), m_controlCToCopyCheckBox);
|
addSearchItem(label, m_controlCToCopyCheckBox->toolTip(), m_controlCToCopyCheckBox);
|
||||||
connect(m_controlCToCopyCheckBox, &QCheckBox::stateChanged,
|
connect(m_controlCToCopyCheckBox, &QCheckBox::stateChanged,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user