Add settings page for Ubuntu One.
This commit is contained in:
parent
24ac9adbe5
commit
1d20ac4eae
|
@ -294,6 +294,7 @@
|
|||
<file>providers/somafm.png</file>
|
||||
<file>providers/songkick.png</file>
|
||||
<file>providers/soundcloud.png</file>
|
||||
<file>providers/ubuntuone.png</file>
|
||||
<file>providers/wikipedia.png</file>
|
||||
<file>sample.mood</file>
|
||||
<file>schema/device-schema.sql</file>
|
||||
|
|
Before Width: | Height: | Size: 764 B After Width: | Height: | Size: 764 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
|
@ -192,6 +192,7 @@ set(SOURCES
|
|||
internet/soundcloudservice.cpp
|
||||
internet/ubuntuoneauthenticator.cpp
|
||||
internet/ubuntuoneservice.cpp
|
||||
internet/ubuntuonesettingspage.cpp
|
||||
internet/ubuntuoneurlhandler.cpp
|
||||
|
||||
library/groupbydialog.cpp
|
||||
|
@ -469,6 +470,7 @@ set(HEADERS
|
|||
internet/soundcloudservice.h
|
||||
internet/ubuntuoneauthenticator.h
|
||||
internet/ubuntuoneservice.h
|
||||
internet/ubuntuonesettingspage.h
|
||||
internet/ubuntuoneurlhandler.h
|
||||
|
||||
library/groupbydialog.h
|
||||
|
@ -645,6 +647,7 @@ set(UI
|
|||
internet/magnatunesettingspage.ui
|
||||
internet/searchboxwidget.ui
|
||||
internet/spotifysettingspage.ui
|
||||
internet/ubuntuonesettingspage.ui
|
||||
|
||||
library/groupbydialog.ui
|
||||
library/libraryfilterwidget.ui
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
/* This file is part of Clementine.
|
||||
Copyright 2012, David Sansome <me@davidsansome.com>
|
||||
|
||||
|
||||
Clementine is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
|
||||
Clementine is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
@ -26,11 +26,9 @@
|
|||
class GoogleDriveService;
|
||||
class Ui_GoogleDriveSettingsPage;
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
|
||||
class GoogleDriveSettingsPage : public SettingsPage {
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
public:
|
||||
GoogleDriveSettingsPage(SettingsDialog* parent = 0);
|
||||
~GoogleDriveSettingsPage();
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
#include "ubuntuoneauthenticator.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QHostInfo>
|
||||
#include <QStringList>
|
||||
|
||||
#include <qjson/parser.h>
|
||||
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/network.h"
|
||||
#include "core/timeconstants.h"
|
||||
|
||||
namespace {
|
||||
static const char* kUbuntuOneEndpoint =
|
||||
"https://login.ubuntu.com/api/1.0/authentications";
|
||||
static const char* kTokenNameTemplate = "Ubuntu One @ %1 [%2]";
|
||||
static const char* kOAuthSSOFinishedEndpoint =
|
||||
"https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/";
|
||||
static const char* kOAuthHeaderPrefix = "OAuth realm=\"\", ";
|
||||
}
|
||||
|
||||
UbuntuOneAuthenticator::UbuntuOneAuthenticator(QObject* parent)
|
||||
|
@ -66,5 +72,67 @@ void UbuntuOneAuthenticator::AuthorisationFinished(QNetworkReply* reply) {
|
|||
token_ = auth_info["token"].toString();
|
||||
token_secret_ = auth_info["token_secret"].toString();
|
||||
|
||||
CopySSOTokens();
|
||||
}
|
||||
|
||||
QByteArray UbuntuOneAuthenticator::GenerateAuthorisationHeader(
|
||||
const QString& consumer_key,
|
||||
const QString& consumer_secret,
|
||||
const QString& token,
|
||||
const QString& token_secret) {
|
||||
typedef QPair<QString, QString> Param;
|
||||
QString timestamp = QString::number(
|
||||
QDateTime::currentMSecsSinceEpoch() / kMsecPerSec);
|
||||
QList<Param> parameters;
|
||||
parameters << Param("oauth_nonce", QString::number(qrand()))
|
||||
<< Param("oauth_timestamp", timestamp)
|
||||
<< Param("oauth_version", "1.0")
|
||||
<< Param("oauth_consumer_key", consumer_key)
|
||||
<< Param("oauth_token", token)
|
||||
<< Param("oauth_signature_method", "PLAINTEXT");
|
||||
qSort(parameters.begin(), parameters.end());
|
||||
QStringList encoded_params;
|
||||
for (const Param& p : parameters) {
|
||||
encoded_params << QString("%1=%2").arg(p.first, p.second);
|
||||
}
|
||||
|
||||
QString signing_key =
|
||||
consumer_secret + "&" + token_secret;
|
||||
QByteArray signature = QUrl::toPercentEncoding(signing_key);
|
||||
|
||||
// Construct authorisation header
|
||||
parameters << Param("oauth_signature", signature);
|
||||
QStringList header_params;
|
||||
for (const Param& p : parameters) {
|
||||
header_params << QString("%1=\"%2\"").arg(p.first, p.second);
|
||||
}
|
||||
QString authorisation_header = header_params.join(", ");
|
||||
authorisation_header.prepend(kOAuthHeaderPrefix);
|
||||
|
||||
return authorisation_header.toAscii();
|
||||
}
|
||||
|
||||
QByteArray UbuntuOneAuthenticator::GenerateAuthorisationHeader() {
|
||||
return GenerateAuthorisationHeader(
|
||||
consumer_key_,
|
||||
consumer_secret_,
|
||||
token_,
|
||||
token_secret_);
|
||||
}
|
||||
|
||||
void UbuntuOneAuthenticator::CopySSOTokens() {
|
||||
QUrl url(kOAuthSSOFinishedEndpoint);
|
||||
QNetworkRequest request(url);
|
||||
request.setRawHeader("Authorization", GenerateAuthorisationHeader());
|
||||
request.setRawHeader("Accept", "application/json");
|
||||
|
||||
QNetworkReply* reply = network_->get(request);
|
||||
NewClosure(reply, SIGNAL(finished()),
|
||||
this, SLOT(CopySSOTokensFinished(QNetworkReply*)), reply);
|
||||
}
|
||||
|
||||
void UbuntuOneAuthenticator::CopySSOTokensFinished(QNetworkReply* reply) {
|
||||
reply->deleteLater();
|
||||
qLog(Debug) << reply->readAll();
|
||||
emit Finished();
|
||||
}
|
||||
|
|
|
@ -17,11 +17,22 @@ class UbuntuOneAuthenticator : public QObject {
|
|||
QString token() const { return token_; }
|
||||
QString token_secret() const { return token_secret_; }
|
||||
|
||||
static QByteArray GenerateAuthorisationHeader(
|
||||
const QString& consumer_key,
|
||||
const QString& consumer_secret,
|
||||
const QString& token,
|
||||
const QString& token_secret);
|
||||
|
||||
signals:
|
||||
void Finished();
|
||||
|
||||
private slots:
|
||||
void AuthorisationFinished(QNetworkReply* reply);
|
||||
void CopySSOTokensFinished(QNetworkReply* reply);
|
||||
|
||||
private:
|
||||
void CopySSOTokens();
|
||||
QByteArray GenerateAuthorisationHeader();
|
||||
|
||||
private:
|
||||
NetworkAccessManager* network_;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "ubuntuoneservice.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QSettings>
|
||||
|
||||
#include <qjson/parser.h>
|
||||
|
||||
|
@ -21,10 +22,7 @@ const char* UbuntuOneService::kSettingsGroup = "Ubuntu One";
|
|||
namespace {
|
||||
static const char* kFileStorageEndpoint =
|
||||
"https://one.ubuntu.com/api/file_storage/v1/~/Ubuntu One/";
|
||||
static const char* kOAuthSSOFinishedEndpoint =
|
||||
"https://one.ubuntu.com/oauth/sso-finished-so-get-tokens/";
|
||||
static const char* kContentRoot = "https://files.one.ubuntu.com";
|
||||
static const char* kOAuthHeaderPrefix = "OAuth realm=\"\", ";
|
||||
}
|
||||
|
||||
UbuntuOneService::UbuntuOneService(Application* app, InternetModel* parent)
|
||||
|
@ -52,6 +50,18 @@ void UbuntuOneService::LazyPopulate(QStandardItem* item) {
|
|||
}
|
||||
|
||||
void UbuntuOneService::Connect() {
|
||||
QSettings s;
|
||||
s.beginGroup(kSettingsGroup);
|
||||
if (s.contains("consumer_key")) {
|
||||
consumer_key_ = s.value("consumer_key").toString();
|
||||
consumer_secret_ = s.value("consumer_secret").toString();
|
||||
token_ = s.value("token").toString();
|
||||
token_secret_ = s.value("token_secret").toString();
|
||||
|
||||
RequestFileList();
|
||||
return;
|
||||
}
|
||||
|
||||
UbuntuOneAuthenticator* authenticator = new UbuntuOneAuthenticator;
|
||||
authenticator->StartAuthorisation(
|
||||
"Username",
|
||||
|
@ -62,36 +72,11 @@ void UbuntuOneService::Connect() {
|
|||
}
|
||||
|
||||
QByteArray UbuntuOneService::GenerateAuthorisationHeader() {
|
||||
typedef QPair<QString, QString> Param;
|
||||
QString timestamp = QString::number(
|
||||
QDateTime::currentMSecsSinceEpoch() / kMsecPerSec);
|
||||
QList<Param> parameters;
|
||||
parameters << Param("oauth_nonce", QString::number(qrand()))
|
||||
<< Param("oauth_timestamp", timestamp)
|
||||
<< Param("oauth_version", "1.0")
|
||||
<< Param("oauth_consumer_key", consumer_key_)
|
||||
<< Param("oauth_token", token_)
|
||||
<< Param("oauth_signature_method", "PLAINTEXT");
|
||||
qSort(parameters.begin(), parameters.end());
|
||||
QStringList encoded_params;
|
||||
for (const Param& p : parameters) {
|
||||
encoded_params << QString("%1=%2").arg(p.first, p.second);
|
||||
}
|
||||
|
||||
QString signing_key =
|
||||
consumer_secret_ + "&" + token_secret_;
|
||||
QByteArray signature = QUrl::toPercentEncoding(signing_key);
|
||||
|
||||
// Construct authorisation header
|
||||
parameters << Param("oauth_signature", signature);
|
||||
QStringList header_params;
|
||||
for (const Param& p : parameters) {
|
||||
header_params << QString("%1=\"%2\"").arg(p.first, p.second);
|
||||
}
|
||||
QString authorisation_header = header_params.join(", ");
|
||||
authorisation_header.prepend(kOAuthHeaderPrefix);
|
||||
|
||||
return authorisation_header.toAscii();
|
||||
return UbuntuOneAuthenticator::GenerateAuthorisationHeader(
|
||||
consumer_key_,
|
||||
consumer_secret_,
|
||||
token_,
|
||||
token_secret_);
|
||||
}
|
||||
|
||||
void UbuntuOneService::AuthenticationFinished(
|
||||
|
@ -103,19 +88,17 @@ void UbuntuOneService::AuthenticationFinished(
|
|||
token_ = authenticator->token();
|
||||
token_secret_ = authenticator->token_secret();
|
||||
|
||||
QUrl sso_url(kOAuthSSOFinishedEndpoint);
|
||||
QNetworkRequest request(sso_url);
|
||||
request.setRawHeader("Authorization", GenerateAuthorisationHeader());
|
||||
request.setRawHeader("Accept", "application/json");
|
||||
QSettings s;
|
||||
s.beginGroup(kSettingsGroup);
|
||||
s.setValue("consumer_key", consumer_key_);
|
||||
s.setValue("consumer_secret", consumer_secret_);
|
||||
s.setValue("token", token_);
|
||||
s.setValue("token_secret", token_secret_);
|
||||
|
||||
qLog(Debug) << "Sending SSO copy request";
|
||||
QNetworkReply* reply = network_->get(request);
|
||||
NewClosure(reply, SIGNAL(finished()),
|
||||
this, SLOT(SSORequestFinished(QNetworkReply*)), reply);
|
||||
RequestFileList();
|
||||
}
|
||||
|
||||
void UbuntuOneService::SSORequestFinished(QNetworkReply* reply) {
|
||||
qLog(Debug) << Q_FUNC_INFO;
|
||||
void UbuntuOneService::RequestFileList() {
|
||||
QUrl files_url(kFileStorageEndpoint);
|
||||
files_url.addQueryItem("include_children", "true");
|
||||
QNetworkRequest request(files_url);
|
||||
|
|
|
@ -23,11 +23,11 @@ class UbuntuOneService : public InternetService {
|
|||
|
||||
private slots:
|
||||
void AuthenticationFinished(UbuntuOneAuthenticator* authenticator);
|
||||
void SSORequestFinished(QNetworkReply* reply);
|
||||
void FileListRequestFinished(QNetworkReply* reply);
|
||||
|
||||
private:
|
||||
void Connect();
|
||||
void RequestFileList();
|
||||
|
||||
private:
|
||||
QByteArray GenerateAuthorisationHeader();
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#include "ubuntuonesettingspage.h"
|
||||
|
||||
#include "ui_ubuntuonesettingspage.h"
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "internet/internetmodel.h"
|
||||
#include "internet/ubuntuoneauthenticator.h"
|
||||
#include "internet/ubuntuoneservice.h"
|
||||
|
||||
UbuntuOneSettingsPage::UbuntuOneSettingsPage(SettingsDialog* parent)
|
||||
: SettingsPage(parent),
|
||||
ui_(new Ui::UbuntuOneSettingsPage),
|
||||
service_(dialog()->app()->internet_model()->Service<UbuntuOneService>()),
|
||||
authenticated_(false) {
|
||||
ui_->setupUi(this);
|
||||
ui_->login_state->AddCredentialGroup(ui_->login_container);
|
||||
connect(ui_->login_button, SIGNAL(clicked()), SLOT(LoginClicked()));
|
||||
|
||||
dialog()->installEventFilter(this);
|
||||
}
|
||||
|
||||
void UbuntuOneSettingsPage::Load() {
|
||||
QSettings s;
|
||||
s.beginGroup(UbuntuOneService::kSettingsGroup);
|
||||
|
||||
const QString user_email = s.value("user_email").toString();
|
||||
if (!user_email.isEmpty()) {
|
||||
ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn, user_email);
|
||||
ui_->username->setText(user_email);
|
||||
}
|
||||
}
|
||||
|
||||
void UbuntuOneSettingsPage::Save() {
|
||||
QSettings s;
|
||||
s.beginGroup(UbuntuOneService::kSettingsGroup);
|
||||
|
||||
if (authenticated_) {
|
||||
s.setValue("user_email", ui_->username->text());
|
||||
}
|
||||
}
|
||||
|
||||
void UbuntuOneSettingsPage::LoginClicked() {
|
||||
ui_->login_button->setEnabled(false);
|
||||
QString username = ui_->username->text();
|
||||
QString password = ui_->password->text();
|
||||
|
||||
UbuntuOneAuthenticator* authenticator = new UbuntuOneAuthenticator;
|
||||
authenticator->StartAuthorisation(username, password);
|
||||
NewClosure(authenticator, SIGNAL(Finished()),
|
||||
this, SLOT(Connected(UbuntuOneAuthenticator*)), authenticator);
|
||||
NewClosure(authenticator, SIGNAL(Finished()),
|
||||
service_, SLOT(AuthenticationFinished(UbuntuOneAuthenticator*)),
|
||||
authenticator);
|
||||
}
|
||||
|
||||
void UbuntuOneSettingsPage::LogoutClicked() {
|
||||
|
||||
}
|
||||
|
||||
void UbuntuOneSettingsPage::Connected(UbuntuOneAuthenticator* authenticator) {
|
||||
ui_->login_state->SetLoggedIn(LoginStateWidget::LoggedIn, ui_->username->text());
|
||||
authenticated_ = true;
|
||||
}
|
||||
|
||||
bool UbuntuOneSettingsPage::eventFilter(QObject* object, QEvent* event) {
|
||||
if (object == dialog() && event->type() == QEvent::Enter) {
|
||||
ui_->login_button->setEnabled(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
return SettingsPage::eventFilter(object, event);
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef UBUNTUONESETTINGSPAGE_H
|
||||
#define UBUNTUONESETTINGSPAGE_H
|
||||
|
||||
#include "ui/settingspage.h"
|
||||
|
||||
class UbuntuOneAuthenticator;
|
||||
class UbuntuOneService;
|
||||
class Ui_UbuntuOneSettingsPage;
|
||||
|
||||
class UbuntuOneSettingsPage : public SettingsPage {
|
||||
Q_OBJECT
|
||||
public:
|
||||
UbuntuOneSettingsPage(SettingsDialog* parent = 0);
|
||||
|
||||
void Load();
|
||||
void Save();
|
||||
|
||||
// QObject
|
||||
bool eventFilter(QObject* object, QEvent* event);
|
||||
|
||||
private slots:
|
||||
void LoginClicked();
|
||||
void LogoutClicked();
|
||||
void Connected(UbuntuOneAuthenticator* authenticator);
|
||||
|
||||
private:
|
||||
Ui_UbuntuOneSettingsPage* ui_;
|
||||
UbuntuOneService* service_;
|
||||
|
||||
bool authenticated_;
|
||||
};
|
||||
|
||||
#endif // UBUNTUONESETTINGSPAGE_H
|
|
@ -0,0 +1,117 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>UbuntuOneSettingsPage</class>
|
||||
<widget class="QWidget" name="UbuntuOneSettingsPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>569</width>
|
||||
<height>491</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Ubuntu One</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../../data/data.qrc">
|
||||
<normaloff>:/providers/ubuntuone.png</normaloff>:/providers/ubuntuone.png</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Clementine can play music that you have uploaded to Ubuntu One</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="LoginStateWidget" name="login_state" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="login_container" native="true">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>28</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="login_button">
|
||||
<property name="text">
|
||||
<string>Login</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="username">
|
||||
<property name="placeholderText">
|
||||
<string>Email address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="password">
|
||||
<property name="placeholderText">
|
||||
<string>Password</string>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>357</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LoginStateWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>widgets/loginstatewidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../data/data.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -37,6 +37,7 @@
|
|||
#include "internet/digitallyimportedsettingspage.h"
|
||||
#include "internet/groovesharksettingspage.h"
|
||||
#include "internet/magnatunesettingspage.h"
|
||||
#include "internet/ubuntuonesettingspage.h"
|
||||
#include "library/librarysettingspage.h"
|
||||
#include "playlist/playlistview.h"
|
||||
#include "podcasts/podcastsettingspage.h"
|
||||
|
@ -147,6 +148,8 @@ SettingsDialog::SettingsDialog(Application* app, BackgroundStreams* streams, QWi
|
|||
AddPage(Page_GoogleDrive, new GoogleDriveSettingsPage(this), providers);
|
||||
#endif
|
||||
|
||||
AddPage(Page_UbuntuOne, new UbuntuOneSettingsPage(this), providers);
|
||||
|
||||
#ifdef HAVE_SPOTIFY
|
||||
AddPage(Page_Spotify, new SpotifySettingsPage(this), providers);
|
||||
#endif
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
Page_Wiimotedev,
|
||||
Page_Podcasts,
|
||||
Page_GoogleDrive,
|
||||
Page_UbuntuOne,
|
||||
};
|
||||
|
||||
enum Role {
|
||||
|
|
Loading…
Reference in New Issue