From 2d88fc6c99d4a04a292021f3023864ee56c473d0 Mon Sep 17 00:00:00 2001 From: allexzander Date: Tue, 20 Apr 2021 17:36:42 +0300 Subject: [PATCH] Obey enforced password for share by email. Signed-off-by: allexzander --- src/gui/ocssharejob.cpp | 7 +- src/gui/ocssharejob.h | 4 +- src/gui/sharemanager.cpp | 71 ++++----- src/gui/sharemanager.h | 42 +++--- src/gui/shareusergroupwidget.cpp | 242 +++++++++++++++++++++++++++---- src/gui/shareusergroupwidget.h | 24 ++- src/gui/shareuserline.ui | 143 +++++++++++++++++- src/libsync/capabilities.cpp | 10 ++ src/libsync/capabilities.h | 2 + 9 files changed, 458 insertions(+), 87 deletions(-) diff --git a/src/gui/ocssharejob.cpp b/src/gui/ocssharejob.cpp index 228208ff6..fcbfafe77 100644 --- a/src/gui/ocssharejob.cpp +++ b/src/gui/ocssharejob.cpp @@ -142,7 +142,8 @@ void OcsShareJob::createLinkShare(const QString &path, void OcsShareJob::createShare(const QString &path, const Share::ShareType shareType, const QString &shareWith, - const Share::Permissions permissions) + const Share::Permissions permissions, + const QString &password) { Q_UNUSED(permissions) setVerb("POST"); @@ -151,6 +152,10 @@ void OcsShareJob::createShare(const QString &path, addParam(QString::fromLatin1("shareType"), QString::number(shareType)); addParam(QString::fromLatin1("shareWith"), shareWith); + if (!password.isEmpty()) { + addParam(QString::fromLatin1("password"), password); + } + start(); } diff --git a/src/gui/ocssharejob.h b/src/gui/ocssharejob.h index 726c0b8ce..074fa0762 100644 --- a/src/gui/ocssharejob.h +++ b/src/gui/ocssharejob.h @@ -113,11 +113,13 @@ public: * @param shareType The type of share (user/group/link/federated) * @param shareWith The uid/gid/federated id to share with * @param permissions The permissions the share will have + * @param password The password to protect the share with */ void createShare(const QString &path, const Share::ShareType shareType, const QString &shareWith = "", - const Share::Permissions permissions = SharePermissionRead); + const Share::Permissions permissions = SharePermissionRead, + const QString &password = ""); /** * Returns information on the items shared with the current user. diff --git a/src/gui/sharemanager.cpp b/src/gui/sharemanager.cpp index 9e2cf8ca8..35e624647 100644 --- a/src/gui/sharemanager.cpp +++ b/src/gui/sharemanager.cpp @@ -56,6 +56,7 @@ Share::Share(AccountPtr account, const QString &ownerDisplayName, const QString &path, const ShareType shareType, + bool isPasswordSet, const Permissions permissions, const QSharedPointer shareWith) : _account(account) @@ -64,6 +65,7 @@ Share::Share(AccountPtr account, , _ownerDisplayName(ownerDisplayName) , _path(path) , _shareType(shareType) + , _isPasswordSet(isPasswordSet) , _permissions(permissions) , _shareWith(shareWith) { @@ -104,6 +106,19 @@ QSharedPointer Share::getShareWith() const return _shareWith; } +void Share::setPassword(const QString &password) +{ + auto *job = new OcsShareJob(_account); + connect(job, &OcsShareJob::shareJobFinished, this, &Share::slotPasswordSet); + connect(job, &OcsJob::ocsError, this, &Share::slotSetPasswordError); + job->setPassword(getId(), password); +} + +bool Share::isPasswordSet() const +{ + return _isPasswordSet; +} + void Share::setPermissions(Permissions permissions) { auto *job = new OcsShareJob(_account); @@ -142,6 +157,17 @@ void Share::slotOcsError(int statusCode, const QString &message) emit serverError(statusCode, message); } +void Share::slotPasswordSet(const QJsonDocument &, const QVariant &value) +{ + _isPasswordSet = !value.toString().isEmpty(); + emit passwordSet(); +} + +void Share::slotSetPasswordError(int statusCode, const QString &message) +{ + emit passwordSetError(statusCode, message); +} + QUrl LinkShare::getLink() const { return _url; @@ -159,11 +185,6 @@ QDate LinkShare::getExpireDate() const return _expireDate; } -bool LinkShare::isPasswordSet() const -{ - return _passwordSet; -} - LinkShare::LinkShare(AccountPtr account, const QString &id, const QString &uidowner, @@ -172,13 +193,12 @@ LinkShare::LinkShare(AccountPtr account, const QString &name, const QString &token, Permissions permissions, - bool passwordSet, + bool isPasswordSet, const QUrl &url, const QDate &expireDate) - : Share(account, id, uidowner, ownerDisplayName, path, Share::TypeLink, permissions) + : Share(account, id, uidowner, ownerDisplayName, path, Share::TypeLink, isPasswordSet, permissions) , _name(name) , _token(token) - , _passwordSet(passwordSet) , _expireDate(expireDate) , _url(url) { @@ -231,20 +251,6 @@ QString LinkShare::getToken() const return _token; } -void LinkShare::setPassword(const QString &password) -{ - auto *job = new OcsShareJob(_account); - connect(job, &OcsShareJob::shareJobFinished, this, &LinkShare::slotPasswordSet); - connect(job, &OcsJob::ocsError, this, &LinkShare::slotSetPasswordError); - job->setPassword(getId(), password); -} - -void LinkShare::slotPasswordSet(const QJsonDocument &, const QVariant &value) -{ - _passwordSet = value.toString() != ""; - emit passwordSet(); -} - void LinkShare::setExpireDate(const QDate &date) { auto *job = new OcsShareJob(_account); @@ -269,11 +275,6 @@ void LinkShare::slotExpireDateSet(const QJsonDocument &reply, const QVariant &va emit expireDateSet(); } -void LinkShare::slotSetPasswordError(int statusCode, const QString &message) -{ - emit passwordSetError(statusCode, message); -} - void LinkShare::slotNameSet(const QJsonDocument &, const QVariant &value) { _name = value.toString(); @@ -286,15 +287,16 @@ UserGroupShare::UserGroupShare(AccountPtr account, const QString &ownerDisplayName, const QString &path, const ShareType shareType, + bool isPasswordSet, const Permissions permissions, const QSharedPointer shareWith, const QDate &expireDate, const QString ¬e) - : Share(account, id, owner, ownerDisplayName, path, shareType, permissions, shareWith) - , _expireDate(expireDate) + : Share(account, id, owner, ownerDisplayName, path, shareType, isPasswordSet, permissions, shareWith) , _note(note) + , _expireDate(expireDate) { - Q_ASSERT(shareType == TypeUser || shareType == TypeGroup); + Q_ASSERT(shareType == TypeUser || shareType == TypeGroup || shareType == TypeEmail); Q_ASSERT(shareWith); } @@ -389,7 +391,8 @@ void ShareManager::slotLinkShareCreated(const QJsonDocument &reply) void ShareManager::createShare(const QString &path, const Share::ShareType shareType, const QString shareWith, - const Share::Permissions desiredPermissions) + const Share::Permissions desiredPermissions, + const QString &password) { auto job = new OcsShareJob(_account); connect(job, &OcsJob::ocsError, this, &ShareManager::slotOcsError); @@ -416,7 +419,7 @@ void ShareManager::createShare(const QString &path, auto *job = new OcsShareJob(_account); connect(job, &OcsShareJob::shareJobFinished, this, &ShareManager::slotShareCreated); connect(job, &OcsJob::ocsError, this, &ShareManager::slotOcsError); - job->createShare(path, shareType, shareWith, validPermissions); + job->createShare(path, shareType, shareWith, validPermissions, password); }); job->getSharedWithMe(); } @@ -458,7 +461,7 @@ void ShareManager::slotSharesFetched(const QJsonDocument &reply) if (shareType == Share::TypeLink) { newShare = parseLinkShare(data); - } else if (shareType == Share::TypeGroup || shareType == Share::TypeUser) { + } else if (shareType == Share::TypeGroup || shareType == Share::TypeUser || shareType == Share::TypeEmail) { newShare = parseUserGroupShare(data); } else { newShare = parseShare(data); @@ -493,6 +496,7 @@ QSharedPointer ShareManager::parseUserGroupShare(const QJsonObje data.value("displayname_owner").toVariant().toString(), data.value("path").toString(), static_cast(data.value("share_type").toInt()), + !data.value("password").toString().isEmpty(), static_cast(data.value("permissions").toInt()), sharee, expireDate, @@ -546,6 +550,7 @@ QSharedPointer ShareManager::parseShare(const QJsonObject &data) data.value("displayname_owner").toVariant().toString(), data.value("path").toString(), (Share::ShareType)data.value("share_type").toInt(), + !data.value("password").toString().isEmpty(), (Share::Permissions)data.value("permissions").toInt(), sharee)); } diff --git a/src/gui/sharemanager.h b/src/gui/sharemanager.h index 8bbce2e74..a764163f6 100644 --- a/src/gui/sharemanager.h +++ b/src/gui/sharemanager.h @@ -61,6 +61,7 @@ public: const QString &ownerDisplayName, const QString &path, const ShareType shareType, + bool isPasswordSet = false, const Permissions permissions = SharePermissionDefault, const QSharedPointer shareWith = QSharedPointer(nullptr)); @@ -109,7 +110,17 @@ public: */ void setPermissions(Permissions permissions); - /** + /* + * Set the password for remote share + * + * On success the passwordSet signal is emitted + * In case of a server error the passwordSetError signal is emitted. + */ + void setPassword(const QString &password); + + bool isPasswordSet() const; + + /* * Deletes a share * * On success the shareDeleted signal is emitted @@ -121,6 +132,8 @@ signals: void permissionsSet(); void shareDeleted(); void serverError(int code, const QString &message); + void passwordSet(); + void passwordSetError(int statusCode, const QString &message); protected: AccountPtr _account; @@ -129,11 +142,14 @@ protected: QString _ownerDisplayName; QString _path; ShareType _shareType; + bool _isPasswordSet; Permissions _permissions; QSharedPointer _shareWith; protected slots: void slotOcsError(int statusCode, const QString &message); + void slotPasswordSet(const QJsonDocument &, const QVariant &value); + void slotSetPasswordError(int statusCode, const QString &message); private slots: void slotDeleted(); @@ -157,7 +173,7 @@ public: const QString &name, const QString &token, const Permissions permissions, - bool passwordSet, + bool isPasswordSet, const QUrl &url, const QDate &expireDate); @@ -210,19 +226,6 @@ public: */ QString getToken() const; - /* - * Set the password - * - * On success the passwordSet signal is emitted - * In case of a server error the serverError signal is emitted. - */ - void setPassword(const QString &password); - - /* - * Is the password set? - */ - bool isPasswordSet() const; - /* * Get the expiration date */ @@ -238,22 +241,17 @@ public: signals: void expireDateSet(); - void passwordSet(); void noteSet(); - void passwordSetError(int statusCode, const QString &message); void nameSet(); private slots: - void slotPasswordSet(const QJsonDocument &, const QVariant &value); void slotNoteSet(const QJsonDocument &, const QVariant &value); void slotExpireDateSet(const QJsonDocument &reply, const QVariant &value); - void slotSetPasswordError(int statusCode, const QString &message); void slotNameSet(const QJsonDocument &, const QVariant &value); private: QString _name; QString _token; - bool _passwordSet; QString _note; QDate _expireDate; QUrl _url; @@ -269,6 +267,7 @@ public: const QString &ownerDisplayName, const QString &path, const ShareType shareType, + bool isPasswordSet, const Permissions permissions, const QSharedPointer shareWith, const QDate &expireDate, @@ -335,7 +334,8 @@ public: void createShare(const QString &path, const Share::ShareType shareType, const QString shareWith, - const Share::Permissions permissions); + const Share::Permissions permissions, + const QString &password = ""); /** * Fetch all the shares for path diff --git a/src/gui/shareusergroupwidget.cpp b/src/gui/shareusergroupwidget.cpp index 41a6c9d2d..3d1052550 100644 --- a/src/gui/shareusergroupwidget.cpp +++ b/src/gui/shareusergroupwidget.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,10 @@ #include +namespace { + const char *passwordIsSetPlaceholder = "●●●●●●●●"; +} + namespace OCC { ShareUserGroupWidget::ShareUserGroupWidget(AccountPtr account, @@ -97,7 +102,7 @@ ShareUserGroupWidget::ShareUserGroupWidget(AccountPtr account, _manager = new ShareManager(_account, this); connect(_manager, &ShareManager::sharesFetched, this, &ShareUserGroupWidget::slotSharesFetched); - connect(_manager, &ShareManager::shareCreated, this, &ShareUserGroupWidget::getShares); + connect(_manager, &ShareManager::shareCreated, this, &ShareUserGroupWidget::slotShareCreated); connect(_manager, &ShareManager::serverError, this, &ShareUserGroupWidget::displayError); connect(_ui->shareeLineEdit, &QLineEdit::returnPressed, this, &ShareUserGroupWidget::slotLineEditReturn); connect(_ui->confirmShare, &QAbstractButton::clicked, this, &ShareUserGroupWidget::slotLineEditReturn); @@ -202,6 +207,16 @@ void ShareUserGroupWidget::getShares() _manager->fetchShares(_sharePath); } +void ShareUserGroupWidget::slotShareCreated(const QSharedPointer &share) +{ + if (share && _account->capabilities().shareEmailPasswordEnabled()) { + // remember this share Id so we can set it's password Line Edit to focus later + _lastCreatedShareId = share->getId(); + } + // fetch all shares including the one we've just created + getShares(); +} + void ShareUserGroupWidget::slotSharesFetched(const QList> &shares) { QScrollArea *scrollArea = _parentScrollArea; @@ -213,6 +228,8 @@ void ShareUserGroupWidget::slotSharesFetched(const QList> int height = 0; QList linkOwners({}); + QPointer justCreatedShareThatNeedsOptionalPassword = nullptr; + foreach (const auto &share, shares) { // We don't handle link shares, only TypeUser or TypeGroup if (share->getShareType() == Share::TypeLink) { @@ -230,9 +247,9 @@ void ShareUserGroupWidget::slotSharesFetched(const QList> } - Q_ASSERT(share->getShareType() == Share::TypeUser || share->getShareType() == Share::TypeGroup); + Q_ASSERT(share->getShareType() == Share::TypeUser || share->getShareType() == Share::TypeGroup || share->getShareType() == Share::TypeEmail); auto userGroupShare = qSharedPointerDynamicCast(share); - auto *s = new ShareUserLine(userGroupShare, _maxSharingPermissions, _isFile, _parentScrollArea); + auto *s = new ShareUserLine(_account, userGroupShare, _maxSharingPermissions, _isFile, _parentScrollArea); connect(s, &ShareUserLine::resizeRequested, this, &ShareUserGroupWidget::slotAdjustScrollWidgetSize); connect(s, &ShareUserLine::visualDeletionDone, this, &ShareUserGroupWidget::getShares); s->setBackgroundRole(layout->count() % 2 == 0 ? QPalette::Base : QPalette::AlternateBase); @@ -242,6 +259,13 @@ void ShareUserGroupWidget::slotSharesFetched(const QList> layout->addWidget(s); + if (!_lastCreatedShareId.isEmpty() && share->getId() == _lastCreatedShareId) { + _lastCreatedShareId = QString(); + if (_account->capabilities().shareEmailPasswordEnabled()) { + justCreatedShareThatNeedsOptionalPassword = s; + } + } + x++; if (x <= 3) { height = newViewPort->sizeHint().height(); @@ -266,6 +290,11 @@ void ShareUserGroupWidget::slotSharesFetched(const QList> _disableCompleterActivated = false; activateShareeLineEdit(); + + if (justCreatedShareThatNeedsOptionalPassword) { + // always set focus to a password Line Edit when the new email share is created on a server with optional passwords enabled for email shares + justCreatedShareThatNeedsOptionalPassword->focusPasswordLineEdit(); + } } void ShareUserGroupWidget::slotAdjustScrollWidgetSize() @@ -338,6 +367,9 @@ void ShareUserGroupWidget::slotCompleterActivated(const QModelIndex &index) * https://github.com/owncloud/core/issues/22122#issuecomment-185637344 * https://github.com/owncloud/client/issues/4996 */ + + _lastCreatedShareId = QString(); + if (sharee->type() == Sharee::Federated && _account->serverVersionInt() < Account::makeServerVersion(9, 1, 0)) { int permissions = SharePermissionRead | SharePermissionUpdate; @@ -347,12 +379,32 @@ void ShareUserGroupWidget::slotCompleterActivated(const QModelIndex &index) _manager->createShare(_sharePath, Share::ShareType(sharee->type()), sharee->shareWith(), SharePermission(permissions)); } else { + QString password; + if (sharee->type() == Sharee::Email && _account->capabilities().shareEmailPasswordEnforced()) { + _ui->shareeLineEdit->setText(QString()); + // always show a dialog for password-enforced email shares + bool ok = false; + + do { + password = QInputDialog::getText( + this, + tr("Password for share required"), + tr("Please enter a password for your email share:"), + QLineEdit::Password, + QString(), + &ok); + } while (password.isEmpty() && ok); + + if (!ok) { + return; + } + } // Default permissions on creation int permissions = SharePermissionCreate | SharePermissionUpdate | SharePermissionDelete | SharePermissionShare; _manager->createShare(_sharePath, Share::ShareType(sharee->type()), - sharee->shareWith(), SharePermission(permissions)); + sharee->shareWith(), SharePermission(permissions), password); } _ui->shareeLineEdit->setEnabled(false); @@ -424,12 +476,14 @@ void ShareUserGroupWidget::activateShareeLineEdit() _ui->shareeLineEdit->setFocus(); } -ShareUserLine::ShareUserLine(QSharedPointer share, - SharePermissions maxSharingPermissions, - bool isFile, - QWidget *parent) +ShareUserLine::ShareUserLine(AccountPtr account, + QSharedPointer share, + SharePermissions maxSharingPermissions, + bool isFile, + QWidget *parent) : QWidget(parent) , _ui(new Ui::ShareUserLine) + , _account(account) , _share(share) , _isFile(isFile) { @@ -463,32 +517,40 @@ ShareUserLine::ShareUserLine(QSharedPointer share, connect(_permissionReshare, &QAction::triggered, this, &ShareUserLine::slotPermissionsChanged); showNoteOptions(false); - _noteLinkAction = new QAction(tr("Note to recipient")); - _noteLinkAction->setCheckable(true); - menu->addAction(_noteLinkAction); - connect(_noteLinkAction, &QAction::triggered, this, &ShareUserLine::toggleNoteOptions); - if (!_share->getNote().isEmpty()) { - _noteLinkAction->setChecked(true); - showNoteOptions(true); + + if (_share->getShareType() != Share::ShareType::TypeEmail) { + // email shares do not support notes + _noteLinkAction = new QAction(tr("Note to recipient")); + _noteLinkAction->setCheckable(true); + menu->addAction(_noteLinkAction); + connect(_noteLinkAction, &QAction::triggered, this, &ShareUserLine::toggleNoteOptions); + if (!_share->getNote().isEmpty()) { + _noteLinkAction->setChecked(true); + showNoteOptions(true); + } } showExpireDateOptions(false); - _expirationDateLinkAction = new QAction(tr("Set expiration date")); - _expirationDateLinkAction->setCheckable(true); - menu->addAction(_expirationDateLinkAction); - connect(_expirationDateLinkAction, &QAction::triggered, this, &ShareUserLine::toggleExpireDateOptions); - const auto expireDate = _share->getExpireDate().isValid() ? share.data()->getExpireDate() : QDate(); - if (!expireDate.isNull()) { - _ui->calendar->setDate(expireDate); - _expirationDateLinkAction->setChecked(true); - showExpireDateOptions(true); + + if (_share->getShareType() != Share::ShareType::TypeEmail) { + // email shares do not support expiration dates + _expirationDateLinkAction = new QAction(tr("Set expiration date")); + _expirationDateLinkAction->setCheckable(true); + menu->addAction(_expirationDateLinkAction); + connect(_expirationDateLinkAction, &QAction::triggered, this, &ShareUserLine::toggleExpireDateOptions); + const auto expireDate = _share->getExpireDate().isValid() ? share.data()->getExpireDate() : QDate(); + if (!expireDate.isNull()) { + _ui->calendar->setDate(expireDate); + _expirationDateLinkAction->setChecked(true); + showExpireDateOptions(true); + } } menu->addSeparator(); - // Adds action to delete share widget - QIcon deleteicon = QIcon::fromTheme(QLatin1String("user-trash"),QIcon(QLatin1String(":/client/theme/delete.svg"))); - _deleteShareButton= new QAction(deleteicon,tr("Unshare"), this); + // Adds action to delete share widget + QIcon deleteicon = QIcon::fromTheme(QLatin1String("user-trash"),QIcon(QLatin1String(":/client/theme/delete.svg"))); + _deleteShareButton= new QAction(deleteicon,tr("Unshare"), this); menu->addAction(_deleteShareButton); connect(_deleteShareButton, &QAction::triggered, this, &ShareUserLine::on_deleteShareButton_clicked); @@ -516,6 +578,28 @@ ShareUserLine::ShareUserLine(QSharedPointer share, connect(_permissionDelete, &QAction::triggered, this, &ShareUserLine::slotPermissionsChanged); } + // Adds action to display password widget (check box) + if (_share->isPasswordSet() || _account->capabilities().shareEmailPasswordEnabled()) { + _passwordProtectLinkAction = new QAction(tr("Password protect"), this); + _passwordProtectLinkAction->setCheckable(true); + _passwordProtectLinkAction->setChecked(_share->isPasswordSet()); + _passwordProtectLinkAction->setEnabled(!_share->isPasswordSet() || !_account->capabilities().shareEmailPasswordEnforced()); + + menu->addAction(_passwordProtectLinkAction); + connect(_passwordProtectLinkAction, &QAction::triggered, this, &ShareUserLine::slotPasswordCheckboxChanged); + + if (_share->isPasswordSet()) { + _ui->lineEdit_password->setPlaceholderText(QString::fromUtf8(passwordIsSetPlaceholder)); + } + + refreshPasswordOptions(); + + connect(_share.data(), &Share::passwordSet, this, &ShareUserLine::slotPasswordSet); + connect(_share.data(), &Share::passwordSetError, this, &ShareUserLine::slotPasswordSetError); + } + + _ui->errorLabel->hide(); + _ui->permissionToolButton->setMenu(menu); _ui->permissionToolButton->setPopupMode(QToolButton::InstantPopup); @@ -675,6 +759,23 @@ void ShareUserLine::slotPermissionsChanged() _share->setPermissions(permissions); } +void ShareUserLine::slotPasswordCheckboxChanged() +{ + if (!_passwordProtectLinkAction->isChecked()) { + if (!_share->isPasswordSet()) { + _ui->lineEdit_password->setText(QString()); + } else { + _share->setPassword(QString()); + } + } + + refreshPasswordOptions(); + + if (_ui->lineEdit_password->isVisible() && _ui->lineEdit_password->isEnabled()) { + _ui->lineEdit_password->setFocus(); + } +} + void ShareUserLine::slotDeleteAnimationFinished() { emit resizeRequested(); @@ -687,6 +788,58 @@ void ShareUserLine::slotDeleteAnimationFinished() connect(this, SIGNAL(destroyed(QObject *)), parentWidget(), SLOT(repaint())); } +void ShareUserLine::refreshPasswordOptions() +{ + _ui->passwordLabel->setVisible(_passwordProtectLinkAction->isChecked()); + _ui->lineEdit_password->setEnabled(_passwordProtectLinkAction->isChecked()); + _ui->lineEdit_password->setVisible(_passwordProtectLinkAction->isChecked()); + _ui->confirmPassword->setVisible(_passwordProtectLinkAction->isChecked()); + + emit resizeRequested(); +} + +void ShareUserLine::refreshPasswordLineEditPlaceholder() +{ + if (_share->isPasswordSet()) { + _ui->lineEdit_password->setPlaceholderText(QString::fromUtf8(passwordIsSetPlaceholder)); + } else { + _ui->lineEdit_password->setPlaceholderText(""); + } +} + +void ShareUserLine::slotPasswordSet() +{ + enableProgessIndicatorAnimation(false); + _ui->lineEdit_password->setEnabled(true); + _ui->confirmPassword->setEnabled(true); + + _ui->lineEdit_password->setText(""); + + _passwordProtectLinkAction->setEnabled(!_share->isPasswordSet() || !_account->capabilities().shareEmailPasswordEnforced()); + + refreshPasswordLineEditPlaceholder(); +} + +void ShareUserLine::slotPasswordSetError(int statusCode, const QString &message) +{ + enableProgessIndicatorAnimation(false); + _ui->lineEdit_password->setEnabled(true); + _ui->confirmPassword->setEnabled(true); + + _passwordProtectLinkAction->setEnabled(!_share->isPasswordSet() || !_account->capabilities().shareEmailPasswordEnforced()); + + qCWarning(lcSharing) << "Error from server" << statusCode << message; + + refreshPasswordLineEditPlaceholder(); + + _ui->lineEdit_password->setFocus(); + + _ui->errorLabel->show(); + _ui->errorLabel->setText(message); + + emit resizeRequested(); +} + void ShareUserLine::slotShareDeleted() { auto *animation = new QPropertyAnimation(this, "maximumHeight", this); @@ -743,6 +896,11 @@ void ShareUserLine::slotStyleChanged() customizeStyle(); } +void ShareUserLine::focusPasswordLineEdit() +{ + _ui->lineEdit_password->setFocus(); +} + void ShareUserLine::customizeStyle() { _ui->permissionToolButton->setIcon(Theme::createColorAwareIcon(":/client/theme/more.svg")); @@ -753,6 +911,9 @@ void ShareUserLine::customizeStyle() _ui->noteConfirmButton->setIcon(Theme::createColorAwareIcon(":/client/theme/confirm.svg")); _ui->confirmExpirationDate->setIcon(Theme::createColorAwareIcon(":/client/theme/confirm.svg")); _ui->progressIndicator->setColor(QGuiApplication::palette().color(QPalette::WindowText)); + + // make sure to force BackgroundRole to QPalette::WindowText for a lable, because it's parent always has a different role set that applies to children unless customized + _ui->errorLabel->setBackgroundRole(QPalette::WindowText); } void ShareUserLine::showNoteOptions(bool show) @@ -838,4 +999,31 @@ void ShareUserLine::disableProgessIndicatorAnimation() { enableProgessIndicatorAnimation(false); } + +void ShareUserLine::setPasswordConfirmed() +{ + if (_ui->lineEdit_password->text().isEmpty()) { + return; + } + + _ui->lineEdit_password->setEnabled(false); + + _ui->confirmPassword->setEnabled(false); + + _ui->errorLabel->hide(); + _ui->errorLabel->setText(QString()); + + enableProgessIndicatorAnimation(true); + _share->setPassword(_ui->lineEdit_password->text()); +} + +void ShareUserLine::on_lineEdit_password_returnPressed() +{ + setPasswordConfirmed(); +} + +void ShareUserLine::on_confirmPassword_clicked() +{ + setPasswordConfirmed(); +} } diff --git a/src/gui/shareusergroupwidget.h b/src/gui/shareusergroupwidget.h index c69c64012..a73722e36 100644 --- a/src/gui/shareusergroupwidget.h +++ b/src/gui/shareusergroupwidget.h @@ -67,6 +67,7 @@ signals: public slots: void getShares(); + void slotShareCreated(const QSharedPointer &share); void slotStyleChanged(); private slots: @@ -110,6 +111,8 @@ private: ShareManager *_manager; QProgressIndicator _pi_sharee; + + QString _lastCreatedShareId; }; /** @@ -120,7 +123,8 @@ class ShareUserLine : public QWidget Q_OBJECT public: - explicit ShareUserLine(QSharedPointer share, + explicit ShareUserLine(AccountPtr account, + QSharedPointer Share, SharePermissions maxSharingPermissions, bool isFile, QWidget *parent = nullptr); @@ -135,17 +139,33 @@ signals: public slots: void slotStyleChanged(); + void focusPasswordLineEdit(); + private slots: void on_deleteShareButton_clicked(); void slotPermissionsChanged(); void slotEditPermissionsChanged(); + void slotPasswordCheckboxChanged(); void slotDeleteAnimationFinished(); + void refreshPasswordOptions(); + + void refreshPasswordLineEditPlaceholder(); + + void slotPasswordSet(); + void slotPasswordSetError(int statusCode, const QString &message); + void slotShareDeleted(); void slotPermissionsSet(); void slotAvatarLoaded(QImage avatar); + void setPasswordConfirmed(); + + void on_lineEdit_password_returnPressed(); + + void on_confirmPassword_clicked(); + private: void displayPermissions(); void loadAvatar(); @@ -164,6 +184,7 @@ private: void disableProgessIndicatorAnimation(); Ui::ShareUserLine *_ui; + AccountPtr _account; QSharedPointer _share; bool _isFile; @@ -175,6 +196,7 @@ private: QAction *_permissionDelete; QAction *_noteLinkAction; QAction *_expirationDateLinkAction; + QAction *_passwordProtectLinkAction; }; } diff --git a/src/gui/shareuserline.ui b/src/gui/shareuserline.ui index cb6324c35..0c2d58b8e 100644 --- a/src/gui/shareuserline.ui +++ b/src/gui/shareuserline.ui @@ -7,7 +7,7 @@ 0 0 980 - 210 + 239 @@ -116,11 +116,23 @@ QLayout::SetMinimumSize + + 10 + + + + 78 + 0 + + Note: + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + @@ -134,7 +146,7 @@ 0 - 60 + 0 @@ -158,8 +170,61 @@ + + + + 10 + + + + + + 78 + 0 + + + + Password: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 0 + + + + + + + + 1 + 0 + + + + QLineEdit::Password + + + + + + + ... + + + + :/client/theme/confirm.svg:/client/theme/confirm.svg + + + + + + + 10 + @@ -172,7 +237,7 @@ Expires: - Qt::AlignCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -202,6 +267,78 @@ + + + + 10 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + + + + + 255 + 0 + 0 + + + + + + + + + 255 + 0 + 0 + + + + + + + + + 123 + 121 + 134 + + + + + + + + Placeholder for Error text + + + Qt::PlainText + + + true + + + + + diff --git a/src/libsync/capabilities.cpp b/src/libsync/capabilities.cpp index 4b991348e..208b7d04f 100644 --- a/src/libsync/capabilities.cpp +++ b/src/libsync/capabilities.cpp @@ -40,6 +40,16 @@ bool Capabilities::shareAPI() const } } +bool Capabilities::shareEmailPasswordEnabled() const +{ + return _capabilities["files_sharing"].toMap()["sharebymail"].toMap()["password"].toMap()["enabled"].toBool(); +} + +bool Capabilities::shareEmailPasswordEnforced() const +{ + return _capabilities["files_sharing"].toMap()["sharebymail"].toMap()["password"].toMap()["enforced"].toBool(); +} + bool Capabilities::sharePublicLink() const { if (_capabilities["files_sharing"].toMap().contains("public")) { diff --git a/src/libsync/capabilities.h b/src/libsync/capabilities.h index 11f784875..078a0cd35 100644 --- a/src/libsync/capabilities.h +++ b/src/libsync/capabilities.h @@ -46,6 +46,8 @@ public: Capabilities(const QVariantMap &capabilities); bool shareAPI() const; + bool shareEmailPasswordEnabled() const; + bool shareEmailPasswordEnforced() const; bool sharePublicLink() const; bool sharePublicLinkAllowUpload() const; bool sharePublicLinkSupportsUploadOnly() const;