mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-17 10:55:32 +08:00
Ref T241, Ref T243 formatting and minor tweaks
* unified how we write thread_local const * ASSERTs * formatting
This commit is contained in:
@@ -479,7 +479,8 @@ namespace BlackCore
|
|||||||
void CAirspaceMonitor::requestDataUpdates()
|
void CAirspaceMonitor::requestDataUpdates()
|
||||||
{
|
{
|
||||||
if (!this->isConnected()) { return; }
|
if (!this->isConnected()) { return; }
|
||||||
for (const CSimulatedAircraft &aircraft : this->getAircraftInRange())
|
const CSimulatedAircraftList aircraftInRange(this->getAircraftInRange());
|
||||||
|
for (const CSimulatedAircraft &aircraft : aircraftInRange)
|
||||||
{
|
{
|
||||||
const CCallsign cs(aircraft.getCallsign());
|
const CCallsign cs(aircraft.getCallsign());
|
||||||
m_network->sendFrequencyQuery(cs);
|
m_network->sendFrequencyQuery(cs);
|
||||||
@@ -497,7 +498,8 @@ namespace BlackCore
|
|||||||
void CAirspaceMonitor::requestAtisUpdates()
|
void CAirspaceMonitor::requestAtisUpdates()
|
||||||
{
|
{
|
||||||
if (!this->isConnected()) { return; }
|
if (!this->isConnected()) { return; }
|
||||||
for (const CAtcStation &station : m_atcStationsOnline)
|
const CAtcStationList stations(this->getAtcStationsOnline());
|
||||||
|
for (const CAtcStation &station : stations)
|
||||||
{
|
{
|
||||||
m_network->sendAtisQuery(station.getCallsign());
|
m_network->sendAtisQuery(station.getCallsign());
|
||||||
}
|
}
|
||||||
@@ -505,7 +507,7 @@ namespace BlackCore
|
|||||||
|
|
||||||
void CAirspaceMonitor::requestAtcBookingsUpdate()
|
void CAirspaceMonitor::requestAtcBookingsUpdate()
|
||||||
{
|
{
|
||||||
Q_ASSERT_X(sApp->getWebDataServices(), Q_FUNC_INFO, "missing reader");
|
Q_ASSERT_X(sApp && sApp->getWebDataServices(), Q_FUNC_INFO, "missing reader");
|
||||||
sApp->getWebDataServices()->readInBackground(BlackMisc::Network::CEntityFlags::BookingEntity);
|
sApp->getWebDataServices()->readInBackground(BlackMisc::Network::CEntityFlags::BookingEntity);
|
||||||
m_bookingsRequested = true;
|
m_bookingsRequested = true;
|
||||||
}
|
}
|
||||||
@@ -513,9 +515,7 @@ namespace BlackCore
|
|||||||
void CAirspaceMonitor::testCreateDummyOnlineAtcStations(int number)
|
void CAirspaceMonitor::testCreateDummyOnlineAtcStations(int number)
|
||||||
{
|
{
|
||||||
if (number < 1) { return; }
|
if (number < 1) { return; }
|
||||||
m_atcStationsOnline.push_back(
|
m_atcStationsOnline.push_back(CTesting::createAtcStations(number));
|
||||||
CTesting::createAtcStations(number)
|
|
||||||
);
|
|
||||||
emit this->changedAtcStationsOnline();
|
emit this->changedAtcStationsOnline();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,9 +528,9 @@ namespace BlackCore
|
|||||||
{
|
{
|
||||||
m_flightPlanCache.clear();
|
m_flightPlanCache.clear();
|
||||||
m_tempFsInnPackets.clear();
|
m_tempFsInnPackets.clear();
|
||||||
removeAllOnlineAtcStations();
|
this->removeAllOnlineAtcStations();
|
||||||
removeAllAircraft();
|
this->removeAllAircraft();
|
||||||
removeAllOtherClients();
|
this->removeAllOtherClients();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAirspaceMonitor::gracefulShutdown()
|
void CAirspaceMonitor::gracefulShutdown()
|
||||||
@@ -542,14 +542,12 @@ namespace BlackCore
|
|||||||
void CAirspaceMonitor::onRealNameReplyReceived(const CCallsign &callsign, const QString &realname)
|
void CAirspaceMonitor::onRealNameReplyReceived(const CCallsign &callsign, const QString &realname)
|
||||||
{
|
{
|
||||||
if (!this->isConnected() || realname.isEmpty()) { return; }
|
if (!this->isConnected() || realname.isEmpty()) { return; }
|
||||||
|
|
||||||
CPropertyIndexVariantMap vm;
|
|
||||||
int wasAtc = false;
|
int wasAtc = false;
|
||||||
|
|
||||||
if (callsign.hasSuffix())
|
if (callsign.hasSuffix())
|
||||||
{
|
{
|
||||||
// very likely and ATC callsign
|
// very likely and ATC callsign
|
||||||
vm = CPropertyIndexVariantMap({CAtcStation::IndexController, CUser::IndexRealName}, realname);
|
const CPropertyIndexVariantMap vm = CPropertyIndexVariantMap({CAtcStation::IndexController, CUser::IndexRealName}, realname);
|
||||||
const int c1 = this->updateOnlineStation(callsign, vm, false, true);
|
const int c1 = this->updateOnlineStation(callsign, vm, false, true);
|
||||||
const int c2 = this->updateBookedStation(callsign, vm, false, true);
|
const int c2 = this->updateBookedStation(callsign, vm, false, true);
|
||||||
wasAtc = c1 > 0 || c2 > 0;
|
wasAtc = c1 > 0 || c2 > 0;
|
||||||
@@ -557,13 +555,13 @@ namespace BlackCore
|
|||||||
|
|
||||||
if (!wasAtc)
|
if (!wasAtc)
|
||||||
{
|
{
|
||||||
vm = CPropertyIndexVariantMap({CSimulatedAircraft::IndexPilot, CUser::IndexRealName}, realname);
|
const CPropertyIndexVariantMap vm = CPropertyIndexVariantMap({CSimulatedAircraft::IndexPilot, CUser::IndexRealName}, realname);
|
||||||
this->updateAircraftInRange(callsign, vm);
|
this->updateAircraftInRange(callsign, vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client
|
// Client
|
||||||
const CVoiceCapabilities caps = sApp->getWebDataServices()->getVoiceCapabilityForCallsign(callsign);
|
const CVoiceCapabilities caps = sApp->getWebDataServices()->getVoiceCapabilityForCallsign(callsign);
|
||||||
vm = CPropertyIndexVariantMap({CClient::IndexUser, CUser::IndexRealName}, realname);
|
CPropertyIndexVariantMap vm = CPropertyIndexVariantMap({CClient::IndexUser, CUser::IndexRealName}, realname);
|
||||||
vm.addValue({ CClient::IndexVoiceCapabilities }, caps);
|
vm.addValue({ CClient::IndexVoiceCapabilities }, caps);
|
||||||
this->updateOrAddClient(callsign, vm, false);
|
this->updateOrAddClient(callsign, vm, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -282,12 +282,12 @@ namespace BlackCore
|
|||||||
m_server.markAsDisconnected();
|
m_server.markAsDisconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDisconnected())
|
if (this->isDisconnected())
|
||||||
{
|
{
|
||||||
stopPositionTimers();
|
stopPositionTimers();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit connectionStatusChanged(convertConnectionStatus(status), convertConnectionStatus(m_status));
|
emit this->connectionStatusChanged(convertConnectionStatus(status), convertConnectionStatus(m_status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -877,6 +877,8 @@ namespace BlackCore
|
|||||||
|
|
||||||
void CNetworkVatlib::onPilotPositionUpdate(VatFsdClient *, const char *callsignChar , const VatPilotPosition *position, void *cbvar)
|
void CNetworkVatlib::onPilotPositionUpdate(VatFsdClient *, const char *callsignChar , const VatPilotPosition *position, void *cbvar)
|
||||||
{
|
{
|
||||||
|
auto *self = cbvar_cast(cbvar);
|
||||||
|
|
||||||
const CCallsign callsign(callsignChar, CCallsign::Aircraft);
|
const CCallsign callsign(callsignChar, CCallsign::Aircraft);
|
||||||
CAircraftSituation situation(
|
CAircraftSituation situation(
|
||||||
callsign,
|
callsign,
|
||||||
@@ -907,8 +909,11 @@ namespace BlackCore
|
|||||||
transponder = CTransponder(position->transponderCode, mode);
|
transponder = CTransponder(position->transponderCode, mode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if (CBuildConfig::isLocalDeveloperDebugBuild())
|
||||||
{
|
{
|
||||||
CLogMessage(static_cast<CNetworkVatlib *>(nullptr)).debug("Wrong transponder code '%1' for '%2'") << position->transponderCode << callsign;
|
CLogMessage(static_cast<CNetworkVatlib *>(nullptr)).debug("Wrong transponder code '%1' for '%2'") << position->transponderCode << callsign;
|
||||||
|
}
|
||||||
|
|
||||||
// I set a default: IFR standby is a reasonable default
|
// I set a default: IFR standby is a reasonable default
|
||||||
transponder = CTransponder(2000, CTransponder::StateStandby);
|
transponder = CTransponder(2000, CTransponder::StateStandby);
|
||||||
@@ -918,8 +923,8 @@ namespace BlackCore
|
|||||||
|
|
||||||
void CNetworkVatlib::onAircraftConfigReceived(VatFsdClient *, const char *callsignChar, const char *aircraftConfig, void *cbvar)
|
void CNetworkVatlib::onAircraftConfigReceived(VatFsdClient *, const char *callsignChar, const char *aircraftConfig, void *cbvar)
|
||||||
{
|
{
|
||||||
const QByteArray json = cbvar_cast(cbvar)->fromFSD(aircraftConfig).toUtf8();
|
|
||||||
QJsonParseError parserError;
|
QJsonParseError parserError;
|
||||||
|
const QByteArray json = cbvar_cast(cbvar)->fromFSD(aircraftConfig).toUtf8();
|
||||||
const QJsonDocument doc = QJsonDocument::fromJson(json, &parserError);
|
const QJsonDocument doc = QJsonDocument::fromJson(json, &parserError);
|
||||||
|
|
||||||
if (parserError.error != QJsonParseError::NoError)
|
if (parserError.error != QJsonParseError::NoError)
|
||||||
@@ -936,7 +941,7 @@ namespace BlackCore
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject config = doc.object().value("config").toObject();
|
const QJsonObject config = doc.object().value("config").toObject();
|
||||||
if (config.empty()) return;
|
if (config.empty()) return;
|
||||||
|
|
||||||
const bool isFull = config.take("is_full_data").toBool(false);
|
const bool isFull = config.take("is_full_data").toBool(false);
|
||||||
@@ -1122,13 +1127,13 @@ namespace BlackCore
|
|||||||
PendingAtisQuery &pendingQuery = m_pendingAtisQueries[sender];
|
PendingAtisQuery &pendingQuery = m_pendingAtisQueries[sender];
|
||||||
pendingQuery.m_atisMessage.push_back(message);
|
pendingQuery.m_atisMessage.push_back(message);
|
||||||
|
|
||||||
// Wait maximum 3 seconds for the reply and release as text message after
|
// Wait maximum 5 seconds for the reply and release as text message after
|
||||||
if (pendingQuery.m_queryTime.secsTo(QDateTime::currentDateTimeUtc()) > 3)
|
if (pendingQuery.m_queryTime.secsTo(QDateTime::currentDateTimeUtc()) > 5)
|
||||||
{
|
{
|
||||||
const QString atisMessage(pendingQuery.m_atisMessage.join(QChar::LineFeed));
|
const QString atisMessage(pendingQuery.m_atisMessage.join(QChar::LineFeed));
|
||||||
CTextMessage tm(atisMessage, sender, receiver);
|
CTextMessage tm(atisMessage, sender, receiver);
|
||||||
tm.setCurrentUtcTime();
|
tm.setCurrentUtcTime();
|
||||||
consolidateTextMessage(tm);
|
this->consolidateTextMessage(tm);
|
||||||
m_pendingAtisQueries.remove(sender);
|
m_pendingAtisQueries.remove(sender);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1136,7 +1141,7 @@ namespace BlackCore
|
|||||||
// 4 digits followed by z (e.g. 0200z) is always the last atis line.
|
// 4 digits followed by z (e.g. 0200z) is always the last atis line.
|
||||||
// Some controllers leave the logoff time empty. Hence we accept anything
|
// Some controllers leave the logoff time empty. Hence we accept anything
|
||||||
// between 0-4 digits.
|
// between 0-4 digits.
|
||||||
QRegularExpression reLogoff("\\d{0,4}z");
|
thread_local const QRegularExpression reLogoff("\\d{0,4}z");
|
||||||
if (reLogoff.match(message).hasMatch())
|
if (reLogoff.match(message).hasMatch())
|
||||||
{
|
{
|
||||||
emit atisLogoffTimeReplyReceived(sender, message);
|
emit atisLogoffTimeReplyReceived(sender, message);
|
||||||
@@ -1210,7 +1215,8 @@ namespace BlackCore
|
|||||||
{
|
{
|
||||||
// detect the stupid z1, z2, z3 placeholders
|
// detect the stupid z1, z2, z3 placeholders
|
||||||
//! \fixme: Anything better as this stupid code here?
|
//! \fixme: Anything better as this stupid code here?
|
||||||
const QString test = fixed.toLower().remove(QRegularExpression("[\\n\\t\\r]"));
|
thread_local const QRegularExpression RegExp("[\\n\\t\\r]");
|
||||||
|
const QString test = fixed.toLower().remove(RegExp);
|
||||||
if (test == "z") return;
|
if (test == "z") return;
|
||||||
if (test.startsWith("z") && test.length() == 2) return; // z1, z2, ..
|
if (test.startsWith("z") && test.length() == 2) return; // z1, z2, ..
|
||||||
if (test.length() == 1) return; // sometimes just z
|
if (test.length() == 1) return; // sometimes just z
|
||||||
|
|||||||
@@ -131,10 +131,16 @@ namespace BlackCore
|
|||||||
//! Command line options this library can handle
|
//! Command line options this library can handle
|
||||||
static const QList<QCommandLineOption> &getCmdLineOptions();
|
static const QList<QCommandLineOption> &getCmdLineOptions();
|
||||||
|
|
||||||
static int const c_positionTimeOffsetMsec = 6000; //!< offset time for received position updates
|
//! Offset times basically telling when to expect the next value from network plus some reserve
|
||||||
static int const c_interimPositionTimeOffsetMsec = 2000; //!< offset time for received interim position updates
|
//! @{
|
||||||
|
static int constexpr c_positionTimeOffsetMsec = 6000; //!< offset time for received position updates
|
||||||
|
static int constexpr c_interimPositionTimeOffsetMsec = 2000; //!< offset time for received interim position updates
|
||||||
|
//! @}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static int constexpr c_processingIntervalMsec = 100; //!< interval for the processing timer
|
||||||
|
static int constexpr c_updatePostionIntervalMsec = 5000; //!< interval for the position update timer (send our position to network)
|
||||||
|
static int constexpr c_updateInterimPostionIntervalMsec = 1000; //!< interval for iterim position updates (send our position as interim position)
|
||||||
static bool getCmdLineClientIdAndKey(int &id, QString &key);
|
static bool getCmdLineClientIdAndKey(int &id, QString &key);
|
||||||
|
|
||||||
void replyToFrequencyQuery(const BlackMisc::Aviation::CCallsign &callsign);
|
void replyToFrequencyQuery(const BlackMisc::Aviation::CCallsign &callsign);
|
||||||
@@ -247,10 +253,7 @@ namespace BlackCore
|
|||||||
QTimer m_positionUpdateTimer;
|
QTimer m_positionUpdateTimer;
|
||||||
QTimer m_interimPositionUpdateTimer;
|
QTimer m_interimPositionUpdateTimer;
|
||||||
|
|
||||||
static int const c_processingIntervalMsec = 100; //!< interval for the processing timer
|
//! Pending ATIS query since
|
||||||
static int const c_updatePostionIntervalMsec = 5000; //!< interval for the position update timer (send our position to network)
|
|
||||||
static int const c_updateInterimPostionIntervalMsec = 1000; //!< interval for iterim position updates (send our position as interim position)
|
|
||||||
|
|
||||||
struct PendingAtisQuery
|
struct PendingAtisQuery
|
||||||
{
|
{
|
||||||
QDateTime m_queryTime = QDateTime::currentDateTimeUtc();
|
QDateTime m_queryTime = QDateTime::currentDateTimeUtc();
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ namespace BlackGui
|
|||||||
const QString raw = rawString.trimmed();
|
const QString raw = rawString.trimmed();
|
||||||
if (raw.isEmpty()) { return QStringList(); }
|
if (raw.isEmpty()) { return QStringList(); }
|
||||||
QStringList dirs;
|
QStringList dirs;
|
||||||
static thread_local QRegularExpression regExp("\n|\r\n|\r");
|
thread_local const QRegularExpression regExp("\n|\r\n|\r");
|
||||||
const QStringList rawLines = raw.split(regExp);
|
const QStringList rawLines = raw.split(regExp);
|
||||||
for (const QString &l : rawLines)
|
for (const QString &l : rawLines)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -295,7 +295,7 @@ namespace BlackMisc
|
|||||||
|
|
||||||
const QRegularExpression &CAltitude::fpAltitudeRegExp()
|
const QRegularExpression &CAltitude::fpAltitudeRegExp()
|
||||||
{
|
{
|
||||||
static thread_local QRegularExpression re("((FL|F)\\d{2,3})|(S\\d{2,4})|(A\\d{2,3})|(M\\d{2,4})|(\\d{3,5}(ft|m))");
|
thread_local const QRegularExpression re("((FL|F)\\d{2,3})|(S\\d{2,4})|(A\\d{2,3})|(M\\d{2,4})|(\\d{3,5}(ft|m))");
|
||||||
return re;
|
return re;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
|
|
||||||
namespace BlackMisc
|
namespace BlackMisc
|
||||||
{
|
{
|
||||||
|
|
||||||
//! Class providing static helper methods for different containers
|
//! Class providing static helper methods for different containers
|
||||||
class CContainerHelper
|
class CContainerHelper
|
||||||
{
|
{
|
||||||
@@ -69,7 +68,6 @@ namespace BlackMisc
|
|||||||
if (a.size() < b.size()) { return -1; }
|
if (a.size() < b.size()) { return -1; }
|
||||||
if (b.size() < a.size()) { return 1; }
|
if (b.size() < a.size()) { return 1; }
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Return a new container of a different type, containing the same elements as this one.
|
//! Return a new container of a different type, containing the same elements as this one.
|
||||||
@@ -101,7 +99,6 @@ namespace BlackMisc
|
|||||||
return derived().removeIf(BlackMisc::Predicates::MemberEqual(k0, v0, keysValues...));
|
return derived().removeIf(BlackMisc::Predicates::MemberEqual(k0, v0, keysValues...));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
//! Simplifies composition, returns 0 for performance
|
//! Simplifies composition, returns 0 for performance
|
||||||
friend uint qHash(const Derived &) { return 0; }
|
friend uint qHash(const Derived &) { return 0; }
|
||||||
|
|
||||||
@@ -199,7 +196,6 @@ namespace BlackMisc
|
|||||||
Derived &derived() { return static_cast<Derived &>(*this); }
|
Derived &derived() { return static_cast<Derived &>(*this); }
|
||||||
const Derived &derived() const { return static_cast<const Derived &>(*this); }
|
const Derived &derived() const { return static_cast<const Derived &>(*this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // guard
|
#endif // guard
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace BlackMisc
|
|||||||
//! \remark parts logging has a \c bool \c log flag
|
//! \remark parts logging has a \c bool \c log flag
|
||||||
void attachLogger(CInterpolationLogger *logger) { m_logger = logger; }
|
void attachLogger(CInterpolationLogger *logger) { m_logger = logger; }
|
||||||
|
|
||||||
//! Is logger attached
|
//! Is logger attached?
|
||||||
bool hasAttachedLogger() const { return m_logger; }
|
bool hasAttachedLogger() const { return m_logger; }
|
||||||
|
|
||||||
//! Get an interpolator info string (for debug info)
|
//! Get an interpolator info string (for debug info)
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ namespace BlackMisc
|
|||||||
if (modelDirs.isEmpty())
|
if (modelDirs.isEmpty())
|
||||||
{
|
{
|
||||||
this->clearCache();
|
this->clearCache();
|
||||||
emit loadingFinished(CStatusMessage(this, CStatusMessage::SeverityError, "Model directories '%1' are empty") << modelDirectories.join(", "), simulator, ParsedData);
|
emit this->loadingFinished(CStatusMessage(this, CStatusMessage::SeverityError, "Model directories '%1' are empty") << modelDirectories.join(", "), simulator, ParsedData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ namespace BlackMisc
|
|||||||
else if (tokens.at(1) == QLatin1String("acf/_author"))
|
else if (tokens.at(1) == QLatin1String("acf/_author"))
|
||||||
{
|
{
|
||||||
if (model.getDistributor().hasDescription()) { continue; }
|
if (model.getDistributor().hasDescription()) { continue; }
|
||||||
const thread_local QRegularExpression end("\\W\\s", QRegularExpression::UseUnicodePropertiesOption);
|
thread_local const QRegularExpression end("\\W\\s", QRegularExpression::UseUnicodePropertiesOption);
|
||||||
QString author = line.mid(tokens.at(2).position());
|
QString author = line.mid(tokens.at(2).position());
|
||||||
author = author.left(author.indexOf(end)).trimmed();
|
author = author.left(author.indexOf(end)).trimmed();
|
||||||
if (author.isEmpty()) { continue; }
|
if (author.isEmpty()) { continue; }
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ void CSwiftData::onStyleSheetsChanged()
|
|||||||
|
|
||||||
void CSwiftData::init()
|
void CSwiftData::init()
|
||||||
{
|
{
|
||||||
|
Q_ASSERT_X(sGui, Q_FUNC_INFO, "Need sGui");
|
||||||
sGui->initMainApplicationWidget(this);
|
sGui->initMainApplicationWidget(this);
|
||||||
this->initLogDisplay();
|
this->initLogDisplay();
|
||||||
|
|
||||||
|
|||||||
@@ -62,11 +62,14 @@ private:
|
|||||||
//! Menu clicked
|
//! Menu clicked
|
||||||
void onMenuClicked();
|
void onMenuClicked();
|
||||||
|
|
||||||
|
//! Init functions
|
||||||
|
//! @{
|
||||||
void init();
|
void init();
|
||||||
void initLogDisplay();
|
void initLogDisplay();
|
||||||
void initStyleSheet();
|
void initStyleSheet();
|
||||||
void initMenu();
|
void initMenu();
|
||||||
void initDynamicMenus();
|
void initDynamicMenus();
|
||||||
|
//! @}
|
||||||
|
|
||||||
void performGracefulShutdown();
|
void performGracefulShutdown();
|
||||||
void consolidationSettingChanged();
|
void consolidationSettingChanged();
|
||||||
|
|||||||
Reference in New Issue
Block a user