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

source code of attica/src/provider.cpp