Add env var IDENTITY_WEBSOCKET
[apps/homescreen.git] / homescreen / src / usermanagement.cpp
1 #include <stdlib.h>
2 #include "usermanagement.h"
3 #include <QDebug>
4 #include <QtCore/QJsonDocument>
5 #include <QByteArray>
6 UserManagement::UserManagement(QObject *root) : QObject()
7 {
8     home = root->findChild<QObject *>("Home");
9     QObject::connect(home, SIGNAL(disconnect()),
10                          this, SLOT(slot_disconnect()));
11     logo = root->findChild<QObject *>("Logo_colour");
12     shortcutArea = root->findChild<QObject *>("ShortcutArea");
13     statusArea = root->findChild<QObject *>("StatusArea");
14     this->appModel = home->findChild<ApplicationModel *>("ApplicationModel");
15     sequence = 0;
16     isRed = false;
17     connect(&timerRed, SIGNAL(timeout()), this, SLOT(slot_turnOffRed()));
18     timerRed.setSingleShot(true);
19     timerRed.setInterval(3000);
20 #ifdef REAL_SERVER
21     connectWebsockets();
22 #else
23     pSocket = NULL;
24     connect(&timerTest, SIGNAL(timeout()), this, SLOT(slot_timerTest()));
25     timerTest.setSingleShot(false);
26     timerTest.start(5000);
27     launchServer();
28 #endif
29 }
30 void UserManagement::slot_disconnect()
31 {
32     appModel->changeLanguage("us");
33     appModel->changeOrder(-1);
34     timerRed.stop();
35     slot_turnOffRed();
36     QMetaObject::invokeMethod(home, "languageChanged");
37     QMetaObject::invokeMethod(shortcutArea, "languageChanged", Q_ARG(QVariant, "en"));
38     QMetaObject::invokeMethod(statusArea, "languageChanged", Q_ARG(QVariant, "en"));
39     QMetaObject::invokeMethod(home, "showSign90", Q_ARG(QVariant, false), Q_ARG(QVariant, "en"));
40     QMetaObject::invokeMethod(home, "showVisa", Q_ARG(QVariant, false), Q_ARG(QVariant, ""));
41     QMetaObject::invokeMethod(home, "showLicence", Q_ARG(QVariant, false), Q_ARG(QVariant, ""));
42     QMetaObject::invokeMethod(home, "changeFlag", Q_ARG(QVariant, "./images/us_flag.png"));
43     QMetaObject::invokeMethod(home, "setUser", Q_ARG(QVariant, ""), Q_ARG(QVariant, ""));
44     QVariantList list;
45     list << 2 << QString().setNum(++sequence) << "agl-identity-agent/logout" << true;
46     listToJson(list, &data);
47     slot_sendData();
48 }
49
50 void UserManagement::setUser(const User &user)
51 {
52     int hash = qHash(user.name + user.first_name);
53     timerRed.stop();
54     appModel->changeLanguage(user.graphPreferredLanguage);
55     appModel->changeOrder(hash);
56     slot_turnOffRed();
57     QMetaObject::invokeMethod(home, "languageChanged");
58     QMetaObject::invokeMethod(shortcutArea, "languageChanged", Q_ARG(QVariant, user.graphPreferredLanguage));
59     QMetaObject::invokeMethod(statusArea, "languageChanged", Q_ARG(QVariant, user.graphPreferredLanguage));
60     QMetaObject::invokeMethod(home, "showSign90", Q_ARG(QVariant, !user.graphActions.contains("Exceed 90 Kph")), Q_ARG(QVariant, user.graphPreferredLanguage));
61     QStringList t;
62     foreach(const QString &s, user.graphActions) {
63         if(!s.contains("Exceed"))
64             t.append(s);
65     }
66     QString type = user.policy;
67     if(user.graphPreferredLanguage == "fr") {
68         if(type == "Owner")
69             type = "PropriĆ©taire";
70         else if(type == "Driver")
71             type = "Conducteur";
72         else if(type == "Maintainer")
73             type = "Maintenance";
74     }
75     QMetaObject::invokeMethod(home, "setUser", Q_ARG(QVariant, type), Q_ARG(QVariant, QVariant::fromValue(t)));
76     if(user.ccNumberMasked.isEmpty())
77         QMetaObject::invokeMethod(home, "showVisa", Q_ARG(QVariant, false), Q_ARG(QVariant, ""));
78     else
79         QMetaObject::invokeMethod(home, "showVisa", Q_ARG(QVariant, true), Q_ARG(QVariant, user.ccNumberMasked));
80     const QString welcome = QString("%1").arg(user.graphPreferredLanguage == "fr" ? "Bonjour " : "Hello") + " ";
81     QMetaObject::invokeMethod(home, "showHello", Q_ARG(QVariant, welcome + user.first_name));
82     QMetaObject::invokeMethod(home, "changeFlag", Q_ARG(QVariant, user.graphPreferredLanguage == "fr" ? "./images/french_flag.png" : "./images/us_flag.png"));
83     if(user.name.toLower() == "philippea")
84         QMetaObject::invokeMethod(home, "showLicence", Q_ARG(QVariant, true), Q_ARG(QVariant, "./images/DL_Philippe.png"));
85     else if(user.name.toLower() == "alainp")
86         QMetaObject::invokeMethod(home, "showLicence", Q_ARG(QVariant, true), Q_ARG(QVariant, "./images/DL_Alain.png"));
87     else if(user.name.toLower() == "olivierc")
88         QMetaObject::invokeMethod(home, "showLicence", Q_ARG(QVariant, true), Q_ARG(QVariant, "./images/DL_Olivier.png"));
89     else
90         QMetaObject::invokeMethod(home, "showLicence", Q_ARG(QVariant, false), Q_ARG(QVariant, ""));
91
92 }
93 void UserManagement::slot_turnOffRed()
94 {
95     if(!isRed)
96         return;
97     QMetaObject::invokeMethod(logo, "setImage", Q_ARG(QVariant, "./images/Utility_Logo_Colour-01.png"));
98     isRed = false;
99 }
100
101 void UserManagement::connectWebsockets()
102 {
103 #ifdef REAL_SERVER
104     const QUrl url(getenv("IDENTITY_WEBSOCKET") ?: REAL_SERVER);
105 #else
106     const QUrl url(QStringLiteral("ws://localhost:1234"));
107 #endif
108     QSslConfiguration config = QSslConfiguration::defaultConfiguration();
109     config.setProtocol(QSsl::SecureProtocols);
110     webSocket.setSslConfiguration(config);
111     connect(&webSocket, &QWebSocket::connected, this, &UserManagement::onConnected);
112     connect(&webSocket, &QWebSocket::disconnected, this, &UserManagement::onClosed);
113     if(!connect(&webSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onWebSocketError(QAbstractSocket::SocketError)))) {
114         qWarning() << "Failed to connect to QWebSocket::error";
115     }
116     webSocket.open(QUrl(url));
117 }
118 void UserManagement::onWebSocketError(QAbstractSocket::SocketError)
119 {
120     qWarning()<<"Websocket error:" << webSocket.errorString();
121 }
122
123 void UserManagement::onConnected()
124 {
125     connect(&webSocket, &QWebSocket::textMessageReceived,
126             this, &UserManagement::onTextMessageReceived);
127     QVariantList list;
128     QByteArray json;
129     list << 2 << QString().setNum(++sequence) << "agl-identity-agent/subscribe" << true;
130     listToJson(list, &json);
131     webSocket.sendTextMessage(QString(json));
132     list .clear();
133     list << 2 << QString().setNum(++sequence) << "agl-identity-agent/scan" << true;
134     listToJson(list, &json);
135     webSocket.sendTextMessage(QString(json));
136 }
137 void UserManagement::onTextMessageReceived(QString message)
138 {
139     QVariantList list;
140     const bool ok = jsonToList(message.toUtf8(), &list);
141     if(!ok || list.size() < 3) {
142         qWarning()<<"error 1 decoding json"<<list.size()<<message;
143         return;
144     }
145     QVariantMap map  = list.at(2).toMap();
146     if(list.first().toInt() == 5) {
147         if(!isRed)
148             QMetaObject::invokeMethod(logo, "setImage", Q_ARG(QVariant, "./images/Utility_Logo_Red-01.png"));
149         isRed = true;
150         timerRed.start();
151         map = map["data"].toMap();
152         if(map["eventName"].toString() == "login") {
153             //qWarning()<<"login received in client";
154             list.clear();
155             list << 2 << QString().setNum(++sequence) << "agl-identity-agent/get" << true;
156             listToJson(list, &data);
157             QTimer::singleShot(300, this, SLOT(slot_sendData()));
158         }
159         return;
160     }
161     if(list.first().toInt() == 3) {
162         if(!map.contains("response")) {
163             return;
164         }
165         map = map["response"].toMap();
166         User user;
167         user.postal_address = map["postal_address"].toString();
168         QStringList temp  = map["loc"].toString().split(",");
169         if(temp.size() == 2) {
170             user.loc.setX(temp.at(0).toDouble());
171             user.loc.setY(temp.at(1).toDouble());
172         }
173         user.graphActions = map["graphActions"].toString().split(",");
174         user.country = map["country"].toString();
175         user.mail = map["mail"].toString();
176         user.city = map["city"].toString();
177         user.graphEmail = map["graphEmail"].toString();
178         user.graphPreferredLanguage = map["graphPreferredLanguage"].toString();
179         user.ccNumberMasked = map["ccNumberMasked"].toString();
180         user.ccExpYear = map["ccExpYear"].toString();
181         user.ccExpMonth = map["ccExpMonth"].toString();
182         user.description = map["description"].toString();
183         user.groups = map["groups"].toStringList();
184         user.last_name = map["last_name"].toString();
185         user.ccNumber = map["ccNumber"].toString();
186         user.house_identifier = map["house_identifier"].toString();
187         user.phone = map["phone"].toString();
188         user.name = map["name"].toString();
189         user.state = map["state"].toString();
190         user.common_name = map["common_name"].toString();
191         user.fax = map["fax"].toString();
192         user.postal_code = map["postal_code"].toString();
193         user.first_name = map["first_name"].toString();
194         user.keytoken = map["keytoken"].toString();
195         user.policy = map["graphPolicies"].toString();
196         setUser(user);
197     }
198 }
199 void UserManagement::slot_sendData()
200 {
201     webSocket.sendTextMessage(QString(data));
202 }
203
204 void UserManagement::onClosed()
205 {
206     qWarning()<<"webSocket closed";
207 }
208 bool UserManagement::listToJson(const QList<QVariant> &list, QByteArray *json) const
209 {
210     QVariant v(list);
211     *json = QJsonDocument::fromVariant(v).toJson(QJsonDocument::Compact);
212     return true;
213 }
214 bool UserManagement::jsonToList(const QByteArray &buf, QList<QVariant> *list) const
215 {
216     if(!list)
217         return false;
218     QJsonParseError err;
219     QVariant v = QJsonDocument::fromJson(buf, &err).toVariant();
220     if(err.error != 0) {
221         qWarning() << "Error parsing json data" << err.errorString() << buf;
222         *list = QList<QVariant>();
223         return false;
224     }
225     *list = v.toList();
226     return true;
227 }
228 bool UserManagement::mapToJson( const QVariantMap &map, QByteArray *json) const
229 {
230     if(!json)
231         return false;
232     QVariant v(map);
233     *json = QJsonDocument::fromVariant(v).toJson(QJsonDocument::Compact);
234     return true;
235 }
236 bool UserManagement::jsonToMap(const QByteArray &buf, QVariantMap *map) const
237 {
238     if(!map)
239         return false;
240     QJsonParseError err;
241     QVariant v = QJsonDocument::fromJson(buf, &err).toVariant();
242     if(err.error != 0) {
243         qWarning() << "Error parsing json data" << err.errorString() << buf;
244         *map = QVariantMap();
245         return false;
246     }
247     *map = v.toMap();
248     return true;
249 }
250 #ifndef REAL_SERVER
251 void UserManagement::launchServer()
252 {
253       webSocketServer = new QWebSocketServer(QStringLiteral("My Server"),
254                                               QWebSocketServer::NonSecureMode, this);
255       if(webSocketServer->listen(QHostAddress::Any, 1234)) {
256           connect(webSocketServer, &QWebSocketServer::newConnection,
257                   this, &UserManagement::onServerNewConnection);
258           connect(webSocketServer, &QWebSocketServer::closed, this, &UserManagement::onServerClosed);
259           QTimer::singleShot(100, this, SLOT(connectWebsockets()));
260       } else {
261           qWarning()<<"unable to launch webSocket server";
262       }
263 }
264 void UserManagement::onServerNewConnection()
265 {
266     pSocket = webSocketServer->nextPendingConnection();
267     connect(pSocket, &QWebSocket::textMessageReceived, this, &UserManagement::processTextMessage, Qt::UniqueConnection);
268     connect(pSocket, &QWebSocket::binaryMessageReceived, this, &UserManagement::processBinaryMessage, Qt::UniqueConnection);
269     connect(pSocket, &QWebSocket::disconnected, this, &UserManagement::serverSocketDisconnected, Qt::UniqueConnection);
270 }
271 void UserManagement::processTextMessage(QString message)
272 {
273     QString clientDetails_1 = "{\"postal_address\":\"201 Mission Street\",\"loc\":\"37.7914374,-122.3950694\",\"graphActions\":\"Install App,Update Software,Open Trunk,View Online\""
274                               ",\"country\":\"USA\",\"mail\":\"bjensen@example.com\",\"city\":\"San Francisco\",\"graphEmail\":"
275                               "\"bjensen@example.com\",\"graphPreferredLanguage\":\"en\",\"ccNumberMasked\":\"-111\",\"ccExpYear\""
276                               ":\"19\",\"ccExpMonth\":\"01\",\"description\":\"Original description\",\"groups\":[],\"last_name\":\""
277                               "Jensen\",\"ccNumber\":\"111-2343-1121-111\",\"house_identifier\":\"ForgeRock\",\"phone\":\""
278                               "+1 408 555 1862\",\"name\":\"bjensen\",\"state\":\"CA\",\"common_name\":\"Barbara Jensen\",\"fax\":\""
279                               "+1 408 555 1862\",\"postal_code\":\"94105\",\"first_name\":\"Barbara\",\"keytoken\":\"a123456\",\"graphPolicies\":\"Driver\"}";
280     QString clientDetails_2 = "{\"postal_address\":\"201 Mission Street\",\"loc\":\"37.7914374,-122.3950694\""
281                               ",\"country\":\"USA\",\"mail\":\"bjensen@example.com\",\"city\":\"San Francisco\",\"graphEmail\":"
282                               "\"bjensen@example.com\",\"graphPreferredLanguage\":\"fr\",\"ccNumberMasked\":\"-222\",\"ccExpYear\""
283                               ":\"19\",\"ccExpMonth\":\"01\",\"description\":\"Original description\",\"groups\":[],\"last_name\":\""
284                               "Jensen\",\"ccNumber\":\"111-2343-1121-111\",\"house_identifier\":\"ForgeRock\",\"phone\":\""
285                               "+1 408 555 1862\",\"name\":\"bjensen\",\"state\":\"CA\",\"common_name\":\"Barbara Jensen\",\"fax\":\""
286                               "+1 408 555 1862\",\"postal_code\":\"94105\",\"first_name\":\"Philippe\",\"keytoken\":\"a123456\",\"graphPolicies\":\"Maintainer\"}";
287     QString clientDetails = clientDetails_1;
288     if(sequence % 2 == 1)
289         clientDetails = clientDetails_2;
290     QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
291     //qDebug() << "message received in server:" << message;
292     if (!pClient)
293         return;
294     QVariantList list;
295     if(!jsonToList(message.toUtf8(), &list))
296         return;
297     if(list.size() < 2)
298         return;
299     const int messType = list.at(0).toInt();
300     const QString messId = list.at(1).toString();
301     const QString cmd = list.at(2).toString();
302     list.clear();
303     QString reply;
304     switch(messType) {
305     case 2:
306         if(cmd == "agl-identity-agent/subscribe") {
307             reply = "[3,\"999maitai999\",{\"jtype\":\"afb-reply\",\"request\":{\"status\":\"success\",\"uuid\":\"1f2f7678-6f2e-4f54-b7b5-d0d4dcbf2e41\"}}]";
308         } else if (cmd == "agl-identity-agent/get") {
309             reply = "[3,\"999maitai99\",{\"jtype\":\"afb-reply\",\"request\":{\"status\":\"success\"},\"response\":....}]";
310             reply = reply.replace("....", clientDetails);
311         } else {
312             qWarning()<<"invalid cmd received:"<<cmd;
313             return;
314         }
315         break;
316     default:
317         qWarning()<<"invalid message type"<<messType;
318         return;
319         break;
320     }
321     reply = reply.replace("999maitai999", messId);
322     pClient->sendTextMessage(reply);
323 }
324 void UserManagement::processBinaryMessage(QByteArray message)
325 {
326     QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
327     qDebug() << "Binary Message received ????:" << message;
328     if (pClient) {
329        // pClient->sendBinaryMessage(message);
330     }
331 }
332 void UserManagement::serverSocketDisconnected()
333 {
334     QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
335     qDebug() << "socketDisconnected:" << pClient;
336     if (pClient) {
337         pClient->deleteLater();
338     }
339 }
340 void UserManagement::slot_timerTest()
341 {
342     if(!pSocket)
343         return;
344     if(sequence > 3) {
345         timerTest.stop();
346         return;
347     }
348     pSocket->sendTextMessage("[5,\"agl-identity-agent/event\",{\"event\":\"agl-identity-agent\/event\",\"data\":{\"eventName\":\"incoming\",\"accountid\":\"D2:D4:71:0D:B5:F1\",\"nickname\":\"D2:D4:71:0D:B5:F1\"},\"jtype\":\"afb-event\"}]");
349     pSocket->sendTextMessage("[5,\"agl-identity-agent/event\",{\"event\":\"agl-identity-agent\/event\",\"data\":{\"eventName\":\"login\",\"accountid\":\"null\"},\"jtype\":\"afb-event\"}]");
350 }
351 void UserManagement::onServerClosed()
352 {
353     qWarning()<<"websocket server closed";
354 }
355 #endif