Get bad request from Google calendar API - c++

I'm trying to insert an event to google calendar using Qt C++.
Before inserting events, I am able to clear the primary calendar using these lines
const QUrl clearPrimaryUrl("https://www.googleapis.com/calendar/v3/calendars/primary/clear");
void GoogleWrapper::clearPrimaryCalendar()
{
QNetworkReply *reply = google.post(clearPrimaryUrl);
connect(reply, &QNetworkReply::finished, [=]()
{
reply->deleteLater();
if(reply->error() != QNetworkReply::NoError)
{
qCritical() << "Google error:" << reply->errorString();
return;
}
emit primaryCalendarCleared();
});
}
google is an QOAuth2AuthorizationCodeFlow object.
Now to insert events, I use these lines:
const QUrl insertEventUrl("https://www.googleapis.com/calendar/v3/calendars/primary/events");
void GoogleWrapper::insertEvent(const QByteArray &eventData)
{
qDebug() << eventData;
QNetworkReply *reply = google.post(insertEventUrl, eventData);
connect(reply, &QNetworkReply::finished, [=]()
{
reply->deleteLater();
if(reply->error() != QNetworkReply::NoError)
{
qCritical() << "Google error:" << reply->errorString();
return;
}
emit eventInserted();
});
}
But the output I received from qCritical was always Error transferring https://www.googleapis.com/calendar/v3/calendars/primary/events - server replied: Bad Request.
I tried output the eventData to a file and copy paste it to Google's try this API and the below json data works perfectly
{
"description": "some teacher name",
"end": {
"dateTime": "2018-12-19T11:15:00Z"
},
"location": "Room",
"start": {
"dateTime": "2018-12-19T09:30:00Z"
},
"summary": "Subject Name"
}
Anyone have any idea what I did wrong?

The issue is solved thanks to #thuga's comment.
My code was missing the line
google.setContentType(QAbstractOAuth2::ContentType::Json);

Related

QNetworkAccessManager send PUT request with JSON

I want to send a put request with JSON body, but with QNetworkAccessManager doesn't have the option to send a request with JSON so I converted it to QByteArray, the structure of the body, when converted to QByteArray, is not a JSON format so that I received an Error with
"Error downloading https://example.api.com/something/DataSet('123456780XYZ') - server replied: Forbidden"
The JSON format I want is like this:
{
"d": {
"Duration": "0.000",
"Id": "123456780XYZ",
"LoadCumulLimit": "0.000",
"Notes": "send from postman in Json format"
}
}
Here is what did I do
QJsonObject data;
data["Duration"] = workplace->data["duration"];
data["Id"] = id;
data["LoadCumulLimit"] = workplace->data["load_cumul_limit"];
data["Notes"] = workplace->dataText["Notes"];
QJsonObject newData;
newData["d"] = data;
QJsonDocument doc(newData);
qDebug() << url;
QByteArray finalData = doc.toJson();
qDebug() << finalData;
reply = manager->put(request, finalData);
connect(reply, &QNetworkReply::finished, [=](){
if(reply->error() == QNetworkReply::NoError){
QString contents = QString::fromUtf8(reply->readAll());
qDebug() << contents;
}
else{
QString err = reply->errorString();
qDebug() << err;
}
reply->deleteLater();
});
But I received the QByteArray like this:
"{\n \"d\": {\n \"Duration\": 8,\n \"IgelId\": \"123456780XYZ\",\n \"LoadCumulLimit\": 25,\n \"Notes\": \"send from IGEL\"\n }\n}\n"

Invalid grant issue with Google OAuth authentication in Qt

