diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index b5ea5b9de2..8ca20c9ad3 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -22,6 +22,7 @@ set(client_UI networksettings.ui protocolwidget.ui settingsdialog.ui + sharedialog.ui sslerrordialog.ui wizard/owncloudadvancedsetuppage.ui wizard/owncloudhttpcredspage.ui @@ -49,6 +50,7 @@ set(client_SRCS protocolwidget.cpp selectivesyncdialog.cpp settingsdialog.cpp + sharedialog.cpp socketapi.cpp sslbutton.cpp sslerrordialog.cpp diff --git a/src/gui/application.cpp b/src/gui/application.cpp index 4aa0c283a6..950013996e 100644 --- a/src/gui/application.cpp +++ b/src/gui/application.cpp @@ -31,6 +31,7 @@ #include "theme.h" #include "utility.h" #include "clientproxy.h" +#include "sharedialog.h" #include "updater/updater.h" #include "creds/abstractcredentials.h" @@ -146,6 +147,9 @@ Application::Application(int &argc, char **argv) : slotAccountStateAdded(ai); } + connect(FolderMan::instance()->socketApi(), SIGNAL(shareCommandReceived(QString)), + this, SLOT(slotShowShareDialog(QString))); + // startup procedure. connect(&_checkConnectionTimer, SIGNAL(timeout()), this, SLOT(slotCheckConnection())); _checkConnectionTimer.setInterval(32 * 1000); // check for connection every 32 seconds. @@ -160,6 +164,7 @@ Application::Application(int &argc, char **argv) : } connect (this, SIGNAL(aboutToQuit()), SLOT(slotCleanup())); + } Application::~Application() @@ -167,6 +172,14 @@ Application::~Application() // qDebug() << "* OCC shutdown"; } +void Application::slotShowShareDialog(const QString &path) +{ + qDebug() << Q_FUNC_INFO << "Opening share dialog"; + ShareDialog *w = new ShareDialog; + w->setPath(path); + w->show(); +} + void Application::slotLogin() { AccountState *a = AccountStateManager::instance()->accountState(); diff --git a/src/gui/application.h b/src/gui/application.h index bcceeb95ff..158a5fb882 100644 --- a/src/gui/application.h +++ b/src/gui/application.h @@ -29,6 +29,7 @@ #include "progressdispatcher.h" #include "clientproxy.h" #include "folderman.h" +#include "sharedialog.h" class QMessageBox; class QSystemTrayIcon; @@ -83,6 +84,7 @@ protected slots: void slotAccountStateRemoved(AccountState *accountState); void slotAccountStateChanged(int state); void slotCrash(); + void slotShowShareDialog(const QString &path); private: void setHelp(); diff --git a/src/gui/folderman.cpp b/src/gui/folderman.cpp index dae476a51e..744ec63396 100644 --- a/src/gui/folderman.cpp +++ b/src/gui/folderman.cpp @@ -276,6 +276,11 @@ QString FolderMan::escapeAlias( const QString& alias ) return a; } +SocketApi *FolderMan::socketApi() +{ + return this->_socketApi; +} + QString FolderMan::unescapeAlias( const QString& alias ) const { QString a(alias); diff --git a/src/gui/folderman.h b/src/gui/folderman.h index 1c212f1f1e..21472b1d44 100644 --- a/src/gui/folderman.h +++ b/src/gui/folderman.h @@ -94,6 +94,8 @@ public: // system, thus need to be escaped. static QString escapeAlias( const QString& ); + SocketApi *socketApi(); + signals: /** * signal to indicate a folder named by alias has changed its sync state. diff --git a/src/gui/sharedialog.cpp b/src/gui/sharedialog.cpp new file mode 100644 index 0000000000..2d3daf9a7c --- /dev/null +++ b/src/gui/sharedialog.cpp @@ -0,0 +1,300 @@ +#include "sharedialog.h" +#include "ui_sharedialog.h" +#include "networkjobs.h" +#include "account.h" +#include "json.h" +#include "folderman.h" +#include +#include + +namespace { + int SHARETYPE_PUBLIC = 3; +} + +namespace OCC { + +ShareDialog::ShareDialog(QWidget *parent) : + QDialog(parent), + _ui(new Ui::ShareDialog) +{ + setAttribute(Qt::WA_DeleteOnClose); + _ui->setupUi(this); + _ui->pushButton_copy->setIcon(QIcon::fromTheme("edit-copy")); + layout()->setSizeConstraint(QLayout::SetFixedSize); + QMovie *movie = new QMovie("/home/azelphur/ownCloud-share-tools/loading-icon.gif"); + movie->start(); + _ui->labelShareSpinner->setMovie(movie); + _ui->labelShareSpinner->hide(); + + _ui->labelPasswordSpinner->setMovie(movie); + _ui->labelPasswordSpinner->hide(); + + _ui->labelCalendarSpinner->setMovie(movie); + _ui->labelCalendarSpinner->hide(); + connect(_ui->checkBox_shareLink, SIGNAL(clicked()), this, SLOT(slotCheckBoxShareLinkClicked())); + connect(_ui->checkBox_password, SIGNAL(clicked()), this, SLOT(slotCheckBoxPasswordClicked())); + connect(_ui->lineEdit_password, SIGNAL(returnPressed()), this, SLOT(slotPasswordReturnPressed())); + connect(_ui->checkBox_expire, SIGNAL(clicked()), this, SLOT(slotCheckBoxExpireClicked())); + connect(_ui->calendar, SIGNAL(clicked(QDate)), SLOT(slotCalendarClicked(QDate))); + + _ui->labelShareSpinner->hide(); + _ui->lineEdit_shareLink->hide(); + _ui->pushButton_copy->hide(); + _ui->lineEdit_password->hide(); + _ui->checkBox_password->hide(); + _ui->checkBox_expire->hide(); + _ui->calendar->hide(); + _ui->lineEdit_shareGroup->setPlaceholderText(tr("Share with group...")); + _ui->lineEdit_shareUser->setPlaceholderText(tr("Share with user...")); + _ui->lineEdit_password->setPlaceholderText(tr("Choose a password for the public link")); +} + +void ShareDialog::setExpireDate(const QString &date) +{ + _ui->labelCalendarSpinner->show(); + QUrl url = Account::concatUrlPath(AccountManager::instance()->account()->url(), QString("ocs/v1.php/apps/files_sharing/api/v1/shares/").append(QString::number(_public_share_id))); + QUrl postData; + QList > getParams; + QList > postParams; + getParams.append(qMakePair(QString::fromLatin1("format"), QString::fromLatin1("json"))); + postParams.append(qMakePair(QString::fromLatin1("expireDate"), date)); + url.setQueryItems(getParams); + postData.setQueryItems(postParams); + OcsShareJob *job = new OcsShareJob("PUT", url, postData, AccountManager::instance()->account(), this); + connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotExpireSet(QString))); + job->start(); +} + +void ShareDialog::slotExpireSet(const QString &reply) +{ + _ui->labelCalendarSpinner->hide(); +} + +void ShareDialog::slotCalendarClicked(const QDate &date) +{ + ShareDialog::setExpireDate(date.toString("yyyy-MM-dd")); +} + +QString ShareDialog::getPath() +{ + return _path; +} + +void ShareDialog::setPath(const QString &path) +{ + _path = path; + ShareDialog::getShares(); +} + +ShareDialog::~ShareDialog() +{ + delete _ui; +} + +void ShareDialog::slotPasswordReturnPressed() +{ + ShareDialog::setPassword(_ui->lineEdit_password->text()); + _ui->lineEdit_password->setPlaceholderText(tr("Password Protected")); + _ui->lineEdit_password->setText(QString()); +} + +void ShareDialog::setPassword(QString password) +{ + _ui->labelPasswordSpinner->show(); + QUrl url = Account::concatUrlPath(AccountManager::instance()->account()->url(), QString("ocs/v1.php/apps/files_sharing/api/v1/shares/").append(QString::number(_public_share_id))); + QUrl postData; + QList > getParams; + QList > postParams; + getParams.append(qMakePair(QString::fromLatin1("format"), QString::fromLatin1("json"))); + postParams.append(qMakePair(QString::fromLatin1("password"), password)); + url.setQueryItems(getParams); + postData.setQueryItems(postParams); + OcsShareJob *job = new OcsShareJob("PUT", url, postData, AccountManager::instance()->account(), this); + connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotPasswordSet(QString))); + job->start(); +} + +void ShareDialog::slotPasswordSet(const QString &reply) +{ + _ui->labelPasswordSpinner->hide(); +} + +void ShareDialog::getShares() +{ + this->setWindowTitle(tr("Sharing %1").arg(_path)); + QUrl url = Account::concatUrlPath(AccountManager::instance()->account()->url(), QLatin1String("ocs/v1.php/apps/files_sharing/api/v1/shares")); + QList > params; + params.append(qMakePair(QString::fromLatin1("format"), QString::fromLatin1("json"))); + params.append(qMakePair(QString::fromLatin1("path"), _path)); + url.setQueryItems(params); + OcsShareJob *job = new OcsShareJob("GET", url, QUrl(), AccountManager::instance()->account(), this); + connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotSharesFetched(QString))); + job->start(); +} + +void ShareDialog::slotSharesFetched(const QString &reply) +{ + bool success = false; + QVariantMap json = QtJson::parse(reply, success).toMap(); + ShareDialog::_shares = json.value("ocs").toMap().values("data")[0].toList(); + for(int i = 0; i < ShareDialog::_shares.count(); i++) + { + QVariantMap data = ShareDialog::_shares[i].toMap(); + + if (data.value("share_type").toInt() == SHARETYPE_PUBLIC) + { + _public_share_id = data.value("id").toULongLong(); + + _ui->lineEdit_shareLink->show(); + _ui->pushButton_copy->show(); + _ui->checkBox_password->show(); + _ui->checkBox_expire->show(); + _ui->pushButton_copy->show(); + _ui->checkBox_shareLink->setChecked(true); + + if (data.value("share_with").isValid()) + { + _ui->checkBox_password->setChecked(true); + _ui->lineEdit_password->setText("********"); + _ui->lineEdit_password->show(); + } + + if (data.value("expiration").isValid()) + { + _ui->calendar->setSelectedDate(QDate::fromString(data.value("expiration").toString(), "yyyy-MM-dd 00:00:00")); + _ui->calendar->show(); + _ui->checkBox_expire->setChecked(true); + } + + const QString url = Account::concatUrlPath(AccountManager::instance()->account()->url(), QString("public.php?service=files&t=%1").arg(data.value("token").toString())).toString(); + _ui->lineEdit_shareLink->setText(url); + } + } +} + +void ShareDialog::slotDeleteShareFetched(const QString &reply) +{ + _ui->labelShareSpinner->hide(); + _ui->lineEdit_shareLink->hide(); + _ui->pushButton_copy->hide(); + _ui->lineEdit_password->hide(); + _ui->checkBox_password->hide(); + _ui->checkBox_expire->hide(); + _ui->calendar->hide(); +} + +void ShareDialog::slotCheckBoxShareLinkClicked() +{ + if (_ui->checkBox_shareLink->checkState() == Qt::Checked) + { + _ui->labelShareSpinner->show(); + QUrl url = Account::concatUrlPath(AccountManager::instance()->account()->url(), QLatin1String("ocs/v1.php/apps/files_sharing/api/v1/shares")); + QUrl postData; + QList > getParams; + QList > postParams; + getParams.append(qMakePair(QString::fromLatin1("format"), QString::fromLatin1("json"))); + postParams.append(qMakePair(QString::fromLatin1("path"), _path)); + postParams.append(qMakePair(QString::fromLatin1("shareType"), QString::number(SHARETYPE_PUBLIC))); + url.setQueryItems(getParams); + postData.setQueryItems(postParams); + OcsShareJob *job = new OcsShareJob("POST", url, postData, AccountManager::instance()->account(), this); + connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotCreateShareFetched(QString))); + job->start(); + } + else + { + _ui->labelShareSpinner->show(); + QUrl url = Account::concatUrlPath(AccountManager::instance()->account()->url(), QString("ocs/v1.php/apps/files_sharing/api/v1/shares/").append(QString::number(_public_share_id))); + QList > getParams; + getParams.append(qMakePair(QString::fromLatin1("format"), QString::fromLatin1("json"))); + url.setQueryItems(getParams); + OcsShareJob *job = new OcsShareJob("DELETE", url, QUrl(), AccountManager::instance()->account(), this); + connect(job, SIGNAL(jobFinished(QString)), this, SLOT(slotDeleteShareFetched(QString))); + job->start(); + } +} + +void ShareDialog::slotCreateShareFetched(const QString &reply) +{ + qDebug() << Q_FUNC_INFO << reply; + _ui->labelShareSpinner->hide(); + bool success; + QVariantMap json = QtJson::parse(reply, success).toMap(); + _public_share_id = json.value("ocs").toMap().values("data")[0].toMap().value("id").toULongLong(); + QString url = json.value("ocs").toMap().values("data")[0].toMap().value("url").toString(); + _ui->lineEdit_shareLink->setText(url); + _ui->lineEdit_shareLink->show(); + _ui->pushButton_copy->show(); + _ui->checkBox_password->show(); + _ui->checkBox_expire->show(); + _ui->pushButton_copy->show(); +} + +void ShareDialog::slotCheckBoxPasswordClicked() +{ + if (_ui->checkBox_password->checkState() == Qt::Checked) + { + _ui->lineEdit_password->show(); + } + else + { + ShareDialog::setPassword(QString()); + _ui->labelPasswordSpinner->show(); + _ui->lineEdit_password->hide(); + } +} + +void ShareDialog::slotCheckBoxExpireClicked() +{ + if (_ui->checkBox_expire->checkState() == Qt::Checked) + { + QDate date = QDate::currentDate().addDays(1); + ShareDialog::setExpireDate(date.toString("dd-MM-yyyy")); + _ui->calendar->setSelectedDate(date); + _ui->calendar->show(); + } + else + { + ShareDialog::setExpireDate(QString()); + _ui->calendar->hide(); + } +} + +OcsShareJob::OcsShareJob(const QByteArray &verb, const QUrl &url, const QUrl &postData, Account* account, QObject* parent) +: AbstractNetworkJob(account, "", parent), + _verb(verb), + _url(url), + _postData(postData) + +{ + setIgnoreCredentialFailure(true); +} + +void OcsShareJob::start() +{ + QNetworkRequest req; + req.setRawHeader("OCS-APIREQUEST", "true"); + req.setRawHeader("Content-Type", "application/x-www-form-urlencoded"); + QBuffer *buffer = new QBuffer; + + QStringList tmp; + Q_FOREACH(auto tmp2, _postData.queryItems()) { + tmp.append(tmp2.first + "=" + tmp2.second); + } + buffer->setData(tmp.join("&").toAscii()); + + setReply(davRequest(_verb, _url, req, buffer)); + setupConnections(reply()); + buffer->setParent(reply()); + AbstractNetworkJob::start(); +} + +bool OcsShareJob::finished() +{ + emit jobFinished(reply()->readAll()); + return true; +} + + + +} diff --git a/src/gui/sharedialog.h b/src/gui/sharedialog.h new file mode 100644 index 0000000000..2467f246c4 --- /dev/null +++ b/src/gui/sharedialog.h @@ -0,0 +1,66 @@ +#ifndef SHAREDIALOG_H +#define SHAREDIALOG_H + +#include "networkjobs.h" +#include + +namespace OCC { + +class OcsShareJob : public AbstractNetworkJob { + Q_OBJECT +public: + explicit OcsShareJob(const QByteArray &verb, const QUrl &url, const QUrl &postData, Account *account, QObject* parent = 0); +public slots: + void start() Q_DECL_OVERRIDE; +signals: + void jobFinished(QString reply); +private slots: + virtual bool finished() Q_DECL_OVERRIDE; +private: + QByteArray _verb; + QUrl _url; + QUrl _postData; +}; + +namespace Ui { +class ShareDialog; +} + +class AbstractCredentials; +class Account; +class QuotaInfo; +class MirallAccessManager; + +class ShareDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ShareDialog(QWidget *parent = 0); + ~ShareDialog(); + void getShares(); + void setPath(const QString &path); + QString getPath(); +private slots: + void slotSharesFetched(const QString &reply); + void slotCreateShareFetched(const QString &reply); + void slotDeleteShareFetched(const QString &reply); + void slotPasswordSet(const QString &reply); + void slotExpireSet(const QString &reply); + void slotCalendarClicked(const QDate &date); + void slotCheckBoxShareLinkClicked(); + void slotCheckBoxPasswordClicked(); + void slotCheckBoxExpireClicked(); + void slotPasswordReturnPressed(); +private: + Ui::ShareDialog *_ui; + QString _path; + QList _shares; + qulonglong _public_share_id; + void setPassword(QString password); + void setExpireDate(const QString &date); +}; + +} + +#endif // SHAREDIALOG_H diff --git a/src/gui/sharedialog.ui b/src/gui/sharedialog.ui new file mode 100644 index 0000000000..43239fcc26 --- /dev/null +++ b/src/gui/sharedialog.ui @@ -0,0 +1,183 @@ + + + OCC::ShareDialog + + + + 0 + 0 + 500 + 535 + + + + Share NewDocument.odt + + + + + + QLayout::SetFixedSize + + + + + Share with + + + + + + + + + User: + + + + + + + + + + Group + + + + + + + + + + Qt::Horizontal + + + + 40 + 5 + + + + + + + + 1 + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + + 40 + 5 + + + + + + + + + + Share link + + + + + + + + + + + + + + + + QLayout::SetDefaultConstraint + + + + + true + + + + + + + + + + + + + + + + + + Set password + + + + + + + + + + + + + + + + + + QLineEdit::Password + + + + + + + + + + + Set expiry date + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gui/socketapi.cpp b/src/gui/socketapi.cpp index b7e4f94628..4149c56725 100644 --- a/src/gui/socketapi.cpp +++ b/src/gui/socketapi.cpp @@ -398,6 +398,28 @@ void SocketApi::command_RETRIEVE_FILE_STATUS(const QString& argument, SocketType sendMessage(socket, message); } +void SocketApi::command_SHARE(const QString& argument, SocketType* socket) +{ + if (!socket) { + qDebug() << Q_FUNC_INFO << "No valid socket object."; + return; + } + + qDebug() << Q_FUNC_INFO << argument; + + Folder *shareFolder = FolderMan::instance()->folderForPath(argument); + if (!shareFolder) { + const QString message = QLatin1String("SHARE:NOP:")+QDir::toNativeSeparators(argument); + sendMessage(socket, message); + } else { + const QString message = QLatin1String("SHARE:OK:")+QDir::toNativeSeparators(argument); + sendMessage(socket, message); + const QString folderForPath = shareFolder->path(); + const QString path = shareFolder->remotePath() + argument.right(argument.count()-folderForPath.count()+1); + emit shareCommandReceived(path); + } +} + void SocketApi::command_VERSION(const QString&, SocketType* socket) { sendMessage(socket, QLatin1String("VERSION:" MIRALL_VERSION_STRING ":" MIRALL_SOCKET_API_VERSION)); diff --git a/src/gui/socketapi.h b/src/gui/socketapi.h index 75a490f2da..ac6000ae27 100644 --- a/src/gui/socketapi.h +++ b/src/gui/socketapi.h @@ -56,6 +56,10 @@ public slots: void slotRegisterPath( const QString& alias ); void slotReadExcludes(); void slotClearExcludesList(); + +signals: + void shareCommandReceived(const QString &path); + private slots: void slotNewConnection(); void onLostConnection(); @@ -74,6 +78,7 @@ private: Q_INVOKABLE void command_RETRIEVE_FOLDER_STATUS(const QString& argument, SocketType* socket); Q_INVOKABLE void command_RETRIEVE_FILE_STATUS(const QString& argument, SocketType* socket); + Q_INVOKABLE void command_SHARE(const QString& argument, SocketType* socket); Q_INVOKABLE void command_VERSION(const QString& argument, SocketType* socket);