Add locations AppDataLocation, AppLocalDataLocation to QStandardPaths.
On Windows, DataLocation currently returns the value obtained by passing CSIDL_COMMON_APPDATA to SHGetSpecialFolderPath(). This is the local non-roaming path. For actually storing settings, the roaming path should be used (CSIDL_APPDATA). Introduce new AppDataLocation to return that path and AppLocalDataLocation for the local path and deprecate DataLocation. [ChangeLog][QtCore][QStandardPaths] QStandardPaths now has new enumeration values AppDataLocation, AppLocalDataLocation to be able to differentiate between roaming and local paths on the Windows operating system. DataLocation is deprecated in favor of AppDataLocation. Task-number: QTBUG-38483 Change-Id: Ib1de8c7031a863ed5eac10c747de6f7ff1a090c7 Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com> Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
parent
32893fa9c4
commit
f3bc9f5c5c
@ -117,10 +117,9 @@ QT_BEGIN_NAMESPACE
|
||||
\value HomeLocation Returns the user's home directory (the same as QDir::homePath()). On Unix
|
||||
systems, this is equal to the HOME environment variable. This value might be
|
||||
generic or application-specific, but the returned path is never empty.
|
||||
\value DataLocation Returns a directory location where persistent
|
||||
application data can be stored. This is an application-specific directory. To obtain a
|
||||
path to store data to be shared with other applications, use
|
||||
QStandardPaths::GenericDataLocation. The returned path is never empty.
|
||||
\value DataLocation Returns the same value as AppLocalDataLocation. This enumeration value
|
||||
is deprecated. Using AppDataLocation is preferable since on Windows, the roaming path is
|
||||
recommended.
|
||||
\value CacheLocation Returns a directory location where user-specific
|
||||
non-essential (cached) data should be written. This is an application-specific directory.
|
||||
The returned path is never empty.
|
||||
@ -142,6 +141,15 @@ QT_BEGIN_NAMESPACE
|
||||
\value GenericConfigLocation Returns a directory location where user-specific
|
||||
configuration files shared between multiple applications should be written.
|
||||
This is a generic value and the returned path is never empty.
|
||||
\value AppDataLocation Returns a directory location where persistent
|
||||
application data can be stored. This is an application-specific directory.
|
||||
To obtain a path to store data to be shared with other applications, use
|
||||
QStandardPaths::GenericDataLocation. The returned path is never empty.
|
||||
On the Windows operating system, this returns the roaming path.
|
||||
This enum value was added in Qt 5.4.
|
||||
\value AppLocalDataLocation Returns the local settings path on the Windows operating
|
||||
system. On all other platforms, it returns the same value as AppDataLocation.
|
||||
This enum value was added in Qt 5.4.
|
||||
|
||||
The following table gives examples of paths on different operating systems.
|
||||
The first path is the writable path (unless noted). Other, additional
|
||||
@ -200,6 +208,12 @@ QT_BEGIN_NAMESPACE
|
||||
\row \li GenericCacheLocation
|
||||
\li "~/Library/Caches", "/Library/Caches"
|
||||
\li "C:/Users/<USER>/AppData/Local/cache"
|
||||
\row \li AppDataLocation
|
||||
\li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
|
||||
\li "C:/Users/<USER>/AppData/Roaming/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data"
|
||||
\row \li AppLocalDataLocation
|
||||
\li "~/Library/Application Support/<APPNAME>", "/Library/Application Support/<APPNAME>". "<APPDIR>/../Resources"
|
||||
\li "C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>", "<APPDIR>", "<APPDIR>/data"
|
||||
\endtable
|
||||
|
||||
\table
|
||||
@ -255,6 +269,12 @@ QT_BEGIN_NAMESPACE
|
||||
\row \li GenericCacheLocation
|
||||
\li "<APPROOT>/data/Cache" (there is no shared cache)
|
||||
\li "~/.cache"
|
||||
\row \li AppDataLocation
|
||||
\li "<APPROOT>/data", "<APPROOT>/app/native/assets"
|
||||
\li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>"
|
||||
\row \li AppLocalDataLocation
|
||||
\li "<APPROOT>/data", "<APPROOT>/app/native/assets"
|
||||
\li "~/.local/share/<APPNAME>", "/usr/local/share/<APPNAME>", "/usr/share/<APPNAME>"
|
||||
\endtable
|
||||
|
||||
\table
|
||||
@ -293,6 +313,8 @@ QT_BEGIN_NAMESPACE
|
||||
\li "<USER>/Downloads", "<USER>/<APPNAME>/Downloads"
|
||||
\row \li GenericCacheLocation
|
||||
\li "<APPROOT>/cache" (there is no shared cache)
|
||||
\row \li AppDataLocation
|
||||
\li "<APPROOT>/files", "<USER>/<APPNAME>/files"
|
||||
\endtable
|
||||
|
||||
In the table above, \c <APPNAME> is usually the organization name, the
|
||||
@ -534,8 +556,6 @@ QString QStandardPaths::displayName(StandardLocation type)
|
||||
return QCoreApplication::translate("QStandardPaths", "Temporary Directory");
|
||||
case HomeLocation:
|
||||
return QCoreApplication::translate("QStandardPaths", "Home");
|
||||
case DataLocation:
|
||||
return QCoreApplication::translate("QStandardPaths", "Application Data");
|
||||
case CacheLocation:
|
||||
return QCoreApplication::translate("QStandardPaths", "Cache");
|
||||
case GenericDataLocation:
|
||||
@ -550,6 +570,9 @@ QString QStandardPaths::displayName(StandardLocation type)
|
||||
return QCoreApplication::translate("QStandardPaths", "Shared Cache");
|
||||
case DownloadLocation:
|
||||
return QCoreApplication::translate("QStandardPaths", "Download");
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
return QCoreApplication::translate("QStandardPaths", "Application Data");
|
||||
}
|
||||
// not reached
|
||||
return QString();
|
||||
|
@ -70,7 +70,9 @@ public:
|
||||
ConfigLocation,
|
||||
DownloadLocation,
|
||||
GenericCacheLocation,
|
||||
GenericConfigLocation
|
||||
GenericConfigLocation,
|
||||
AppDataLocation,
|
||||
AppLocalDataLocation = DataLocation
|
||||
};
|
||||
|
||||
static QString writableLocation(StandardLocation type);
|
||||
|
@ -244,7 +244,8 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
return getFilesDir() + testDir() + QLatin1String("/settings");
|
||||
case QStandardPaths::GenericDataLocation:
|
||||
return getExternalStorageDirectory() + testDir();
|
||||
case QStandardPaths::DataLocation:
|
||||
case QStandardPaths::AppDataLocation:
|
||||
case QStandardPaths::AppLocalDataLocation:
|
||||
return getFilesDir() + testDir();
|
||||
case QStandardPaths::GenericCacheLocation:
|
||||
case QStandardPaths::RuntimeLocation:
|
||||
@ -301,7 +302,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
<< getExternalFilesDir("DIRECTORY_DOWNLOADS");
|
||||
}
|
||||
|
||||
if (type == DataLocation) {
|
||||
if (type == AppDataLocation || type == AppLocalDataLocation) {
|
||||
return QStringList() << writableLocation(type)
|
||||
<< getExternalFilesDir();
|
||||
}
|
||||
|
@ -63,7 +63,8 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
const QString sharedRoot = sharedDir.absolutePath();
|
||||
|
||||
switch (type) {
|
||||
case DataLocation:
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
return QDir::homePath() + testModeInsert();
|
||||
case DesktopLocation:
|
||||
case HomeLocation:
|
||||
@ -108,7 +109,7 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
if (type == FontsLocation)
|
||||
return QStringList(QLatin1String("/base/usr/fonts"));
|
||||
|
||||
if (type == DataLocation)
|
||||
if (type == AppDataLocation || type == AppLocalDataLocation)
|
||||
dirs.append(QDir::homePath() + testModeInsert() + QLatin1String("native/assets"));
|
||||
|
||||
const QString localDir = writableLocation(type);
|
||||
|
@ -90,7 +90,8 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
case HomeLocation:
|
||||
location = bundlePath();
|
||||
break;
|
||||
case DataLocation:
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
case GenericDataLocation:
|
||||
location = pathForDirectory(NSDocumentDirectory);
|
||||
break;
|
||||
|
@ -83,7 +83,8 @@ OSType translateLocation(QStandardPaths::StandardLocation type)
|
||||
return kTemporaryFolderType;
|
||||
case QStandardPaths::GenericDataLocation:
|
||||
case QStandardPaths::RuntimeLocation:
|
||||
case QStandardPaths::DataLocation:
|
||||
case QStandardPaths::AppDataLocation:
|
||||
case QStandardPaths::AppLocalDataLocation:
|
||||
return kApplicationSupportFolderType;
|
||||
case QStandardPaths::GenericCacheLocation:
|
||||
case QStandardPaths::CacheLocation:
|
||||
@ -128,7 +129,7 @@ static QString macLocation(QStandardPaths::StandardLocation type, short domain)
|
||||
|
||||
QString path = getFullPath(ref);
|
||||
|
||||
if (type == QStandardPaths::DataLocation || type == QStandardPaths::CacheLocation)
|
||||
if (type == QStandardPaths::AppDataLocation || type == QStandardPaths::AppLocalDataLocation || type == QStandardPaths::CacheLocation)
|
||||
appendOrganizationAndApp(path);
|
||||
return path;
|
||||
}
|
||||
@ -140,9 +141,10 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
QString path;
|
||||
switch (type) {
|
||||
case GenericDataLocation:
|
||||
case DataLocation:
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
path = qttestDir + QLatin1String("/Application Support");
|
||||
if (type == DataLocation)
|
||||
if (type != GenericDataLocation)
|
||||
appendOrganizationAndApp(path);
|
||||
return path;
|
||||
case GenericCacheLocation:
|
||||
@ -165,7 +167,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
case TempLocation:
|
||||
return QDir::tempPath();
|
||||
case GenericDataLocation:
|
||||
case DataLocation:
|
||||
case AppLocalDataLocation:
|
||||
case GenericCacheLocation:
|
||||
case CacheLocation:
|
||||
case RuntimeLocation:
|
||||
@ -179,13 +181,13 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
{
|
||||
QStringList dirs;
|
||||
|
||||
if (type == GenericDataLocation || type == DataLocation || type == GenericCacheLocation || type == CacheLocation) {
|
||||
if (type == GenericDataLocation || type == AppDataLocation || type == AppLocalDataLocation || type == GenericCacheLocation || type == CacheLocation) {
|
||||
const QString path = macLocation(type, kOnAppropriateDisk);
|
||||
if (!path.isEmpty())
|
||||
dirs.append(path);
|
||||
}
|
||||
|
||||
if (type == DataLocation) {
|
||||
if (type == AppDataLocation || type == AppLocalDataLocation) {
|
||||
CFBundleRef mainBundle = CFBundleGetMainBundle();
|
||||
if (mainBundle) {
|
||||
CFURLRef bundleUrl = CFBundleCopyBundleURL(mainBundle);
|
||||
|
@ -90,7 +90,8 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
appendOrganizationAndApp(xdgCacheHome);
|
||||
return xdgCacheHome;
|
||||
}
|
||||
case DataLocation:
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
case GenericDataLocation:
|
||||
{
|
||||
QString xdgDataHome = QFile::decodeName(qgetenv("XDG_DATA_HOME"));
|
||||
@ -98,7 +99,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
xdgDataHome = QDir::homePath() + QLatin1String("/.qttest/share");
|
||||
if (xdgDataHome.isEmpty())
|
||||
xdgDataHome = QDir::homePath() + QLatin1String("/.local/share");
|
||||
if (type == QStandardPaths::DataLocation)
|
||||
if (type == AppDataLocation || type == AppLocalDataLocation)
|
||||
appendOrganizationAndApp(xdgDataHome);
|
||||
return xdgDataHome;
|
||||
}
|
||||
@ -305,7 +306,8 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
for (int i = 0; i < dirs.count(); ++i)
|
||||
dirs[i].append(QLatin1String("/applications"));
|
||||
break;
|
||||
case DataLocation:
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
dirs = xdgDataDirs();
|
||||
for (int i = 0; i < dirs.count(); ++i)
|
||||
appendOrganizationAndApp(dirs[i]);
|
||||
|
@ -81,6 +81,18 @@ static QString convertCharArray(const wchar_t *path)
|
||||
return QDir::fromNativeSeparators(QString::fromWCharArray(path));
|
||||
}
|
||||
|
||||
static inline int clsidForAppDataLocation(QStandardPaths::StandardLocation type)
|
||||
{
|
||||
#ifndef Q_OS_WINCE
|
||||
return type == QStandardPaths::AppDataLocation ?
|
||||
CSIDL_APPDATA : // "Roaming" path
|
||||
CSIDL_LOCAL_APPDATA; // Local path
|
||||
#else
|
||||
Q_UNUSED(type)
|
||||
return CSIDL_APPDATA;
|
||||
#endif
|
||||
}
|
||||
|
||||
QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
{
|
||||
QString result;
|
||||
@ -92,15 +104,12 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
wchar_t path[MAX_PATH];
|
||||
|
||||
switch (type) {
|
||||
case ConfigLocation: // same as DataLocation, on Windows (oversight, but too late to fix it)
|
||||
case GenericConfigLocation: // same as GenericDataLocation, on Windows
|
||||
case DataLocation:
|
||||
case ConfigLocation: // same as AppLocalDataLocation, on Windows
|
||||
case GenericConfigLocation: // same as GenericDataLocation on Windows
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
case GenericDataLocation:
|
||||
#if defined Q_OS_WINCE
|
||||
if (SHGetSpecialFolderPath(0, path, CSIDL_APPDATA, FALSE))
|
||||
#else
|
||||
if (SHGetSpecialFolderPath(0, path, CSIDL_LOCAL_APPDATA, FALSE))
|
||||
#endif
|
||||
if (SHGetSpecialFolderPath(0, path, clsidForAppDataLocation(type), FALSE))
|
||||
result = convertCharArray(path);
|
||||
if (isTestModeEnabled())
|
||||
result += QLatin1String("/qttest");
|
||||
@ -165,7 +174,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
// Although Microsoft has a Cache key it is a pointer to IE's cache, not a cache
|
||||
// location for everyone. Most applications seem to be using a
|
||||
// cache directory located in their AppData directory
|
||||
return writableLocation(DataLocation) + QLatin1String("/cache");
|
||||
return writableLocation(AppLocalDataLocation) + QLatin1String("/cache");
|
||||
|
||||
case GenericCacheLocation:
|
||||
return writableLocation(GenericDataLocation) + QLatin1String("/cache");
|
||||
@ -192,11 +201,12 @@ QStringList QStandardPaths::standardLocations(StandardLocation type)
|
||||
{
|
||||
wchar_t path[MAX_PATH];
|
||||
switch (type) {
|
||||
case ConfigLocation: // same as DataLocation, on Windows (oversight, but too late to fix it)
|
||||
case ConfigLocation: // same as AppLocalDataLocation, on Windows (oversight, but too late to fix it)
|
||||
case GenericConfigLocation: // same as GenericDataLocation, on Windows
|
||||
case DataLocation:
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
case GenericDataLocation:
|
||||
if (SHGetSpecialFolderPath(0, path, CSIDL_COMMON_APPDATA, FALSE)) {
|
||||
if (SHGetSpecialFolderPath(0, path, clsidForAppDataLocation(type), FALSE)) {
|
||||
QString result = convertCharArray(path);
|
||||
if (type != GenericDataLocation && type != GenericConfigLocation) {
|
||||
#ifndef QT_BOOTSTRAPPED
|
||||
|
@ -73,9 +73,10 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
QString result;
|
||||
|
||||
switch (type) {
|
||||
case ConfigLocation: // same as DataLocation, on Windows
|
||||
case ConfigLocation: // same as AppLocalDataLocation, on Windows
|
||||
case GenericConfigLocation: // same as GenericDataLocation, on Windows
|
||||
case DataLocation:
|
||||
case AppDataLocation:
|
||||
case AppLocalDataLocation:
|
||||
case GenericDataLocation: {
|
||||
ComPtr<IApplicationDataStatics> applicationDataStatics;
|
||||
if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
|
||||
@ -98,7 +99,7 @@ QString QStandardPaths::writableLocation(StandardLocation type)
|
||||
break;
|
||||
}
|
||||
case CacheLocation:
|
||||
return writableLocation(DataLocation) + QLatin1String("/cache");
|
||||
return writableLocation(AppLocalDataLocation) + QLatin1String("/cache");
|
||||
|
||||
case GenericCacheLocation:
|
||||
return writableLocation(GenericDataLocation) + QLatin1String("/cache");
|
||||
|
@ -314,7 +314,7 @@ extern Q_CORE_EXPORT QString qt_applicationName_noFallback();
|
||||
|
||||
QString QDesktopServices::storageLocationImpl(QStandardPaths::StandardLocation type)
|
||||
{
|
||||
if (type == QStandardPaths::DataLocation) {
|
||||
if (type == QStandardPaths::AppLocalDataLocation) {
|
||||
// Preserve Qt 4 compatibility:
|
||||
// * QCoreApplication::applicationName() must default to empty
|
||||
// * Unix data location is under the "data/" subdirectory
|
||||
|
@ -56,7 +56,7 @@
|
||||
#define Q_XDG_PLATFORM
|
||||
#endif
|
||||
|
||||
static const int MaxStandardLocation = QStandardPaths::GenericConfigLocation;
|
||||
static const int MaxStandardLocation = QStandardPaths::AppDataLocation;
|
||||
|
||||
class tst_qstandardpaths : public QObject
|
||||
{
|
||||
@ -129,7 +129,8 @@ static const char * const enumNames[MaxStandardLocation + 1 - int(QStandardPaths
|
||||
"ConfigLocation",
|
||||
"DownloadLocation",
|
||||
"GenericCacheLocation",
|
||||
"GenericConfigLocation"
|
||||
"GenericConfigLocation",
|
||||
"AppDataLocation"
|
||||
};
|
||||
|
||||
void tst_qstandardpaths::dump()
|
||||
@ -238,7 +239,8 @@ void tst_qstandardpaths::enableTestMode()
|
||||
// Check this for locations where test programs typically write. Not desktop, download, music etc...
|
||||
typedef QHash<QStandardPaths::StandardLocation, QString> LocationHash;
|
||||
LocationHash testLocations;
|
||||
testLocations.insert(QStandardPaths::DataLocation, QStandardPaths::writableLocation(QStandardPaths::DataLocation));
|
||||
testLocations.insert(QStandardPaths::AppDataLocation, QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
||||
testLocations.insert(QStandardPaths::AppLocalDataLocation, QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
|
||||
testLocations.insert(QStandardPaths::GenericDataLocation, QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation));
|
||||
testLocations.insert(QStandardPaths::ConfigLocation, QStandardPaths::writableLocation(QStandardPaths::ConfigLocation));
|
||||
testLocations.insert(QStandardPaths::GenericConfigLocation, QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation));
|
||||
@ -294,18 +296,18 @@ void tst_qstandardpaths::testDataLocation()
|
||||
// applications are sandboxed.
|
||||
#if !defined(Q_OS_BLACKBERRY) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WINRT)
|
||||
const QString base = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
|
||||
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::DataLocation), base + "/tst_qstandardpaths");
|
||||
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation), base + "/tst_qstandardpaths");
|
||||
QCoreApplication::instance()->setOrganizationName("Qt");
|
||||
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::DataLocation), base + "/Qt/tst_qstandardpaths");
|
||||
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation), base + "/Qt/tst_qstandardpaths");
|
||||
QCoreApplication::instance()->setApplicationName("QtTest");
|
||||
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::DataLocation), base + "/Qt/QtTest");
|
||||
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation), base + "/Qt/QtTest");
|
||||
#endif
|
||||
|
||||
#ifdef Q_XDG_PLATFORM
|
||||
setDefaultLocations();
|
||||
const QString expectedAppDataDir = QDir::homePath() + QString::fromLatin1("/.local/share/Qt/QtTest");
|
||||
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::DataLocation), expectedAppDataDir);
|
||||
const QStringList appDataDirs = QStandardPaths::standardLocations(QStandardPaths::DataLocation);
|
||||
QCOMPARE(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation), expectedAppDataDir);
|
||||
const QStringList appDataDirs = QStandardPaths::standardLocations(QStandardPaths::AppLocalDataLocation);
|
||||
QCOMPARE(appDataDirs.count(), 3);
|
||||
QCOMPARE(appDataDirs.at(0), expectedAppDataDir);
|
||||
QCOMPARE(appDataDirs.at(1), QString::fromLatin1("/usr/local/share/Qt/QtTest"));
|
||||
@ -463,7 +465,7 @@ void tst_qstandardpaths::testAllWritableLocations_data()
|
||||
QTest::newRow("PicturesLocation") << QStandardPaths::PicturesLocation;
|
||||
QTest::newRow("TempLocation") << QStandardPaths::TempLocation;
|
||||
QTest::newRow("HomeLocation") << QStandardPaths::HomeLocation;
|
||||
QTest::newRow("DataLocation") << QStandardPaths::DataLocation;
|
||||
QTest::newRow("AppLocalDataLocation") << QStandardPaths::AppLocalDataLocation;
|
||||
QTest::newRow("DownloadLocation") << QStandardPaths::DownloadLocation;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user