Qt/QML App for Friendiqa
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

updatenews.cpp 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. // This file is part of Friendiqa
  2. // https://git.friendi.ca/lubuwest/Friendiqa
  3. // Copyright (C) 2017 Marco R. <thomasschmidt45@gmx.net>
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // In addition, as a special exception, the copyright holders give
  11. // permission to link the code of portions of this program with the
  12. // OpenSSL library under certain conditions as described in each
  13. // individual source file, and distribute linked combinations including
  14. // the two.
  15. //
  16. // You must obey the GNU General Public License in all respects for all
  17. // of the code used other than OpenSSL. If you modify file(s) with this
  18. // exception, you may extend this exception to your version of the
  19. // file(s), but you are not obligated to do so. If you do not wish to do
  20. // so, delete this exception statement from your version. If you delete
  21. // this exception statement from all source files in the program, then
  22. // also delete it here.
  23. //
  24. // This program is distributed in the hope that it will be useful,
  25. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. // GNU General Public License for more details.
  28. //
  29. // You should have received a copy of the GNU General Public License
  30. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  31. #include "updatenews.h"
  32. #include <QHttpPart>
  33. #include <QTextCodec>
  34. #include <QUrlQuery>
  35. #include <QList>
  36. #include <QDataStream>
  37. #include <QJsonDocument>
  38. #include <QJsonObject>
  39. #include <QJsonArray>
  40. #include <QQmlEngine>
  41. #include <QSqlQuery>
  42. #include <QSqlRecord>
  43. #include <QSqlDatabase>
  44. #include <QSqlError>
  45. #include <QDateTime>
  46. //#include "AndroidNative/systemdispatcher.h"
  47. UPDATENEWS *UPDATENEWS::instance()
  48. {
  49. static UPDATENEWS udn;
  50. return &udn;
  51. }
  52. UPDATENEWS::UPDATENEWS(QObject *parent) : QObject(parent)
  53. {
  54. }
  55. void UPDATENEWS::setUrl(QString url)
  56. {
  57. if (url!=m_url) {
  58. m_url = url;
  59. xhr.setUrl(url);
  60. emit urlChanged(m_url);
  61. }
  62. }
  63. void UPDATENEWS::setDatabase()
  64. {
  65. static QQmlEngine qe;
  66. QString db_url=qe.offlineStorageDatabaseFilePath("Friendiqa");
  67. m_db = QSqlDatabase::addDatabase("QSQLITE");
  68. m_db.setDatabaseName(QUrl("file://"+db_url+".sqlite").toLocalFile());
  69. //qDebug() << db_url;
  70. if (!m_db.open())
  71. {
  72. qDebug() << "Error: connection with database fail " << m_db.lastError();
  73. }
  74. }
  75. void UPDATENEWS::login()
  76. {
  77. QSqlQuery query("SELECT * FROM config WHERE isActive=0",m_db);
  78. while (query.next())
  79. {
  80. username = query.value(1).toString();
  81. QByteArray bpassword=query.value(2).toByteArray();
  82. QString password=QByteArray::fromBase64(bpassword);
  83. m_login=username+":"+password ;
  84. xhr.setLogin(m_login);
  85. m_url=query.value(0).toString();
  86. xhr.setUrl(m_url);
  87. m_imagedir=query.value(3).toString();
  88. xhr.setImagedir(m_imagedir);
  89. QString isActive=query.value(7).toString();
  90. m_updateInterval=query.value(5).toInt();
  91. m_api="/api/statuses/friends_timeline";
  92. xhr.setApi(m_api);
  93. }
  94. }
  95. void UPDATENEWS::timeline()
  96. {
  97. qDebug()<<"Friendiqa start timeline";
  98. QSqlQuery query("SELECT status_id FROM news WHERE username='"+ username +"' ORDER BY status_id DESC LIMIT 1",m_db);
  99. if (query.isActive() && query.isSelect()){query.first();};
  100. QString lastid=query.value(0).toString();
  101. xhr.clearParams();
  102. xhr.setParam("since_id",lastid);
  103. xhr.setParam("count","50");
  104. xhr.get();
  105. QObject::connect(&xhr,SIGNAL(success(QByteArray,QString)),this,SLOT(store(QByteArray,QString)));
  106. QObject::connect(&xhr,SIGNAL(error(QString,QString,QString,int)),this,SLOT(showError(QString,QString,QString,int)));
  107. }
  108. //void UPDATENEWS::startservice(QString type,QVariantMap map)
  109. //{
  110. // qDebug ()<<"Friediqa start service "<<type;
  111. // if (type=="androidnativeServiceStarted"){
  112. // setDatabase();
  113. // login();
  114. // timeline();
  115. // }
  116. //}
  117. void UPDATENEWS::store(QByteArray serverreply,QString apiname)
  118. {
  119. QJsonDocument news;
  120. qDebug()<<apiname << news;
  121. QJsonParseError jsonerror;
  122. news=QJsonDocument::fromJson(serverreply,&jsonerror);
  123. if (news.isArray()){
  124. for (int i=0; i < news.array().count();i++){
  125. QJsonValue newsitem=news[i];
  126. QSqlQuery query(m_db);
  127. query.prepare("INSERT INTO news (username,messagetype,text,created_at,in_reply_to_status_id,source,status_id,in_reply_to_user_id,geo,favorited,uid,statusnet_html,statusnet_conversation_id,friendica_activities,friendica_activities_self,attachments,friendica_owner) " "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
  128. query.bindValue(0,username);
  129. query.bindValue(1,"0");
  130. query.bindValue(2, newsitem["text"].toString().toUtf8().toBase64());
  131. QString sourcedate=newsitem["created_at"].toString();
  132. QString formateddate=sourcedate.mid(0,3)+", "+sourcedate.mid(8,3)+sourcedate.mid(4,3)+sourcedate.mid(25,5)+sourcedate.mid(10,15);
  133. query.bindValue(3,QDateTime::fromString(formateddate,Qt::RFC2822Date).toMSecsSinceEpoch() );
  134. if(newsitem["in_reply_to_status_id"]!=QJsonValue::Null){query.bindValue(4, newsitem["in_reply_to_status_id"].toInt());};
  135. query.bindValue(5,newsitem["source"]);
  136. query.bindValue(6,newsitem["id"].toInt());
  137. if(newsitem["in_reply_to_user_id"]!=QJsonValue::Null){ query.bindValue(7,newsitem["in_reply_to_user_id"].toInt());};
  138. query.bindValue(8,newsitem["geo"]);
  139. query.bindValue( 9, newsitem["favorited"].toInt());
  140. query.bindValue(10, newsitem["user"]["id"].toInt());
  141. query.bindValue(11, newsitem["statusnet_html"].toString().toUtf8().toBase64());
  142. query.bindValue(12, newsitem["statusnet_conversation_id"].toInt());
  143. QJsonArray likeArray;QJsonArray dislikeArray;QJsonArray attendyesArray;QJsonArray attendnoArray;QJsonArray attendmaybeArray;
  144. if (newsitem.toObject().contains("friendica_activities")){
  145. for (int a=0; a < newsitem["friendica_activities"]["like"].toArray().count();a++){
  146. likeArray.append(newsitem["friendica_activities"]["like"][a]["url"].toString());
  147. }
  148. for (int b=0; b < newsitem["friendica_activities"]["dislike"].toArray().count();b++){
  149. dislikeArray.append(newsitem["friendica_activities"]["dislike"][b]["url"].toString());
  150. }
  151. for (int c=0; c < newsitem["friendica_activities"]["attendyes"].toArray().count();c++){
  152. attendyesArray.append(newsitem["friendica_activities"]["attendyes"][c]["url"].toString());
  153. }
  154. for (int d=0; d < newsitem["friendica_activities"]["attendno"].toArray().count();d++){
  155. attendnoArray.append(newsitem["friendica_activities"]["attendno"][d]["url"].toString());
  156. }
  157. for (int e = 0; e < newsitem["friendica_activities"]["attendmaybe"].toArray().count();e++){
  158. attendmaybeArray.append(newsitem["friendica_activities"]["attendmaybe"][e]["url"].toString());
  159. }
  160. };
  161. QJsonArray friendica_activities; friendica_activities={likeArray,dislikeArray,attendyesArray,attendnoArray,attendmaybeArray};
  162. QJsonDocument activities; activities.setArray(friendica_activities);
  163. query.bindValue(13,activities.toJson(QJsonDocument::Compact).toBase64());
  164. query.bindValue(14,"[]");
  165. if (newsitem["attachments"]!=QJsonValue::Undefined){
  166. query.bindValue(15, QJsonDocument(newsitem["attachments"].toArray()).toJson(QJsonDocument::Compact).toBase64());
  167. };
  168. query.bindValue(16, newsitem["friendica_owner"]["url"]);
  169. query.exec() ;
  170. }
  171. }
  172. else {
  173. qDebug()<< "Friendiqa updatenews error";
  174. emit this->error(m_api,QTextCodec::codecForName("utf-8")->toUnicode(serverreply));
  175. if(m_updateInterval!=0){
  176. m_db.close();
  177. m_db.removeDatabase(m_db.connectionName());
  178. emit quitapp();
  179. alarm.setAlarm(m_updateInterval);
  180. };
  181. }
  182. QList<QJsonValue> newcontacts=findNewContacts(news);
  183. updateContacts(newcontacts);
  184. startImagedownload();
  185. connect(&xhr, SIGNAL(downloaded(QString, QString, QString, int)), this, SLOT(updateImageLocation(QString,QString, QString, int)));
  186. }
  187. void UPDATENEWS::updateImageLocation(QString downloadtype,QString imageurl, QString filename, int index){
  188. if (downloadtype=="contactlist"){
  189. QSqlQuery testquery("SELECT profile_image FROM contacts WHERE profile_image_url ='"+imageurl+ "' AND username = '" +username+"'",m_db);
  190. testquery.exec();
  191. //qDebug()<< "update imageurl for " <<imageurl << " from " <<testquery.value(0).toString() <<" to "<< filename <<" index " << index << " newcontactnames.length " <<newcontactnames.length();
  192. QSqlQuery query("UPDATE contacts SET profile_image='"+ filename +"' WHERE profile_image_url ='"+imageurl+ "' AND username = '" +username+"'",m_db);
  193. query.exec();
  194. if (index==(newcontactnames.length()-1)){
  195. if(m_updateInterval!=0){
  196. m_db.close();
  197. m_db.removeDatabase(m_db.connectionName());
  198. emit quitapp();
  199. alarm.setAlarm(m_updateInterval);
  200. };
  201. }
  202. }
  203. }
  204. QList <QJsonValue> UPDATENEWS::findNewContacts(QJsonDocument news){
  205. QSqlQuery query("SELECT profile_image_url FROM contacts",m_db);
  206. QList<QString> imageurls;
  207. while (query.next()){
  208. imageurls.append(query.value(0).toString());
  209. }
  210. QList<QJsonValue> newcontacts;
  211. qDebug()<<"updatenews findcontacts count "<<news.array().count();
  212. for (int i=0; i<news.array().count();i++){
  213. //main contacts
  214. if(imageurls.contains(news[i]["user"]["profile_image_url"].toString()) || newcontactimagelinks.contains(news[i]["user"]["profile_image_url"].toString())){
  215. }
  216. else{
  217. newcontacts.append(news[i]["user"]);
  218. newcontactimagelinks.append(news[i]["user"]["profile_image_url"].toString());
  219. newcontactnames.append(news[i]["user"]["screen_name"].toString());
  220. }
  221. //like/dislike contacts
  222. if (news[i].toObject().contains("friendica_activities") ){
  223. for (int a=0; a < news[i]["friendica_activities"]["like"].toArray().count();a++){
  224. if(imageurls.contains(news[i]["friendica_activities"]["like"][a]["profile_image_url"].toString()) || newcontactimagelinks.contains(news[i]["friendica_activities"]["like"][a]["profile_image_url"].toString())){
  225. }
  226. else{
  227. newcontacts.append(news[i]["friendica_activities"]["like"][a]);
  228. newcontactimagelinks.append(news[i]["friendica_activities"]["like"][a]["profile_image_url"].toString());
  229. newcontactnames.append(news[i]["friendica_activities"][a]["screen_name"].toString());
  230. }
  231. }
  232. for (int b=0; b < news[i]["friendica_activities"]["dislike"].toArray().count();b++){
  233. if(imageurls.contains(news[i]["friendica_activities"]["dislike"][b]["profile_image_url"].toString()) || newcontactimagelinks.contains(news[i]["friendica_activities"]["dislike"][b]["profile_image_url"].toString())){
  234. }
  235. else{
  236. newcontacts.append(news[i]["friendica_activities"]["dislike"][b]);
  237. newcontactimagelinks.append(news[i]["friendica_activities"]["dislike"][b]["profile_image_url"].toString());
  238. newcontactnames.append(news[i]["friendica_activities"][b]["screen_name"].toString());
  239. }
  240. }
  241. }
  242. //owner contacts
  243. if (news[i].toObject().contains("friendica_owner") ){
  244. if(imageurls.contains(news[i]["friendica_owner"]["profile_image_url"].toString()) || newcontactimagelinks.contains(news[i]["friendica_owner"]["profile_image_url"].toString())){
  245. }
  246. else{
  247. newcontacts.append(news[i]["friendica_owner"]);
  248. newcontactimagelinks.append(news[i]["friendica_owner"]["profile_image_url"].toString());
  249. newcontactnames.append(news[i]["friendica_owner"]["screen_name"].toString());
  250. }
  251. }
  252. }
  253. return newcontacts;
  254. }
  255. void UPDATENEWS::updateContacts(QList<QJsonValue> contacts){
  256. qint64 currentTime =QDateTime::currentMSecsSinceEpoch();
  257. for (int i=0; i < contacts.count();i++){
  258. QJsonValue contact=contacts[i];
  259. QSqlQuery query(m_db);
  260. //qDebug() << "updatecontact " << contact["screen_name"];
  261. QSqlQuery testquery("SELECT url FROM contacts WHERE username='"+ username +"' AND url='" + contact["url"].toString() +"'",m_db);
  262. if (testquery.first()){
  263. query.prepare("UPDATE contacts SET id=?, name=?, screen_name=?, location=?,imageAge=?,"
  264. "profile_image_url=?, description=?, protected=?, followers_count=?,"
  265. "friends_count=?, created_at=?, favourites_count=?, utc_offset=?, time_zone=?, statuses_count=?,"
  266. "following=?, verified=?, statusnet_blocking=?, notifications=?, statusnet_profile_url=?, cid=?, network=?, timestamp=? "
  267. " WHERE username='"+ username +"' AND url='" + contact["url"].toString() +"'");
  268. query.bindValue(0, contact["id"].toInt());
  269. query.bindValue(1, contact["name"].toString().toUtf8().toBase64());
  270. query.bindValue(2, contact["screen_name"]);
  271. query.bindValue(3, contact["location"]);
  272. query.bindValue(4, currentTime);
  273. query.bindValue(5, contact["profile_image_url"]);
  274. if(contact["description"].isNull() ){query.bindValue(6,"");}else{query.bindValue(6, contact["description"].toString().toUtf8().toBase64());};
  275. query.bindValue(7,contact["protected"].toBool());
  276. query.bindValue(8,contact["followers_count"].toInt());
  277. query.bindValue(9,contact["friends_count"].toInt());
  278. QString sourcedate=contact["created_at"].toString();
  279. QString formateddate=sourcedate.mid(0,3)+", "+sourcedate.mid(8,3)+sourcedate.mid(4,3)+sourcedate.mid(25,5)+sourcedate.mid(10,15);
  280. query.bindValue(10,QDateTime::fromString(formateddate,Qt::RFC2822Date).toMSecsSinceEpoch() );
  281. query.bindValue(11,contact["favorites_count"].toInt());
  282. query.bindValue(12,contact["utc_offset"].toInt());
  283. query.bindValue(13,contact["time_zone"].toString());
  284. query.bindValue(14,contact["statuses_count"].toInt());
  285. query.bindValue(15,contact["following"].toBool());
  286. query.bindValue(16,contact["verfied"].toBool());
  287. query.bindValue(17,contact["statusnet_blocking"].toBool());
  288. query.bindValue(18,contact["notifications"].toBool());
  289. query.bindValue(19,contact["statusnet_profile_url"]);
  290. query.bindValue(20,contact["cid"].toInt());
  291. query.bindValue(21,contact["network"]);
  292. qint64 timestamp=0;
  293. QString timestamphelper=contact["profile_image_url"].toString();
  294. try {timestamp=timestamphelper.mid(timestamphelper.indexOf("?ts")+4,timestamphelper.length()).toUInt();} catch(...){};
  295. query.bindValue(22,timestamp);
  296. }
  297. else{
  298. query.prepare("INSERT INTO contacts (username, id, name, screen_name, location,imageAge,"
  299. "profile_image_url, description, profile_image, url, protected, followers_count,"
  300. "friends_count, created_at, favourites_count, utc_offset, time_zone, statuses_count,"
  301. "following, verified, statusnet_blocking, notifications, statusnet_profile_url, cid, network, isFriend, timestamp)"
  302. "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
  303. query.bindValue(0,username);
  304. query.bindValue(1, contact["id"].toInt());
  305. query.bindValue(2, contact["name"].toString().toUtf8().toBase64());
  306. query.bindValue(3, contact["screen_name"]);
  307. query.bindValue(4, contact["location"]);
  308. query.bindValue(5, currentTime);
  309. query.bindValue(6, contact["profile_image_url"]);
  310. if(contact["description"].isNull() ){query.bindValue(7,"");}else{query.bindValue(7, contact["description"].toString().toUtf8().toBase64());};
  311. query.bindValue(8,"none");
  312. query.bindValue(9, contact["url"].toString());
  313. query.bindValue(10,contact["protected"].toBool());
  314. query.bindValue(11,contact["followers_count"].toInt());
  315. query.bindValue(12,contact["friends_count"].toInt());
  316. QString sourcedate=contact["created_at"].toString();
  317. QString formateddate=sourcedate.mid(0,3)+", "+sourcedate.mid(8,3)+sourcedate.mid(4,3)+sourcedate.mid(25,5)+sourcedate.mid(10,15);
  318. query.bindValue(13,QDateTime::fromString(formateddate,Qt::RFC2822Date).toMSecsSinceEpoch() );
  319. query.bindValue(14,contact["favorites_count"].toInt());
  320. query.bindValue(15,contact["utc_offset"].toInt());
  321. query.bindValue(16,contact["time_zone"].toString());
  322. query.bindValue(17,contact["statuses_count"].toInt());
  323. query.bindValue(18,contact["following"].toBool());
  324. query.bindValue(19,contact["verfied"].toBool());
  325. query.bindValue(20,contact["statusnet_blocking"].toBool());
  326. query.bindValue(21,contact["notifications"].toBool());
  327. query.bindValue(22,contact["statusnet_profile_url"]);
  328. query.bindValue(23,contact["cid"].toInt());
  329. query.bindValue(24,contact["network"]);
  330. query.bindValue(25, 0);
  331. qint64 timestamp=0;
  332. QString timestamphelper=contact["profile_image_url"].toString();
  333. try {timestamp=timestamphelper.mid(timestamphelper.indexOf("?ts")+4,timestamphelper.length()).toUInt();} catch(...){};
  334. query.bindValue(26,timestamp);
  335. }
  336. query.exec() ;
  337. }
  338. emit this->success(m_api);
  339. if ((contacts.count()==0) && (m_updateInterval!=0)){
  340. m_db.close();
  341. m_db.removeDatabase(m_db.connectionName());
  342. emit quitapp();
  343. alarm.setAlarm(m_updateInterval);
  344. };
  345. }
  346. QString UPDATENEWS::url() const
  347. {
  348. return m_url;
  349. }
  350. void UPDATENEWS::startImagedownload()
  351. {
  352. xhr.setDownloadtype("contactlist");
  353. xhr.setFilelist(newcontactimagelinks);
  354. xhr.setContactlist(newcontactnames);
  355. xhr.setImagedir(m_imagedir);
  356. xhr.getlist();
  357. }
  358. void UPDATENEWS::showError(QString data, QString url,QString api, int code )
  359. {
  360. emit this->error(api,data);
  361. if(m_updateInterval!=0){
  362. m_db.close();
  363. m_db.removeDatabase(m_db.connectionName());
  364. emit quitapp();
  365. alarm.setAlarm(m_updateInterval);
  366. };
  367. }