KBlog

gdata.cpp
1 /*
2  This file is part of the kblog library.
3 
4  Copyright (c) 2007 Christian Weilbach <[email protected]>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "gdata.h"
23 #include "gdata_p.h"
24 #include "blogpost.h"
25 #include "blogcomment.h"
26 #include "feedretriever.h"
27 
28 #include <syndication/loader.h>
29 #include <syndication/item.h>
30 #include <syndication/category.h>
31 
32 #include <kio/job.h>
33 #include "kblog_debug.h"
34 #include <KLocalizedString>
35 #include <QUrl>
36 #include <QUrlQuery>
37 
38 #include <QByteArray>
39 #include <QRegExp>
40 
41 #define TIMEOUT 600
42 
43 using namespace KBlog;
44 
45 GData::GData(const QUrl &server, QObject *parent)
46  : Blog(server, *new GDataPrivate, parent)
47 {
48  qCDebug(KBLOG_LOG);
49  setUrl(server);
50 }
51 
53 {
54  qCDebug(KBLOG_LOG);
55 }
56 
58 {
59  qCDebug(KBLOG_LOG);
60  return QStringLiteral("Google Blogger Data");
61 }
62 
64 {
65  qCDebug(KBLOG_LOG);
66  return d_func()->mFullName;
67 }
68 
70 {
71  qCDebug(KBLOG_LOG);
72  Q_D(GData);
73  d->mFullName = fullName;
74 }
75 
77 {
78  qCDebug(KBLOG_LOG);
79  return d_func()->mProfileId;
80 }
81 
82 void GData::setProfileId(const QString &pid)
83 {
84  qCDebug(KBLOG_LOG);
85  Q_D(GData);
86  d->mProfileId = pid;
87 }
88 
90 {
91  qCDebug(KBLOG_LOG);
92  QByteArray data;
94  QUrl blogUrl = url();
95  connect(job, SIGNAL(result(KJob*)),
96  this, SLOT(slotFetchProfileId(KJob*)));
97 }
98 
100 {
101  qCDebug(KBLOG_LOG);
103  connect(loader,
104  SIGNAL(loadingComplete(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)),
105  this,
106  SLOT(slotListBlogs(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)));
107  loader->loadFrom(QUrl(QStringLiteral("http://www.blogger.com/feeds/%1/blogs").arg(profileId())), new FeedRetriever);
108 }
109 
110 void GData::listRecentPosts(const QStringList &labels, int number,
111  const QDateTime &upMinTime, const QDateTime &upMaxTime,
112  const QDateTime &pubMinTime, const QDateTime &pubMaxTime)
113 {
114  qCDebug(KBLOG_LOG);
115  Q_D(GData);
116  QString urlString(QStringLiteral("http://www.blogger.com/feeds/") + blogId() + QStringLiteral("/posts/default"));
117  if (! labels.empty()) {
118  urlString += QStringLiteral("/-/") + labels.join(QLatin1Char('/'));
119  }
120  qCDebug(KBLOG_LOG) << "listRecentPosts()";
121  QUrl url(urlString);
122  QUrlQuery q;
123 
124  if (!upMinTime.isNull()) {
125  q.addQueryItem(QStringLiteral("updated-min"), upMinTime.toUTC().toString(QStringLiteral("yyyy-MM-ddTHH:mm:ssZ")));
126  }
127 
128  if (!upMaxTime.isNull()) {
129  q.addQueryItem(QStringLiteral("updated-max"), upMaxTime.toUTC().toString(QStringLiteral("yyyy-MM-ddTHH:mm:ssZ")));
130  }
131 
132  if (!pubMinTime.isNull()) {
133  q.addQueryItem(QStringLiteral("published-min"), pubMinTime.toUTC().toString(QStringLiteral("yyyy-MM-ddTHH:mm:ssZ")));
134  }
135 
136  if (!pubMaxTime.isNull()) {
137  q.addQueryItem(QStringLiteral("published-max"), pubMaxTime.toUTC().toString(QStringLiteral("yyyy-MM-ddTHH:mm:ssZ")));
138  }
139  url.setQuery(q);
140 
142  if (number > 0) {
143  d->mListRecentPostsMap[ loader ] = number;
144  }
145  connect(loader,
146  SIGNAL(loadingComplete(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)),
147  this,
148  SLOT(slotListRecentPosts(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)));
149  loader->loadFrom(url, new FeedRetriever);
150 }
151 
152 void GData::listRecentPosts(int number)
153 {
154  qCDebug(KBLOG_LOG);
155  listRecentPosts(QStringList(), number);
156 }
157 
159 {
160  qCDebug(KBLOG_LOG);
161  Q_D(GData);
163  d->mListCommentsMap[ loader ] = post;
164  connect(loader,
165  SIGNAL(loadingComplete(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)),
166  this,
167  SLOT(slotListComments(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)));
168  loader->loadFrom(QUrl(QStringLiteral("http://www.blogger.com/feeds/") + blogId() + QLatin1Char('/') +
169  post->postId() + QStringLiteral("/comments/default")), new FeedRetriever);
170 }
171 
173 {
174  qCDebug(KBLOG_LOG);
176  connect(loader,
177  SIGNAL(loadingComplete(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)),
178  this,
179  SLOT(slotListAllComments(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)));
180  loader->loadFrom(QUrl(QStringLiteral("http://www.blogger.com/feeds/%1/comments/default").arg(blogId())), new FeedRetriever);
181 }
182 
184 {
185  qCDebug(KBLOG_LOG);
186  Q_D(GData);
187 
188  if (!post) {
189  qCritical() << "post is null pointer";
190  return;
191  }
192 
193  qCDebug(KBLOG_LOG);
195  d->mFetchPostMap[ loader ] = post;
196  connect(loader,
197  SIGNAL(loadingComplete(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)),
198  this,
199  SLOT(slotFetchPost(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)));
200  loader->loadFrom(QUrl(QStringLiteral("http://www.blogger.com/feeds/%1/posts/default").arg(blogId())), new FeedRetriever);
201 }
202 
204 {
205  qCDebug(KBLOG_LOG);
206  Q_D(GData);
207 
208  if (!post) {
209  qCritical() << "post is null pointer";
210  return;
211  }
212 
213  if (!d->authenticate()) {
214  qCritical() << "Authentication failed.";
215  Q_EMIT errorPost(Atom, i18n("Authentication failed."), post);
216  return;
217  }
218 
219  QString atomMarkup = QStringLiteral("<entry xmlns='http://www.w3.org/2005/Atom'>");
220  atomMarkup += QStringLiteral("<id>tag:blogger.com,1999:blog-") + blogId();
221  atomMarkup += QStringLiteral(".post-") + post->postId() + QStringLiteral("</id>");
222  atomMarkup += QStringLiteral("<published>") + post->creationDateTime().toString() + QStringLiteral("</published>");
223  atomMarkup += QStringLiteral("<updated>") + post->modificationDateTime().toString() + QStringLiteral("</updated>");
224  atomMarkup += QStringLiteral("<title type='text'>") + post->title() + QStringLiteral("</title>");
225  if (post->isPrivate()) {
226  atomMarkup += QStringLiteral("<app:control xmlns:app='http://purl.org/atom/app#'>");
227  atomMarkup += QStringLiteral("<app:draft>yes</app:draft></app:control>");
228  }
229  atomMarkup += QStringLiteral("<content type='xhtml'>");
230  atomMarkup += QStringLiteral("<div xmlns='http://www.w3.org/1999/xhtml'>");
231  atomMarkup += post->content();
232  atomMarkup += QStringLiteral("</div></content>");
233  const auto tags = post->tags();
234  for (const QString &tag : tags) {
235  atomMarkup += QStringLiteral("<category scheme='http://www.blogger.com/atom/ns#' term='") + tag + QStringLiteral("' />");
236  }
237  atomMarkup += QStringLiteral("<author>");
238  if (!fullName().isEmpty()) {
239  atomMarkup += QStringLiteral("<name>") + fullName() + QStringLiteral("</name>");
240  }
241  atomMarkup += QStringLiteral("<email>") + username() + QStringLiteral("</email>");
242  atomMarkup += QStringLiteral("</author>");
243  atomMarkup += QStringLiteral("</entry>");
244  QByteArray postData;
245  QDataStream stream(&postData, QIODevice::WriteOnly);
246  stream.writeRawData(atomMarkup.toUtf8().constData(), atomMarkup.toUtf8().length());
247 
249  QUrl(QStringLiteral("http://www.blogger.com/feeds/") + blogId() + QStringLiteral("/posts/default/") + post->postId()),
251 
252  Q_ASSERT(job);
253 
254  d->mModifyPostMap[ job ] = post;
255 
256  job->addMetaData(QStringLiteral("content-type"), QStringLiteral("Content-Type: application/atom+xml; charset=utf-8"));
257  job->addMetaData(QStringLiteral("ConnectTimeout"), QStringLiteral("50"));
258  job->addMetaData(QStringLiteral("UserAgent"), userAgent());
259  job->addMetaData(QStringLiteral("customHTTPHeader"),
260  QStringLiteral("Authorization: GoogleLogin auth=") + d->mAuthenticationString +
261  QStringLiteral("\r\nX-HTTP-Method-Override: PUT"));
262 
263  connect(job, SIGNAL(result(KJob*)),
264  this, SLOT(slotModifyPost(KJob*)));
265 }
266 
268 {
269  qCDebug(KBLOG_LOG);
270  Q_D(GData);
271 
272  if (!post) {
273  qCritical() << "post is null pointer";
274  return;
275  }
276 
277  if (!d->authenticate()) {
278  qCritical() << "Authentication failed.";
279  Q_EMIT errorPost(Atom, i18n("Authentication failed."), post);
280  return;
281  }
282 
283  QString atomMarkup = QStringLiteral("<entry xmlns='http://www.w3.org/2005/Atom'>");
284  atomMarkup += QStringLiteral("<title type='text'>") + post->title() + QStringLiteral("</title>");
285  if (post->isPrivate()) {
286  atomMarkup += QStringLiteral("<app:control xmlns:app='http://purl.org/atom/app#'>");
287  atomMarkup += QStringLiteral("<app:draft>yes</app:draft></app:control>");
288  }
289  atomMarkup += QStringLiteral("<content type='xhtml'>");
290  atomMarkup += QStringLiteral("<div xmlns='http://www.w3.org/1999/xhtml'>");
291  atomMarkup += post->content(); // FIXME check for Utf
292  atomMarkup += QStringLiteral("</div></content>");
295  for (; it != end; ++it) {
296  atomMarkup += QStringLiteral("<category scheme='http://www.blogger.com/atom/ns#' term='") + (*it) + QStringLiteral("' />");
297  }
298  atomMarkup += QStringLiteral("<author>");
299  if (!fullName().isEmpty()) {
300  atomMarkup += QStringLiteral("<name>") + fullName() + QStringLiteral("</name>");
301  }
302  atomMarkup += QStringLiteral("<email>") + username() + QStringLiteral("</email>");
303  atomMarkup += QStringLiteral("</author>");
304  atomMarkup += QStringLiteral("</entry>");
305 
306  QByteArray postData;
307  QDataStream stream(&postData, QIODevice::WriteOnly);
308  stream.writeRawData(atomMarkup.toUtf8().constData(), atomMarkup.toUtf8().length());
309 
311  QUrl(QStringLiteral("http://www.blogger.com/feeds/") + blogId() + QStringLiteral("/posts/default")),
313 
314  Q_ASSERT(job);
315  d->mCreatePostMap[ job ] = post;
316 
317  job->addMetaData(QStringLiteral("content-type"), QStringLiteral("Content-Type: application/atom+xml; charset=utf-8"));
318  job->addMetaData(QStringLiteral("ConnectTimeout"), QStringLiteral("50"));
319  job->addMetaData(QStringLiteral("UserAgent"), userAgent());
320  job->addMetaData(QStringLiteral("customHTTPHeader"),
321  QStringLiteral("Authorization: GoogleLogin auth=") + d->mAuthenticationString);
322 
323  connect(job, SIGNAL(result(KJob*)),
324  this, SLOT(slotCreatePost(KJob*)));
325 }
326 
328 {
329  qCDebug(KBLOG_LOG);
330  Q_D(GData);
331 
332  if (!post) {
333  qCritical() << "post is null pointer";
334  return;
335  }
336 
337  if (!d->authenticate()) {
338  qCritical() << "Authentication failed.";
339  Q_EMIT errorPost(Atom, i18n("Authentication failed."), post);
340  return;
341  }
342 
343  QByteArray postData;
344 
346  QUrl(QStringLiteral("http://www.blogger.com/feeds/") + blogId() + QStringLiteral("/posts/default/") + post->postId()),
348  if (!job) {
349  qCWarning(KBLOG_LOG) << "Unable to create KIO job for http://www.blogger.com/feeds/"
350  << blogId() << QStringLiteral("/posts/default/") + post->postId();
351  return;
352  }
353 
354  d->mRemovePostMap[ job ] = post;
355 
356 
357  job->addMetaData(QStringLiteral("ConnectTimeout"), QStringLiteral("50"));
358  job->addMetaData(QStringLiteral("UserAgent"), userAgent());
359  job->addMetaData(QStringLiteral("customHTTPHeader"),
360  QStringLiteral("Authorization: GoogleLogin auth=") + d->mAuthenticationString +
361  QStringLiteral("\r\nX-HTTP-Method-Override: DELETE"));
362 
363  connect(job, SIGNAL(result(KJob*)),
364  this, SLOT(slotRemovePost(KJob*)));
365 }
366 
368 {
369  qCDebug(KBLOG_LOG);
370 
371  if (!comment) {
372  qCritical() << "comment is null pointer";
373  return;
374  }
375 
376  if (!post) {
377  qCritical() << "post is null pointer";
378  return;
379  }
380 
381  Q_D(GData);
382  if (!d->authenticate()) {
383  qCritical() << "Authentication failed.";
384  Q_EMIT errorComment(Atom, i18n("Authentication failed."), post, comment);
385  return;
386  }
387  QString atomMarkup = QStringLiteral("<entry xmlns='http://www.w3.org/2005/Atom'>");
388  atomMarkup += QStringLiteral("<title type=\"text\">") + comment->title() + QStringLiteral("</title>");
389  atomMarkup += QStringLiteral("<content type=\"html\">") + comment->content() + QStringLiteral("</content>");
390  atomMarkup += QStringLiteral("<author>");
391  atomMarkup += QStringLiteral("<name>") + comment->name() + QStringLiteral("</name>");
392  atomMarkup += QStringLiteral("<email>") + comment->email() + QStringLiteral("</email>");
393  atomMarkup += QStringLiteral("</author></entry>");
394 
395  QByteArray postData;
396  qCDebug(KBLOG_LOG) << postData;
397  QDataStream stream(&postData, QIODevice::WriteOnly);
398  stream.writeRawData(atomMarkup.toUtf8().constData(), atomMarkup.toUtf8().length());
399 
401  QUrl(QStringLiteral("http://www.blogger.com/feeds/") + blogId() + QStringLiteral("/") + post->postId() + QStringLiteral("/comments/default")),
403 
404  if (!job) {
405  qCWarning(KBLOG_LOG) << "Unable to create KIO job for http://www.blogger.com/feeds/"
406  << blogId() << "/" << post->postId() << "/comments/default";
407  return;
408  }
409  d->mCreateCommentMap[ job ][post] = comment;
410 
411 
412  job->addMetaData(QStringLiteral("content-type"), QStringLiteral("Content-Type: application/atom+xml; charset=utf-8"));
413  job->addMetaData(QStringLiteral("ConnectTimeout"), QStringLiteral("50"));
414  job->addMetaData(QStringLiteral("customHTTPHeader"),
415  QStringLiteral("Authorization: GoogleLogin auth=") + d->mAuthenticationString);
416  job->addMetaData(QStringLiteral("UserAgent"), userAgent());
417 
418  connect(job, SIGNAL(result(KJob*)),
419  this, SLOT(slotCreateComment(KJob*)));
420 }
421 
423 {
424  qCDebug(KBLOG_LOG);
425  Q_D(GData);
426  qCDebug(KBLOG_LOG);
427 
428  if (!comment) {
429  qCritical() << "comment is null pointer";
430  return;
431  }
432 
433  if (!post) {
434  qCritical() << "post is null pointer";
435  return;
436  }
437 
438  if (!d->authenticate()) {
439  qCritical() << "Authentication failed.";
440  Q_EMIT errorComment(Atom, i18n("Authentication failed."), post, comment);
441  return;
442  }
443 
444  QByteArray postData;
445 
447  QUrl(QStringLiteral("http://www.blogger.com/feeds/") + blogId() + QStringLiteral("/") + post->postId() +
448  QStringLiteral("/comments/default/") + comment->commentId()), KIO::HideProgressInfo);
449  d->mRemoveCommentMap[ job ][ post ] = comment;
450 
451  if (!job) {
452  qCWarning(KBLOG_LOG) << "Unable to create KIO job for http://www.blogger.com/feeds/"
453  << blogId() << post->postId()
454  << "/comments/default/" << comment->commentId();
455  }
456 
457  job->addMetaData(QStringLiteral("ConnectTimeout"), QStringLiteral("50"));
458  job->addMetaData(QStringLiteral("UserAgent"), userAgent());
459  job->addMetaData(QStringLiteral("customHTTPHeader"),
460  QStringLiteral("Authorization: GoogleLogin auth=") +
461  d->mAuthenticationString + QStringLiteral("\r\nX-HTTP-Method-Override: DELETE"));
462 
463  connect(job, SIGNAL(result(KJob*)),
464  this, SLOT(slotRemoveComment(KJob*)));
465 }
466 
467 GDataPrivate::GDataPrivate(): mAuthenticationString(), mAuthenticationTime()
468 {
469  qCDebug(KBLOG_LOG);
470 }
471 
472 GDataPrivate::~GDataPrivate()
473 {
474  qCDebug(KBLOG_LOG);
475 }
476 
477 bool GDataPrivate::authenticate()
478 {
479  qCDebug(KBLOG_LOG);
480  Q_Q(GData);
481  QByteArray data;
482  QUrl authGateway(QStringLiteral("https://www.google.com/accounts/ClientLogin"));
483  QUrlQuery query;
484  query.addQueryItem(QStringLiteral("Email"), q->username());
485  query.addQueryItem(QStringLiteral("Passwd"), q->password());
486  query.addQueryItem(QStringLiteral("source"), q->userAgent());
487  query.addQueryItem(QStringLiteral("service"), QStringLiteral("blogger"));
488  authGateway.setQuery(query);
489  if (!mAuthenticationTime.isValid() ||
490  QDateTime::currentDateTime().currentSecsSinceEpoch() - mAuthenticationTime.currentSecsSinceEpoch() > TIMEOUT ||
491  mAuthenticationString.isEmpty()) {
494  q, [&data](KIO::Job *, const QByteArray &newdata) {
495  data.reserve(data.size() + newdata.size());
496  memcpy(data.data() + data.size(), newdata.data(), newdata.size());
497  });
498  if (job->exec()) {
499  QRegExp rx(QStringLiteral("Auth=(.+)"));
500  if (rx.indexIn(QLatin1String(data)) != -1) {
501  qCDebug(KBLOG_LOG) << "RegExp got authentication string:" << rx.cap(1);
502  mAuthenticationString = rx.cap(1);
503  mAuthenticationTime = QDateTime::currentDateTime();
504  return true;
505  }
506  }
507  return false;
508  }
509  return true;
510 }
511 
512 void GDataPrivate::slotFetchProfileId(KJob *job)
513 {
514  qCDebug(KBLOG_LOG);
515  if (!job) {
516  qCritical() << "job is a null pointer.";
517  return;
518  }
519  Q_Q(GData);
521  const QString data = QString::fromUtf8(stj->data().constData(), stj->data().size());
522  if (!job->error()) {
523  QRegExp pid(QStringLiteral("http://www.blogger.com/profile/(\\d+)"));
524  if (pid.indexIn(data) != -1) {
525  q->setProfileId(pid.cap(1));
526  qCDebug(KBLOG_LOG) << "QRegExp bid( 'http://www.blogger.com/profile/(\\d+)' matches" << pid.cap(1);
527  Q_EMIT q->fetchedProfileId(pid.cap(1));
528  } else {
529  qCritical() << "QRegExp bid( 'http://www.blogger.com/profile/(\\d+)' "
530  << " could not regexp the Profile ID";
531  Q_EMIT q->error(GData::Other, i18n("Could not regexp the Profile ID."));
532  Q_EMIT q->fetchedProfileId(QString());
533  }
534  } else {
535  qCritical() << "Job Error: " << job->errorString();
536  Q_EMIT q->error(GData::Other, job->errorString());
537  Q_EMIT q->fetchedProfileId(QString());
538  }
539 }
540 
541 void GDataPrivate::slotListBlogs(Syndication::Loader *loader,
542  const Syndication::FeedPtr &feed,
543  Syndication::ErrorCode status)
544 {
545  qCDebug(KBLOG_LOG);
546  Q_Q(GData);
547  if (!loader) {
548  qCritical() << "loader is a null pointer.";
549  return;
550  }
551  if (status != Syndication::Success) {
552  Q_EMIT q->error(GData::Atom, i18n("Could not get blogs."));
553  return;
554  }
555 
556  QList<QMap<QString, QString> > blogsList;
557 
558  QList<Syndication::ItemPtr> items = feed->items();
561  for (; it != end; ++it) {
562  QRegExp rx(QStringLiteral("blog-(\\d+)"));
563  QMap<QString, QString> blogInfo;
564  if (rx.indexIn((*it)->id()) != -1) {
565  qCDebug(KBLOG_LOG) << "QRegExp rx( 'blog-(\\d+)' matches" << rx.cap(1);
566  blogInfo[QStringLiteral("id")] = rx.cap(1);
567  blogInfo[QStringLiteral("title")] = (*it)->title();
568  blogInfo[QStringLiteral("url")] = (*it)->link();
569  blogInfo[QStringLiteral("summary")] = (*it)->description(); //TODO fix/add more
570  blogsList << blogInfo;
571  } else {
572  qCritical() << "QRegExp rx( 'blog-(\\d+)' does not match anything in:"
573  << (*it)->id();
574  Q_EMIT q->error(GData::Other, i18n("Could not regexp the blog id path."));
575  }
576  }
577  qCDebug(KBLOG_LOG) << "Emitting listedBlogs(); ";
578  Q_EMIT q->listedBlogs(blogsList);
579 }
580 
581 void GDataPrivate::slotListComments(Syndication::Loader *loader,
582  const Syndication::FeedPtr &feed,
583  Syndication::ErrorCode status)
584 {
585  qCDebug(KBLOG_LOG);
586  Q_Q(GData);
587  if (!loader) {
588  qCritical() << "loader is a null pointer.";
589  return;
590  }
591  BlogPost *post = mListCommentsMap[ loader ];
592  mListCommentsMap.remove(loader);
593 
594  if (status != Syndication::Success) {
595  Q_EMIT q->errorPost(GData::Atom, i18n("Could not get comments."), post);
596  return;
597  }
598 
599  QList<KBlog::BlogComment> commentList;
600 
601  QList<Syndication::ItemPtr> items = feed->items();
604  for (; it != end; ++it) {
605  BlogComment comment;
606  QRegExp rx(QStringLiteral("post-(\\d+)"));
607  if (rx.indexIn((*it)->id()) == -1) {
608  qCritical() << "QRegExp rx( 'post-(\\d+)' does not match" << rx.cap(1);
609  Q_EMIT q->error(GData::Other, i18n("Could not regexp the comment id path."));
610  } else {
611  comment.setCommentId(rx.cap(1));
612  }
613  qCDebug(KBLOG_LOG) << "QRegExp rx( 'post-(\\d+)' matches" << rx.cap(1);
614  comment.setTitle((*it)->title());
615  comment.setContent((*it)->content());
616 // FIXME: assuming UTC for now
617  comment.setCreationDateTime(QDateTime::fromSecsSinceEpoch((*it)->datePublished()));
618  comment.setModificationDateTime(QDateTime::fromSecsSinceEpoch((*it)->dateUpdated()));
619  commentList.append(comment);
620  }
621  qCDebug(KBLOG_LOG) << "Emitting listedComments()";
622  Q_EMIT q->listedComments(post, commentList);
623 }
624 
625 void GDataPrivate::slotListAllComments(Syndication::Loader *loader,
626  const Syndication::FeedPtr &feed,
627  Syndication::ErrorCode status)
628 {
629  qCDebug(KBLOG_LOG);
630  Q_Q(GData);
631  if (!loader) {
632  qCritical() << "loader is a null pointer.";
633  return;
634  }
635 
636  if (status != Syndication::Success) {
637  Q_EMIT q->error(GData::Atom, i18n("Could not get comments."));
638  return;
639  }
640 
641  QList<KBlog::BlogComment> commentList;
642 
643  QList<Syndication::ItemPtr> items = feed->items();
646  for (; it != end; ++it) {
647  BlogComment comment;
648  QRegExp rx(QStringLiteral("post-(\\d+)"));
649  if (rx.indexIn((*it)->id()) == -1) {
650  qCritical() << "QRegExp rx( 'post-(\\d+)' does not match" << rx.cap(1);
651  Q_EMIT q->error(GData::Other, i18n("Could not regexp the comment id path."));
652  } else {
653  comment.setCommentId(rx.cap(1));
654  }
655 
656  qCDebug(KBLOG_LOG) << "QRegExp rx( 'post-(\\d+)' matches" << rx.cap(1);
657  comment.setTitle((*it)->title());
658  comment.setContent((*it)->content());
659 // FIXME: assuming UTC for now
660  comment.setCreationDateTime(QDateTime::fromSecsSinceEpoch((*it)->datePublished()));
661  comment.setModificationDateTime(QDateTime::fromSecsSinceEpoch((*it)->dateUpdated()));
662  commentList.append(comment);
663  }
664  qCDebug(KBLOG_LOG) << "Emitting listedAllComments()";
665  Q_EMIT q->listedAllComments(commentList);
666 }
667 
668 void GDataPrivate::slotListRecentPosts(Syndication::Loader *loader,
669  const Syndication::FeedPtr &feed,
670  Syndication::ErrorCode status)
671 {
672  qCDebug(KBLOG_LOG);
673  Q_Q(GData);
674  if (!loader) {
675  qCritical() << "loader is a null pointer.";
676  return;
677  }
678 
679  if (status != Syndication::Success) {
680  Q_EMIT q->error(GData::Atom, i18n("Could not get posts."));
681  return;
682  }
683  int number = 0;
684 
685  if (mListRecentPostsMap.contains(loader)) {
686  number = mListRecentPostsMap[ loader ];
687  }
688  mListRecentPostsMap.remove(loader);
689 
690  QList<KBlog::BlogPost> postList;
691 
692  QList<Syndication::ItemPtr> items = feed->items();
695  for (; it != end; ++it) {
696  BlogPost post;
697  QRegExp rx(QStringLiteral("post-(\\d+)"));
698  if (rx.indexIn((*it)->id()) == -1) {
699  qCritical() << "QRegExp rx( 'post-(\\d+)' does not match" << rx.cap(1);
700  Q_EMIT q->error(GData::Other, i18n("Could not regexp the post id path."));
701  } else {
702  post.setPostId(rx.cap(1));
703  }
704 
705  qCDebug(KBLOG_LOG) << "QRegExp rx( 'post-(\\d+)' matches" << rx.cap(1);
706  post.setTitle((*it)->title());
707  post.setContent((*it)->content());
708  post.setLink(QUrl((*it)->link()));
709  QStringList labels;
710  int catCount = (*it)->categories().count();
711  QList< Syndication::CategoryPtr > cats = (*it)->categories();
712  for (int i = 0; i < catCount; ++i) {
713  if (cats[i]->label().isEmpty()) {
714  labels.append(cats[i]->term());
715  } else {
716  labels.append(cats[i]->label());
717  }
718  }
719  post.setTags(labels);
720 // FIXME: assuming UTC for now
721  post.setCreationDateTime(QDateTime::fromSecsSinceEpoch((*it)->datePublished()));
722  post.setModificationDateTime(QDateTime::fromSecsSinceEpoch((*it)->dateUpdated()));
724  postList.append(post);
725  if (number-- == 0) {
726  break;
727  }
728  }
729  qCDebug(KBLOG_LOG) << "Emitting listedRecentPosts()";
730  Q_EMIT q->listedRecentPosts(postList);
731 }
732 
733 void GDataPrivate::slotFetchPost(Syndication::Loader *loader,
734  const Syndication::FeedPtr &feed,
735  Syndication::ErrorCode status)
736 {
737  qCDebug(KBLOG_LOG);
738  Q_Q(GData);
739  if (!loader) {
740  qCritical() << "loader is a null pointer.";
741  return;
742  }
743 
744  bool success = false;
745 
746  BlogPost *post = mFetchPostMap.take(loader);
747  qCritical() << "Post" << post;
748  post->postId();
749 
750  if (status != Syndication::Success) {
751  Q_EMIT q->errorPost(GData::Atom, i18n("Could not get posts."), post);
752  return;
753  }
754 
755  QString postId = post->postId();
756  QList<Syndication::ItemPtr> items = feed->items();
759  for (; it != end; ++it) {
760  QRegExp rx(QStringLiteral("post-(\\d+)"));
761  if (rx.indexIn((*it)->id()) != -1 &&
762  rx.cap(1) == postId) {
763  qCDebug(KBLOG_LOG) << "QRegExp rx( 'post-(\\d+)' matches" << rx.cap(1);
764  post->setPostId(rx.cap(1));
765  post->setTitle((*it)->title());
766  post->setContent((*it)->content());
768  post->setLink(QUrl((*it)->link()));
769  post->setCreationDateTime(QDateTime::fromSecsSinceEpoch((*it)->datePublished()).toLocalTime());
770  post->setModificationDateTime(QDateTime::fromSecsSinceEpoch((*it)->dateUpdated()).toLocalTime());
771  qCDebug(KBLOG_LOG) << "Emitting fetchedPost( postId=" << postId << ");";
772  success = true;
773  Q_EMIT q->fetchedPost(post);
774  break;
775  }
776  }
777  if (!success) {
778  qCritical() << "QRegExp rx( 'post-(\\d+)' does not match"
779  << mFetchPostMap[ loader ]->postId() << ".";
780  Q_EMIT q->errorPost(GData::Other, i18n("Could not regexp the blog id path."), post);
781  }
782 }
783 
784 void GDataPrivate::slotCreatePost(KJob *job)
785 {
786  qCDebug(KBLOG_LOG);
787  if (!job) {
788  qCritical() << "job is a null pointer.";
789  return;
790  }
792  const QString data = QString::fromUtf8(stj->data().constData(), stj->data().size());
793 
794  Q_Q(GData);
795 
796  KBlog::BlogPost *post = mCreatePostMap[ job ];
797  mCreatePostMap.remove(job);
798 
799  if (job->error() != 0) {
800  qCritical() << "slotCreatePost error:" << job->errorString();
801  Q_EMIT q->errorPost(GData::Atom, job->errorString(), post);
802  return;
803  }
804 
805  QRegExp rxId(QStringLiteral("post-(\\d+)")); //FIXME check and do better handling, esp the creation date time
806  if (rxId.indexIn(data) == -1) {
807  qCritical() << "Could not regexp the id out of the result:" << data;
808  Q_EMIT q->errorPost(GData::Atom,
809  i18n("Could not regexp the id out of the result."), post);
810  return;
811  }
812  qCDebug(KBLOG_LOG) << "QRegExp rx( 'post-(\\d+)' ) matches" << rxId.cap(1);
813 
814  QRegExp rxPub(QStringLiteral("<published>(.+)</published>"));
815  if (rxPub.indexIn(data) == -1) {
816  qCritical() << "Could not regexp the published time out of the result:" << data;
817  Q_EMIT q->errorPost(GData::Atom,
818  i18n("Could not regexp the published time out of the result."), post);
819  return;
820  }
821  qCDebug(KBLOG_LOG) << "QRegExp rx( '<published>(.+)</published>' ) matches" << rxPub.cap(1);
822 
823  QRegExp rxUp(QStringLiteral("<updated>(.+)</updated>"));
824  if (rxUp.indexIn(data) == -1) {
825  qCritical() << "Could not regexp the update time out of the result:" << data;
826  Q_EMIT q->errorPost(GData::Atom,
827  i18n("Could not regexp the update time out of the result."), post);
828  return;
829  }
830  qCDebug(KBLOG_LOG) << "QRegExp rx( '<updated>(.+)</updated>' ) matches" << rxUp.cap(1);
831 
832  post->setPostId(rxId.cap(1));
836  qCDebug(KBLOG_LOG) << "Emitting createdPost()";
837  Q_EMIT q->createdPost(post);
838 }
839 
840 void GDataPrivate::slotModifyPost(KJob *job)
841 {
842  qCDebug(KBLOG_LOG);
843  if (!job) {
844  qCritical() << "job is a null pointer.";
845  return;
846  }
848  const QString data = QString::fromUtf8(stj->data().constData(), stj->data().size());
849 
850  KBlog::BlogPost *post = mModifyPostMap[ job ];
851  mModifyPostMap.remove(job);
852  Q_Q(GData);
853  if (job->error() != 0) {
854  qCritical() << "slotModifyPost error:" << job->errorString();
855  Q_EMIT q->errorPost(GData::Atom, job->errorString(), post);
856  return;
857  }
858 
859  QRegExp rxId(QStringLiteral("post-(\\d+)")); //FIXME check and do better handling, esp creation date time
860  if (rxId.indexIn(data) == -1) {
861  qCritical() << "Could not regexp the id out of the result:" << data;
862  Q_EMIT q->errorPost(GData::Atom,
863  i18n("Could not regexp the id out of the result."), post);
864  return;
865  }
866  qCDebug(KBLOG_LOG) << "QRegExp rx( 'post-(\\d+)' ) matches" << rxId.cap(1);
867 
868  QRegExp rxPub(QStringLiteral("<published>(.+)</published>"));
869  if (rxPub.indexIn(data) == -1) {
870  qCritical() << "Could not regexp the published time out of the result:" << data;
871  Q_EMIT q->errorPost(GData::Atom,
872  i18n("Could not regexp the published time out of the result."), post);
873  return;
874  }
875  qCDebug(KBLOG_LOG) << "QRegExp rx( '<published>(.+)</published>' ) matches" << rxPub.cap(1);
876 
877  QRegExp rxUp(QStringLiteral("<updated>(.+)</updated>"));
878  if (rxUp.indexIn(data) == -1) {
879  qCritical() << "Could not regexp the update time out of the result:" << data;
880  Q_EMIT q->errorPost(GData::Atom,
881  i18n("Could not regexp the update time out of the result."), post);
882  return;
883  }
884  qCDebug(KBLOG_LOG) << "QRegExp rx( '<updated>(.+)</updated>' ) matches" << rxUp.cap(1);
885  post->setPostId(rxId.cap(1));
886  post->setCreationDateTime(QDateTime::fromString(rxPub.cap(1)));
887  post->setModificationDateTime(QDateTime::fromString(rxUp.cap(1)));
888  post->setStatus(BlogPost::Modified);
889  Q_EMIT q->modifiedPost(post);
890 }
891 
892 void GDataPrivate::slotRemovePost(KJob *job)
893 {
894  qCDebug(KBLOG_LOG);
895  if (!job) {
896  qCritical() << "job is a null pointer.";
897  return;
898  }
900  const QString data = QString::fromUtf8(stj->data().constData(), stj->data().size());
901 
902  KBlog::BlogPost *post = mRemovePostMap[ job ];
903  mRemovePostMap.remove(job);
904  Q_Q(GData);
905  if (job->error() != 0) {
906  qCritical() << "slotRemovePost error:" << job->errorString();
907  Q_EMIT q->errorPost(GData::Atom, job->errorString(), post);
908  return;
909  }
910 
911  post->setStatus(BlogPost::Removed);
912  qCDebug(KBLOG_LOG) << "Emitting removedPost()";
913  Q_EMIT q->removedPost(post);
914 }
915 
916 void GDataPrivate::slotCreateComment(KJob *job)
917 {
918  qCDebug(KBLOG_LOG);
919  if (!job) {
920  qCritical() << "job is a null pointer.";
921  return;
922  }
924  const QString data = QString::fromUtf8(stj->data().constData(), stj->data().size());
925  qCDebug(KBLOG_LOG) << "Dump data: " << data;
926 
927  Q_Q(GData);
928 
929  KBlog::BlogComment *comment = mCreateCommentMap[ job ].cbegin().value();
930  KBlog::BlogPost *post = mCreateCommentMap[ job ].cbegin().key();
931  mCreateCommentMap.remove(job);
932 
933  if (job->error() != 0) {
934  qCritical() << "slotCreateComment error:" << job->errorString();
935  Q_EMIT q->errorComment(GData::Atom, job->errorString(), post, comment);
936  return;
937  }
938 
939 // TODO check for result and fit appropriately
940  QRegExp rxId(QStringLiteral("post-(\\d+)"));
941  if (rxId.indexIn(data) == -1) {
942  qCritical() << "Could not regexp the id out of the result:" << data;
943  Q_EMIT q->errorPost(GData::Atom,
944  i18n("Could not regexp the id out of the result."), post);
945  return;
946  }
947  qCDebug(KBLOG_LOG) << "QRegExp rx( 'post-(\\d+)' ) matches" << rxId.cap(1);
948 
949  QRegExp rxPub(QStringLiteral("<published>(.+)</published>"));
950  if (rxPub.indexIn(data) == -1) {
951  qCritical() << "Could not regexp the published time out of the result:" << data;
952  Q_EMIT q->errorPost(GData::Atom,
953  i18n("Could not regexp the published time out of the result."), post);
954  return;
955  }
956  qCDebug(KBLOG_LOG) << "QRegExp rx( '<published>(.+)</published>' ) matches" << rxPub.cap(1);
957 
958  QRegExp rxUp(QStringLiteral("<updated>(.+)</updated>"));
959  if (rxUp.indexIn(data) == -1) {
960  qCritical() << "Could not regexp the update time out of the result:" << data;
961  Q_EMIT q->errorPost(GData::Atom,
962  i18n("Could not regexp the update time out of the result."), post);
963  return;
964  }
965  qCDebug(KBLOG_LOG) << "QRegExp rx( '<updated>(.+)</updated>' ) matches" << rxUp.cap(1);
966  comment->setCommentId(rxId.cap(1));
967  comment->setCreationDateTime(QDateTime::fromString(rxPub.cap(1)));
970  qCDebug(KBLOG_LOG) << "Emitting createdComment()";
971  Q_EMIT q->createdComment(post, comment);
972 }
973 
974 void GDataPrivate::slotRemoveComment(KJob *job)
975 {
976  qCDebug(KBLOG_LOG);
977  if (!job) {
978  qCritical() << "job is a null pointer.";
979  return;
980  }
982  const QString data = QString::fromUtf8(stj->data().constData(), stj->data().size());
983 
984  Q_Q(GData);
985 
986  KBlog::BlogComment *comment = mRemoveCommentMap[ job ].cbegin().value();
987  KBlog::BlogPost *post = mRemoveCommentMap[ job ].cbegin().key();
988  mRemoveCommentMap.remove(job);
989 
990  if (job->error() != 0) {
991  qCritical() << "slotRemoveComment error:" << job->errorString();
992  Q_EMIT q->errorComment(GData::Atom, job->errorString(), post, comment);
993  return;
994  }
995 
997  qCDebug(KBLOG_LOG) << "Emitting removedComment()";
998  Q_EMIT q->removedComment(post, comment);
999 }
1000 
1001 #include "moc_gdata.cpp"
QString title() const
Returns the title.
Definition: blogpost.cpp:152
QString toString(Qt::DateFormat format) const const
QString cap(int nth) const const
void setStatus(Status status)
Sets the status.
void setCreationDateTime(const QDateTime &datetime)
Sets the creation time.
Definition: blogpost.cpp:311
QDateTime toUTC() const const
void addMetaData(const QString &key, const QString &value)
Status of a successfully fetched post.
Definition: blogpost.h:395
void reserve(int size)
void setLink(const QUrl &link) const
Set the link path.
Definition: blogpost.cpp:209
virtual void listBlogs()
List the blogs available for this authentication on the server.
Definition: gdata.cpp:99
void setCommentId(const QString &id)
Sets the comment&#39;s id.
Definition: blogcomment.cpp:83
QStringList tags() const
Returns the tags list as a QStringList.
Definition: blogpost.cpp:254
KIOCORE_EXPORT StoredTransferJob * storedHttpPost(const QByteArray &arr, const QUrl &url, JobFlags flags=DefaultFlags)
virtual QString errorString() const
void modifyPost(KBlog::BlogPost *post) override
Modify a post on server.
Definition: gdata.cpp:203
HideProgressInfo
QString profileId() const
Returns the profile id of the blog.
Definition: gdata.cpp:76
bool exec()
Status of a successfully created post.
Definition: blogpost.h:398
A class that can be used for access to GData blogs.
Definition: gdata.h:71
QString interfaceName() const override
Returns the of the inherited object.
Definition: gdata.cpp:57
void setModificationDateTime(const QDateTime &datetime)
Sets the modification date-time.
QDateTime fromSecsSinceEpoch(qint64 secs, Qt::TimeSpec spec, int offsetSeconds)
QString join(const QString &separator) const const
int length() const const
QString & remove(int position, int n)
~GData()
Destructor.
Definition: gdata.cpp:52
void createPost(KBlog::BlogPost *post) override
Create a new post on server.
Definition: gdata.cpp:267
QByteArray data() const
QDateTime creationDateTime() const
Returns the creation date time.
Definition: blogpost.cpp:306
QString email() const
Returns the E-Mail address of the commentator.
Definition: blogcomment.cpp:88
QString commentId() const
Returns the comment&#39;s id.
Definition: blogcomment.cpp:78
void setTitle(const QString &title)
Sets the title.
Definition: blogpost.cpp:157
QDateTime modificationDateTime() const
Returns the modification date time.
Definition: blogpost.cpp:316
virtual void removeComment(KBlog::BlogPost *post, KBlog::BlogComment *comment)
Remove a comment from the server.
Definition: gdata.cpp:422
void setPostId(const QString &postId)
Sets the post id value.
Definition: blogpost.cpp:147
QString username() const
Returns the username used in blog authentication.
Definition: blog.cpp:90
int indexIn(const QString &str, int offset, QRegExp::CaretMode caretMode) const const
virtual void listAllComments()
List the all comments available for this authentication on the server.
Definition: gdata.cpp:172
void addQueryItem(const QString &key, const QString &value)
int count(const T &value) const const
void append(const T &value)
QString fromUtf8(const char *str, int size)
A class that represents a blog comment on the blog post.
Definition: blogcomment.h:51
bool empty() const const
void setContent(const QString &content)
Sets the content.
Definition: blogcomment.cpp:73
virtual void setProfileId(const QString &pid)
Get the profile&#39;s id of the blog.
Definition: gdata.cpp:82
QString title() const
Returns the title.
Definition: blogcomment.cpp:58
This file is part of the for accessing Blog Servers and defines the GData class.
virtual void createComment(KBlog::BlogPost *post, KBlog::BlogComment *comment)
Create a comment on the server.
Definition: gdata.cpp:367
GData(const QUrl &server, QObject *parent=nullptr)
Create an object for GData.
Definition: gdata.cpp:45
void errorPost(KBlog::Blog::ErrorType type, const QString &errorMessage, KBlog::BlogPost *post)
This signal is emitted when an error occurs with XML parsing or a structural problem in an operation ...
virtual void setFullName(const QString &fullName)
Sets the user&#39;s name for the blog.
Definition: gdata.cpp:69
const char * constData() const const
QString name() const
Returns the commentator&#39;s name.
Definition: blogcomment.cpp:98
void setContent(const QString &content)
Sets the content.
Definition: blogpost.cpp:167
QString blogId() const
Returns the unique ID for the specific blog on the server.
Definition: blog.cpp:108
KIOCORE_EXPORT StoredTransferJob * storedGet(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
void setStatus(Status status)
Sets the status.
Definition: blogpost.cpp:331
Status of a successfully modified post.
Definition: blogpost.h:401
void loadFrom(const QUrl &url, DataRetriever *retriever)
virtual void setUrl(const QUrl &url)
Sets the URL for the blog&#39;s XML-RPC interface.
Definition: blog.cpp:114
QString fullName() const
Returns the full name of user of the blog.
Definition: gdata.cpp:63
QString content() const
Returns the content.
Definition: blogpost.cpp:162
QDateTime fromString(const QString &string, Qt::DateFormat format)
virtual void listComments(KBlog::BlogPost *post)
List the comments available for this post on the server.
Definition: gdata.cpp:158
QString content() const
Returns the content.
Definition: blogcomment.cpp:68
QString i18n(const char *text, const TYPE &arg...)
Namespace for blog related classes.
Definition: blog.h:53
void data(KIO::Job *job, const QByteArray &data)
QDateTime currentDateTime()
bool isNull() const const
An error in the syndication client.
Definition: blog.h:102
A class that represents a blog post on the server.
Definition: blogpost.h:65
void removePost(KBlog::BlogPost *post) override
Remove a post from the server.
Definition: gdata.cpp:327
void fetchPost(KBlog::BlogPost *post) override
Fetch the Post with a specific id.
Definition: gdata.cpp:183
int writeRawData(const char *s, int len)
Status of a successfully created comment.
Definition: blogcomment.h:210
char * data()
void setQuery(const QString &query, QUrl::ParsingMode mode)
void setTitle(const QString &title)
Sets the title.
Definition: blogcomment.cpp:63
void listRecentPosts(int number) override
List recent posts on the server.
Definition: gdata.cpp:152
void fetchProfileId()
Get information about the profile from the blog.
Definition: gdata.cpp:89
KIOCORE_EXPORT TransferJob * http_post(const QUrl &url, const QByteArray &postData, JobFlags flags=DefaultFlags)
void setTags(const QStringList &tags)
Set the tags list.
Definition: blogpost.cpp:259
qint64 currentSecsSinceEpoch()
void setModificationDateTime(const QDateTime &datetime)
Sets the modification time.
Definition: blogpost.cpp:321
QUrl url() const
Get the URL for the blog&#39;s XML-RPC interface.
Definition: blog.cpp:120
void setCreationDateTime(const QDateTime &datetime)
Sets the creation date-time.
QList::const_iterator constEnd() const const
QList::const_iterator constBegin() const const
A class that provides methods to call functions on a supported blog web application.
Definition: blog.h:72
int size() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
T qobject_cast(QObject *object)
Status of a successfully removed post.
Definition: blogpost.h:404
void errorComment(KBlog::Blog::ErrorType type, const QString &errorMessage, KBlog::BlogPost *post, KBlog::BlogComment *comment)
This signal is emitted when an error occurs with XML parsing or a structural problem in an operation ...
bool isPrivate() const
Returns if the post is published or not.
Definition: blogpost.cpp:132
static Loader * create()
Any other miscellaneous error.
Definition: blog.h:110
Q_EMITQ_EMIT
QString postId() const
Returns the postId.
Definition: blogpost.cpp:142
QString userAgent() const
Returns the HTTP user agent string used to make the HTTP requests.
Definition: blog.cpp:57
int error() const
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jun 5 2020 23:08:10 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.