I'm developing a Qt application and I want to use Google authentication for it. I created a Google API as explained in the following link: https://blog.qt.io/blog/2017/01/25/connecting-qt-application-google-services-using-oauth-2-0/ but I have a problem with it. It doesn't work in many cases and I get ProtocolInvalidOperationError(302) error for https://accounts.google.com/o/oauth2/token request URL in
QOAuthHttpServerReplyHandler::networkReplyFinished(QNetworkReply *reply)
method of Qt class.
Note that I override QOAuthHttpServerReplyHandler::networkReplyFinished(QNetworkReply *reply) to get this error, because it doesn't emit any signal in this case, and the return value for reply->readAll() is as below:
{
"error": "invalid_grant",
"error_description": "Malformed auth code."
}
My Login.cpp code is something as below:
Login::Login() {
google = new QOAuth2AuthorizationCodeFlow;
google->setScope("email");
google->setAuthorizationUrl("https://accounts.google.com/o/oauth2/auth");
google->setClientIdentifier(Utility::decrypt(encryptedClientId));
google->setAccessTokenUrl("https://accounts.google.com/o/oauth2/token");
google->setClientIdentifierSharedKey(Utility::decrypt(encryptedClientSecret));
connect(google, &QOAuth2AuthorizationCodeFlow::authorizeWithBrowser,
&QDesktopServices::openUrl);
connect(google,&QOAuth2AuthorizationCodeFlow::authorizationCallbackReceived,[=](const QVariantMap data){
QString code(data["code"].toString());
if(!code2.isEmpty())
{
const QUrl redirectUri= "http://localhost:56413/cb";
QJsonObject postdata;
postdata.insert("code",code);
postdata.insert("client_id", Utility::decrypt(encryptedClientId));
postdata.insert("client_secret", Utility::decrypt(encryptedClientSecret));
postdata.insert("redirect_uri", redirectUri.toString());
postdata.insert("grant_type","authorization_code");
QString serviceURL = "oauth2/v4/token";
NetworkManager::GetInstance()->Post(postdata,serviceURL,"https://www.googleapis.com/",[=](int statusCode,int resultnumber, QJsonObject obj){
if (statusCode >= 200 &&
statusCode < 300)
{
// it's ok, do nothing
}
else {
//show error
}
});
}
});
}
void Login::googleLoginButtonPressed() {
int googlePort = 56413;
if(replyHandler == nullptr)
replyHandler = new QOAuthHttpServerReplyHandlerArio(googlePort, this);
google->setReplyHandler(replyHandler);
QObject::connect(replyHandler, &QOAuthHttpServerReplyHandler::tokensReceived, [=](const QVariantMap &map) {
googleToken = map["id_token"].toString();
connect(google, &QOAuth2AuthorizationCodeFlow::granted, [=]() {
auto reply = google->get(QUrl("https://www.googleapis.com/plus/v1/people/me"));
connect_reply = connect(reply, &QNetworkReply::finished, [=]() {
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if (statusCode >= 200 &&
statusCode < 300)
{
//NOW register or login the user with email
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll().data());
email = jsonResponse.object().value("emails").toArray()[0].toObject().value("value").toString();
reply->deleteLater();
}
else {
//error
}
});
});
});
google->grant();
}
what's the problem?
Thanks for your help.
We have posted a lengthy document describing how to authenticate with Google SSO and Qt and this is one of the problems we discuss. I suspect the reason is that the login code returned by Google is URL-encoded, and Qt does not decode it automatically for you. So before you set your replyHandler, you need to invoke setModifyParametersFunction to decode it, in the middle of the flow.
google->setModifyParametersFunction([](QAbstractOAuth::Stage stage, QVariantMap* parameters) {
// Percent-decode the "code" parameter so Google can match it
if (stage == QAbstractOAuth::Stage::RequestingAccessToken) {
QByteArray code = parameters->value("code").toByteArray();
(*parameters)["code"] = QUrl::fromPercentEncoding(code);
}
});

QNetworkReply Never emit a finished signal

I am writing a simple qt network application. I try to read the data from the QNetworkReply but it seems that the finished signal never emit. What happens?
QByteArray utils::Login(QString account)
{
QNetworkAccessManager* manager = new QNetworkAccessManager();
QNetworkRequest* request = new QNetworkRequest();
request->setUrl(QUrl(Urls::loginUrl));
request->setRawHeader("Host", "10.136.2.5");
request->setRawHeader("Referer", "http://10.136.2.5/jnuweb/");
request->setRawHeader("Content-Type", "application/json; charset=utf-8");
request->setRawHeader("Connection", "keep-alive");
request->setRawHeader("X-Requested-With", "XMLHttpRequest");
request->setRawHeader("Accept", "*/*");
request->setRawHeader("Accept-Encoding", "deflate");
QJsonObject* requestContent = new QJsonObject();
requestContent->insert("user", QJsonValue(account));
requestContent->insert("password", QJsonValue(Urls::initPassword));
QNetworkReply* reply = manager-> post(*request, QJsonDocument(*requestContent).toJson(QJsonDocument::Compact));
QObject::connect(reply, &QNetworkReply::finished, [=]()
{
QList<QPair<QByteArray, QByteArray>> responses = reply -> rawHeaderPairs();
qDebug() << responses;
});
}

unexpected result in parsing nested json in qt (array does not exist)

