mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-09-25 22:36:34 -04:00
Web API: /sdrangel/devicesets (POST, DELETE) implementation
This commit is contained in:
parent
c91918840e
commit
3086c4772b
@ -7638,7 +7638,7 @@ except ApiException as e:
|
|||||||
</div>
|
</div>
|
||||||
<div id="generator">
|
<div id="generator">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
Generated 2017-11-25T20:11:05.104+01:00
|
Generated 2017-11-25T22:31:12.548+01:00
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -35,6 +35,7 @@ namespace Swagger
|
|||||||
class SWGPresetTransfer;
|
class SWGPresetTransfer;
|
||||||
class SWGPresetIdentifier;
|
class SWGPresetIdentifier;
|
||||||
class SWGDeviceSetList;
|
class SWGDeviceSetList;
|
||||||
|
class SWGDeviceSet;
|
||||||
class SWGErrorResponse;
|
class SWGErrorResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +186,7 @@ public:
|
|||||||
{ return 501; }
|
{ return 501; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler of /sdrangel/preset (DELETE) swagger/sdrangel/code/html2/index.html#api-Default-instanceChannels
|
* Handler of /sdrangel/devicesets (GET) swagger/sdrangel/code/html2/index.html#api-Default-instanceChannels
|
||||||
* returns the Http status code (default 501: not implemented)
|
* returns the Http status code (default 501: not implemented)
|
||||||
*/
|
*/
|
||||||
virtual int instanceDeviceSetsGet(
|
virtual int instanceDeviceSetsGet(
|
||||||
@ -193,6 +194,26 @@ public:
|
|||||||
Swagger::SWGErrorResponse& error __attribute__((unused)))
|
Swagger::SWGErrorResponse& error __attribute__((unused)))
|
||||||
{ return 501; }
|
{ return 501; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler of /sdrangel/devicesets (POST) swagger/sdrangel/code/html2/index.html#api-Default-instanceChannels
|
||||||
|
* returns the Http status code (default 501: not implemented)
|
||||||
|
*/
|
||||||
|
virtual int instanceDeviceSetsPost(
|
||||||
|
bool tx __attribute__((unused)),
|
||||||
|
Swagger::SWGDeviceSet& response __attribute__((unused)),
|
||||||
|
Swagger::SWGErrorResponse& error __attribute__((unused)))
|
||||||
|
{ return 501; }
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler of /sdrangel/devicesets (DELETE) swagger/sdrangel/code/html2/index.html#api-Default-instanceChannels
|
||||||
|
* returns the Http status code (default 501: not implemented)
|
||||||
|
*/
|
||||||
|
virtual int instanceDeviceSetsDelete(
|
||||||
|
Swagger::SWGDeviceSetList& response __attribute__((unused)),
|
||||||
|
Swagger::SWGErrorResponse& error __attribute__((unused)))
|
||||||
|
{ return 501; }
|
||||||
|
|
||||||
static QString instanceSummaryURL;
|
static QString instanceSummaryURL;
|
||||||
static QString instanceDevicesURL;
|
static QString instanceDevicesURL;
|
||||||
static QString instanceChannelsURL;
|
static QString instanceChannelsURL;
|
||||||
|
@ -487,6 +487,37 @@ void WebAPIRequestMapper::instanceDeviceSetsService(qtwebapp::HttpRequest& reque
|
|||||||
response.write(errorResponse.asJson().toUtf8());
|
response.write(errorResponse.asJson().toUtf8());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (request.getMethod() == "POST")
|
||||||
|
{
|
||||||
|
Swagger::SWGDeviceSet normalResponse;
|
||||||
|
QByteArray txStr = request.getParameter("tx");
|
||||||
|
bool tx = false;
|
||||||
|
|
||||||
|
if (txStr.length() != 0) {
|
||||||
|
tx = !(txStr == "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = m_adapter->instanceDeviceSetsPost(tx, normalResponse, errorResponse);
|
||||||
|
response.setStatus(status);
|
||||||
|
|
||||||
|
if (status == 200) {
|
||||||
|
response.write(normalResponse.asJson().toUtf8());
|
||||||
|
} else {
|
||||||
|
response.write(errorResponse.asJson().toUtf8());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (request.getMethod() == "DELETE")
|
||||||
|
{
|
||||||
|
Swagger::SWGDeviceSetList normalResponse;
|
||||||
|
int status = m_adapter->instanceDeviceSetsDelete(normalResponse, errorResponse);
|
||||||
|
response.setStatus(status);
|
||||||
|
|
||||||
|
if (status == 200) {
|
||||||
|
response.write(normalResponse.asJson().toUtf8());
|
||||||
|
} else {
|
||||||
|
response.write(errorResponse.asJson().toUtf8());
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
response.setStatus(405,"Invalid HTTP method");
|
response.setStatus(405,"Invalid HTTP method");
|
||||||
|
@ -65,6 +65,8 @@
|
|||||||
MESSAGE_CLASS_DEFINITION(MainWindow::MsgLoadPreset, Message)
|
MESSAGE_CLASS_DEFINITION(MainWindow::MsgLoadPreset, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(MainWindow::MsgSavePreset, Message)
|
MESSAGE_CLASS_DEFINITION(MainWindow::MsgSavePreset, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(MainWindow::MsgDeletePreset, Message)
|
MESSAGE_CLASS_DEFINITION(MainWindow::MsgDeletePreset, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(MainWindow::MsgAddDeviceSet, Message)
|
||||||
|
MESSAGE_CLASS_DEFINITION(MainWindow::MsgRemoveLastDeviceSet, Message)
|
||||||
|
|
||||||
MainWindow *MainWindow::m_instance = 0;
|
MainWindow *MainWindow::m_instance = 0;
|
||||||
|
|
||||||
@ -706,6 +708,26 @@ bool MainWindow::handleMessage(const Message& cmd)
|
|||||||
m_settings.deletePreset(presetToDelete);
|
m_settings.deletePreset(presetToDelete);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if (MsgAddDeviceSet::match(cmd))
|
||||||
|
{
|
||||||
|
MsgAddDeviceSet& notif = (MsgAddDeviceSet&) cmd;
|
||||||
|
|
||||||
|
if (notif.isTx()) {
|
||||||
|
addSinkDevice();
|
||||||
|
} else {
|
||||||
|
addSourceDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (MsgRemoveLastDeviceSet::match(cmd))
|
||||||
|
{
|
||||||
|
if (m_deviceUIs.size() > 1) {
|
||||||
|
removeLastDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -153,6 +153,41 @@ private:
|
|||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class MsgAddDeviceSet : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isTx() const { return m_tx; }
|
||||||
|
|
||||||
|
static MsgAddDeviceSet* create(bool tx)
|
||||||
|
{
|
||||||
|
return new MsgAddDeviceSet(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_tx;
|
||||||
|
|
||||||
|
MsgAddDeviceSet(bool tx) :
|
||||||
|
Message(),
|
||||||
|
m_tx(tx)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MsgRemoveLastDeviceSet : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
|
public:
|
||||||
|
static MsgRemoveLastDeviceSet* create()
|
||||||
|
{
|
||||||
|
return new MsgRemoveLastDeviceSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MsgRemoveLastDeviceSet() :
|
||||||
|
Message()
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PGroup,
|
PGroup,
|
||||||
PItem
|
PItem
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "loggerwithfile.h"
|
#include "loggerwithfile.h"
|
||||||
#include "device/devicesourceapi.h"
|
#include "device/devicesourceapi.h"
|
||||||
@ -551,6 +553,46 @@ int WebAPIAdapterGUI::instanceDeviceSetsGet(
|
|||||||
return 200;
|
return 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WebAPIAdapterGUI::instanceDeviceSetsPost(
|
||||||
|
bool tx,
|
||||||
|
Swagger::SWGDeviceSet& response,
|
||||||
|
Swagger::SWGErrorResponse& error __attribute__((unused)))
|
||||||
|
{
|
||||||
|
MainWindow::MsgAddDeviceSet *msg = MainWindow::MsgAddDeviceSet::create(tx);
|
||||||
|
m_mainWindow.m_inputMessageQueue.push(msg);
|
||||||
|
|
||||||
|
usleep(100000);
|
||||||
|
|
||||||
|
const DeviceUISet *lastDeviceSet = m_mainWindow.m_deviceUIs.back();
|
||||||
|
getDeviceSet(&response,lastDeviceSet, (int) m_mainWindow.m_deviceUIs.size() - 1);
|
||||||
|
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WebAPIAdapterGUI::instanceDeviceSetsDelete(
|
||||||
|
Swagger::SWGDeviceSetList& response,
|
||||||
|
Swagger::SWGErrorResponse& error)
|
||||||
|
{
|
||||||
|
if (m_mainWindow.m_deviceUIs.size() > 1)
|
||||||
|
{
|
||||||
|
MainWindow::MsgRemoveLastDeviceSet *msg = MainWindow::MsgRemoveLastDeviceSet::create();
|
||||||
|
m_mainWindow.m_inputMessageQueue.push(msg);
|
||||||
|
|
||||||
|
usleep(100000);
|
||||||
|
|
||||||
|
getDeviceSetList(&response);
|
||||||
|
|
||||||
|
return 200;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error.init();
|
||||||
|
*error.getMessage() = "No more device sets to be removed";
|
||||||
|
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WebAPIAdapterGUI::getDeviceSetList(Swagger::SWGDeviceSetList* deviceSetList)
|
void WebAPIAdapterGUI::getDeviceSetList(Swagger::SWGDeviceSetList* deviceSetList)
|
||||||
{
|
{
|
||||||
deviceSetList->init();
|
deviceSetList->init();
|
||||||
@ -560,35 +602,42 @@ void WebAPIAdapterGUI::getDeviceSetList(Swagger::SWGDeviceSetList* deviceSetList
|
|||||||
|
|
||||||
for (int i = 0; it != m_mainWindow.m_deviceUIs.end(); ++it, i++)
|
for (int i = 0; it != m_mainWindow.m_deviceUIs.end(); ++it, i++)
|
||||||
{
|
{
|
||||||
QList<Swagger::SWGDeviceSet*> *deviceSet = deviceSetList->getDeviceSets();
|
QList<Swagger::SWGDeviceSet*> *deviceSets = deviceSetList->getDeviceSets();
|
||||||
deviceSet->append(new Swagger::SWGDeviceSet());
|
deviceSets->append(new Swagger::SWGDeviceSet());
|
||||||
Swagger::SWGSamplingDevice *samplingDevice = deviceSet->back()->getSamplingDevice();
|
|
||||||
samplingDevice->init();
|
|
||||||
samplingDevice->setIndex(i);
|
|
||||||
samplingDevice->setTx((*it)->m_deviceSinkEngine != 0);
|
|
||||||
|
|
||||||
if ((*it)->m_deviceSinkEngine) // Tx data
|
getDeviceSet(deviceSets->back(), *it, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebAPIAdapterGUI::getDeviceSet(Swagger::SWGDeviceSet *deviceSet, const DeviceUISet* deviceUISet, int deviceUISetIndex)
|
||||||
{
|
{
|
||||||
*samplingDevice->getHwType() = (*it)->m_deviceSinkAPI->getHardwareId();
|
Swagger::SWGSamplingDevice *samplingDevice = deviceSet->getSamplingDevice();
|
||||||
*samplingDevice->getSerial() = (*it)->m_deviceSinkAPI->getSampleSinkSerial();
|
samplingDevice->init();
|
||||||
samplingDevice->setSequence((*it)->m_deviceSinkAPI->getSampleSinkSequence());
|
samplingDevice->setIndex(deviceUISetIndex);
|
||||||
samplingDevice->setNbStreams((*it)->m_deviceSinkAPI->getNbItems());
|
samplingDevice->setTx(deviceUISet->m_deviceSinkEngine != 0);
|
||||||
samplingDevice->setStreamIndex((*it)->m_deviceSinkAPI->getItemIndex());
|
|
||||||
(*it)->m_deviceSinkAPI->getDeviceEngineStateStr(*samplingDevice->getState());
|
if (deviceUISet->m_deviceSinkEngine) // Tx data
|
||||||
DeviceSampleSink *sampleSink = (*it)->m_deviceSinkEngine->getSink();
|
{
|
||||||
|
*samplingDevice->getHwType() = deviceUISet->m_deviceSinkAPI->getHardwareId();
|
||||||
|
*samplingDevice->getSerial() = deviceUISet->m_deviceSinkAPI->getSampleSinkSerial();
|
||||||
|
samplingDevice->setSequence(deviceUISet->m_deviceSinkAPI->getSampleSinkSequence());
|
||||||
|
samplingDevice->setNbStreams(deviceUISet->m_deviceSinkAPI->getNbItems());
|
||||||
|
samplingDevice->setStreamIndex(deviceUISet->m_deviceSinkAPI->getItemIndex());
|
||||||
|
deviceUISet->m_deviceSinkAPI->getDeviceEngineStateStr(*samplingDevice->getState());
|
||||||
|
DeviceSampleSink *sampleSink = deviceUISet->m_deviceSinkEngine->getSink();
|
||||||
|
|
||||||
if (sampleSink) {
|
if (sampleSink) {
|
||||||
samplingDevice->setCenterFrequency(sampleSink->getCenterFrequency());
|
samplingDevice->setCenterFrequency(sampleSink->getCenterFrequency());
|
||||||
samplingDevice->setBandwidth(sampleSink->getSampleRate());
|
samplingDevice->setBandwidth(sampleSink->getSampleRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceSet->back()->setChannelcount((*it)->m_deviceSinkAPI->getNbChannels());
|
deviceSet->setChannelcount(deviceUISet->m_deviceSinkAPI->getNbChannels());
|
||||||
QList<Swagger::SWGChannel*> *channels = deviceSet->back()->getChannels();
|
QList<Swagger::SWGChannel*> *channels = deviceSet->getChannels();
|
||||||
|
|
||||||
for (int i = 0; i < deviceSet->back()->getChannelcount(); i++)
|
for (int i = 0; i < deviceSet->getChannelcount(); i++)
|
||||||
{
|
{
|
||||||
channels->append(new Swagger::SWGChannel);
|
channels->append(new Swagger::SWGChannel);
|
||||||
ChannelSourceAPI *channel = (*it)->m_deviceSinkAPI->getChanelAPIAt(i);
|
ChannelSourceAPI *channel = deviceUISet->m_deviceSinkAPI->getChanelAPIAt(i);
|
||||||
channels->back()->setDeltaFrequency(channel->getDeltaFrequency());
|
channels->back()->setDeltaFrequency(channel->getDeltaFrequency());
|
||||||
channels->back()->setIndex(channel->getIndexInDeviceSet());
|
channels->back()->setIndex(channel->getIndexInDeviceSet());
|
||||||
channels->back()->setUid(channel->getUID());
|
channels->back()->setUid(channel->getUID());
|
||||||
@ -597,28 +646,28 @@ void WebAPIAdapterGUI::getDeviceSetList(Swagger::SWGDeviceSetList* deviceSetList
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((*it)->m_deviceSourceEngine) // Rx data
|
if (deviceUISet->m_deviceSourceEngine) // Rx data
|
||||||
{
|
{
|
||||||
*samplingDevice->getHwType() = (*it)->m_deviceSourceAPI->getHardwareId();
|
*samplingDevice->getHwType() = deviceUISet->m_deviceSourceAPI->getHardwareId();
|
||||||
*samplingDevice->getSerial() = (*it)->m_deviceSourceAPI->getSampleSourceSerial();
|
*samplingDevice->getSerial() = deviceUISet->m_deviceSourceAPI->getSampleSourceSerial();
|
||||||
samplingDevice->setSequence((*it)->m_deviceSourceAPI->getSampleSourceSequence());
|
samplingDevice->setSequence(deviceUISet->m_deviceSourceAPI->getSampleSourceSequence());
|
||||||
samplingDevice->setNbStreams((*it)->m_deviceSourceAPI->getNbItems());
|
samplingDevice->setNbStreams(deviceUISet->m_deviceSourceAPI->getNbItems());
|
||||||
samplingDevice->setStreamIndex((*it)->m_deviceSourceAPI->getItemIndex());
|
samplingDevice->setStreamIndex(deviceUISet->m_deviceSourceAPI->getItemIndex());
|
||||||
(*it)->m_deviceSourceAPI->getDeviceEngineStateStr(*samplingDevice->getState());
|
deviceUISet->m_deviceSourceAPI->getDeviceEngineStateStr(*samplingDevice->getState());
|
||||||
DeviceSampleSource *sampleSource = (*it)->m_deviceSourceEngine->getSource();
|
DeviceSampleSource *sampleSource = deviceUISet->m_deviceSourceEngine->getSource();
|
||||||
|
|
||||||
if (sampleSource) {
|
if (sampleSource) {
|
||||||
samplingDevice->setCenterFrequency(sampleSource->getCenterFrequency());
|
samplingDevice->setCenterFrequency(sampleSource->getCenterFrequency());
|
||||||
samplingDevice->setBandwidth(sampleSource->getSampleRate());
|
samplingDevice->setBandwidth(sampleSource->getSampleRate());
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceSet->back()->setChannelcount((*it)->m_deviceSourceAPI->getNbChannels());
|
deviceSet->setChannelcount(deviceUISet->m_deviceSourceAPI->getNbChannels());
|
||||||
QList<Swagger::SWGChannel*> *channels = deviceSet->back()->getChannels();
|
QList<Swagger::SWGChannel*> *channels = deviceSet->getChannels();
|
||||||
|
|
||||||
for (int i = 0; i < deviceSet->back()->getChannelcount(); i++)
|
for (int i = 0; i < deviceSet->getChannelcount(); i++)
|
||||||
{
|
{
|
||||||
channels->append(new Swagger::SWGChannel);
|
channels->append(new Swagger::SWGChannel);
|
||||||
ChannelSinkAPI *channel = (*it)->m_deviceSourceAPI->getChanelAPIAt(i);
|
ChannelSinkAPI *channel = deviceUISet->m_deviceSourceAPI->getChanelAPIAt(i);
|
||||||
channels->back()->setDeltaFrequency(channel->getDeltaFrequency());
|
channels->back()->setDeltaFrequency(channel->getDeltaFrequency());
|
||||||
channels->back()->setIndex(channel->getIndexInDeviceSet());
|
channels->back()->setIndex(channel->getIndexInDeviceSet());
|
||||||
channels->back()->setUid(channel->getUID());
|
channels->back()->setUid(channel->getUID());
|
||||||
@ -627,7 +676,6 @@ void WebAPIAdapterGUI::getDeviceSetList(Swagger::SWGDeviceSetList* deviceSetList
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
QtMsgType WebAPIAdapterGUI::getMsgTypeFromString(const QString& msgTypeString)
|
QtMsgType WebAPIAdapterGUI::getMsgTypeFromString(const QString& msgTypeString)
|
||||||
{
|
{
|
||||||
|
@ -101,10 +101,20 @@ public:
|
|||||||
Swagger::SWGDeviceSetList& response,
|
Swagger::SWGDeviceSetList& response,
|
||||||
Swagger::SWGErrorResponse& error);
|
Swagger::SWGErrorResponse& error);
|
||||||
|
|
||||||
|
virtual int instanceDeviceSetsPost(
|
||||||
|
bool tx,
|
||||||
|
Swagger::SWGDeviceSet& response,
|
||||||
|
Swagger::SWGErrorResponse& error);
|
||||||
|
|
||||||
|
virtual int instanceDeviceSetsDelete(
|
||||||
|
Swagger::SWGDeviceSetList& response,
|
||||||
|
Swagger::SWGErrorResponse& error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MainWindow& m_mainWindow;
|
MainWindow& m_mainWindow;
|
||||||
|
|
||||||
void getDeviceSetList(Swagger::SWGDeviceSetList* deviceSetList);
|
void getDeviceSetList(Swagger::SWGDeviceSetList* deviceSetList);
|
||||||
|
void getDeviceSet(Swagger::SWGDeviceSet *deviceSet, const DeviceUISet* deviceUISet, int deviceUISetIndex);
|
||||||
static QtMsgType getMsgTypeFromString(const QString& msgTypeString);
|
static QtMsgType getMsgTypeFromString(const QString& msgTypeString);
|
||||||
static void getMsgTypeString(const QtMsgType& msgType, QString& level);
|
static void getMsgTypeString(const QtMsgType& msgType, QString& level);
|
||||||
};
|
};
|
||||||
|
@ -421,6 +421,8 @@ paths:
|
|||||||
$ref: "#/definitions/DeviceSetList"
|
$ref: "#/definitions/DeviceSetList"
|
||||||
"404":
|
"404":
|
||||||
description: "No more device sets to be deleted"
|
description: "No more device sets to be deleted"
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/ErrorResponse"
|
||||||
"500":
|
"500":
|
||||||
description: Error
|
description: Error
|
||||||
schema:
|
schema:
|
||||||
|
@ -7638,7 +7638,7 @@ except ApiException as e:
|
|||||||
</div>
|
</div>
|
||||||
<div id="generator">
|
<div id="generator">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
Generated 2017-11-25T20:11:05.104+01:00
|
Generated 2017-11-25T22:31:12.548+01:00
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user