mirror of
https://gitea.msk.dinamika-avia.ru/Constanta-Design/RRJServer.git
synced 2026-03-27 19:45:43 +03:00
Merge branch 'work7' into DEV
This commit is contained in:
@@ -14,7 +14,6 @@ kanban-plugin: board
|
||||
|
||||
## feature
|
||||
|
||||
- [ ] /RRJ-95NEW-100/tasksAMM.xml заменить получение на docs
|
||||
- [ ] отправка таски поштучно, при обновления статуса (проверка и тд)
|
||||
- [ ] регистрация времени включения и выключения тренажера (по приходу уходу пакета is unity) с регистрацие БД
|
||||
- [ ] Подсчет учебного времени - дельта между включением и выключением
|
||||
@@ -32,6 +31,7 @@ kanban-plugin: board
|
||||
|
||||
(от 18 фимов) или при кривом назначении задачи(назначить 2-3 подряд гуи перестает обновлятся)
|
||||
- [ ] Убрать ошибки QObject::moveToThread: Cannot move objects with a parent
|
||||
- [ ] /RRJ-95NEW-100/tasksAMM.xml заменить получение на docs
|
||||
|
||||
|
||||
## backlog
|
||||
|
||||
@@ -665,6 +665,34 @@ QList<TaskAmmFim> DataBaseLMS::selectTasksAMMofTrainee(int id_trainee)
|
||||
return listTasks;
|
||||
}
|
||||
|
||||
TaskAmmFim DataBaseLMS::selectTaskAMMbyID(int id_task)
|
||||
{
|
||||
TaskAmmFim task;
|
||||
/*
|
||||
QString queryStr = QString("SELECT tasks_amm.task_id, tasks_amm.title, tasks_amm.dm_code, tasks_amm.status, "
|
||||
"trainees.trainee_id "
|
||||
"FROM public.tasks_amm JOIN public.trainees ON trainees.trainee_id = tasks_amm.trainee_task "
|
||||
"WHERE tasks_amm.trainee_task = %1 "
|
||||
"ORDER BY tasks_amm.task_id ASC").arg(
|
||||
id_trainee);
|
||||
|
||||
QSqlQuery query = QSqlQuery(*db);
|
||||
|
||||
if(queryExec(queryStr, &query))
|
||||
{
|
||||
if (query.first())
|
||||
{//Задача
|
||||
task.setID(query.value(0).toInt());
|
||||
task.ammProcedure.title = query.value(1).toString();
|
||||
task.ammProcedure.dmCode = query.value(2).toString();
|
||||
task.status = query.value(3).toString();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
int DataBaseLMS::insertTaskFIM(TaskAmmFim task, int id_trainee)
|
||||
{
|
||||
QString queryStr;
|
||||
@@ -1035,6 +1063,13 @@ QList<TaskAmmFim> DataBaseLMS::selectTasksFIMofTrainee(int id_trainee)
|
||||
return listTasks;
|
||||
}
|
||||
|
||||
TaskAmmFim DataBaseLMS::selectTaskFIMbyID(int id_task)
|
||||
{
|
||||
TaskAmmFim task;
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
int DataBaseLMS::deleteReportFIM(int task_id)
|
||||
{
|
||||
QString queryStr;
|
||||
|
||||
@@ -71,12 +71,14 @@ protected:
|
||||
int updateStatusTaskAMM(int task_id, QString status);
|
||||
int deleteTaskAMM(int id_task);
|
||||
QList<TaskAmmFim> selectTasksAMMofTrainee(int id_trainee);
|
||||
TaskAmmFim selectTaskAMMbyID(int id_task);
|
||||
//Задача FIM
|
||||
int insertTaskFIM(TaskAmmFim task, int id_trainee);
|
||||
int updateTaskFIM(TaskAmmFim task);
|
||||
int updateStatusTaskFIM(int task_id, QString status);
|
||||
int deleteTaskFIM(int id_task);
|
||||
QList<TaskAmmFim> selectTasksFIMofTrainee(int id_trainee);
|
||||
TaskAmmFim selectTaskFIMbyID(int id_task);
|
||||
|
||||
int deleteReportFIM(int task_id);
|
||||
int insertReportFIM(TaskAmmFim task);
|
||||
|
||||
@@ -371,7 +371,7 @@ void RecognizeSystem::recognize(QTcpSocket *socket)
|
||||
break;
|
||||
};
|
||||
|
||||
//xml-ответы на запросы AdditionalFiles
|
||||
//xml-ответы на запросы AdditionalFiles (сигнал о чтении ранее принятого)
|
||||
if(packetType == PacketType::TYPE_XMLANSWER_QUERY_TASKS_XML_FIM ||
|
||||
packetType == PacketType::TYPE_XMLANSWER_QUERY_TASKS_XML_AMM)
|
||||
{
|
||||
@@ -381,7 +381,7 @@ void RecognizeSystem::recognize(QTcpSocket *socket)
|
||||
if(packetType == PacketType::TYPE_XMLANSWER_QUERY_TASKS_XML_FIM)
|
||||
xmlFileName = "./" + additionalFilesFolderName + "/tasksFIM.xml";
|
||||
else
|
||||
xmlFileName = "./" + additionalFilesFolderName + "/tasksAMM.xml";
|
||||
xmlFileName = "./" + additionalFilesFolderName + "/docs.xml"; //"/tasksAMM.xml";
|
||||
|
||||
QFile xmlInFile(xmlFileName);
|
||||
if (!xmlInFile.open(QFile::ReadOnly | QFile::Text))
|
||||
|
||||
@@ -64,6 +64,7 @@ AMMtasksWidget::AMMtasksWidget(ConnectorToServer* connectorToServer, TypeListTre
|
||||
ui->horizontalLayout_3->setAlignment(Qt::AlignmentFlag::AlignLeft);
|
||||
|
||||
ui->btnDelete->setVisible(false);
|
||||
ui->btnCheck->setVisible(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -233,7 +233,11 @@ void TaskAMMFIMTreePreparation::domElementParserAMM(QDomElement element, Module*
|
||||
|
||||
QDomNamedNodeMap nodeMap = childElement.attributes();
|
||||
|
||||
if(name == "pm")
|
||||
if(name == "doc")
|
||||
{
|
||||
module = new PM();
|
||||
}
|
||||
else if(name == "pm")
|
||||
{
|
||||
module = new PM();
|
||||
PM* PMmodul = static_cast<PM*>(module);
|
||||
@@ -274,11 +278,7 @@ void TaskAMMFIMTreePreparation::domElementParserAMM(QDomElement element, Module*
|
||||
|
||||
PM* PMmodulParent = static_cast<PM*>(moduleParent);
|
||||
PMmodulParent->addChildModule(module);
|
||||
}
|
||||
|
||||
//Активность
|
||||
if(nodeMap.namedItem("active").nodeValue() == "true")
|
||||
module->setIsActiveTrue();
|
||||
}
|
||||
}
|
||||
else if(name == "rus" || name == "eng")
|
||||
{
|
||||
@@ -298,11 +298,17 @@ void TaskAMMFIMTreePreparation::domElementParserAMM(QDomElement element, Module*
|
||||
DM* DMmodulParent = static_cast<DM*>(moduleParent);
|
||||
|
||||
if(name == "rus")
|
||||
{
|
||||
DMmodulParent->setLangStructRus(nodeMap.namedItem("techName").nodeValue(),
|
||||
nodeMap.namedItem("infoName").nodeValue(),
|
||||
nodeMap.namedItem("pdf").nodeValue(),
|
||||
nodeMap.namedItem("bookmark").nodeValue(),
|
||||
nodeMap.namedItem("xml").nodeValue());
|
||||
|
||||
//Активность
|
||||
if(nodeMap.namedItem("canplay").nodeValue() == "1")
|
||||
DMmodulParent->setIsActiveTrue();
|
||||
}
|
||||
else
|
||||
DMmodulParent->setLangStructEng(nodeMap.namedItem("techName").nodeValue(),
|
||||
nodeMap.namedItem("infoName").nodeValue(),
|
||||
|
||||
@@ -102,7 +102,7 @@ QByteArray DBAnswerParser::listClassrooms(bool result, QList<Classroom> *listCla
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray DBAnswerParser::listTasksAMMofTrainee(bool result, QList<TaskAmmFim> *listTasks, int trainee_id)
|
||||
QByteArray DBAnswerParser::listTasksAMMofTrainee(bool result, QList<TaskAmmFim> *listTasks, int trainee_id, bool full_list)
|
||||
{
|
||||
QDomDocument commonDOM;
|
||||
if(! dataParser->loadBlankXML(":/resources/blankXML/ListTasksAMM.xml", &commonDOM))
|
||||
@@ -110,6 +110,10 @@ QByteArray DBAnswerParser::listTasksAMMofTrainee(bool result, QList<TaskAmmFim>
|
||||
|
||||
QDomNode listNode = commonDOM.namedItem("ListTasksAMM");
|
||||
listNode.toElement().setAttribute("trainee_id", QString::number(trainee_id));
|
||||
if(full_list)
|
||||
listNode.toElement().setAttribute("full_list", "true");
|
||||
else
|
||||
listNode.toElement().setAttribute("full_list", "false");
|
||||
|
||||
for(TaskAmmFim task : *listTasks)
|
||||
{
|
||||
@@ -127,7 +131,7 @@ QByteArray DBAnswerParser::listTasksAMMofTrainee(bool result, QList<TaskAmmFim>
|
||||
return commonDOM.toByteArray();
|
||||
}
|
||||
|
||||
QByteArray DBAnswerParser::listTasksFIMofTrainee(bool result, QList<TaskAmmFim> *listTasks, int trainee_id)
|
||||
QByteArray DBAnswerParser::listTasksFIMofTrainee(bool result, QList<TaskAmmFim> *listTasks, int trainee_id, bool full_list)
|
||||
{
|
||||
QDomDocument commonDOM;
|
||||
if(! dataParser->loadBlankXML(":/resources/blankXML/ListTasksFIM.xml", &commonDOM))
|
||||
@@ -135,6 +139,10 @@ QByteArray DBAnswerParser::listTasksFIMofTrainee(bool result, QList<TaskAmmFim>
|
||||
|
||||
QDomNode listNode = commonDOM.namedItem("ListTasksFIM");
|
||||
listNode.toElement().setAttribute("trainee_id", QString::number(trainee_id));
|
||||
if(full_list)
|
||||
listNode.toElement().setAttribute("full_list", "true");
|
||||
else
|
||||
listNode.toElement().setAttribute("full_list", "false");
|
||||
|
||||
for(TaskAmmFim task : *listTasks)
|
||||
{
|
||||
|
||||
@@ -19,8 +19,8 @@ public:
|
||||
QByteArray listComputers(bool result, QList<Computer> *listComputers);
|
||||
QByteArray listClassrooms(bool result, QList<Classroom> *listClassrooms);
|
||||
|
||||
QByteArray listTasksAMMofTrainee(bool result, QList<TaskAmmFim> *listTasks, int trainee_id);
|
||||
QByteArray listTasksFIMofTrainee(bool result, QList<TaskAmmFim> *listTasks, int trainee_id);
|
||||
QByteArray listTasksAMMofTrainee(bool result, QList<TaskAmmFim> *listTasks, int trainee_id, bool full_list);
|
||||
QByteArray listTasksFIMofTrainee(bool result, QList<TaskAmmFim> *listTasks, int trainee_id, bool full_list);
|
||||
signals:
|
||||
|
||||
private:
|
||||
|
||||
@@ -261,32 +261,40 @@ void ProcessingSystem::processingClientQueryToDB(ClientHandler *client, ClientQu
|
||||
|
||||
case TypeQueryToDB::TYPE_QUERY_ASSIGN_TASK_AMM_TO_TRAINEE:
|
||||
{
|
||||
if(int id_new = providerDBLMS->newTaskAMM(*(TaskAmmFim*)data, id))
|
||||
int id_trainee = id;
|
||||
if(int id_new = providerDBLMS->newTaskAMM(*(TaskAmmFim*)data, id_trainee))
|
||||
{
|
||||
//Отправка списка задач AMM всем клиентам GUI
|
||||
//sendListTasksAMMofTraineetoClient(client, id);
|
||||
emit sigStatusTasksAMMofTraineeChanged(id);
|
||||
//sendListTasksAMMofTraineetoClient(client, id_trainee);
|
||||
emit sigStatusTasksAMMofTraineeChanged(id_trainee);
|
||||
|
||||
//Отправка списка задач AMM клиенту Юнити
|
||||
if(ClientHandler* clientUnity = getUnityClientById(id))
|
||||
if(ClientHandler* clientUnity = getUnityClientById(id_trainee))
|
||||
{//Есть такой
|
||||
sendListTasksAMMofTraineetoClient(clientUnity, id);
|
||||
//sendListTasksAMMofTraineetoClient(clientUnity, id_trainee);
|
||||
QList<int> listID;
|
||||
listID.append(id_new);
|
||||
sendListTasksAMMofTraineeByIDtoClient(clientUnity, id_trainee, listID);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TypeQueryToDB::TYPE_QUERY_ASSIGN_TASK_FIM_TO_TRAINEE:
|
||||
{
|
||||
if(int id_new = providerDBLMS->newTaskFIM(*(TaskAmmFim*)data, id))
|
||||
int id_trainee = id;
|
||||
if(int id_new = providerDBLMS->newTaskFIM(*(TaskAmmFim*)data, id_trainee))
|
||||
{
|
||||
//Отправка списка задач FIM всем клиентам GUI
|
||||
//sendListTasksFIMofTraineetoClient(client, id);
|
||||
emit sigStatusTasksFIMofTraineeChanged(id);
|
||||
//sendListTasksFIMofTraineetoClient(client, id_trainee);
|
||||
emit sigStatusTasksFIMofTraineeChanged(id_trainee);
|
||||
|
||||
//Отправка списка задач FIM клиенту Юнити
|
||||
if(ClientHandler* clientUnity = getUnityClientById(id))
|
||||
if(ClientHandler* clientUnity = getUnityClientById(id_trainee))
|
||||
{//Есть такой
|
||||
sendListTasksFIMofTraineetoClient(clientUnity, id);
|
||||
//sendListTasksFIMofTraineetoClient(clientUnity, id_trainee);
|
||||
QList<int> listID;
|
||||
listID.append(id_new);
|
||||
sendListTasksFIMofTraineeByIDtoClient(clientUnity, id_trainee, listID);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -294,14 +302,16 @@ void ProcessingSystem::processingClientQueryToDB(ClientHandler *client, ClientQu
|
||||
|
||||
case TypeQueryToDB::TYPE_QUERY_GET_TASKS_AMM_FOR_TRAINEE:
|
||||
{
|
||||
int id_trainee = id;
|
||||
//Отправка списка задач AMM клиенту GUI
|
||||
sendListTasksAMMofTraineetoClient(client, id);
|
||||
sendListTasksAMMofTraineetoClient(client, id_trainee);
|
||||
break;
|
||||
}
|
||||
case TypeQueryToDB::TYPE_QUERY_GET_TASKS_FIM_FOR_TRAINEE:
|
||||
{
|
||||
int id_trainee = id;
|
||||
//Отправка списка задач FIM клиенту GUI
|
||||
sendListTasksFIMofTraineetoClient(client, id);
|
||||
sendListTasksFIMofTraineetoClient(client, id_trainee);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -371,7 +381,10 @@ void ProcessingSystem::processingClientQueryToDB(ClientHandler *client, ClientQu
|
||||
//Отправка списка задач AMM клиенту Юнити
|
||||
if(ClientHandler* clientUnity = getUnityClientById(id_trainee))
|
||||
{//Есть такой
|
||||
sendListTasksAMMofTraineetoClient(clientUnity, id_trainee);
|
||||
//sendListTasksAMMofTraineetoClient(clientUnity, id_trainee);
|
||||
QList<int> listID;
|
||||
listID.append(id);
|
||||
sendListTasksAMMofTraineeByIDtoClient(clientUnity, id_trainee, listID);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -389,7 +402,10 @@ void ProcessingSystem::processingClientQueryToDB(ClientHandler *client, ClientQu
|
||||
//Отправка списка задач FIM клиенту Юнити
|
||||
if(ClientHandler* clientUnity = getUnityClientById(id_trainee))
|
||||
{//Есть такой
|
||||
sendListTasksFIMofTraineetoClient(clientUnity, id_trainee);
|
||||
//sendListTasksFIMofTraineetoClient(clientUnity, id_trainee);
|
||||
QList<int> listID;
|
||||
listID.append(id);
|
||||
sendListTasksFIMofTraineeByIDtoClient(clientUnity, id_trainee, listID);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -484,7 +500,7 @@ void ProcessingSystem::setCurrentDataInfo(DataInfo *dataInfo)
|
||||
void ProcessingSystem::sendListTasksAMMofTraineetoClient(ClientHandler *client, int id_trainee)
|
||||
{
|
||||
QList<TaskAmmFim> listTasks = providerDBLMS->GetListTasksAMMofTrainee(id_trainee);
|
||||
QByteArray arrayAnswer = dataParser->DbAnswer()->listTasksAMMofTrainee(true, &listTasks, id_trainee);
|
||||
QByteArray arrayAnswer = dataParser->DbAnswer()->listTasksAMMofTrainee(true, &listTasks, id_trainee, true);
|
||||
//client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_TRAINEE);
|
||||
client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_TRAINEE);
|
||||
}
|
||||
@@ -492,7 +508,57 @@ void ProcessingSystem::sendListTasksAMMofTraineetoClient(ClientHandler *client,
|
||||
void ProcessingSystem::sendListTasksFIMofTraineetoClient(ClientHandler *client, int id_trainee)
|
||||
{
|
||||
QList<TaskAmmFim> listTasks = providerDBLMS->GetListTasksFIMofTrainee(id_trainee);
|
||||
QByteArray arrayAnswer = dataParser->DbAnswer()->listTasksFIMofTrainee(true, &listTasks, id_trainee);
|
||||
QByteArray arrayAnswer = dataParser->DbAnswer()->listTasksFIMofTrainee(true, &listTasks, id_trainee, true);
|
||||
//client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_TRAINEE);
|
||||
client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_TRAINEE);
|
||||
}
|
||||
|
||||
void ProcessingSystem::sendListTasksAMMofTraineeByIDtoClient(ClientHandler *client, int id_trainee, QList<int> listID)
|
||||
{
|
||||
QList<TaskAmmFim> listTasks = providerDBLMS->GetListTasksAMMofTrainee(id_trainee);
|
||||
|
||||
for(int i = 0; i < listTasks.count(); i++)
|
||||
{
|
||||
TaskAmmFim task = listTasks.at(i);
|
||||
bool flNeed = false;
|
||||
for(int id : listID)
|
||||
{
|
||||
if(id == task.getID())
|
||||
{
|
||||
flNeed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!flNeed)
|
||||
listTasks.removeAt(i);
|
||||
}
|
||||
|
||||
QByteArray arrayAnswer = dataParser->DbAnswer()->listTasksAMMofTrainee(true, &listTasks, id_trainee, false);
|
||||
//client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_TRAINEE);
|
||||
client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_TRAINEE);
|
||||
}
|
||||
|
||||
void ProcessingSystem::sendListTasksFIMofTraineeByIDtoClient(ClientHandler *client, int id_trainee, QList<int> listID)
|
||||
{
|
||||
QList<TaskAmmFim> listTasks = providerDBLMS->GetListTasksFIMofTrainee(id_trainee);
|
||||
|
||||
for(int i = 0; i < listTasks.count(); i++)
|
||||
{
|
||||
TaskAmmFim task = listTasks.at(i);
|
||||
bool flNeed = false;
|
||||
for(int id : listID)
|
||||
{
|
||||
if(id == task.getID())
|
||||
{
|
||||
flNeed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!flNeed)
|
||||
listTasks.removeAt(i);
|
||||
}
|
||||
|
||||
QByteArray arrayAnswer = dataParser->DbAnswer()->listTasksFIMofTrainee(true, &listTasks, id_trainee, false);
|
||||
//client->sendXmlAnswer(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_TRAINEE);
|
||||
client->sendFileBlockByteArray(arrayAnswer, PacketType::TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_TRAINEE);
|
||||
}
|
||||
@@ -507,12 +573,12 @@ void ProcessingSystem::sendTaskListToUnity(ClientHandler *client)
|
||||
|
||||
//AMM
|
||||
QList<TaskAmmFim> listTasksAMM = providerDBLMS->GetListTasksAMMofTrainee(id_trainee);
|
||||
QByteArray arrayAnswerTasksAMM = dataParser->DbAnswer()->listTasksAMMofTrainee(true, &listTasksAMM, id_trainee);
|
||||
QByteArray arrayAnswerTasksAMM = dataParser->DbAnswer()->listTasksAMMofTrainee(true, &listTasksAMM, id_trainee, true);
|
||||
client->sendFileBlockByteArray(arrayAnswerTasksAMM, PacketType::TYPE_XMLANSWER_QUERY_TASKS_AMM_OF_TRAINEE);
|
||||
|
||||
//FIM
|
||||
QList<TaskAmmFim> listTasksFIM = providerDBLMS->GetListTasksFIMofTrainee(id_trainee);
|
||||
QByteArray arrayAnswerFIM = dataParser->DbAnswer()->listTasksFIMofTrainee(true, &listTasksFIM, id_trainee);
|
||||
QByteArray arrayAnswerFIM = dataParser->DbAnswer()->listTasksFIMofTrainee(true, &listTasksFIM, id_trainee, true);
|
||||
client->sendFileBlockByteArray(arrayAnswerFIM, PacketType::TYPE_XMLANSWER_QUERY_TASKS_FIM_OF_TRAINEE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,10 @@ public:
|
||||
|
||||
void sendListTasksAMMofTraineetoClient(ClientHandler* client, int id_trainee);
|
||||
void sendListTasksFIMofTraineetoClient(ClientHandler* client, int id_trainee);
|
||||
|
||||
void sendListTasksAMMofTraineeByIDtoClient(ClientHandler* client, int id_trainee, QList<int> listID);
|
||||
void sendListTasksFIMofTraineeByIDtoClient(ClientHandler* client, int id_trainee, QList<int> listID);
|
||||
|
||||
ClientHandler* getUnityClientById(int id);
|
||||
void processingClientDeAutorization(QString login);
|
||||
signals:
|
||||
|
||||
@@ -25,7 +25,7 @@ static const QString versionListFile = staticDataFolderName + "/versionList.xml"
|
||||
static const QString hashFileName = staticDataFolderName + "/serverHash.xml";
|
||||
static const QString buildHashName = staticDataFolderName + "/buildHash.xml";
|
||||
static const QString buildDataPath = "/Application/" + projectFolderName + "/RRJ_Data/";
|
||||
static const QString tasksAMMfileName = "/tasksAmm.xml";
|
||||
static const QString tasksAMMfileName = "/docs.xml"; //"/tasksAmm.xml";
|
||||
static const QString tasksFIMfileName = "/tasksFIM.xml";
|
||||
static const QString clientHash = staticDataFolderName + "/clientHash.xml";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user