I am new in qt and I also searched in stack overflow but I can't get my answer so this not a duplicated post because all similar post have array [] but in this code i have not any array
I want to parse this complex JSON file:
{
"query": {
"lang": "en-US",
"results": {
"channel": {
"units": {
"distance": "mi",
"pressure": "in"
},
"ttl": "60",
"location": {
"city": "city",
"country": "not important",
"region": " kkk"
},
"wind": {
"chill": "99",
"direction": "180",
"speed": "14"
}
}
...(more code)
i want to get chill data but out put is " " , please help me to print chill data in qt
its a part of my code:
QNetworkAccessManager manager;
QNetworkReply *response = manager.get(QNetworkRequest(QUrl(url)));
QEventLoop event;
connect(response, SIGNAL(finished()), &event, SLOT(quit()));
event.exec();
json = response->readAll();
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
QJsonObject jsonObj = doc.object();
foreach (const QJsonValue &value, jsonObj) {
QJsonObject jsonobj = value.toObject();
qDebug() << jsonobj["chill"].toString();
}
output of qDebug()<<doc.object(); is
D/libuntitled7.so(13258): : ** QJsonObject({"query":{"count":1,"created":"2017-07-06T21:21:16Z","lang":"en-US","results":{"channel":{"astronomy":{"sunrise":"5:48 am","sunset":"8:15 pm"},"atmosphere":{"humidity":"16","pressure":"875.0","rising":"0","visibility":"16.1"},"description":"Yahoo! Weather","image":{"height":"18","link":"http://weather.yahoo.com","title":"Yahoo! Weather","url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif","width":"142"},"item":{"condition":{"code":"31","date":"Fri, 07 Jul 2017 12:30 AM IRDT","temp":"85","text":"Clear"},"description":"<![CDATA[<img src=\"http://l.yimg.com/a/i/us/we/52/31.gif\"/>\n<BR/>\n<b>Forecast:</b>\n<BR /> Fri - Sunny. High: 97Low: 78\n<BR /> Sat - Sunny. High: 100Low: 79\n<BR /> Sun - Sunny. High: 101Low: 81\n<BR /> Mon - Sunny. High: 100Low: 81\n<BR /> Tue - Mostly
D/libuntitled7.so(13258): ..\untitled7\dialog2.cpp:84 (void Dialog2::on_pushButton_clicked()):
and next out put is 86
As I comment #MohammedB.B. a way is to manually search through the keys, another way is to create a function that searches through the keys, in this case I present the second form:
QJsonObject findObject(QString key, QJsonObject object){
if(object.isEmpty())
return QJsonObject();
if(object.keys().contains(key)){
return object;
}
else{
for(const QString& _key: object.keys()){
if(object[_key].isObject()){
const QJsonObject& result = findObject(key, object[_key].toObject());
if(!result.isEmpty()){
return result;
}
}
}
}
return QJsonObject();
}
QJsonValue findValuebyKey(QString key, QJsonDocument doc){
QJsonObject obj_key = findObject(key, doc.object());
return obj_key[key];
}
Example:
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
qDebug()<<findValuebyKey("chill", doc).toString();
Output:
"99"
Note:If you generate problems the "for" enable c ++ 11, you can do this by adding CONFIG += c++11 to your .pro
You need to iterate in your channels array too. Easy solution:
const QJsonDocument doc = QJsonDocument::fromJson(response->readAll().toUtf8());
// Access to "query"
const QJsonObject queryObject = doc.object();
// Access to "results"
const QJsonObject resultsObject = queryObject.value("results").toObject();
// Access to "chanels"
const QJsonObject channelsObject = resultsObject.value("channels").toObject();
// Access to "wind"
const QJsonObject windObject = channelsObject.value("wind").toObject();
// And then access to "chill"
const QJsonValue chill = windObject.value("chill");
Best practice its to create a recursive function to parse the JSON recursively.

Qt Network Access Manager JSON Get Response

I'm trying to pull JSON data from a URL using the Qt framework, and I've run into some issues with getting a return from the get request. I've seen multiple questions asked regarding my issue, but none of the given solutions has solved my problem.
So I have a button that, once clicked, should execute the get request. Here's my code.
//When button is pressed
void Test1::onClickCapture()
{
qDebug() << "Capture Clicked!!";
toPopulate();
}
//Code to execute the connection
void Test1::toPopulate() {
qDebug() << "Populating!";
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QNetworkRequest request;
QUrl url("https://jsonplaceholder.typicode.com/posts/1");
request.setUrl(url);
QNetworkReply *reply = manager->get(request);
connect(reply, &QNetworkReply::readyRead, this, &Test1::onResult);
}
//And finally, my onResult slot
void Test1::onResult() {
reply->deleteLater();
if (reply->error() != QNetworkReply::NoError) {
return;
}
qDebug() << "Response!";
}
Every time I debug the code, it never gets to my onResult slot.
I also get this error, which may be relevant.
QObject::connect: Cannot connect (null)::aboutToQuit() to QNativeWifiEngine::closeHandle()
I have modified your code. It's working fine for me:
//Code to execute the connection
void MainWindow::toPopulate() {
qDebug() << "Populating!";
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QNetworkRequest request;
QUrl url("https://jsonplaceholder.typicode.com/posts/1");
request.setUrl(url);
QNetworkReply *reply = manager->get(request);
connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloading(qint64,qint64)));
connect(reply, SIGNAL(finished()), this, SLOT(onResult()));
}
void MainWindow::downloading(qint64 bytesReceived, qint64 bytesTotal) {
qDebug() << "Downloading " << bytesReceived/bytesTotal*100 << " %.";
}
//And finally, my onResult slot
void MainWindow::onResult() {
QNetworkReply* reply = qobject_cast<QNetworkReply*> (QObject::sender());
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Error downloading. " << reply->errorString();
return;
}
reply->deleteLater();
qDebug() << "Response! " << reply->readAll();
}
Result:
Populating!
Downloading -29200 %.
Downloading 100 %.
Response! "{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"sunt aut facere repellat provident occaecati excepturi optio reprehenderit\",\n \"body\": \"quia et suscipit\\nsuscipit recusandae consequuntur expedita et cum\\nreprehenderit molestiae ut ut quas totam\\nnostrum rerum est autem sunt rem eveniet architecto\"\n}"