31 #include <QNetworkRequest> 32 #include <QNetworkReply> 33 #include <QNetworkCookie> 39 #include <QFutureInterface> 48 #include <xmlsettingsdialog/basesettingsmanager.h> 58 QUrl URLFromClientID (
const QString&
id,
const QStringList& scope)
60 auto url = QUrl::fromEncoded (
"https://oauth.vk.com/authorize?redirect_uri=http%3A%2F%2Foauth.vk.com%2Fblank.html&response_type=token&state=");
63 (
"scope", scope.join (
","));
69 const QString&
id,
const QStringList& scope,
74 , AccountHR_ (accName)
75 , AuthNAM_ (new QNetworkAccessManager (this))
79 , URL_ (URLFromClientID (ID_, scope))
80 , ScheduleTimer_ (new QTimer (this))
82 AuthNAM_->setCookieJar (Cookies_);
83 Cookies_->
Load (cookies);
85 ScheduleTimer_->setSingleShot (
true);
86 connect (ScheduleTimer_,
89 SLOT (execScheduledRequest ()));
94 return !Token_.isEmpty () &&
95 (!ValidFor_ || ReceivedAt_.secsTo (QDateTime::currentDateTime ()) < ValidFor_);
100 return !Token_.isEmpty () || !Cookies_->allCookies ().isEmpty ();
105 const auto& newUrl = URLFromClientID (ID_, scope);
111 ReceivedAt_ = QDateTime ();
123 for (
const auto& queue : PrioManagedQueues_)
125 for (
const auto& queue : ManagedQueues_)
132 InvokeQueues (Token_);
139 iface.reportStarted ();
147 [
this, iface] ()
mutable { ReportFutureResult (iface, Token_); });
151 return iface.future ();
158 qWarning () << Q_FUNC_INFO
159 <<
"cannot manage request queue if queue manager wasn't set";
163 ManagedQueues_ << queue;
172 qWarning () << Q_FUNC_INFO
173 <<
"cannot manage request queue if queue manager wasn't set";
177 PrioManagedQueues_ << queue;
184 SilentMode_ = silent;
187 void VkAuthManager::InvokeQueues (
const QString& token)
189 ScheduleTrack (token);
191 for (
auto queue : PrioManagedQueues_)
192 while (!queue->isEmpty ())
194 const auto& pair = queue->takeFirst ();
195 const auto&
f = pair.first;
196 Queue_->
Schedule ([
f, token] {
f (token); },
nullptr, pair.second);
199 for (
auto queue : ManagedQueues_)
200 while (!queue->isEmpty ())
202 const auto&
f = queue->takeFirst ();
207 void VkAuthManager::RequestURL (
const QUrl& url)
209 qDebug () << Q_FUNC_INFO << url;
210 auto reply = AuthNAM_->get (QNetworkRequest (url));
212 SIGNAL (finished ()),
214 SLOT (handleGotForm ()));
217 void VkAuthManager::RequestAuthKey ()
219 if (IsRequestScheduled_ && ScheduleTimer_->isActive ())
220 ScheduleTimer_->stop ();
226 IsRequesting_ =
true;
229 bool VkAuthManager::CheckReply (QUrl location)
231 if (location.path () !=
"/blank.html")
232 return CheckError (location);
234 location = QUrl::fromEncoded (location.toEncoded ().replace (
'#',
'?'));
235 const QUrlQuery query { location };
236 Token_ = query.queryItemValue (
"access_token");
237 ValidFor_ = query.queryItemValue (
"expires_in").toInt ();
238 ReceivedAt_ = QDateTime::currentDateTime ();
239 qDebug () << Q_FUNC_INFO << Token_ << ValidFor_;
240 IsRequesting_ =
false;
242 InvokeQueues (Token_);
249 bool VkAuthManager::CheckError (
const QUrl& url)
251 if (url.path () !=
"/error")
254 const auto errNum = QUrlQuery { url }.queryItemValue (
"err").toInt ();
256 IsRequesting_ =
false;
258 qWarning () << Q_FUNC_INFO
270 tr (
"VK.com authentication for %1 failed because of error %2. " 271 "Report upstream please.")
275 Proxy_->GetEntityManager ()->HandleEntity (e);
280 void VkAuthManager::ScheduleTrack (
const QString& key)
285 if (!Proxy_->GetSettingsManager ()->property (
"TrackVK").toBool ())
290 QUrl url {
"https://api.vk.com/method/stats.trackVisitor" };
291 Util::UrlOperator { url }
292 (
"access_token", key);
294 auto reply = AuthNAM_->get (QNetworkRequest { url });
296 SIGNAL (finished ()),
298 SLOT (deleteLater ()));
305 ReceivedAt_ = QDateTime ();
312 class CloseEventFilter :
public QObject
316 CloseEventFilter (
const F& handler, QObject *handlee)
317 : QObject { handlee }
318 , Handler_ { handler }
320 handlee->installEventFilter (
this);
323 bool eventFilter (QObject*, QEvent *event)
334 auto view =
new QWebView;
335 view->setWindowTitle (tr (
"VK.com authentication for %1")
338 view->resize (800, 600);
339 view->page ()->setNetworkAccessManager (AuthNAM_);
345 SIGNAL (urlChanged (QUrl)),
347 SLOT (handleViewUrlChanged (QUrl)));
349 new CloseEventFilter { [
this] { emit
authCanceled (); }, view };
352 void VkAuthManager::execScheduledRequest ()
354 IsRequestScheduled_ =
false;
359 void VkAuthManager::handleGotForm ()
361 auto reply = qobject_cast<QNetworkReply*> (sender ());
362 reply->deleteLater ();
364 if (reply->error () != QNetworkReply::NoError)
366 qWarning () << Q_FUNC_INFO
368 << reply->errorString ();
370 IsRequesting_ =
false;
372 if (!IsRequestScheduled_)
374 IsRequestScheduled_ =
true;
375 ScheduleTimer_->start (30000);
381 const auto& location = reply->header (QNetworkRequest::LocationHeader).toUrl ();
382 if (location.isEmpty ())
388 if (CheckReply (location))
391 RequestURL (location);
394 void VkAuthManager::handleViewUrlChanged (
const QUrl& url)
396 if (!CheckReply (url))
400 sender ()->deleteLater ();
std::variant< SilentMode > AuthKeyError_t
Manipulates query part of an QUrl object.
A simple scheduling manager for a queue of functors.
constexpr detail::ExprTree< detail::ExprType::LeafStaticPlaceholder, detail::MemberPtrs< Ptr > > f
void Load(const QByteArray &data)
void cookiesChanged(const QByteArray &)
ScheduleGuard_t ManageQueue(RequestQueue_ptr)
std::shared_ptr< ICoreProxy > ICoreProxy_ptr
bool IsAuthenticated() const
VkAuthManager(const QString &accountName, const QString &clientId, const QStringList &scope, const QByteArray &cookies, ICoreProxy_ptr, QueueManager *=nullptr, QObject *=nullptr)
bool HadAuthentication() const
detail::ScopeGuard< F > MakeScopeGuard(const F &f)
Returns an object performing passed function on scope exit.
void Schedule(std::function< void()> functor, QObject *dependent=nullptr, QueuePriority prio=QueuePriority::Normal)
Adds the given functor.
QFuture< AuthKeyResult_t > GetAuthKeyFuture()
void gotAuthKey(const QString &)
A customized cookie jar with additional features.
void UpdateScope(const QStringList &)
Entity MakeNotification(const QString &header, const QString &text, Priority priority)
An utility function to make a Entity with notification.