1 /***************************************************************************
2     Copyright (C) 2012 Robby Stephenson <robby@periapsis.org>
3  ***************************************************************************/
4 
5 /***************************************************************************
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or         *
8  *   modify it under the terms of the GNU General Public License as        *
9  *   published by the Free Software Foundation; either version 2 of        *
10  *   the License or (at your option) version 3 or any later version        *
11  *   accepted by the membership of KDE e.V. (or its successor approved     *
12  *   by the membership of KDE e.V.), which shall act as a proxy            *
13  *   defined in Section 14 of version 3 of the license.                    *
14  *                                                                         *
15  *   This program is distributed in the hope that it will be useful,       *
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  *   GNU General Public License for more details.                          *
19  *                                                                         *
20  *   You should have received a copy of the GNU General Public License     *
21  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
22  *                                                                         *
23  ***************************************************************************/
24 
25 #include "springerfetcher.h"
26 #include "../entry.h"
27 #include "../utils/isbnvalidator.h"
28 #include "../tellico_debug.h"
29 
30 #include <KLocalizedString>
31 #include <KConfigGroup>
32 #include <QUrl>
33 
34 #include <QLabel>
35 #include <QVBoxLayout>
36 #include <QDomDocument>
37 #include <QUrlQuery>
38 
39 namespace {
40   static const char* SPRINGER_BASE_URL = "http://api.springer.com/metadata/pam";
41   static const char* SPRINGER_API_KEY = "m2z42cbw68qhhjcrm8tbj2hc";
42   static const int SPRINGER_QUERY_COUNT = 10;
43 }
44 
45 using namespace Tellico;
46 using Tellico::Fetch::SpringerFetcher;
47 
SpringerFetcher(QObject * parent_)48 SpringerFetcher::SpringerFetcher(QObject* parent_)
49     : XMLFetcher(parent_), m_start(0), m_total(-1) {
50   setLimit(SPRINGER_QUERY_COUNT);
51   setXSLTFilename(QStringLiteral("springer2tellico.xsl"));
52 }
53 
~SpringerFetcher()54 SpringerFetcher::~SpringerFetcher() {
55 }
56 
source() const57 QString SpringerFetcher::source() const {
58   return m_name.isEmpty() ? defaultName() : m_name;
59 }
60 
attribution() const61 QString SpringerFetcher::attribution() const {
62   return i18n("This data is licensed under <a href=""%1"">specific terms</a>.",
63               QLatin1String("https://dev.springernature.com/"));
64 }
65 
canSearch(Fetch::FetchKey k) const66 bool SpringerFetcher::canSearch(Fetch::FetchKey k) const  {
67   return k == Title || k == Person || k == Keyword || k == ISBN || k == DOI || k == Raw;
68 }
69 
canFetch(int type) const70 bool SpringerFetcher::canFetch(int type) const {
71   return type == Data::Collection::Bibtex;
72 }
73 
readConfigHook(const KConfigGroup &)74 void SpringerFetcher::readConfigHook(const KConfigGroup&) {
75 }
76 
resetSearch()77 void SpringerFetcher::resetSearch() {
78   m_start = 0;
79   m_total = -1;
80 }
81 
searchUrl()82 QUrl SpringerFetcher::searchUrl() {
83   QUrl u(QString::fromLatin1(SPRINGER_BASE_URL));
84   QUrlQuery q;
85   q.addQueryItem(QStringLiteral("api_key"), QLatin1String(SPRINGER_API_KEY));
86   q.addQueryItem(QStringLiteral("s"), QString::number(m_start + 1));
87   q.addQueryItem(QStringLiteral("p"), QString::number(SPRINGER_QUERY_COUNT));
88 
89   switch(request().key()) {
90     case Title:
91       q.addQueryItem(QStringLiteral("q"), QStringLiteral("title:\"%1\" OR book:\"%1\"").arg(request().value()));
92       break;
93 
94     case Person:
95       q.addQueryItem(QStringLiteral("q"), QStringLiteral("name:%1").arg(request().value()));
96       break;
97 
98     case Keyword:
99       q.addQueryItem(QStringLiteral("q"), QStringLiteral("\"%1\"").arg(request().value()));
100       break;
101 
102     case ISBN:
103       {
104         // only grab first value
105         QString v = request().value().section(QLatin1Char(';'), 0);
106         v = ISBNValidator::isbn13(v);
107         q.addQueryItem(QStringLiteral("q"), QStringLiteral("isbn:%1").arg(v));
108       }
109       break;
110 
111     case DOI:
112       q.addQueryItem(QStringLiteral("q"), QStringLiteral("doi:%1").arg(request().value()));
113       break;
114 
115     case Raw:
116       q.addQueryItem(QStringLiteral("q"), request().value());
117       break;
118 
119     default:
120       return QUrl();
121   }
122   u.setQuery(q);
123 
124 //  myDebug() << "url:" << u.url();
125   return u;
126 }
127 
parseData(QByteArray & data_)128 void SpringerFetcher::parseData(QByteArray& data_) {
129   QDomDocument dom;
130   if(!dom.setContent(data_, false)) {
131     myWarning() << "server did not return valid XML.";
132     return;
133   }
134   // total is /response/result/total
135   QDomNode n = dom.documentElement().namedItem(QStringLiteral("result"))
136                                     .namedItem(QStringLiteral("total"));
137   QDomElement e = n.toElement();
138   if(!e.isNull()) {
139     m_total = e.text().toInt();
140 //    myDebug() << "total = " << m_total;
141   }
142 }
143 
checkMoreResults(int count_)144 void SpringerFetcher::checkMoreResults(int count_) {
145   m_start = count_;
146   m_hasMoreResults = m_start < m_total;
147 }
148 
updateRequest(Data::EntryPtr entry_)149 Tellico::Fetch::FetchRequest SpringerFetcher::updateRequest(Data::EntryPtr entry_) {
150   const QString doi = entry_->field(QStringLiteral("doi"));
151   if(!doi.isEmpty()) {
152     return FetchRequest(Fetch::DOI, doi);
153   }
154 
155   const QString isbn = entry_->field(QStringLiteral("isbn"));
156   if(!isbn.isEmpty()) {
157     return FetchRequest(Fetch::ISBN, isbn);
158   }
159 
160   const QString title = entry_->field(QStringLiteral("title"));
161   if(!title.isEmpty()) {
162     return FetchRequest(Fetch::Title, title);
163   }
164 
165   return FetchRequest();
166 }
167 
configWidget(QWidget * parent_) const168 Tellico::Fetch::ConfigWidget* SpringerFetcher::configWidget(QWidget* parent_) const {
169   return new SpringerFetcher::ConfigWidget(parent_, this);
170 }
171 
defaultName()172 QString SpringerFetcher::defaultName() {
173   return QStringLiteral("SpringerLink");
174 }
175 
defaultIcon()176 QString SpringerFetcher::defaultIcon() {
177   return favIcon("https://link.springer.com/static/sites/link/images/favicon-32x32.png");
178 }
179 
ConfigWidget(QWidget * parent_,const SpringerFetcher * fetcher_)180 SpringerFetcher::ConfigWidget::ConfigWidget(QWidget* parent_, const SpringerFetcher* fetcher_)
181     : Fetch::ConfigWidget(parent_) {
182   QVBoxLayout* l = new QVBoxLayout(optionsWidget());
183   l->addWidget(new QLabel(i18n("This source has no options."), optionsWidget()));
184   l->addStretch();
185 
186   // now add additional fields widget
187   addFieldsWidget(SpringerFetcher::allOptionalFields(), fetcher_ ? fetcher_->optionalFields() : QStringList());
188 }
189 
saveConfigHook(KConfigGroup &)190 void SpringerFetcher::ConfigWidget::saveConfigHook(KConfigGroup&) {
191 }
192 
preferredName() const193 QString SpringerFetcher::ConfigWidget::preferredName() const {
194   return SpringerFetcher::defaultName();
195 }
196