KNewStuff

atticaprovider.cpp
1 /*
2  SPDX-FileCopyrightText: 2009-2010 Frederik Gladhorn <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6 
7 #include "atticaprovider_p.h"
8 
9 #include "commentsmodel.h"
10 #include "question.h"
11 #include "tagsfilterchecker.h"
12 
13 #include <QCollator>
14 #include <knewstuffcore_debug.h>
15 #include <KLocalizedString>
16 
17 #include <attica/providermanager.h>
18 #include <attica/provider.h>
19 #include <attica/listjob.h>
20 #include <attica/content.h>
21 #include <attica/downloaditem.h>
22 #include <attica/accountbalance.h>
23 #include <attica/person.h>
24 
25 using namespace Attica;
26 
27 namespace KNSCore
28 {
29 
30 AtticaProvider::AtticaProvider(const QStringList &categories, const QString& additionalAgentInformation)
31  : mEntryJob(nullptr)
32  , mInitialized(false)
33 {
34  // init categories map with invalid categories
35  for (const QString &category : categories) {
36  mCategoryMap.insert(category, Attica::Category());
37  }
38 
39  connect(&m_providerManager, &ProviderManager::providerAdded, this, [=](const Attica::Provider &provider){
40  providerLoaded(provider);
41  m_provider.setAdditionalAgentInformation(additionalAgentInformation);
42  });
43  connect(&m_providerManager, SIGNAL(authenticationCredentialsMissing(Provider)),
44  SLOT(authenticationCredentialsMissing(Provider)));
45  connect(this, &Provider::loadComments, this, &AtticaProvider::loadComments);
46  connect(this, &Provider::loadPerson, this, &AtticaProvider::loadPerson);
47 }
48 
49 AtticaProvider::AtticaProvider(const Attica::Provider &provider, const QStringList &categories, const QString& additionalAgentInformation)
50  : mEntryJob(nullptr)
51  , mInitialized(false)
52 {
53  // init categories map with invalid categories
54  for (const QString &category : categories) {
55  mCategoryMap.insert(category, Attica::Category());
56  }
57  providerLoaded(provider);
58  m_provider.setAdditionalAgentInformation(additionalAgentInformation);
59 }
60 
61 QString AtticaProvider::id() const
62 {
63  return m_providerId;
64 }
65 
66 void AtticaProvider::authenticationCredentialsMissing(const KNSCore::Provider &)
67 {
68  qCDebug(KNEWSTUFFCORE) << "Authentication missing!";
69  // FIXME Show autentication dialog
70 }
71 
72 bool AtticaProvider::setProviderXML(const QDomElement &xmldata)
73 {
74  if (xmldata.tagName() != QLatin1String("provider")) {
75  return false;
76  }
77 
78  // FIXME this is quite ugly, repackaging the xml into a string
79  QDomDocument doc(QStringLiteral("temp"));
80  qCDebug(KNEWSTUFFCORE) << "setting provider xml" << doc.toString();
81 
82  doc.appendChild(xmldata.cloneNode(true));
83  m_providerManager.addProviderFromXml(doc.toString());
84 
85  if (!m_providerManager.providers().isEmpty()) {
86  qCDebug(KNEWSTUFFCORE) << "base url of attica provider:" << m_providerManager.providers().constLast().baseUrl().toString();
87  } else {
88  qCCritical(KNEWSTUFFCORE) << "Could not load provider.";
89  return false;
90  }
91  return true;
92 }
93 
94 void AtticaProvider::setCachedEntries(const KNSCore::EntryInternal::List &cachedEntries)
95 {
96  mCachedEntries = cachedEntries;
97 }
98 
99 void AtticaProvider::providerLoaded(const Attica::Provider &provider)
100 {
101  mName = provider.name();
102  qCDebug(KNEWSTUFFCORE) << "Added provider: " << provider.name();
103 
104  m_provider = provider;
105  m_provider.setAdditionalAgentInformation(mName);
106  m_providerId = provider.baseUrl().toString();
107 
108  Attica::ListJob<Attica::Category> *job = m_provider.requestCategories();
109  connect(job, &BaseJob::finished, this, &AtticaProvider::listOfCategoriesLoaded);
110  job->start();
111 }
112 
113 void AtticaProvider::listOfCategoriesLoaded(Attica::BaseJob *listJob)
114 {
115  if (!jobSuccess(listJob)) {
116  return;
117  }
118 
119  qCDebug(KNEWSTUFFCORE) << "loading categories: " << mCategoryMap.keys();
120 
121  auto *job = static_cast<Attica::ListJob<Attica::Category>*>(listJob);
122  const Category::List categoryList = job->itemList();
123 
124  QList<CategoryMetadata> categoryMetadataList;
125  for (const Category &category : categoryList) {
126  if (mCategoryMap.contains(category.name())) {
127  qCDebug(KNEWSTUFFCORE) << "Adding category: " << category.name() << category.displayName();
128  //If there is only the placeholder category, replace it
129  if (mCategoryMap.contains(category.name()) && !mCategoryMap.value(category.name()).isValid()) {
130  mCategoryMap.replace(category.name(), category);
131  } else {
132  mCategoryMap.insert(category.name(), category);
133  }
134 
135  CategoryMetadata categoryMetadata;
136  categoryMetadata.id = category.id();
137  categoryMetadata.name = category.name();
138  categoryMetadata.displayName = category.displayName();
139  categoryMetadataList << categoryMetadata;
140  }
141  }
142  std::sort(categoryMetadataList.begin(), categoryMetadataList.end(), [](const AtticaProvider::CategoryMetadata &i, const AtticaProvider::CategoryMetadata &j) -> bool {
143  const QString a(i.displayName.isEmpty() ? i.name : i.displayName);
144  const QString b(j.displayName.isEmpty() ? j.name : j.displayName);
145 
146  return (QCollator().compare(a, b) < 0);
147  });
148 
149  bool correct = false;
150  for(auto it = mCategoryMap.cbegin(), itEnd = mCategoryMap.cend(); it!=itEnd; ++it) {
151  if (!it.value().isValid()) {
152  qCWarning(KNEWSTUFFCORE) << "Could not find category" << it.key();
153  } else {
154  correct = true;
155  }
156  }
157 
158  if (correct) {
159  mInitialized = true;
160  Q_EMIT providerInitialized(this);
161  Q_EMIT categoriesMetadataLoded(categoryMetadataList);
162  } else {
163  Q_EMIT signalErrorCode(KNSCore::ConfigFileError, i18n("All categories are missing"), QVariant());
164  }
165 }
166 
167 bool AtticaProvider::isInitialized() const
168 {
169  return mInitialized;
170 }
171 
172 void AtticaProvider::loadEntries(const KNSCore::Provider::SearchRequest &request)
173 {
174  if (mEntryJob) {
175  mEntryJob->abort();
176  mEntryJob = nullptr;
177  }
178 
179  mCurrentRequest = request;
180  switch (request.filter) {
181  case None:
182  break;
183  case ExactEntryId: {
184  ItemJob<Content> *job = m_provider.requestContent(request.searchTerm);
185  connect(job, &BaseJob::finished, this, &AtticaProvider::detailsLoaded);
186  job->start();
187  return;
188  }
189  case Installed:
190  if (request.page == 0) {
191  Q_EMIT loadingFinished(request, installedEntries());
192  } else {
193  Q_EMIT loadingFinished(request, EntryInternal::List());
194  }
195  return;
196  case Updates:
197  checkForUpdates();
198  return;
199  }
200 
201  Attica::Provider::SortMode sorting = atticaSortMode(request.sortMode);
202  Attica::Category::List categoriesToSearch;
203 
204  if (request.categories.isEmpty()) {
205  // search in all categories
206  categoriesToSearch = mCategoryMap.values();
207  } else {
208  categoriesToSearch.reserve(request.categories.size());
209  for (const QString &categoryName : qAsConst(request.categories)) {
210  categoriesToSearch.append(mCategoryMap.values(categoryName));
211  }
212  }
213 
214  ListJob<Content> *job = m_provider.searchContents(categoriesToSearch, request.searchTerm, sorting, request.page, request.pageSize);
215  connect(job, &BaseJob::finished, this, &AtticaProvider::categoryContentsLoaded);
216 
217  mEntryJob = job;
218  job->start();
219 }
220 
221 void AtticaProvider::checkForUpdates()
222 {
223  if (mCachedEntries.isEmpty()) {
224  Q_EMIT loadingFinished(mCurrentRequest, {});
225  }
226 
227  for (const EntryInternal &e : qAsConst(mCachedEntries)) {
228  ItemJob<Content> *job = m_provider.requestContent(e.uniqueId());
229  connect(job, &BaseJob::finished, this, &AtticaProvider::detailsLoaded);
230  m_updateJobs.insert(job);
231  job->start();
232  qCDebug(KNEWSTUFFCORE) << "Checking for update: " << e.name();
233  }
234 }
235 
236 void AtticaProvider::loadEntryDetails(const KNSCore::EntryInternal &entry)
237 {
238  ItemJob<Content> *job = m_provider.requestContent(entry.uniqueId());
239  connect(job, &BaseJob::finished, this, &AtticaProvider::detailsLoaded);
240  job->start();
241 }
242 
243 void AtticaProvider::detailsLoaded(BaseJob *job)
244 {
245  if (jobSuccess(job)) {
246  auto *contentJob = static_cast<ItemJob<Content>*>(job);
247  Content content = contentJob->result();
248  EntryInternal entry = entryFromAtticaContent(content);
249  Q_EMIT entryDetailsLoaded(entry);
250  qCDebug(KNEWSTUFFCORE) << "check update finished: " << entry.name();
251  }
252 
253  if (m_updateJobs.remove(job) && m_updateJobs.isEmpty()) {
254  qCDebug(KNEWSTUFFCORE) << "check update finished.";
255  QList<EntryInternal> updatable;
256  for (const EntryInternal &entry : qAsConst(mCachedEntries)) {
257  if (entry.status() == KNS3::Entry::Updateable) {
258  updatable.append(entry);
259  }
260  }
261  Q_EMIT loadingFinished(mCurrentRequest, updatable);
262  }
263 }
264 
265 void AtticaProvider::categoryContentsLoaded(BaseJob *job)
266 {
267  if (!jobSuccess(job)) {
268  return;
269  }
270 
271  auto *listJob = static_cast<ListJob<Content>*>(job);
272  const Content::List contents = listJob->itemList();
273 
274  EntryInternal::List entries;
275  TagsFilterChecker checker(tagFilter());
276  TagsFilterChecker downloadschecker(downloadTagFilter());
277  for (const Content &content : contents) {
278  if (!content.isValid()) {
279  qCDebug(KNEWSTUFFCORE) << "Filtered out an invalid entry. This suggests something is not right on the originating server. Please contact the administrators of" << name() << "and inform them there is an issue with content in the category or categories" << mCurrentRequest.categories;
280  continue;
281  }
282  if (checker.filterAccepts(content.tags())) {
283  bool filterAcceptsDownloads = true;
284  if (content.downloads() > 0) {
285  filterAcceptsDownloads = false;
286  const QList<Attica::DownloadDescription> descs = content.downloadUrlDescriptions();
287  for (const Attica::DownloadDescription &dli : descs) {
288  if (downloadschecker.filterAccepts(dli.tags())) {
289  filterAcceptsDownloads = true;
290  break;
291  }
292  }
293  }
294  if (filterAcceptsDownloads) {
295  mCachedContent.insert(content.id(), content);
296  entries.append(entryFromAtticaContent(content));
297  } else {
298  qCDebug(KNEWSTUFFCORE) << "Filter has excluded" << content.name() << "on download filter" << downloadTagFilter();
299  }
300  } else {
301  qCDebug(KNEWSTUFFCORE) << "Filter has excluded" << content.name() << "on entry filter" << tagFilter();
302  }
303  }
304 
305  qCDebug(KNEWSTUFFCORE) << "loaded: " << mCurrentRequest.hashForRequest() << " count: " << entries.size();
306  Q_EMIT loadingFinished(mCurrentRequest, entries);
307  mEntryJob = nullptr;
308 }
309 
310 Attica::Provider::SortMode AtticaProvider::atticaSortMode(const SortMode &sortMode)
311 {
312  switch(sortMode) {
313  case Newest:
314  return Attica::Provider::Newest;
315  case Alphabetical:
316  return Attica::Provider::Alphabetical;
317  case Downloads:
318  return Attica::Provider::Downloads;
319  default:
320  return Attica::Provider::Rating;
321  }
322 }
323 
324 void AtticaProvider::loadPayloadLink(const KNSCore::EntryInternal &entry, int linkId)
325 {
326  Attica::Content content = mCachedContent.value(entry.uniqueId());
327  const DownloadDescription desc = content.downloadUrlDescription(linkId);
328 
329  if (desc.hasPrice()) {
330  // Ask for balance, then show information...
331  ItemJob<AccountBalance> *job = m_provider.requestAccountBalance();
332  connect(job, &BaseJob::finished, this, &AtticaProvider::accountBalanceLoaded);
333  mDownloadLinkJobs[job] = qMakePair(entry, linkId);
334  job->start();
335 
336  qCDebug(KNEWSTUFFCORE) << "get account balance";
337  } else {
338  ItemJob<DownloadItem> *job = m_provider.downloadLink(entry.uniqueId(), QString::number(linkId));
339  connect(job, &BaseJob::finished, this, &AtticaProvider::downloadItemLoaded);
340  mDownloadLinkJobs[job] = qMakePair(entry, linkId);
341  job->start();
342 
343  qCDebug(KNEWSTUFFCORE) << " link for " << entry.uniqueId();
344  }
345 }
346 
347 void AtticaProvider::loadComments(const EntryInternal &entry, int commentsPerPage, int page)
348 {
349  ListJob<Attica::Comment> *job = m_provider.requestComments(Attica::Comment::ContentComment, entry.uniqueId(), QStringLiteral("0"), page, commentsPerPage);
350  connect(job, &BaseJob::finished, this, &AtticaProvider::loadedComments);
351  job->start();
352 }
353 
355 QList<std::shared_ptr<KNSCore::Comment>> getCommentsList(const Attica::Comment::List &comments, std::shared_ptr<KNSCore::Comment> parent) {
357  for (const Attica::Comment &comment : comments) {
358  qCDebug(KNEWSTUFFCORE) << "Appending comment with id" << comment.id() << ", which has" << comment.childCount() << "children";
359  auto knsComment = std::make_shared<KNSCore::Comment>();
360  knsComment->id = comment.id();
361  knsComment->subject = comment.subject();
362  knsComment->text = comment.text();
363  knsComment->childCount = comment.childCount();
364  knsComment->username = comment.user();
365  knsComment->date = comment.date();
366  knsComment->score = comment.score();
367  knsComment->parent = parent;
368  knsComments << knsComment;
369  if (comment.childCount() > 0) {
370  qCDebug(KNEWSTUFFCORE) << "Getting more comments, as this one has children, and we currently have this number of comments:" << knsComments.count();
371  knsComments << getCommentsList(comment.children(), knsComment);
372  qCDebug(KNEWSTUFFCORE) << "After getting the children, we now have the following number of comments:" << knsComments.count();
373  }
374  }
375  return knsComments;
376 }
377 
378 void AtticaProvider::loadedComments(Attica::BaseJob *baseJob)
379 {
380  if (!jobSuccess(baseJob)) {
381  return;
382  }
383 
384  auto *job = static_cast<ListJob<Attica::Comment>*>(baseJob);
385  Attica::Comment::List comments = job->itemList();
386 
387  QList<std::shared_ptr<KNSCore::Comment>> receivedComments = getCommentsList(comments, nullptr);
388  Q_EMIT commentsLoaded(receivedComments);
389 }
390 
391 void AtticaProvider::loadPerson(const QString &username)
392 {
393  if (m_provider.hasPersonService()) {
394  ItemJob<Attica::Person> *job = m_provider.requestPerson(username);
395  job->setProperty("username", username);
396  connect(job, &BaseJob::finished, this, &AtticaProvider::loadedPerson);
397  job->start();
398  }
399 }
400 
401 void AtticaProvider::loadedPerson(Attica::BaseJob *baseJob)
402 {
403  if (!jobSuccess(baseJob)) {
404  return;
405  }
406 
407  auto *job = static_cast<ItemJob<Attica::Person>*>(baseJob);
408  Attica::Person person = job->result();
409 
410  auto author = std::make_shared<KNSCore::Author>();
411  author->setId(job->property("username").toString()); // This is a touch hack-like, but it ensures we actually have the data in case it is not returned by the server
412  author->setName(QStringLiteral("%1 %2").arg(person.firstName(), person.lastName()).trimmed());
413  author->setHomepage(person.homepage());
414  author->setProfilepage(person.extendedAttribute(QStringLiteral("profilepage")));
415  author->setAvatarUrl(person.avatarUrl());
416  author->setDescription(person.extendedAttribute(QStringLiteral("description")));
417  Q_EMIT personLoaded(author);
418 }
419 
420 void AtticaProvider::accountBalanceLoaded(Attica::BaseJob *baseJob)
421 {
422  if (!jobSuccess(baseJob)) {
423  return;
424  }
425 
426  auto *job = static_cast<ItemJob<AccountBalance>*>(baseJob);
427  AccountBalance item = job->result();
428 
429  QPair<EntryInternal, int> pair = mDownloadLinkJobs.take(job);
430  EntryInternal entry(pair.first);
431  Content content = mCachedContent.value(entry.uniqueId());
432  if (content.downloadUrlDescription(pair.second).priceAmount() < item.balance()) {
433  qCDebug(KNEWSTUFFCORE) << "Your balance is greater than the price."
434  << content.downloadUrlDescription(pair.second).priceAmount() << " balance: " << item.balance();
435  Question question;
436  question.setQuestion(i18nc("the price of a download item, parameter 1 is the currency, 2 is the price",
437  "This item costs %1 %2.\nDo you want to buy it?",
438  item.currency(), content.downloadUrlDescription(pair.second).priceAmount()
439  ));
440  if(question.ask() == Question::YesResponse) {
441  ItemJob<DownloadItem> *job = m_provider.downloadLink(entry.uniqueId(), QString::number(pair.second));
442  connect(job, &BaseJob::finished, this, &AtticaProvider::downloadItemLoaded);
443  mDownloadLinkJobs[job] = qMakePair(entry, pair.second);
444  job->start();
445  } else {
446  return;
447  }
448  } else {
449  qCDebug(KNEWSTUFFCORE) << "You don't have enough money on your account!"
450  << content.downloadUrlDescription(0).priceAmount() << " balance: " << item.balance();
451  Q_EMIT signalInformation(i18n("Your account balance is too low:\nYour balance: %1\nPrice: %2",
452  item.balance(), content.downloadUrlDescription(0).priceAmount()));
453  }
454 }
455 
456 void AtticaProvider::downloadItemLoaded(BaseJob *baseJob)
457 {
458  if (!jobSuccess(baseJob)) {
459  return;
460  }
461 
462  auto *job = static_cast<ItemJob<DownloadItem>*>(baseJob);
463  DownloadItem item = job->result();
464 
465  EntryInternal entry = mDownloadLinkJobs.take(job).first;
466  entry.setPayload(QString(item.url().toString()));
467  Q_EMIT payloadLinkLoaded(entry);
468 }
469 
470 EntryInternal::List AtticaProvider::installedEntries() const
471 {
472  EntryInternal::List entries;
473  for (const EntryInternal &entry : qAsConst(mCachedEntries)) {
474  if (entry.status() == KNS3::Entry::Installed || entry.status() == KNS3::Entry::Updateable) {
475  entries.append(entry);
476  }
477  }
478  return entries;
479 }
480 
481 void AtticaProvider::vote(const EntryInternal &entry, uint rating)
482 {
483  PostJob *job = m_provider.voteForContent(entry.uniqueId(), rating);
484  connect(job, &BaseJob::finished, this, &AtticaProvider::votingFinished);
485  job->start();
486 }
487 
488 void AtticaProvider::votingFinished(Attica::BaseJob *job)
489 {
490  if (!jobSuccess(job)) {
491  return;
492  }
493  Q_EMIT signalInformation(i18nc("voting for an item (good/bad)", "Your vote was recorded."));
494 }
495 
496 void AtticaProvider::becomeFan(const EntryInternal &entry)
497 {
498  PostJob *job = m_provider.becomeFan(entry.uniqueId());
499  connect(job, &BaseJob::finished, this, &AtticaProvider::becomeFanFinished);
500  job->start();
501 }
502 
503 void AtticaProvider::becomeFanFinished(Attica::BaseJob *job)
504 {
505  if (!jobSuccess(job)) {
506  return;
507  }
508  Q_EMIT signalInformation(i18n("You are now a fan."));
509 }
510 
511 bool AtticaProvider::jobSuccess(Attica::BaseJob *job) const
512 {
513  if (job->metadata().error() == Attica::Metadata::NoError) {
514  return true;
515  }
516  qCDebug(KNEWSTUFFCORE) << "job error: " << job->metadata().error() << " status code: " << job->metadata().statusCode() << job->metadata().message();
517 
518  if (job->metadata().error() == Attica::Metadata::NetworkError) {
519  Q_EMIT signalErrorCode(KNSCore::NetworkError, i18n("Network error %1: %2", job->metadata().statusCode(), job->metadata().statusString()), job->metadata().statusCode());
520  }
521  if (job->metadata().error() == Attica::Metadata::OcsError) {
522  if (job->metadata().statusCode() == 200) {
523  Q_EMIT signalErrorCode(KNSCore::OcsError, i18n("Too many requests to server. Please try again in a few minutes."), job->metadata().statusCode());
524  } else if (job->metadata().statusCode() == 405) {
525  Q_EMIT signalErrorCode(KNSCore::OcsError, i18n("The Open Collaboration Services instance %1 does not support the attempted function.", name()), job->metadata().statusCode());
526  } else {
527  Q_EMIT signalErrorCode(KNSCore::OcsError, i18n("Unknown Open Collaboration Service API error. (%1)", job->metadata().statusCode()), job->metadata().statusCode());
528  }
529  }
530  return false;
531 }
532 
533 EntryInternal AtticaProvider::entryFromAtticaContent(const Attica::Content &content)
534 {
535  EntryInternal entry;
536 
537  entry.setProviderId(id());
538  entry.setUniqueId(content.id());
539  entry.setStatus(KNS3::Entry::Downloadable);
540  entry.setVersion(content.version());
541  entry.setReleaseDate(content.updated().date());
542  entry.setCategory(content.attribute(QStringLiteral("typeid")));
543 
544  int index = mCachedEntries.indexOf(entry);
545  if (index >= 0) {
546  EntryInternal &cacheEntry = mCachedEntries[index];
547  // check if updateable
548  if (((cacheEntry.status() == KNS3::Entry::Installed) || (cacheEntry.status() == KNS3::Entry::Updateable)) &&
549  ((cacheEntry.version() != entry.version()) || (cacheEntry.releaseDate() != entry.releaseDate()))) {
550  cacheEntry.setStatus(KNS3::Entry::Updateable);
551  cacheEntry.setUpdateVersion(entry.version());
552  cacheEntry.setUpdateReleaseDate(entry.releaseDate());
553  }
554  entry = cacheEntry;
555  } else {
556  mCachedEntries.append(entry);
557  }
558 
559  entry.setName(content.name());
560  entry.setHomepage(content.detailpage());
561  entry.setRating(content.rating());
562  entry.setNumberOfComments(content.numberOfComments());
563  entry.setDownloadCount(content.downloads());
564  entry.setNumberFans(content.attribute(QStringLiteral("fans")).toInt());
565  entry.setDonationLink(content.attribute(QStringLiteral("donationpage")));
566  entry.setKnowledgebaseLink(content.attribute(QStringLiteral("knowledgebasepage")));
567  entry.setNumberKnowledgebaseEntries(content.attribute(QStringLiteral("knowledgebaseentries")).toInt());
568  entry.setHomepage(content.detailpage());
569 
570  entry.setPreviewUrl(content.smallPreviewPicture(QStringLiteral("1")), EntryInternal::PreviewSmall1);
571  entry.setPreviewUrl(content.smallPreviewPicture(QStringLiteral("2")), EntryInternal::PreviewSmall2);
572  entry.setPreviewUrl(content.smallPreviewPicture(QStringLiteral("3")), EntryInternal::PreviewSmall3);
573 
574  entry.setPreviewUrl(content.previewPicture(QStringLiteral("1")), EntryInternal::PreviewBig1);
575  entry.setPreviewUrl(content.previewPicture(QStringLiteral("2")), EntryInternal::PreviewBig2);
576  entry.setPreviewUrl(content.previewPicture(QStringLiteral("3")), EntryInternal::PreviewBig3);
577 
578  entry.setLicense(content.license());
579  Author author;
580  author.setId(content.author());
581  author.setName(content.author());
582  author.setHomepage(content.attribute(QStringLiteral("profilepage")));
583  entry.setAuthor(author);
584 
585  entry.setSource(EntryInternal::Online);
586  entry.setSummary(content.description());
587  entry.setShortSummary(content.summary());
588  entry.setChangelog(content.changelog());
589  entry.setTags(content.tags());
590 
593  for (const Attica::DownloadDescription &desc : descs) {
594  EntryInternal::DownloadLinkInformation info;
595  info.name = desc.name();
596  info.priceAmount = desc.priceAmount();
597  info.distributionType = desc.distributionType();
598  info.descriptionLink = desc.link();
599  info.id = desc.id();
600  info.size = desc.size();
601  info.isDownloadtypeLink = desc.type() == Attica::DownloadDescription::LinkDownload;
602  info.tags = desc.tags();
603  entry.appendDownloadLinkInformation(info);
604  }
605 
606  return entry;
607 }
608 
609 } // namespace
610 
void setRating(int rating)
Sets the rating between 0 (worst) and 100 (best).
A way to ask a user a question from inside a GUI-less library (like KNewStuffCore) ...
Definition: question.h:41
The configuration file is missing or somehow incorrect. The configuration file filename will be held ...
Definition: errorcode.h:29
void setUniqueId(const QString &id)
Set the object&#39;s unique ID.
void setName(const QString &name)
Sets the full name of the author.
Definition: core/author.cpp:77
QString uniqueId() const
Get the object&#39;s unique ID.
QString name() const
QDomNode appendChild(const QDomNode &newChild)
void setId(const QString &id)
Sets the user ID of the author.
Definition: core/author.cpp:67
void setHomepage(const QString &homepage)
Sets the homepage of the author.
QString toString(int indent) const const
void setCategory(const QString &category)
Sets the data category, e.g.
QString summary() const
Contains the core functionality for handling interaction with NewStuff providers. ...
QString attribute(const QString &key) const
void setKnowledgebaseLink(const QString &link)
Set the link for the knowledgebase.
used to keep track of a search
Definition: provider.h:67
QDate releaseDate() const
Retrieve the date of the object&#39;s publication.
KNewStuff author information.
Definition: core/author.h:30
QString toString(QUrl::FormattingOptions options) const const
void setShortSummary(const QString &summary)
Sets a short description of what the object is all about (should be very short)
QList< std::shared_ptr< KNSCore::Comment > > getCommentsList(const Attica::Comment::List &comments, std::shared_ptr< KNSCore::Comment > parent)
TODO KF6 QList is discouraged, and we&#39;ll probably want to switch this (and the rest of the KNS librar...
int size() const const
void setPayload(const QString &url)
Sets the object&#39;s file.
int downloads() const
void setSummary(const QString &summary)
Sets a description (which can potentially be very long)
QString number(int n, int base)
int count(const T &value) const const
QString version() const
Retrieve the version string of the object.
void append(const T &value)
int numberOfComments() const
void setUpdateVersion(const QString &version)
Sets the version number that is available as update.
QStringList tags() const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void setAdditionalAgentInformation(const QString &additionalInformation)
int toInt(bool *ok, int base) const const
bool isEmpty() const const
void setLicense(const QString &license)
Sets the license (abbreviation) applicable to the object.
void setAuthor(const Author &author)
Sets the author of the object.
void setSource(Source source)
The source of this entry can be Cache, Registry or Online -.
QString id() const
void setPreviewUrl(const QString &url, PreviewType type=PreviewSmall1)
Sets the object&#39;s preview file, if available.
void setNumberOfComments(int comments)
Sets the number of comments in the asset.
void setStatus(KNS3::Entry::Status status)
Sets the entry&#39;s status.
An error reported by the OCS API server. In signalErrorCode, this will be accompanied by the OCS erro...
Definition: errorcode.h:28
KNewStuff Base Provider class.
Definition: provider.h:42
Apply simple filtering logic to a list of tags.
QDateTime updated() const
void setNumberFans(int fans)
Sets how many people are fans.
void setDownloadCount(int downloads)
Sets the number of downloads.
QList::iterator end()
QString description() const
void setVersion(const QString &version)
Sets the version number.
QString i18n(const char *text, const TYPE &arg...)
void setDonationLink(const QString &link)
Set a string representation of the URL for the donation website for this entry.
void setUpdateReleaseDate(const QDate &releasedate)
Sets the release date that is available as update.
QDate date() const const
QString name() const
KNewStuff data entry container.
Definition: entryinternal.h:49
void insert(int i, const T &value)
QDomNode cloneNode(bool deep) const const
void setTags(const QStringList &tags)
Set the tags for the content item.
bool filterAccepts(const QStringList &tags)
Check whether the filter list accepts the passed list of tags.
A network error. In signalErrorCode, this will be accompanied by the QtNetwork error code in the meta...
Definition: errorcode.h:27
QUrl detailpage() const
void setNumberKnowledgebaseEntries(int num)
Set the number of knowledgebase entries for this entry.
void setName(const QString &name)
Sets the name for this data object.
QString tagName() const const
void setHomepage(const QUrl &page)
Set a link to a website containing information about this entry.
KNS3::Entry::Status status() const
Retrieves the entry&#39;s status.
int compare(const QString &s1, const QString &s2) const const
void setChangelog(const QString &changelog)
The user written changelog.
int rating() const
QString name() const
Retrieve the name of the data object.
QUrl baseUrl() const
QList< DownloadDescription > downloadUrlDescriptions() const
void clearDownloadLinkInformation()
Remove all download options from this entry.
Definition: engine.h:28
QList::iterator begin()
void setReleaseDate(const QDate &releasedate)
Sets the release date.
void appendDownloadLinkInformation(const DownloadLinkInformation &info)
Add a new download option to this entry.
DownloadDescription downloadUrlDescription(int number) const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Jan 18 2021 22:43:49 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.