Endpoints réels domaine circuit : GET /elements/familles et GET /elements
This commit is contained in:
@@ -5,25 +5,40 @@
|
|||||||
#include <QSqlQuery>
|
#include <QSqlQuery>
|
||||||
#include <QSqlError>
|
#include <QSqlError>
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QJsonArray>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
#include <QUrlQuery>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// shipheart_api - SPIKE (Phase 1)
|
// shipheart_api - Phase 4 : première tranche verticale, domaine "circuit"
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Objectif unique de ce fichier : valider que QHttpServer + QtSql fonctionnent
|
// Deux endpoints réels, remplaçant le spike (/ping conservé comme sonde de vie
|
||||||
// bien ensemble sur le CM5, avant d'investir dans la conception des vrais
|
// générique, /test-db retiré car superflu désormais) :
|
||||||
// endpoints (cf synthèse, section 20). Pas de logique métier ici.
|
// - GET /elements/familles?type=circuit
|
||||||
|
// - GET /elements?type=circuit&famille=<id>
|
||||||
|
// Logique et requêtes SQL reprises à l'identique de home.qml (init_circuits(),
|
||||||
|
// mise_a_jour_onglets_circuits(), mise_a_jour_circuits() - cf synthèse §20.4)
|
||||||
|
// et des constantes documentées dans le schéma (TB_Circuits.Etat, cf §20).
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
// Types de familles (cf TB_Familles.Type_source / TB_Events.Type_source) :
|
||||||
|
static const int TYPE_SOURCE_CIRCUIT = 1;
|
||||||
|
|
||||||
|
// États circuit (cf commentaire colonne TB_Circuits.Etat dans le schéma) :
|
||||||
|
static const int ETAT_CIRCUIT_OK = 0;
|
||||||
|
static const int ETAT_CIRCUIT_LIMITATION = 1;
|
||||||
|
static const int ETAT_CIRCUIT_PROTECTION = 2;
|
||||||
|
static const int ETAT_CIRCUIT_DISJONCTE = 3;
|
||||||
|
static const int ETAT_CIRCUIT_ABSENCE_TERRE = 8;
|
||||||
|
static const int ETAT_CIRCUIT_ABSENCE_MASSE = 9;
|
||||||
|
static const int ETAT_COMMANDE_CARTE_OK = 0;
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
|
|
||||||
// --- Connexion MariaDB locale ---
|
// --- Connexion MariaDB locale ---
|
||||||
// TODO : remplacer par les vrais identifiants (mêmes que ceux utilisés par
|
|
||||||
// shipheart_qt/shipheart_appli - cf BDD_USER_NAME/BDD_USER_PWD/BDD_BASE_NAME
|
|
||||||
// dans shipheart.h du projet shipheart_qt).
|
|
||||||
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
|
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
|
||||||
db.setHostName("localhost");
|
db.setHostName("localhost");
|
||||||
db.setUserName("koriolan");
|
db.setUserName("koriolan");
|
||||||
@@ -38,26 +53,154 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
QHttpServer server;
|
QHttpServer server;
|
||||||
|
|
||||||
// Route de test simple, sans BDD :
|
// Sonde de vie générique, sans BDD :
|
||||||
server.route("/ping", []() {
|
server.route("/ping", []() {
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
obj["status"] = "ok";
|
obj["status"] = "ok";
|
||||||
obj["message"] = "shipheart_api spike vivant";
|
|
||||||
return QHttpServerResponse(QJsonDocument(obj).toJson());
|
return QHttpServerResponse(QJsonDocument(obj).toJson());
|
||||||
});
|
});
|
||||||
|
|
||||||
// Route de test avec une vraie requête MariaDB (nombre de circuits en base) :
|
// ------------------------------------------------------------------
|
||||||
server.route("/test-db", []() {
|
// GET /elements/familles?type=circuit
|
||||||
QSqlQuery query("SELECT COUNT(*) FROM TB_Circuits");
|
// Liste des familles avec état d'alarme agrégé (fusionne les deux
|
||||||
QJsonObject obj;
|
// requêtes onglets de mise_a_jour_onglets_circuits()).
|
||||||
if (query.next()) {
|
// ------------------------------------------------------------------
|
||||||
obj["nb_circuits"] = query.value(0).toInt();
|
server.route("/elements/familles", [](const QHttpServerRequest &request) {
|
||||||
obj["status"] = "ok";
|
QUrlQuery query(request.query());
|
||||||
} else {
|
const QString type = query.queryItemValue("type");
|
||||||
obj["status"] = "erreur";
|
|
||||||
obj["message"] = query.lastError().text();
|
if (type != "circuit") {
|
||||||
|
QJsonObject err;
|
||||||
|
err["status"] = "erreur";
|
||||||
|
err["message"] = "type non supporté (seul 'circuit' est implémenté à ce stade)";
|
||||||
|
return QHttpServerResponse(QJsonDocument(err).toJson(), QHttpServerResponder::StatusCode::NotImplemented);
|
||||||
}
|
}
|
||||||
return QHttpServerResponse(QJsonDocument(obj).toJson());
|
|
||||||
|
QJsonArray familles;
|
||||||
|
QSqlQuery q1(QString("SELECT Cle_primaire, Nom FROM TB_Familles WHERE Type_source=%1 ORDER BY Priorite_affichage").arg(TYPE_SOURCE_CIRCUIT));
|
||||||
|
|
||||||
|
while (q1.next()) {
|
||||||
|
const int idFamille = q1.value(0).toInt();
|
||||||
|
const QString nom = q1.value(1).toString();
|
||||||
|
int etat = 0;
|
||||||
|
|
||||||
|
// Alarmes (Events) liées à cette famille :
|
||||||
|
QSqlQuery q2;
|
||||||
|
q2.prepare("SELECT COUNT(*) FROM TB_Events WHERE Type_source=:type AND Validite=1 AND Alarme_source>0 "
|
||||||
|
"AND Etat_test=1 AND ID_Source IN (SELECT Cle_primaire FROM TB_Circuits WHERE ID_Famille=:famille)");
|
||||||
|
q2.bindValue(":type", TYPE_SOURCE_CIRCUIT);
|
||||||
|
q2.bindValue(":famille", idFamille);
|
||||||
|
q2.exec();
|
||||||
|
if (q2.next() && q2.value(0).toInt() > 0) etat = 1;
|
||||||
|
|
||||||
|
// État agrégé des circuits de la famille :
|
||||||
|
QSqlQuery q3;
|
||||||
|
q3.prepare("SELECT Etat, Etat_commande_carte, Etat_systeme FROM TB_Circuits "
|
||||||
|
"WHERE ID_Famille=:famille AND Priorite_affichage_accueil>0");
|
||||||
|
q3.bindValue(":famille", idFamille);
|
||||||
|
q3.exec();
|
||||||
|
while (q3.next()) {
|
||||||
|
const int etatCircuit = q3.value(0).toInt();
|
||||||
|
const int etatCommandeCarte = q3.value(1).toInt();
|
||||||
|
const int etatSysteme = q3.value(2).toInt();
|
||||||
|
|
||||||
|
if (etatSysteme != 0
|
||||||
|
|| etatCircuit == ETAT_CIRCUIT_LIMITATION
|
||||||
|
|| etatCircuit == ETAT_CIRCUIT_PROTECTION
|
||||||
|
|| etatCircuit == ETAT_CIRCUIT_DISJONCTE
|
||||||
|
|| etatCircuit == ETAT_CIRCUIT_ABSENCE_TERRE
|
||||||
|
|| etatCircuit == ETAT_CIRCUIT_ABSENCE_MASSE) {
|
||||||
|
etat = 2;
|
||||||
|
} else if (etat < 2 && (etatCommandeCarte != ETAT_COMMANDE_CARTE_OK || etatCircuit != ETAT_CIRCUIT_OK)) {
|
||||||
|
etat = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject obj;
|
||||||
|
obj["id"] = idFamille;
|
||||||
|
obj["nom"] = nom;
|
||||||
|
obj["etat"] = etat;
|
||||||
|
familles.append(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject reponse;
|
||||||
|
reponse["status"] = "ok";
|
||||||
|
reponse["familles"] = familles;
|
||||||
|
return QHttpServerResponse(QJsonDocument(reponse).toJson());
|
||||||
|
});
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// GET /elements?type=circuit&famille=<id>
|
||||||
|
// Liste des circuits de la famille - sert chargement initial ET
|
||||||
|
// rafraîchissement périodique (même requête que init_circuits() et
|
||||||
|
// mise_a_jour_circuits(), cf §20.4 : ce n'est pas deux besoins
|
||||||
|
// différents, mais un seul, appelé deux fois).
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
server.route("/elements", [](const QHttpServerRequest &request) {
|
||||||
|
QUrlQuery query(request.query());
|
||||||
|
const QString type = query.queryItemValue("type");
|
||||||
|
const QString familleStr = query.queryItemValue("famille");
|
||||||
|
|
||||||
|
if (type != "circuit") {
|
||||||
|
QJsonObject err;
|
||||||
|
err["status"] = "erreur";
|
||||||
|
err["message"] = "type non supporté (seul 'circuit' est implémenté à ce stade)";
|
||||||
|
return QHttpServerResponse(QJsonDocument(err).toJson(), QHttpServerResponder::StatusCode::NotImplemented);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
const int idFamille = familleStr.toInt(&ok);
|
||||||
|
if (!ok) {
|
||||||
|
QJsonObject err;
|
||||||
|
err["status"] = "erreur";
|
||||||
|
err["message"] = "paramètre 'famille' manquant ou invalide";
|
||||||
|
return QHttpServerResponse(QJsonDocument(err).toJson(), QHttpServerResponder::StatusCode::BadRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonArray elements;
|
||||||
|
QSqlQuery q;
|
||||||
|
q.prepare(
|
||||||
|
"SELECT Cle_primaire, Etat_systeme, Nom, Etat_commande_carte, Mode_commande, Etat, Consigne, Old_consigne, "
|
||||||
|
"Mode_test, Tension, Intensite, Frequence, "
|
||||||
|
"(SELECT Type FROM TB_Modules_config WHERE Adresse_k_bus=TB_Circuits.Adresse_module) AS type_circuit, "
|
||||||
|
"No_circuit, "
|
||||||
|
"(SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Visibilite=1 AND "
|
||||||
|
"(Action_circuits LIKE CONCAT(TB_Circuits.Cle_primaire,'/%') OR Action_circuits LIKE CONCAT('%;', TB_Circuits.Cle_primaire,'/%'))) AS nb_events, "
|
||||||
|
"Validation_cdes_events, "
|
||||||
|
"(SELECT COUNT(*) FROM TB_Events WHERE Validite=1 AND Type_source=:type AND Alarme_source>0 AND Etat_test=1 "
|
||||||
|
"AND ID_Source=TB_Circuits.Cle_primaire) AS Nb_alarmes "
|
||||||
|
"FROM TB_Circuits WHERE Priorite_affichage_accueil>0 AND ID_Famille=:famille "
|
||||||
|
"ORDER BY Priorite_affichage_accueil, Cle_primaire"
|
||||||
|
);
|
||||||
|
q.bindValue(":type", TYPE_SOURCE_CIRCUIT);
|
||||||
|
q.bindValue(":famille", idFamille);
|
||||||
|
q.exec();
|
||||||
|
|
||||||
|
while (q.next()) {
|
||||||
|
QJsonObject obj;
|
||||||
|
obj["id"] = q.value(0).toInt();
|
||||||
|
obj["etat_systeme"] = q.value(1).toInt();
|
||||||
|
obj["nom"] = q.value(2).toString();
|
||||||
|
obj["etat_commande_carte"] = q.value(3).toInt();
|
||||||
|
obj["mode_commande"] = q.value(4).toInt();
|
||||||
|
obj["etat"] = q.value(5).toInt();
|
||||||
|
obj["consigne"] = q.value(6).toInt();
|
||||||
|
obj["old_consigne"] = q.value(7).toInt();
|
||||||
|
obj["mode_test"] = q.value(8).toInt();
|
||||||
|
obj["tension"] = q.value(9).toDouble();
|
||||||
|
obj["intensite"] = q.value(10).toDouble();
|
||||||
|
obj["frequence"] = q.value(11).toDouble();
|
||||||
|
obj["type_circuit"] = q.value(12).toInt();
|
||||||
|
obj["no_circuit"] = q.value(13).toInt();
|
||||||
|
obj["validation_cdes_events"] = (q.value(14).toInt() == 0) ? -1 : q.value(15).toInt();
|
||||||
|
obj["etat_events"] = q.value(16).toInt();
|
||||||
|
elements.append(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonObject reponse;
|
||||||
|
reponse["status"] = "ok";
|
||||||
|
reponse["elements"] = elements;
|
||||||
|
return QHttpServerResponse(QJsonDocument(reponse).toJson());
|
||||||
});
|
});
|
||||||
|
|
||||||
auto tcpServer = new QTcpServer();
|
auto tcpServer = new QTcpServer();
|
||||||
@@ -66,7 +209,7 @@ int main(int argc, char *argv[])
|
|||||||
delete tcpServer;
|
delete tcpServer;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
qInfo() << "shipheart_api spike en écoute sur le port" << tcpServer->serverPort();
|
qInfo() << "shipheart_api en écoute sur le port" << tcpServer->serverPort();
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
|
|||||||
Executable
BIN
Binary file not shown.
Reference in New Issue
Block a user