Attica

provider.cpp
1 /*
2  This file is part of KDE.
3 
4  SPDX-FileCopyrightText: 2008 Cornelius Schumacher <[email protected]>
5  SPDX-FileCopyrightText: 2010 Sebastian K├╝gler <[email protected]>
6  SPDX-FileCopyrightText: 2011 Laszlo Papp <[email protected]>
7 
8  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
9 */
10 
11 #include "provider.h"
12 
13 #include "accountbalance.h"
14 #include "accountbalanceparser.h"
15 #include "achievementparser.h"
16 #include "activity.h"
17 #include "activityparser.h"
18 #include "buildservice.h"
19 #include "buildserviceparser.h"
20 #include "buildservicejob.h"
21 #include "buildservicejobparser.h"
22 #include "buildservicejoboutput.h"
23 #include "buildservicejoboutputparser.h"
24 #include "privatedata.h"
25 #include "privatedataparser.h"
26 #include "categoryparser.h"
27 #include "commentparser.h"
28 #include "config.h"
29 #include "content.h"
30 #include "contentparser.h"
31 #include "distributionparser.h"
32 #include "downloaditem.h"
33 #include "downloaditemparser.h"
34 #include "event.h"
35 #include "eventparser.h"
36 #include "folder.h"
37 #include "folderparser.h"
38 #include "forumparser.h"
39 #include "homepagetype.h"
40 #include "homepagetypeparser.h"
41 #include "knowledgebaseentry.h"
42 #include "knowledgebaseentryparser.h"
43 #include "licenseparser.h"
44 #include "messageparser.h"
45 #include "person.h"
46 #include "personparser.h"
47 #include "platformdependent_v2.h"
48 #include "postjob.h"
49 #include "postfiledata.h"
50 #include "project.h"
51 #include "projectparser.h"
52 #include "publisher.h"
53 #include "publisherparser.h"
54 #include "publisherfield.h"
55 #include "publisherfieldparser.h"
56 #include "remoteaccount.h"
57 #include "remoteaccountparser.h"
58 #include "topic.h"
59 #include "topicparser.h"
60 #include "version.h"
61 
62 #include <QNetworkAccessManager>
63 #include <QDebug>
64 #include <QUrlQuery>
65 #include <QNetworkReply>
66 #include <QFile>
67 #include <QCoreApplication>
68 
69 using namespace Attica;
70 
72 {
73  if (prov.isValid())
74  s.nospace() << "Provider(" << prov.name() << ':' << prov.baseUrl() << ')';
75  else
76  s.nospace() << "Provider(Invalid)";
77  return s.space();
78 }
79 
80 class Provider::Private : public QSharedData
81 {
82 public:
83  QUrl m_baseUrl;
84  QUrl m_icon;
85  QString m_name;
86  QString m_credentialsUserName;
87  QString m_credentialsPassword;
88  QString m_personVersion;
89  QString m_friendVersion;
90  QString m_messageVersion;
91  QString m_achievementVersion;
92  QString m_activityVersion;
93  QString m_contentVersion;
94  QString m_fanVersion;
95  QString m_forumVersion;
96  QString m_knowledgebaseVersion;
97  QString m_eventVersion;
98  QString m_commentVersion;
99  QString m_registerUrl;
100  PlatformDependent *m_internals;
101  QString m_additionalAgentInformation;
102 
103  Private()
104  : m_internals(nullptr)
105  {}
106 
107  Private(const Private &other)
108  : QSharedData(other), m_baseUrl(other.m_baseUrl), m_name(other.m_name)
109  , m_credentialsUserName(other.m_credentialsUserName)
110  , m_credentialsPassword(other.m_credentialsPassword)
111  , m_personVersion(other.m_personVersion)
112  , m_friendVersion(other.m_friendVersion)
113  , m_messageVersion(other.m_messageVersion)
114  , m_achievementVersion(other.m_achievementVersion)
115  , m_activityVersion(other.m_activityVersion)
116  , m_contentVersion(other.m_contentVersion)
117  , m_fanVersion(other.m_fanVersion)
118  , m_forumVersion(other.m_forumVersion)
119  , m_knowledgebaseVersion(other.m_knowledgebaseVersion)
120  , m_eventVersion(other.m_eventVersion)
121  , m_commentVersion(other.m_commentVersion)
122  , m_registerUrl(other.m_registerUrl)
123  , m_internals(other.m_internals)
124  , m_additionalAgentInformation(other.m_additionalAgentInformation)
125  {
126  }
127 
128  Private(PlatformDependent *internals, const QUrl &baseUrl, const QString &name, const QUrl &icon,
129  const QString &person, const QString &friendV, const QString &message, const QString &achievement,
130  const QString &activity, const QString &content, const QString &fan, const QString &forum,
131  const QString &knowledgebase, const QString &event, const QString &comment, const QString &registerUrl,
133  : m_baseUrl(baseUrl), m_icon(icon), m_name(name)
134  , m_personVersion(person)
135  , m_friendVersion(friendV)
136  , m_messageVersion(message)
137  , m_achievementVersion(achievement)
138  , m_activityVersion(activity)
139  , m_contentVersion(content)
140  , m_fanVersion(fan)
141  , m_forumVersion(forum)
142  , m_knowledgebaseVersion(knowledgebase)
143  , m_eventVersion(event)
144  , m_commentVersion(comment)
145  , m_registerUrl(registerUrl)
146  , m_internals(internals)
147  , m_additionalAgentInformation(additionalAgentInformation)
148  {
149  if (m_baseUrl.isEmpty()) {
150  return;
151  }
152  QString user;
153  QString pass;
154  if (m_internals->hasCredentials(m_baseUrl) && m_internals->loadCredentials(m_baseUrl, user, pass)) {
155  m_credentialsUserName = user;
156  m_credentialsPassword = pass;
157  }
158  }
159 
160  ~Private()
161  {
162  }
163 };
164 
165 Provider::Provider()
166  : d(new Private)
167 {
168 }
169 
170 Provider::Provider(const Provider &other)
171  : d(other.d)
172 {
173 }
174 
175 Provider::Provider(PlatformDependent *internals, const QUrl &baseUrl, const QString &name, const QUrl &icon,
176  const QString &person, const QString &friendV, const QString &message, const QString &achievement,
177  const QString &activity, const QString &content, const QString &fan, const QString &forum,
178  const QString &knowledgebase, const QString &event, const QString &comment)
179  : d(new Private(internals, baseUrl, name, icon, person, friendV, message, achievement, activity, content,
180  fan, forum, knowledgebase, event, comment, QString(), QString()))
181 {
182 }
183 
184 Provider::Provider(PlatformDependent *internals, const QUrl &baseUrl, const QString &name, const QUrl &icon,
185  const QString &person, const QString &friendV, const QString &message, const QString &achievement,
186  const QString &activity, const QString &content, const QString &fan, const QString &forum,
187  const QString &knowledgebase, const QString &event, const QString &comment, const QString &registerUrl)
188  : d(new Private(internals, baseUrl, name, icon, person, friendV, message, achievement, activity, content,
189  fan, forum, knowledgebase, event, comment, registerUrl, QString()))
190 {
191 }
192 
193 Provider::Provider(PlatformDependent *internals, const QUrl &baseUrl, const QString &name, const QUrl &icon,
194  const QString &person, const QString &friendV, const QString &message, const QString &achievement,
195  const QString &activity, const QString &content, const QString &fan, const QString &forum,
196  const QString &knowledgebase, const QString &event, const QString &comment, const QString &registerUrl,
197  const QString &additionalAgentInformation)
198  : d(new Private(internals, baseUrl, name, icon, person, friendV, message, achievement, activity, content,
199  fan, forum, knowledgebase, event, comment, registerUrl, additionalAgentInformation))
200 {
201 }
202 
203 Provider &Provider::operator=(const Attica::Provider &other)
204 {
205  d = other.d;
206  return *this;
207 }
208 
209 Provider::~Provider()
210 {
211 }
212 
214 {
215  return d->m_baseUrl;
216 }
217 
218 bool Provider::isValid() const
219 {
220  return d->m_baseUrl.isValid();
221 }
222 
224 {
225  if (!isValid()) {
226  return false;
227  }
228 
229  return d->m_internals->isEnabled(d->m_baseUrl);
230 }
231 
232 void Provider::setEnabled(bool enabled)
233 {
234  if (!isValid()) {
235  return;
236  }
237 
238  d->m_internals->enableProvider(d->m_baseUrl, enabled);
239 }
240 
241 void Provider::setAdditionalAgentInformation(const QString& additionalInformation) {
242  d->m_additionalAgentInformation = additionalInformation;
243 }
244 
246  return d->m_additionalAgentInformation;
247 }
248 
250 {
251  return d->m_name;
252 }
253 
255 {
256  if (!isValid()) {
257  return false;
258  }
259 
260  return d->m_internals->hasCredentials(d->m_baseUrl);
261 }
262 
264 {
265  if (!isValid()) {
266  return false;
267  }
268 
269  return d->m_internals->hasCredentials(d->m_baseUrl);
270 }
271 
273 {
274  if (!isValid()) {
275  return false;
276  }
277 
278  if (d->m_internals->loadCredentials(d->m_baseUrl, user, password)) {
279  d->m_credentialsUserName = user;
280  d->m_credentialsPassword = password;
281  return true;
282  }
283  return false;
284 }
285 
286 bool Provider::saveCredentials(const QString &user, const QString &password)
287 {
288  if (!isValid()) {
289  return false;
290  }
291 
292  d->m_credentialsUserName = user;
293  d->m_credentialsPassword = password;
294  return d->m_internals->saveCredentials(d->m_baseUrl, user, password);
295 }
296 
297 PostJob *Provider::checkLogin(const QString &user, const QString &password)
298 {
299  if (!isValid()) {
300  return nullptr;
301  }
302 
303  QMap<QString, QString> postParameters;
304 
305  postParameters.insert(QLatin1String("login"), user);
306  postParameters.insert(QLatin1String("password"), password);
307 
308  return new PostJob(d->m_internals, createRequest(QLatin1String("person/check")), postParameters);
309 }
310 
311 ItemJob<Config> *Provider::requestConfig()
312 {
313  if (!isValid()) {
314  return nullptr;
315  }
316 
317  QUrl url = createUrl(QLatin1String("config"));
318  return doRequestConfig(url);
319 }
320 
321 PostJob *Provider::registerAccount(const QString &id, const QString &password, const QString &mail, const QString &firstName, const QString &lastName)
322 {
323  if (!isValid()) {
324  return nullptr;
325  }
326 
327  QMap<QString, QString> postParameters;
328 
329  postParameters.insert(QLatin1String("login"), id);
330  postParameters.insert(QLatin1String("password"), password);
331  postParameters.insert(QLatin1String("firstname"), firstName);
332  postParameters.insert(QLatin1String("lastname"), lastName);
333  postParameters.insert(QLatin1String("email"), mail);
334 
335  return new PostJob(d->m_internals, createRequest(QLatin1String("person/add")), postParameters);
336 }
337 
338 const QString &Provider::getRegisterAccountUrl() const
339 {
340  return d->m_registerUrl;
341 }
342 
343 ItemJob<Person> *Provider::requestPerson(const QString &id)
344 {
345  if (!isValid()) {
346  return nullptr;
347  }
348 
349  QUrl url = createUrl(QLatin1String("person/data/") + id);
350  return doRequestPerson(url);
351 }
352 
353 ItemJob<Person> *Provider::requestPersonSelf()
354 {
355  if (!isValid()) {
356  return nullptr;
357  }
358 
359  QUrl url = createUrl(QLatin1String("person/self"));
360  return doRequestPerson(url);
361 }
362 
363 ItemJob<AccountBalance> *Provider::requestAccountBalance()
364 {
365  if (!isValid()) {
366  return nullptr;
367  }
368 
369  QUrl url = createUrl(QLatin1String("person/balance"));
370  return doRequestAccountBalance(url);
371 }
372 
373 ListJob<Person> *Provider::requestPersonSearchByName(const QString &name)
374 {
375  if (!isValid()) {
376  return nullptr;
377  }
378 
379  QUrl url = createUrl(QStringLiteral("person/data"));
380  QUrlQuery q(url);
381  q.addQueryItem(QStringLiteral("name"), name);
382  url.setQuery(q);
383  return doRequestPersonList(url);
384 }
385 
386 ListJob<Person> *Provider::requestPersonSearchByLocation(qreal latitude, qreal longitude, qreal distance, int page, int pageSize)
387 {
388  if (!isValid()) {
389  return nullptr;
390  }
391 
392  QUrl url = createUrl(QStringLiteral("person/data"));
393  QUrlQuery q(url);
394  q.addQueryItem(QStringLiteral("latitude"), QString::number(latitude));
395  q.addQueryItem(QStringLiteral("longitude"), QString::number(longitude));
396  if (distance > 0.0) {
397  q.addQueryItem(QStringLiteral("distance"), QString::number(distance));
398  }
399  q.addQueryItem(QStringLiteral("page"), QString::number(page));
400  q.addQueryItem(QStringLiteral("pagesize"), QString::number(pageSize));
401  url.setQuery(q);
402 
403  return doRequestPersonList(url);
404 }
405 
406 ListJob<Person> *Provider::requestFriends(const QString &id, int page, int pageSize)
407 {
408  if (!isValid()) {
409  return nullptr;
410  }
411 
412  QUrl url = createUrl(QLatin1String("friend/data/") + id);
413  QUrlQuery q(url);
414  q.addQueryItem(QLatin1String("page"), QString::number(page));
415  q.addQueryItem(QLatin1String("pagesize"), QString::number(pageSize));
416  url.setQuery(q);
417 
418  return doRequestPersonList(url);
419 }
420 
421 ListJob<Person> *Provider::requestSentInvitations(int page, int pageSize)
422 {
423  if (!isValid()) {
424  return nullptr;
425  }
426 
427  QUrl url = createUrl(QStringLiteral("friend/sentinvitations"));
428  QUrlQuery q(url);
429  q.addQueryItem(QStringLiteral("page"), QString::number(page));
430  q.addQueryItem(QStringLiteral("pagesize"), QString::number(pageSize));
431  url.setQuery(q);
432 
433  return doRequestPersonList(url);
434 }
435 
436 ListJob<Person> *Provider::requestReceivedInvitations(int page, int pageSize)
437 {
438  if (!isValid()) {
439  return nullptr;
440  }
441 
442  QUrl url = createUrl(QStringLiteral("friend/receivedinvitations"));
443  QUrlQuery q(url);
444  q.addQueryItem(QStringLiteral("page"), QString::number(page));
445  q.addQueryItem(QStringLiteral("pagesize"), QString::number(pageSize));
446  url.setQuery(q);
447 
448  return doRequestPersonList(url);
449 }
450 
451 ListJob<Achievement> *Provider::requestAchievements(const QString &contentId, const QString &achievementId, const QString &userId)
452 {
453  if (!isValid()) {
454  return nullptr;
455  }
456 
457  QUrl url = createUrl(QLatin1String("achievements/content/") + contentId + achievementId);
458  QUrlQuery q(url);
459  q.addQueryItem(QStringLiteral("user_id"), userId);
460  url.setQuery(q);
461  return doRequestAchievementList(url);
462 }
463 
464 ItemPostJob<Achievement> *Provider::addNewAchievement(const QString &contentId, const Achievement &newAchievement)
465 {
466  if (!isValid()) {
467  return nullptr;
468  }
469 
470  StringMap postParameters;
471  int i = 0, j = 0;
472 
473  postParameters.insert(QLatin1String("name"), newAchievement.name());
474  postParameters.insert(QLatin1String("description"), newAchievement.description());
475  postParameters.insert(QLatin1String("explanation"), newAchievement.explanation());
476  postParameters.insert(QLatin1String("points"), QString::number(newAchievement.points()));
477  postParameters.insert(QLatin1String("image"), newAchievement.image().toLocalFile());
478  const auto dependenciesList = newAchievement.dependencies();
479  for (const QString &dependency : dependenciesList) {
480  postParameters.insert(QString::fromLatin1("dependencies[%1]").arg(QString::number(i++)), dependency);
481  }
482 
483  postParameters.insert(QLatin1String("type"), Achievement::achievementTypeToString(newAchievement.type()));
484  const auto optionsList = newAchievement.options();
485  for (const QString &option : optionsList) {
486  postParameters.insert(QString::fromLatin1("options[%1]").arg(QString::number(j++)), option);
487  }
488 
489  postParameters.insert(QLatin1String("steps"), QString::number(newAchievement.steps()));
490  postParameters.insert(QLatin1String("visibility"), Achievement::achievementVisibilityToString(newAchievement.visibility()));
491 
492  return new ItemPostJob<Achievement>(d->m_internals, createRequest(QLatin1String("achievements/content/") + contentId), postParameters);
493 }
494 
495 PutJob *Provider::editAchievement(const QString &contentId, const QString &achievementId, const Achievement &achievement)
496 {
497  if (!isValid()) {
498  return nullptr;
499  }
500 
501  if (!dynamic_cast<Attica::PlatformDependentV2 *>(d->m_internals)) {
502  return nullptr;
503  }
504 
505  StringMap postParameters;
506  int i = 0, j = 0;
507 
508  postParameters.insert(QLatin1String("name"), achievement.name());
509  postParameters.insert(QLatin1String("description"), achievement.description());
510  postParameters.insert(QLatin1String("explanation"), achievement.explanation());
511  postParameters.insert(QLatin1String("points"), QString::number(achievement.points()));
512  postParameters.insert(QLatin1String("image"), achievement.image().toLocalFile());
513  const auto dependenciesList = achievement.dependencies();
514  for (const QString &dependency : dependenciesList) {
515  postParameters.insert(QString::fromLatin1("dependencies[%1]").arg(QString::number(i++)), dependency);
516  }
517 
518  postParameters.insert(QLatin1String("type"), Achievement::achievementTypeToString(achievement.type()));
519  const auto optionsList = achievement.options();
520  for (const QString &option : optionsList) {
521  postParameters.insert(QString::fromLatin1("options[%1]").arg(QString::number(j++)), option);
522  }
523 
524  postParameters.insert(QLatin1String("steps"), QString::number(achievement.steps()));
525  postParameters.insert(QLatin1String("visibility"), Achievement::achievementVisibilityToString(achievement.visibility()));
526 
527  return new ItemPutJob<Achievement>(d->m_internals, createRequest(QLatin1String("achievement/content/") + contentId + achievementId), postParameters);
528 }
529 
530 DeleteJob *Provider::deleteAchievement(const QString &contentId, const QString &achievementId)
531 {
532  if (!isValid()) {
533  return nullptr;
534  }
535 
536  if (!dynamic_cast<Attica::PlatformDependentV2 *>(d->m_internals)) {
537  return nullptr;
538  }
539 
540  return new ItemDeleteJob<Achievement>(d->m_internals, createRequest(QLatin1String("achievements/progress/") + contentId + achievementId));
541 }
542 
543 PostJob *Provider::setAchievementProgress(const QString &id, const QVariant &progress, const QDateTime &timestamp)
544 {
545  if (!isValid()) {
546  return nullptr;
547  }
548 
549  StringMap postParameters;
550 
551  postParameters.insert(QLatin1String("progress"), progress.toString());
552  postParameters.insert(QLatin1String("timestamp"), timestamp.toString());
553 
554  return new ItemPostJob<Achievement>(d->m_internals, createRequest(QLatin1String("achievements/progress/") + id), postParameters);
555 }
556 
557 DeleteJob *Provider::resetAchievementProgress(const QString &id)
558 {
559  if (!isValid()) {
560  return nullptr;
561  }
562 
563  if (!dynamic_cast<Attica::PlatformDependentV2 *>(d->m_internals)) {
564  return nullptr;
565  }
566 
567  return new ItemDeleteJob<Achievement>(d->m_internals, createRequest(QLatin1String("achievements/progress/") + id));
568 }
569 
570 ListJob<Activity> *Provider::requestActivities()
571 {
572  if (!isValid()) {
573  return nullptr;
574  }
575 
576  //qCDebug(ATTICA) << "request activity";
577  QUrl url = createUrl(QLatin1String("activity"));
578  return doRequestActivityList(url);
579 }
580 
581 ListJob<Project> *Provider::requestProjects()
582 {
583  if (!isValid()) {
584  return nullptr;
585  }
586 
587  //qCDebug(ATTICA) << "request projects";
588  QUrl url = createUrl(QLatin1String("buildservice/project/list"));
589  return new ListJob<Project>(d->m_internals, createRequest(url));
590 }
591 
592 ItemJob<Project> *Provider::requestProject(const QString &id)
593 {
594  if (!isValid()) {
595  return nullptr;
596  }
597 
598  QUrl url = createUrl(QLatin1String("buildservice/project/get/") + id);
599  //qCDebug(ATTICA) << url;
600  return new ItemJob<Project>(d->m_internals, createRequest(url));
601 }
602 
603 QMap<QString, QString> projectPostParameters(const Project &project)
604 {
605  QMap<QString, QString> postParameters;
606 
607  if (!project.name().isEmpty()) {
608  postParameters.insert(QLatin1String("name"), project.name());
609  }
610  if (!project.summary().isEmpty()) {
611  postParameters.insert(QLatin1String("summary"), project.summary());
612  }
613  if (!project.description().isEmpty()) {
614  postParameters.insert(QLatin1String("description"), project.description());
615  }
616  if (!project.url().isEmpty()) {
617  postParameters.insert(QLatin1String("url"), project.url());
618  }
619  if (!project.developers().isEmpty()) {
620  postParameters.insert(QLatin1String("developers"), project.developers().join(QLatin1Char('\n')));
621  }
622  if (!project.version().isEmpty()) {
623  postParameters.insert(QLatin1String("version"), project.version());
624  }
625  if (!project.license().isEmpty()) {
626  postParameters.insert(QLatin1String("license"), project.license());
627  }
628  if (!project.requirements().isEmpty()) {
629  postParameters.insert(QLatin1String("requirements"), project.requirements());
630  }
631  // The specfile generator expects an empty string parameter if it is supposed to regenerate the spec file
632  // So we need to check for nullity here as opposed to an empty string.
633  if (!project.specFile().isNull()) {
634  postParameters.insert(QLatin1String("specfile"), project.specFile());
635  }
636  return postParameters;
637 }
638 
639 PostJob *Provider::createProject(const Project &project)
640 {
641  if (!isValid()) {
642  return nullptr;
643  }
644 
645  return new PostJob(d->m_internals, createRequest(QLatin1String("buildservice/project/create")),
646  projectPostParameters(project));
647 }
648 
649 PostJob *Provider::editProject(const Project &project)
650 {
651  if (!isValid()) {
652  return nullptr;
653  }
654 
655  return new PostJob(d->m_internals, createRequest(
656  QLatin1String("buildservice/project/edit/") + project.id()),
657  projectPostParameters(project));
658 }
659 
660 PostJob *Provider::deleteProject(const Project &project)
661 {
662  if (!isValid()) {
663  return nullptr;
664  }
665 
666  return new PostJob(d->m_internals, createRequest(
667  QLatin1String("buildservice/project/delete/") + project.id()),
668  projectPostParameters(project));
669 }
670 
671 ItemJob<BuildService> *Provider::requestBuildService(const QString &id)
672 {
673  if (!isValid()) {
674  return nullptr;
675  }
676 
677  QUrl url = createUrl(QLatin1String("buildservice/buildservices/get/") + id);
678  return new ItemJob<BuildService>(d->m_internals, createRequest(url));
679 }
680 
681 ItemJob<Publisher> *Provider::requestPublisher(const QString &id)
682 {
683  if (!isValid()) {
684  return nullptr;
685  }
686 
687  //qCDebug(ATTICA) << "request publisher" << id;
688  QUrl url = createUrl(QLatin1String("buildservice/publishing/getpublisher/") + id);
689  return new ItemJob<Publisher>(d->m_internals, createRequest(url));
690 }
691 
692 PostJob *Provider::savePublisherField(const Project &project, const PublisherField &field)
693 {
694  if (!isValid()) {
695  return nullptr;
696  }
697 
698  StringMap postParameters;
699  postParameters.insert(QLatin1String("fields[0][name]"), field.name());
700  postParameters.insert(QLatin1String("fields[0][fieldtype]"), field.type());
701  postParameters.insert(QLatin1String("fields[0][data]"), field.data());
702 
703  QString url = QLatin1String("buildservice/publishing/savefields/") + project.id();
704  //qCDebug(ATTICA) << "saving field values...";
705  return new PostJob(d->m_internals, createRequest(url), postParameters);
706 }
707 
708 PostJob *Provider::publishBuildJob(const BuildServiceJob &buildjob, const Publisher &publisher)
709 {
710  if (!isValid()) {
711  return nullptr;
712  }
713 
714  StringMap postParameters;
715  postParameters.insert(QLatin1String("dummyparameter"), QLatin1String("dummyvalue"));
716 
717  QString url = QLatin1String("buildservice/publishing/publishtargetresult/") +
718  buildjob.id() + QLatin1Char('/') + publisher.id();
719  //qCDebug(ATTICA) << "pub'ing";
720  return new PostJob(d->m_internals, createRequest(url), postParameters);
721 }
722 
723 // Buildservices and their jobs
724 ItemJob<BuildServiceJobOutput> *Provider::requestBuildServiceJobOutput(const QString &id)
725 {
726  if (!isValid()) {
727  return nullptr;
728  }
729 
730  QUrl url = createUrl(QLatin1String("buildservice/jobs/getoutput/") + id);
731  //qCDebug(ATTICA) << url;
732  return new ItemJob<BuildServiceJobOutput>(d->m_internals, createRequest(url));
733 }
734 
735 ItemJob<BuildServiceJob> *Provider::requestBuildServiceJob(const QString &id)
736 {
737  if (!isValid()) {
738  return nullptr;
739  }
740 
741  QUrl url = createUrl(QLatin1String("buildservice/jobs/get/") + id);
742  //qCDebug(ATTICA) << url;
743  return new ItemJob<BuildServiceJob>(d->m_internals, createRequest(url));
744 }
745 
746 QMap<QString, QString> buildServiceJobPostParameters(const BuildServiceJob &buildjob)
747 {
748  QMap<QString, QString> postParameters;
749 
750  if (!buildjob.name().isEmpty()) {
751  postParameters.insert(QLatin1String("name"), buildjob.name());
752  }
753  if (!buildjob.projectId().isEmpty()) {
754  postParameters.insert(QLatin1String("projectid"), buildjob.projectId());
755  }
756  if (!buildjob.target().isEmpty()) {
757  postParameters.insert(QLatin1String("target"), buildjob.target());
758  }
759  if (!buildjob.buildServiceId().isEmpty()) {
760  postParameters.insert(QLatin1String("buildservice"), buildjob.buildServiceId());
761  }
762 
763  return postParameters;
764 }
765 
766 PostJob *Provider::cancelBuildServiceJob(const BuildServiceJob &job)
767 {
768  if (!isValid()) {
769  return nullptr;
770  }
771 
772  StringMap postParameters;
773  postParameters.insert(QLatin1String("dummyparameter"), QLatin1String("dummyvalue"));
774  //qCDebug(ATTICA) << "b....................b";
775  return new PostJob(d->m_internals, createRequest(
776  QLatin1String("buildservice/jobs/cancel/") + job.id()), postParameters);
777 }
778 
779 PostJob *Provider::createBuildServiceJob(const BuildServiceJob &job)
780 {
781  if (!isValid()) {
782  return nullptr;
783  }
784 
785  StringMap postParameters;
786  // A postjob won't be run without parameters.
787  // so even while we don't need any in this case,
788  // we add dummy data to the request
789  postParameters.insert(QLatin1String("dummyparameter"), QLatin1String("dummyvalue"));
790  //qCDebug(ATTICA) << "Creating new BSJ on" << job.buildServiceId();
791  return new PostJob(d->m_internals, createRequest(
792  QLatin1String("buildservice/jobs/create/") +
793  job.projectId() + QLatin1Char('/') + job.buildServiceId() + QLatin1Char('/') + job.target()),
794  postParameters);
795 }
796 
797 ListJob<BuildService> *Provider::requestBuildServices()
798 {
799  if (!isValid()) {
800  return nullptr;
801  }
802 
803  //qCDebug(ATTICA) << "request projects";
804  QUrl url = createUrl(QLatin1String("buildservice/buildservices/list"));
805  return new ListJob<BuildService>(d->m_internals, createRequest(url));
806 }
807 
808 ListJob<Publisher> *Provider::requestPublishers()
809 {
810  if (!isValid()) {
811  return nullptr;
812  }
813 
814  QUrl url = createUrl(QLatin1String("buildservice/publishing/getpublishingcapabilities"));
815  //qCDebug(ATTICA) << "request publishers" << url;
816  return new ListJob<Publisher>(d->m_internals, createRequest(url));
817 }
818 
819 ListJob<BuildServiceJob> *Provider::requestBuildServiceJobs(const Project &project)
820 {
821  if (!isValid()) {
822  return nullptr;
823  }
824 
825  //qCDebug(ATTICA) << "request projects";
826  QUrl url = createUrl(QLatin1String("buildservice/jobs/list/") + project.id());
827  return new ListJob<BuildServiceJob>(d->m_internals, createRequest(url));
828 }
829 
830 ListJob<RemoteAccount> *Provider::requestRemoteAccounts()
831 {
832  if (!isValid()) {
833  return nullptr;
834  }
835 
836  //qCDebug(ATTICA) << "request remoteaccounts";
837  QUrl url = createUrl(QLatin1String("buildservice/remoteaccounts/list/"));
838  return new ListJob<RemoteAccount>(d->m_internals, createRequest(url));
839 }
840 
841 PostJob *Provider::createRemoteAccount(const RemoteAccount &account)
842 {
843  if (!isValid()) {
844  return nullptr;
845  }
846 
847  StringMap postParameters;
848  // A postjob won't be run without parameters.
849  // so even while we don't need any in this case,
850  // we add dummy data to the request
851  postParameters.insert(QLatin1String("login"), account.login());
852  postParameters.insert(QLatin1String("password"), account.password());
853  postParameters.insert(QLatin1String("type"), account.type());
854  postParameters.insert(QLatin1String("typeid"), account.remoteServiceId()); // FIXME: remoteserviceid?
855  postParameters.insert(QLatin1String("data"), account.data());
856  //qCDebug(ATTICA) << "Creating new Remoteaccount" << account.id() << account.login() << account.password();
857  return new PostJob(d->m_internals, createRequest(QLatin1String("buildservice/remoteaccounts/add")),
858  postParameters);
859 }
860 
861 PostJob *Provider::editRemoteAccount(const RemoteAccount &account)
862 {
863  if (!isValid()) {
864  return nullptr;
865  }
866 
867  StringMap postParameters;
868  // A postjob won't be run without parameters.
869  // so even while we don't need any in this case,
870  // we add dummy data to the request
871  postParameters.insert(QLatin1String("login"), account.login());
872  postParameters.insert(QLatin1String("password"), account.password());
873  postParameters.insert(QLatin1String("type"), account.type());
874  postParameters.insert(QLatin1String("typeid"), account.remoteServiceId()); // FIXME: remoteserviceid?
875  postParameters.insert(QLatin1String("data"), account.data());
876  //qCDebug(ATTICA) << "Creating new Remoteaccount" << account.id() << account.login() << account.password();
877  return new PostJob(d->m_internals, createRequest(QLatin1String("buildservice/remoteaccounts/edit/") + account.id()),
878  postParameters);
879 }
880 
881 ItemJob<RemoteAccount> *Provider::requestRemoteAccount(const QString &id)
882 {
883  if (!isValid()) {
884  return nullptr;
885  }
886 
887  QUrl url = createUrl(QLatin1String("buildservice/remoteaccounts/get/") + id);
888  //qCDebug(ATTICA) << url;
889  return new ItemJob<RemoteAccount>(d->m_internals, createRequest(url));
890 }
891 
893 {
894  if (!isValid()) {
895  return nullptr;
896  }
897 
898  StringMap postParameters;
899  return new PostJob(d->m_internals, createRequest(
900  QLatin1String("buildservice/remoteaccounts/remove/") + id),
901  postParameters);
902 }
903 
904 PostJob *Provider::uploadTarballToBuildService(const QString &projectId, const QString &fileName, const QByteArray &payload)
905 {
906  if (!isValid()) {
907  return nullptr;
908  }
909 
910  QUrl url = createUrl(QLatin1String("buildservice/project/uploadsource/") + projectId);
911  //qCDebug(ATTICA) << "Up'ing tarball" << url << projectId << fileName << payload;
912  PostFileData postRequest(url);
913  postRequest.addFile(fileName, payload, QLatin1String("application/octet-stream"), QLatin1String("source"));
914  return new PostJob(d->m_internals, postRequest.request(), postRequest.data());
915 }
916 
917 // Activity
918 
919 PostJob *Provider::postActivity(const QString &message)
920 {
921  if (!isValid()) {
922  return nullptr;
923  }
924 
925  StringMap postParameters;
926  postParameters.insert(QLatin1String("message"), message);
927  return new PostJob(d->m_internals, createRequest(QLatin1String("activity")), postParameters);
928 }
929 
930 PostJob *Provider::inviteFriend(const QString &to, const QString &message)
931 {
932  if (!isValid()) {
933  return nullptr;
934  }
935 
936  StringMap postParameters;
937  postParameters.insert(QLatin1String("message"), message);
938  return new PostJob(d->m_internals, createRequest(QLatin1String("friend/invite/") + to), postParameters);
939 }
940 
941 PostJob *Provider::approveFriendship(const QString &to)
942 {
943  if (!isValid()) {
944  return nullptr;
945  }
946 
947  return new PostJob(d->m_internals, createRequest(QLatin1String("friend/approve/") + to));
948 }
949 
950 PostJob *Provider::declineFriendship(const QString &to)
951 {
952  if (!isValid()) {
953  return nullptr;
954  }
955 
956  return new PostJob(d->m_internals, createRequest(QLatin1String("friend/decline/") + to));
957 }
958 
959 PostJob *Provider::cancelFriendship(const QString &to)
960 {
961  if (!isValid()) {
962  return nullptr;
963  }
964 
965  return new PostJob(d->m_internals, createRequest(QLatin1String("friend/cancel/") + to));
966 }
967 
968 PostJob *Provider::postLocation(qreal latitude, qreal longitude, const QString &city, const QString &country)
969 {
970  if (!isValid()) {
971  return nullptr;
972  }
973 
974  StringMap postParameters;
975  postParameters.insert(QLatin1String("latitude"), QString::number(latitude));
976  postParameters.insert(QLatin1String("longitude"), QString::number(longitude));
977  postParameters.insert(QLatin1String("city"), city);
978  postParameters.insert(QLatin1String("country"), country);
979  return new PostJob(d->m_internals, createRequest(QLatin1String("person/self")), postParameters);
980 }
981 
982 ListJob<Folder> *Provider::requestFolders()
983 {
984  if (!isValid()) {
985  return nullptr;
986  }
987 
988  return doRequestFolderList(createUrl(QLatin1String("message")));
989 }
990 
991 ListJob<Message> *Provider::requestMessages(const Folder &folder)
992 {
993  if (!isValid()) {
994  return nullptr;
995  }
996 
997  return doRequestMessageList(createUrl(QLatin1String("message/") + folder.id()));
998 }
999 
1000 ListJob<Message> *Provider::requestMessages(const Folder &folder, Message::Status status)
1001 {
1002  if (!isValid()) {
1003  return nullptr;
1004  }
1005 
1006  QUrl url = createUrl(QLatin1String("message/") + folder.id());
1007  QUrlQuery q(url);
1008  q.addQueryItem(QStringLiteral("status"), QString::number(status));
1009  url.setQuery(q);
1010  return doRequestMessageList(url);
1011 }
1012 
1013 ItemJob<Message> *Provider::requestMessage(const Folder &folder, const QString &id)
1014 {
1015  if (!isValid()) {
1016  return nullptr;
1017  }
1018 
1019  return new ItemJob<Message>(d->m_internals, createRequest(QLatin1String("message/") + folder.id() + QLatin1Char('/') + id));
1020 }
1021 
1022 PostJob *Provider::postMessage(const Message &message)
1023 {
1024  if (!isValid()) {
1025  return nullptr;
1026  }
1027 
1028  StringMap postParameters;
1029  postParameters.insert(QLatin1String("message"), message.body());
1030  postParameters.insert(QLatin1String("subject"), message.subject());
1031  postParameters.insert(QLatin1String("to"), message.to());
1032  return new PostJob(d->m_internals, createRequest(QLatin1String("message/2")), postParameters);
1033 }
1034 
1035 ListJob<Category> *Provider::requestCategories()
1036 {
1037  if (!isValid()) {
1038  return nullptr;
1039  }
1040 
1041  QUrl url = createUrl(QLatin1String("content/categories"));
1042  ListJob<Category> *job = new ListJob<Category>(d->m_internals, createRequest(url));
1043  return job;
1044 }
1045 
1046 ListJob< License > *Provider::requestLicenses()
1047 {
1048  if (!isValid()) {
1049  return nullptr;
1050  }
1051 
1052  QUrl url = createUrl(QLatin1String("content/licenses"));
1053  ListJob<License> *job = new ListJob<License>(d->m_internals, createRequest(url));
1054  return job;
1055 }
1056 
1057 ListJob< Distribution > *Provider::requestDistributions()
1058 {
1059  if (!isValid()) {
1060  return nullptr;
1061  }
1062 
1063  QUrl url = createUrl(QLatin1String("content/distributions"));
1064  ListJob<Distribution> *job = new ListJob<Distribution>(d->m_internals, createRequest(url));
1065  return job;
1066 }
1067 
1068 ListJob< HomePageType > *Provider::requestHomePageTypes()
1069 {
1070  if (!isValid()) {
1071  return nullptr;
1072  }
1073 
1074  QUrl url = createUrl(QLatin1String("content/homepages"));
1075  ListJob<HomePageType> *job = new ListJob<HomePageType>(d->m_internals, createRequest(url));
1076  return job;
1077 }
1078 
1079 ListJob<Content> *Provider::searchContents(const Category::List &categories, const QString &search, SortMode sortMode, uint page, uint pageSize)
1080 {
1081  return searchContents(categories, QString(), Distribution::List(), License::List(), search, sortMode, page, pageSize);
1082 }
1083 
1084 ListJob<Content> *Provider::searchContentsByPerson(const Category::List &categories, const QString &person, const QString &search, SortMode sortMode, uint page, uint pageSize)
1085 {
1086  return searchContents(categories, person, Distribution::List(), License::List(), search, sortMode, page, pageSize);
1087 }
1088 
1089 ListJob<Content> *Provider::searchContents(const Category::List &categories, const QString &person, const Distribution::List &distributions, const License::List &licenses, const QString &search, SortMode sortMode, uint page, uint pageSize)
1090 {
1091  if (!isValid()) {
1092  return nullptr;
1093  }
1094 
1095  QUrl url = createUrl(QStringLiteral("content/data"));
1096  QUrlQuery q(url);
1097  QStringList categoryIds;
1098  categoryIds.reserve(categories.count());
1099  for (const Category &category : categories) {
1100  categoryIds.append(category.id());
1101  }
1102  q.addQueryItem(QStringLiteral("categories"), categoryIds.join(QLatin1Char('x')));
1103 
1104  QStringList distributionIds;
1105  for (const Distribution &distribution : distributions) {
1106  distributionIds.append(QString::number(distribution.id()));
1107  }
1108  q.addQueryItem(QStringLiteral("distribution"), distributionIds.join(QLatin1Char(',')));
1109 
1110  QStringList licenseIds;
1111  for (const License &license : licenses) {
1112  licenseIds.append(QString::number(license.id()));
1113  }
1114  q.addQueryItem(QStringLiteral("license"), licenseIds.join(QLatin1Char(',')));
1115 
1116  if (!person.isEmpty()) {
1117  q.addQueryItem(QStringLiteral("user"), person);
1118  }
1119 
1120  q.addQueryItem(QStringLiteral("search"), search);
1121  QString sortModeString;
1122  switch (sortMode) {
1123  case Newest:
1124  sortModeString = QLatin1String("new");
1125  break;
1126  case Alphabetical:
1127  sortModeString = QLatin1String("alpha");
1128  break;
1129  case Rating:
1130  sortModeString = QLatin1String("high");
1131  break;
1132  case Downloads:
1133  sortModeString = QLatin1String("down");
1134  break;
1135  }
1136 
1137  if (!sortModeString.isEmpty()) {
1138  q.addQueryItem(QStringLiteral("sortmode"), sortModeString);
1139  }
1140 
1141  q.addQueryItem(QStringLiteral("page"), QString::number(page));
1142  q.addQueryItem(QStringLiteral("pagesize"), QString::number(pageSize));
1143 
1144  url.setQuery(q);
1145  ListJob<Content> *job = new ListJob<Content>(d->m_internals, createRequest(url));
1146  return job;
1147 }
1148 
1149 ItemJob<Content> *Provider::requestContent(const QString &id)
1150 {
1151  if (!isValid()) {
1152  return nullptr;
1153  }
1154 
1155  QUrl url = createUrl(QLatin1String("content/data/") + id);
1156  ItemJob<Content> *job = new ItemJob<Content>(d->m_internals, createRequest(url));
1157  return job;
1158 }
1159 
1160 ItemPostJob<Content> *Provider::addNewContent(const Category &category, const Content &cont)
1161 {
1162  if (!isValid() || !category.isValid()) {
1163  return nullptr;
1164  }
1165 
1166  QUrl url = createUrl(QLatin1String("content/add"));
1167  StringMap pars(cont.attributes());
1168 
1169  pars.insert(QLatin1String("type"), category.id());
1170  pars.insert(QLatin1String("name"), cont.name());
1171 
1172  //qCDebug(ATTICA) << "Parameter map: " << pars;
1173 
1174  return new ItemPostJob<Content>(d->m_internals, createRequest(url), pars);
1175 }
1176 
1177 ItemPostJob<Content> *Provider::editContent(const Category &updatedCategory, const QString &contentId, const Content &updatedContent)
1178 {
1179  if (!isValid()) {
1180  return nullptr;
1181  }
1182 
1183  // FIXME I get a server error message here, though the name of the item is changed
1184  QUrl url = createUrl(QLatin1String("content/edit/") + contentId);
1185  StringMap pars(updatedContent.attributes());
1186 
1187  pars.insert(QLatin1String("type"), updatedCategory.id());
1188  pars.insert(QLatin1String("name"), updatedContent.name());
1189 
1190  //qCDebug(ATTICA) << "Parameter map: " << pars;
1191 
1192  return new ItemPostJob<Content>(d->m_internals, createRequest(url), pars);
1193 }
1194 
1195 /*
1196 PostJob* Provider::setDownloadFile(const QString& contentId, QIODevice* payload)
1197 {
1198  QUrl url = createUrl("content/uploaddownload/" + contentId);
1199  PostFileData postRequest(url);
1200  // FIXME mime type
1201  //postRequest.addFile("localfile", payload, "application/octet-stream");
1202  postRequest.addFile("localfile", payload, "image/jpeg");
1203  return new PostJob(d->m_internals, postRequest.request(), postRequest.data());
1204 }
1205 */
1206 
1207 PostJob *Provider::deleteContent(const QString &contentId)
1208 {
1209  if (!isValid()) {
1210  return nullptr;
1211  }
1212 
1213  QUrl url = createUrl(QLatin1String("content/delete/") + contentId);
1214  PostFileData postRequest(url);
1215  postRequest.addArgument(QLatin1String("contentid"), contentId);
1216  return new PostJob(d->m_internals, postRequest.request(), postRequest.data());
1217 }
1218 
1219 PostJob *Provider::setDownloadFile(const QString &contentId, const QString &fileName, const QByteArray &payload)
1220 {
1221  if (!isValid()) {
1222  return nullptr;
1223  }
1224 
1225  QUrl url = createUrl(QLatin1String("content/uploaddownload/") + contentId);
1226  PostFileData postRequest(url);
1227  postRequest.addArgument(QLatin1String("contentid"), contentId);
1228  // FIXME mime type
1229  postRequest.addFile(fileName, payload, QLatin1String("application/octet-stream"));
1230  return new PostJob(d->m_internals, postRequest.request(), postRequest.data());
1231 }
1232 
1233 PostJob *Provider::deleteDownloadFile(const QString &contentId)
1234 {
1235  if (!isValid()) {
1236  return nullptr;
1237  }
1238 
1239  QUrl url = createUrl(QLatin1String("content/deletedownload/") + contentId);
1240  PostFileData postRequest(url);
1241  postRequest.addArgument(QLatin1String("contentid"), contentId);
1242  return new PostJob(d->m_internals, postRequest.request(), postRequest.data());
1243 }
1244 
1245 PostJob *Provider::setPreviewImage(const QString &contentId, const QString &previewId, const QString &fileName, const QByteArray &image)
1246 {
1247  if (!isValid()) {
1248  return nullptr;
1249  }
1250 
1251  QUrl url = createUrl(QLatin1String("content/uploadpreview/") + contentId + QLatin1Char('/') + previewId);
1252 
1253  PostFileData postRequest(url);
1254  postRequest.addArgument(QLatin1String("contentid"), contentId);
1255  postRequest.addArgument(QLatin1String("previewid"), previewId);
1256  // FIXME mime type
1257  postRequest.addFile(fileName, image, QLatin1String("application/octet-stream"));
1258 
1259  return new PostJob(d->m_internals, postRequest.request(), postRequest.data());
1260 }
1261 
1262 PostJob *Provider::deletePreviewImage(const QString &contentId, const QString &previewId)
1263 {
1264  if (!isValid()) {
1265  return nullptr;
1266  }
1267 
1268  QUrl url = createUrl(QLatin1String("content/deletepreview/") + contentId + QLatin1Char('/') + previewId);
1269  PostFileData postRequest(url);
1270  postRequest.addArgument(QLatin1String("contentid"), contentId);
1271  postRequest.addArgument(QLatin1String("previewid"), previewId);
1272  return new PostJob(d->m_internals, postRequest.request(), postRequest.data());
1273 }
1274 
1275 #if ATTICA_BUILD_DEPRECATED_SINCE(0, 2)
1276 PostJob *Provider::voteForContent(const QString &contentId, bool positiveVote)
1277 {
1278  if (!isValid()) {
1279  return nullptr;
1280  }
1281 
1282  StringMap postParameters;
1283  postParameters.insert(QLatin1String("vote"), positiveVote ? QLatin1String("good") : QLatin1String("bad"));
1284  //qCDebug(ATTICA) << "vote: " << positiveVote;
1285  return new PostJob(d->m_internals, createRequest(QLatin1String("content/vote/") + contentId), postParameters);
1286 }
1287 #endif
1288 
1289 PostJob *Provider::voteForContent(const QString &contentId, uint rating)
1290 {
1291  if (!isValid()) {
1292  return nullptr;
1293  }
1294 
1295  // according to OCS API, the rating is 0..100
1296  if (rating > 100) {
1297  qWarning() << "Rating cannot be superior to 100, fallback to 100.";
1298  rating = 100;
1299  }
1300 
1301  StringMap postParameters;
1302  postParameters.insert(QLatin1String("vote"), QString::number(rating));
1303  //qCDebug(ATTICA) << "vote: " << QString::number(rating);
1304  return new PostJob(d->m_internals, createRequest(QLatin1String("content/vote/") + contentId), postParameters);
1305 }
1306 
1307 PostJob *Provider::becomeFan(const QString &contentId)
1308 {
1309  if (!isValid()) {
1310  return nullptr;
1311  }
1312 
1313  QUrl url = createUrl(QLatin1String("fan/add/") + contentId);
1314  PostFileData postRequest(url);
1315  postRequest.addArgument(QLatin1String("contentid"), contentId);
1316  return new PostJob(d->m_internals, postRequest.request(), postRequest.data());
1317 }
1318 
1319 ListJob<Person> *Provider::requestFans(const QString &contentId, uint page, uint pageSize)
1320 {
1321  if (!isValid()) {
1322  return nullptr;
1323  }
1324 
1325  QUrl url = createUrl(QLatin1String("fan/data/") + contentId);
1326  QUrlQuery q(url);
1327  q.addQueryItem(QStringLiteral("contentid"), contentId);
1328  q.addQueryItem(QStringLiteral("page"), QString::number(page));
1329  q.addQueryItem(QStringLiteral("pagesize"), QString::number(pageSize));
1330  url.setQuery(q);
1331  ListJob<Person> *job = new ListJob<Person>(d->m_internals, createRequest(url));
1332  return job;
1333 }
1334 
1335 ListJob<Forum> *Provider::requestForums(uint page, uint pageSize)
1336 {
1337  if (!isValid()) {
1338  return nullptr;
1339  }
1340 
1341  QUrl url = createUrl(QStringLiteral("forum/list"));
1342  QUrlQuery q(url);
1343  q.addQueryItem(QStringLiteral("page"), QString::number(page));
1344  q.addQueryItem(QStringLiteral("pagesize"), QString::number(pageSize));
1345  url.setQuery(q);
1346 
1347  return doRequestForumList(url);
1348 }
1349 
1350 ListJob<Topic> *Provider::requestTopics(const QString &forum, const QString &search, const QString &description, Provider::SortMode mode, int page, int pageSize)
1351 {
1352  if (!isValid()) {
1353  return nullptr;
1354  }
1355 
1356  QUrl url = createUrl(QStringLiteral("forum/topics/list"));
1357  QUrlQuery q(url);
1358  q.addQueryItem(QStringLiteral("forum"), forum);
1359  q.addQueryItem(QStringLiteral("search"), search);
1360  q.addQueryItem(QStringLiteral("description"), description);
1361  QString sortModeString;
1362  switch (mode) {
1363  case Newest:
1364  sortModeString = QLatin1String("new");
1365  break;
1366  case Alphabetical:
1367  sortModeString = QLatin1String("alpha");
1368  break;
1369  default:
1370  break;
1371  }
1372  if (!sortModeString.isEmpty()) {
1373  q.addQueryItem(QStringLiteral("sortmode"), sortModeString);
1374  }
1375  q.addQueryItem(QStringLiteral("page"), QString::number(page));
1376  q.addQueryItem(QStringLiteral("pagesize"), QString::number(pageSize));
1377  url.setQuery(q);
1378 
1379  return doRequestTopicList(url);
1380 }
1381 
1382 PostJob *Provider::postTopic(const QString &forumId, const QString &subject, const QString &content)
1383 {
1384  if (!isValid()) {
1385  return nullptr;
1386  }
1387 
1388  StringMap postParameters;
1389  postParameters.insert(QLatin1String("subject"), subject);
1390  postParameters.insert(QLatin1String("content"), content);
1391  postParameters.insert(QLatin1String("forum"), forumId);
1392  return new PostJob(d->m_internals, createRequest(QLatin1String("forum/topic/add")), postParameters);
1393 }
1394 
1395 ItemJob<DownloadItem> *Provider::downloadLink(const QString &contentId, const QString &itemId)
1396 {
1397  if (!isValid()) {
1398  return nullptr;
1399  }
1400 
1401  QUrl url = createUrl(QLatin1String("content/download/") + contentId + QLatin1Char('/') + itemId);
1402  ItemJob<DownloadItem> *job = new ItemJob<DownloadItem>(d->m_internals, createRequest(url));
1403  return job;
1404 }
1405 
1406 ItemJob<KnowledgeBaseEntry> *Provider::requestKnowledgeBaseEntry(const QString &id)
1407 {
1408  if (!isValid()) {
1409  return nullptr;
1410  }
1411 
1412  QUrl url = createUrl(QLatin1String("knowledgebase/data/") + id);
1413  ItemJob<KnowledgeBaseEntry> *job = new ItemJob<KnowledgeBaseEntry>(d->m_internals, createRequest(url));
1414  return job;
1415 }
1416 
1417 ListJob<KnowledgeBaseEntry> *Provider::searchKnowledgeBase(const Content &content, const QString &search, Provider::SortMode sortMode, int page, int pageSize)
1418 {
1419  if (!isValid()) {
1420  return nullptr;
1421  }
1422 
1423  QUrl url = createUrl(QStringLiteral("knowledgebase/data"));
1424  QUrlQuery q(url);
1425  if (content.isValid()) {
1426  q.addQueryItem(QStringLiteral("content"), content.id());
1427  }
1428 
1429  q.addQueryItem(QStringLiteral("search"), search);
1430  QString sortModeString;
1431  switch (sortMode) {
1432  case Newest:
1433  sortModeString = QLatin1String("new");
1434  break;
1435  case Alphabetical:
1436  sortModeString = QLatin1String("alpha");
1437  break;
1438  case Rating:
1439  sortModeString = QLatin1String("high");
1440  break;
1441  //FIXME: knowledge base doesn't have downloads
1442  case Downloads:
1443  sortModeString = QLatin1String("new");
1444  break;
1445  }
1446  if (!sortModeString.isEmpty()) {
1447  q.addQueryItem(QStringLiteral("sortmode"), sortModeString);
1448  }
1449 
1450  q.addQueryItem(QStringLiteral("page"), QString::number(page));
1451  q.addQueryItem(QStringLiteral("pagesize"), QString::number(pageSize));
1452  url.setQuery(q);
1453 
1454  ListJob<KnowledgeBaseEntry> *job = new ListJob<KnowledgeBaseEntry>(d->m_internals, createRequest(url));
1455  return job;
1456 }
1457 
1458 ItemJob<Event> *Provider::requestEvent(const QString &id)
1459 {
1460  if (!isValid()) {
1461  return nullptr;
1462  }
1463 
1464  ItemJob<Event> *job = new ItemJob<Event>(d->m_internals, createRequest(QLatin1String("event/data/") + id));
1465  return job;
1466 }
1467 
1468 ListJob<Event> *Provider::requestEvent(const QString &country, const QString &search, const QDate &startAt, Provider::SortMode mode, int page, int pageSize)
1469 {
1470  if (!isValid()) {
1471  return nullptr;
1472  }
1473 
1474  QUrl url = createUrl(QStringLiteral("event/data"));
1475  QUrlQuery q(url);
1476 
1477  if (!search.isEmpty()) {
1478  q.addQueryItem(QStringLiteral("search"), search);
1479  }
1480 
1481  QString sortModeString;
1482  switch (mode) {
1483  case Newest:
1484  sortModeString = QLatin1String("new");
1485  break;
1486  case Alphabetical:
1487  sortModeString = QLatin1String("alpha");
1488  break;
1489  default:
1490  break;
1491  }
1492  if (!sortModeString.isEmpty()) {
1493  q.addQueryItem(QStringLiteral("sortmode"), sortModeString);
1494  }
1495 
1496  if (!country.isEmpty()) {
1497  q.addQueryItem(QStringLiteral("country"), country);
1498  }
1499 
1500  q.addQueryItem(QStringLiteral("startat"), startAt.toString(Qt::ISODate));
1501 
1502  q.addQueryItem(QStringLiteral("page"), QString::number(page));
1503  q.addQueryItem(QStringLiteral("pagesize"), QString::number(pageSize));
1504  url.setQuery(q);
1505 
1506  ListJob<Event> *job = new ListJob<Event>(d->m_internals, createRequest(url));
1507  return job;
1508 }
1509 
1510 ListJob<Comment> *Provider::requestComments(const Comment::Type commentType, const QString &id, const QString &id2, int page, int pageSize)
1511 {
1512  if (!isValid()) {
1513  return nullptr;
1514  }
1515 
1516  QString commentTypeString;
1517  commentTypeString = Comment::commentTypeToString(commentType);
1518  if (commentTypeString.isEmpty()) {
1519  return nullptr;
1520  }
1521 
1522  QUrl url = createUrl(QLatin1String("comments/data/") + commentTypeString + QLatin1Char('/') + id + QLatin1Char('/') + id2);
1523 
1524  QUrlQuery q(url);
1525  q.addQueryItem(QStringLiteral("page"), QString::number(page));
1526  q.addQueryItem(QStringLiteral("pagesize"), QString::number(pageSize));
1527  url.setQuery(q);
1528 
1529  ListJob<Comment> *job = new ListJob<Comment>(d->m_internals, createRequest(url));
1530  return job;
1531 }
1532 
1533 ItemPostJob<Comment> *Provider::addNewComment(const Comment::Type commentType, const QString &id, const QString &id2, const QString &parentId, const QString &subject, const QString &message)
1534 {
1535  if (!isValid()) {
1536  return nullptr;
1537  }
1538 
1539  QString commentTypeString;
1540  commentTypeString = Comment::commentTypeToString(commentType);
1541  if (commentTypeString.isEmpty()) {
1542  return nullptr;
1543  }
1544 
1545  QMap<QString, QString> postParameters;
1546 
1547  postParameters.insert(QLatin1String("type"), commentTypeString);
1548  postParameters.insert(QLatin1String("content"), id);
1549  postParameters.insert(QLatin1String("content2"), id2);
1550  postParameters.insert(QLatin1String("parent"), parentId);
1551  postParameters.insert(QLatin1String("subject"), subject);
1552  postParameters.insert(QLatin1String("message"), message);
1553 
1554  return new ItemPostJob<Comment>(d->m_internals, createRequest(QLatin1String("comments/add")), postParameters);
1555 }
1556 
1557 PostJob *Provider::voteForComment(const QString &id, uint rating)
1558 {
1559  if (!isValid() || (rating > 100)) {
1560  return nullptr;
1561  }
1562 
1563  QMap<QString, QString> postParameters;
1564  postParameters.insert(QLatin1String("vote"), QString::number(rating));
1565 
1566  QUrl url = createUrl(QLatin1String("comments/vote/") + id);
1567  return new PostJob(d->m_internals, createRequest(url), postParameters);
1568 }
1569 
1570 PostJob *Provider::setPrivateData(const QString &app, const QString &key, const QString &value)
1571 {
1572  if (!isValid()) {
1573  return nullptr;
1574  }
1575 
1576  QUrl url = createUrl(QLatin1String("privatedata/setattribute/") + app + QLatin1Char('/') + key);
1577  PostFileData postRequest(url);
1578 
1579  postRequest.addArgument(QLatin1String("value"), value);
1580 
1581  return new PostJob(d->m_internals, postRequest.request(), postRequest.data());
1582 }
1583 
1584 ItemJob<PrivateData> *Provider::requestPrivateData(const QString &app, const QString &key)
1585 {
1586  if (!isValid()) {
1587  return nullptr;
1588  }
1589 
1590  ItemJob<PrivateData> *job = new ItemJob<PrivateData>(d->m_internals, createRequest(QLatin1String("privatedata/getattribute/") + app + QLatin1Char('/') + key));
1591  return job;
1592 }
1593 
1594 QUrl Provider::createUrl(const QString &path)
1595 {
1596  QUrl url(d->m_baseUrl.toString() + path);
1597  return url;
1598 }
1599 
1600 QNetworkRequest Provider::createRequest(const QUrl &url)
1601 {
1602  QNetworkRequest request(url);
1603  request.setHeader(QNetworkRequest::ContentTypeHeader,QStringLiteral("application/x-www-form-urlencoded"));
1604 
1605  QString agentHeader;
1607  agentHeader = QString::fromLocal8Bit("%1/%2").arg(QCoreApplication::instance()->applicationName(), QCoreApplication::instance()->applicationVersion());
1608  } else {
1609  agentHeader = QString::fromLocal8Bit("Attica/%1").arg(QLatin1String(LIBATTICA_VERSION_STRING));
1610  }
1611  if (!d->m_additionalAgentInformation.isEmpty()) {
1612  agentHeader = QString::fromLocal8Bit("%1 (+%2)").arg(agentHeader, d->m_additionalAgentInformation);
1613  }
1614  request.setHeader(QNetworkRequest::UserAgentHeader, agentHeader);
1615 
1616  if (!d->m_credentialsUserName.isEmpty()) {
1617  request.setAttribute((QNetworkRequest::Attribute) BaseJob::UserAttribute, QVariant(d->m_credentialsUserName));
1618  request.setAttribute((QNetworkRequest::Attribute) BaseJob::PasswordAttribute, QVariant(d->m_credentialsPassword));
1619  }
1620  return request;
1621 }
1622 
1623 QNetworkRequest Provider::createRequest(const QString &path)
1624 {
1625  return createRequest(createUrl(path));
1626 }
1627 
1628 ItemJob<Config>* Provider::doRequestConfig(const QUrl& url)
1629 {
1630  return new ItemJob<Config>(d->m_internals, createRequest(url));
1631 }
1632 
1633 ItemJob<Person> *Provider::doRequestPerson(const QUrl &url)
1634 {
1635  return new ItemJob<Person>(d->m_internals, createRequest(url));
1636 }
1637 
1638 ItemJob<AccountBalance> *Provider::doRequestAccountBalance(const QUrl &url)
1639 {
1640  return new ItemJob<AccountBalance>(d->m_internals, createRequest(url));
1641 }
1642 
1643 ListJob<Person> *Provider::doRequestPersonList(const QUrl &url)
1644 {
1645  return new ListJob<Person>(d->m_internals, createRequest(url));
1646 }
1647 
1648 ListJob<Achievement> *Provider::doRequestAchievementList(const QUrl &url)
1649 {
1650  return new ListJob<Achievement>(d->m_internals, createRequest(url));
1651 }
1652 
1653 ListJob<Activity> *Provider::doRequestActivityList(const QUrl &url)
1654 {
1655  return new ListJob<Activity>(d->m_internals, createRequest(url));
1656 }
1657 
1658 ListJob<Folder> *Provider::doRequestFolderList(const QUrl &url)
1659 {
1660  return new ListJob<Folder>(d->m_internals, createRequest(url));
1661 }
1662 
1663 ListJob<Forum> *Provider::doRequestForumList(const QUrl &url)
1664 {
1665  return new ListJob<Forum>(d->m_internals, createRequest(url));
1666 }
1667 
1668 ListJob<Topic> *Provider::doRequestTopicList(const QUrl &url)
1669 {
1670  return new ListJob<Topic>(d->m_internals, createRequest(url));
1671 }
1672 
1673 ListJob<Message> *Provider::doRequestMessageList(const QUrl &url)
1674 {
1675  return new ListJob<Message>(d->m_internals, createRequest(url));
1676 }
1677 
1679 {
1680  return d->m_achievementVersion;
1681 }
1682 
1684 {
1685  return d->m_activityVersion;
1686 }
1688 {
1689  return d->m_commentVersion;
1690 }
1692 {
1693  return d->m_contentVersion;
1694 }
1696 {
1697  return d->m_fanVersion;
1698 }
1700 {
1701  return d->m_forumVersion;
1702 }
1704 {
1705  return d->m_friendVersion;
1706 }
1708 {
1709  return d->m_knowledgebaseVersion;
1710 }
1712 {
1713  return d->m_messageVersion;
1714 }
1716 {
1717  return d->m_personVersion;
1718 }
1719 
1721 {
1722  return !d->m_achievementVersion.isEmpty();
1723 }
1724 
1726 {
1727  return !d->m_activityVersion.isEmpty();
1728 }
1730 {
1731  return !d->m_commentVersion.isEmpty();
1732 }
1734 {
1735  return !d->m_contentVersion.isEmpty();
1736 }
1738 {
1739  return !d->m_fanVersion.isEmpty();
1740 }
1742 {
1743  return !d->m_forumVersion.isEmpty();
1744 }
1746 {
1747  return !d->m_friendVersion.isEmpty();
1748 }
1750 {
1751  return !d->m_knowledgebaseVersion.isEmpty();
1752 }
1754 {
1755  return !d->m_messageVersion.isEmpty();
1756 }
1758 {
1759  return !d->m_personVersion.isEmpty();
1760 }
Represents a single content.
Definition: content.h:31
PostJob * setPreviewImage(const QString &contentId, const QString &previewId, const QString &fileName, const QByteArray &image)
Upload an image file as preview for the content.
Definition: provider.cpp:1245
QString toString(Qt::DateFormat format) const const
The Distribution class contains information about one distribution that the server offers...
Definition: distribution.h:24
bool isEnabled() const
Test if the provider is enabled by the settings.
Definition: provider.cpp:223
ListJob< Content > * searchContents(const Category::List &categories, const QString &search=QString(), SortMode mode=Rating, uint page=0, uint pageSize=10)
Request a list of Contents.
Definition: provider.cpp:1079
DeleteJob * deleteAchievement(const QString &contentId, const QString &achievementId)
Deletes an achievement on the server.
Definition: provider.cpp:530
QString name() const
A name for the provider that can be displayed to the user.
Definition: provider.cpp:249
ItemJob< RemoteAccount > * requestRemoteAccount(const QString &id)
Get a remote account by its ID.
Definition: provider.cpp:881
QString toString(Qt::DateFormat format) const const
QString id() const
Gets the id of the Folder.
Definition: folder.cpp:52
Rating
PostJob * createBuildServiceJob(const BuildServiceJob &job)
Create a new job for a given project on a given buildservice for a given target.
Definition: provider.cpp:779
void reserve(int alloc)
QString forumServiceVersion() const
Version of the forum part of the API.
Definition: provider.cpp:1699
bool hasContentService() const
Test if the server supports the content part of the API.
Definition: provider.cpp:1733
PostJob * deleteRemoteAccount(const QString &id)
Deletes a remote account stored on the OCS server.
Definition: provider.cpp:892
Represents a single content category.
Definition: category.h:22
QDebug & nospace()
ListJob< Project > * requestProjects()
Get a list of build service projects.
Definition: provider.cpp:581
QString join(const QString &separator) const const
PostJob * publishBuildJob(const BuildServiceJob &buildjob, const Publisher &publisher)
Publish the result of a completed build job to a publisher.
Definition: provider.cpp:708
QString contentServiceVersion() const
Version of the content part of the API.
Definition: provider.cpp:1691
bool isEmpty() const const
QString personServiceVersion() const
Version of the person part of the API.
Definition: provider.cpp:1715
bool hasKnowledgebaseService() const
Test if the server supports the knowledgebase part of the API.
Definition: provider.cpp:1749
ListJob< Publisher > * requestPublishers()
Get a list of publishers.
Definition: provider.cpp:808
bool hasForumService() const
Test if the server supports the forum part of the API.
Definition: provider.cpp:1741
PostJob * editRemoteAccount(const RemoteAccount &account)
Edit an existing remote account.
Definition: provider.cpp:861
ItemJob< Config > * requestConfig()
Fetches server config.
Definition: provider.cpp:311
bool saveCredentials(const QString &user, const QString &password)
Sets (and remembers) user name and password for this provider.
Definition: provider.cpp:286
void addQueryItem(const QString &key, const QString &value)
PostJob * cancelBuildServiceJob(const BuildServiceJob &job)
Cancel a job.
Definition: provider.cpp:766
QString number(int n, int base)
int count(const T &value) const const
QString fromLocal8Bit(const char *str, int size)
ItemJob< BuildServiceJobOutput > * requestBuildServiceJobOutput(const QString &id)
Get the build output for a specific build service job.
Definition: provider.cpp:724
void append(const T &value)
ItemJob< Publisher > * requestPublisher(const QString &id)
Get the information for a specific publisher.
Definition: provider.cpp:681
bool hasCommentService() const
Test if the server supports the comments part of the API.
Definition: provider.cpp:1729
bool hasFriendService() const
Test if the server supports the friend part of the API.
Definition: provider.cpp:1745
void setAdditionalAgentInformation(const QString &additionalInformation)
Set a custom identifier for your application (sent along with the requests as the http agent header i...
Definition: provider.cpp:241
bool isEmpty() const const
bool isValid() const
Returns true if the provider has been set up and can be used.
Definition: provider.cpp:218
bool isValid() const
Checks whether this Content has an id.
Definition: content.cpp:144
bool loadCredentials(QString &user, QString &password)
Load user name and password from the store.
Definition: provider.cpp:272
QCoreApplication * instance()
QString id() const
Gets the id of the Content.
Definition: content.cpp:64
PostJob * setPrivateData(const QString &app, const QString &key, const QString &value)
Sets the value of an attribute.
Definition: provider.cpp:1570
bool hasAchievementService() const
Test if the server supports the achievement part of the API.
Definition: provider.cpp:1720
ListJob< License > * requestLicenses()
Get a list of licenses (such as GPL)
Definition: provider.cpp:1046
PutJob * editAchievement(const QString &contentId, const QString &achievementId, const Achievement &achievement)
Post modifications to an Achievement on the server.
Definition: provider.cpp:495
QString commentServiceVersion() const
Version of the comments part of the API.
Definition: provider.cpp:1687
bool hasPersonService() const
Test if the server supports the person part of the API.
Definition: provider.cpp:1757
QDebug & space()
bool hasMessageService() const
Test if the server supports the message part of the API.
Definition: provider.cpp:1753
void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value)
QString achievementServiceVersion() const
Version of the achievement part of the API.
Definition: provider.cpp:1678
QString knowledgebaseServiceVersion() const
Version of the knowledgebase part of the API.
Definition: provider.cpp:1707
QString friendServiceVersion() const
Version of the friend part of the API.
Definition: provider.cpp:1703
QString id() const
Gets the id of the Category.
Definition: category.cpp:55
QString fanServiceVersion() const
Version of the fan part of the API.
Definition: provider.cpp:1695
PostJob * createProject(const Project &project)
Post modifications to a Project on the server.
Definition: provider.cpp:639
QDataStream & operator<<(QDataStream &out, const KDateTime::Spec &spec)
const char * data() const const
ListJob< BuildServiceJob > * requestBuildServiceJobs(const Project &project)
Get a list of build service projects.
Definition: provider.cpp:819
bool isValid() const
Checks whether this Category has an id.
Definition: category.cpp:80
ListJob< Distribution > * requestDistributions()
Get a list of distributions (such as Ark, Debian)
Definition: provider.cpp:1057
QString name() const
Gets the name of the Content.
Definition: content.cpp:74
PostJob * voteForComment(const QString &id, uint rating)
Vote a comment item.
Definition: provider.cpp:1557
The Provider class represents one Open Collaboration Service provider.
Definition: provider.h:95
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
Attica::PostJob * uploadTarballToBuildService(const QString &projectId, const QString &fileName, const QByteArray &payload)
Upload a tarball to the buildservice.
Definition: provider.cpp:904
The License class contains information about one license that the server offers.
Definition: license.h:21
void setAttribute(QNetworkRequest::Attribute code, const QVariant &value)
PostJob * savePublisherField(const Project &project, const PublisherField &field)
Save the value of a single publishing field.
Definition: provider.cpp:692
void setQuery(const QString &query, QUrl::ParsingMode mode)
ItemPostJob< Comment > * addNewComment(const Comment::Type commentType, const QString &id, const QString &id2, const QString &parentId, const QString &subject, const QString &message)
Add a new comment.
Definition: provider.cpp:1533
bool hasFanService() const
Test if the server supports the fan part of the API.
Definition: provider.cpp:1737
PostJob * createRemoteAccount(const RemoteAccount &account)
Create a new remote account, an account for a build service instance which is stored in the OCS servi...
Definition: provider.cpp:841
QString fromLatin1(const char *str, int size)
ListJob< Category > * requestCategories()
Get a list of categories (such as wallpaper)
Definition: provider.cpp:1035
ItemJob< BuildServiceJob > * requestBuildServiceJob(const QString &id)
Get the information for a specific build service job, such as status and progress.
Definition: provider.cpp:735
QMap::iterator insert(const Key &key, const T &value)
QMap< QString, QString > attributes() const
Get all attributes that are not included in the basis set of attributes exposed by the Content class...
Definition: content.cpp:139
bool hasCredentials() const
Test if the provider has user name/password available.
Definition: provider.cpp:263
QString messageServiceVersion() const
Version of the message part of the API.
Definition: provider.cpp:1711
ItemJob< Content > * requestContent(const QString &contentId)
Retrieve a single content.
Definition: provider.cpp:1149
PostJob * deleteProject(const Project &project)
Deletes a project on the server.
Definition: provider.cpp:660
PostJob * voteForContent(const QString &contentId, bool positiveVote)
Vote for a content item This version is for the old OCS API < 1.6.
Definition: provider.cpp:1276
PostJob * editProject(const Project &project)
Post modifications to a Project on the server.
Definition: provider.cpp:649
QUrl baseUrl() const
A url that identifies this provider.
Definition: provider.cpp:213
ItemJob< PrivateData > * requestPrivateData()
Fetches all stored private data.
Definition: provider.h:318
ListJob< Content > * searchContentsByPerson(const Category::List &categories, const QString &person, const QString &search=QString(), SortMode mode=Rating, uint page=0, uint pageSize=10)
Request a list of Contents.
Definition: provider.cpp:1084
QString toString() const const
ListJob< BuildService > * requestBuildServices()
Get a list of build service build services.
Definition: provider.cpp:797
ListJob< Achievement > * requestAchievements(const QString &contentId, const QString &achievementId, const QString &userId)
Get a list of achievements.
Definition: provider.cpp:451
ItemPostJob< Achievement > * addNewAchievement(const QString &id, const Achievement &newAchievement)
Add a new achievement.
Definition: provider.cpp:464
ListJob< RemoteAccount > * requestRemoteAccounts()
Get a list of remote accounts, account for a build service instance which is stored in the OCS servic...
Definition: provider.cpp:830
Represents a single mail folder.
Definition: folder.h:23
ListJob< HomePageType > * requestHomePageTypes()
Get a list of home page types (such as blog, Facebook)
Definition: provider.cpp:1068
bool hasActivityService() const
Test if the server supports the activity part of the API.
Definition: provider.cpp:1725
QString activityServiceVersion() const
Version of the activity part of the API.
Definition: provider.cpp:1683
ItemJob< Project > * requestProject(const QString &id)
Get a Project&#39;s data.
Definition: provider.cpp:592
ItemJob< BuildService > * requestBuildService(const QString &id)
Get the information for a specific build service instance.
Definition: provider.cpp:671
QString additionalAgentInformation() const
The custom identifier sent along with requests.
Definition: provider.cpp:245
PostJob * checkLogin(const QString &user, const QString &password)
Test if the server accepts the login/password.
Definition: provider.cpp:297
ListJob< Comment > * requestComments(const Comment::Type commentType, const QString &id, const QString &id2, int page, int pageSize)
Request a list of comments for a content / forum / knowledgebase / event.
Definition: provider.cpp:1510
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Jan 18 2021 23:03:37 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.