File indexing completed on 2024-12-22 04:45:28
0001 /* 0002 SPDX-FileCopyrightText: 2018-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "setavatarjob.h" 0008 #include "restapimethod.h" 0009 #include "rocketchatqtrestapi_debug.h" 0010 0011 #include <KLocalizedString> 0012 0013 #include <QFile> 0014 #include <QHttpMultiPart> 0015 #include <QJsonDocument> 0016 #include <QJsonObject> 0017 #include <QMimeDatabase> 0018 #include <QNetworkReply> 0019 using namespace RocketChatRestApi; 0020 SetAvatarJob::SetAvatarJob(QObject *parent) 0021 : UserBaseJob(parent) 0022 { 0023 } 0024 0025 SetAvatarJob::~SetAvatarJob() = default; 0026 0027 bool SetAvatarJob::start() 0028 { 0029 if (!canStart()) { 0030 deleteLater(); 0031 return false; 0032 } 0033 addStartRestApiInfo("SetAvatarJob::start"); 0034 if (!mAvatarInfo.mAvatarUrl.isEmpty()) { 0035 submitPostRequest(json()); 0036 } else { 0037 const QString fileNameAsLocalFile = mAvatarInfo.mImageUrl.toLocalFile(); 0038 auto file = new QFile(fileNameAsLocalFile); 0039 if (!file->open(QIODevice::ReadOnly)) { 0040 qCWarning(ROCKETCHATQTRESTAPI_LOG) << " Impossible to open filename " << mAvatarInfo.mImageUrl; 0041 Q_EMIT failed(i18n("File not found \'%1\'", fileNameAsLocalFile)); 0042 delete file; 0043 deleteLater(); 0044 return false; 0045 } 0046 QMimeDatabase db; 0047 const QMimeType mimeType = db.mimeTypeForFile(fileNameAsLocalFile); 0048 0049 auto multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); 0050 0051 QHttpPart filePart; 0052 filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(mimeType.name())); 0053 const QString filePartInfo = QStringLiteral("form-data; name=\"image\"; filename=\"%1\"").arg(mAvatarInfo.mImageUrl.fileName()); 0054 filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(filePartInfo)); 0055 0056 filePart.setBodyDevice(file); 0057 file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart 0058 multiPart->append(filePart); 0059 0060 QHttpPart userPart; 0061 userPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(QLatin1String("form-data; name=\"userId\""))); 0062 userPart.setBody(userId().toUtf8()); 0063 multiPart->append(userPart); 0064 0065 mReply = networkAccessManager()->post(request(), multiPart); 0066 // connect(reply, &QNetworkReply::uploadProgress, this, &UploadFileJob::slotUploadProgress); 0067 connect(mReply.data(), &QNetworkReply::finished, this, &SetAvatarJob::slotSetAvatar); 0068 multiPart->setParent(mReply); // delete the multiPart with the reply 0069 } 0070 return true; 0071 } 0072 0073 void SetAvatarJob::slotSetAvatar() 0074 { 0075 auto reply = mReply; 0076 if (reply) { 0077 const QJsonDocument replyJson = convertToJsonDocument(reply); 0078 onPostRequestResponse(mReply->errorString(), replyJson); 0079 reply->deleteLater(); 0080 } 0081 deleteLater(); 0082 } 0083 0084 void SetAvatarJob::onPostRequestResponse(const QString &replyErrorString, const QJsonDocument &replyJson) 0085 { 0086 const QJsonObject replyObject = replyJson.object(); 0087 if (replyObject[QLatin1String("success")].toBool()) { 0088 addLoggerInfo(QByteArrayLiteral("SetAvatarJob: success: ") + replyJson.toJson(QJsonDocument::Indented)); 0089 Q_EMIT setAvatarDone(); 0090 } else { 0091 emitFailedMessage(replyErrorString, replyObject); 0092 addLoggerWarning(QByteArrayLiteral("SetAvatarJob: Problem: ") + replyJson.toJson(QJsonDocument::Indented)); 0093 } 0094 } 0095 0096 SetAvatarJob::SetAvatarInfo SetAvatarJob::avatarInfo() const 0097 { 0098 return mAvatarInfo; 0099 } 0100 0101 void SetAvatarJob::setAvatarInfo(const SetAvatarInfo &avatarInfo) 0102 { 0103 mAvatarInfo = avatarInfo; 0104 } 0105 0106 QString SetAvatarJob::errorMessage(const QString &str, const QJsonObject &details) 0107 { 0108 if (str == QLatin1String("error-avatar-invalid-url")) { 0109 const QString url = details[QLatin1String("url")].toString(); 0110 return i18n("Invalid avatar URL: %1", url); 0111 } else if (str == QLatin1String("error-avatar-url-handling")) { 0112 const QString url = details[QLatin1String("url")].toString(); 0113 const QString username = details[QLatin1String("username")].toString(); 0114 return i18n("Error while handling avatar setting from a URL \"%1\" for %2", url, username); 0115 } 0116 0117 return RestApiAbstractJob::errorMessage(str, details); 0118 } 0119 0120 bool SetAvatarJob::requireHttpAuthentication() const 0121 { 0122 return true; 0123 } 0124 0125 bool SetAvatarJob::canStart() const 0126 { 0127 if (!hasUserIdentifier()) { 0128 qCWarning(ROCKETCHATQTRESTAPI_LOG) << "SetAvatarJob: identifier is empty"; 0129 return false; 0130 } 0131 if (!RestApiAbstractJob::canStart()) { 0132 return false; 0133 } 0134 if (!mAvatarInfo.isValid()) { 0135 qCWarning(ROCKETCHATQTRESTAPI_LOG) << "SetAvatarJob: mAvatarInfo is not valid"; 0136 return false; 0137 } 0138 return true; 0139 } 0140 0141 QNetworkRequest SetAvatarJob::request() const 0142 { 0143 const QUrl url = mRestApiMethod->generateUrl(RestApiUtil::RestApiUrlType::UsersSetAvatar); 0144 QNetworkRequest request(url); 0145 addAuthRawHeader(request); 0146 addRequestAttribute(request, !mAvatarInfo.mAvatarUrl.isEmpty()); // Don't show "json" when we send image 0147 return request; 0148 } 0149 0150 QJsonDocument SetAvatarJob::json() const 0151 { 0152 QJsonObject jsonObj; 0153 jsonObj[QLatin1String("avatarUrl")] = mAvatarInfo.mAvatarUrl; 0154 generateJson(jsonObj); 0155 const QJsonDocument postData = QJsonDocument(jsonObj); 0156 return postData; 0157 } 0158 0159 bool SetAvatarJob::SetAvatarInfo::isValid() const 0160 { 0161 return !mAvatarUrl.isEmpty() || !mImageUrl.isEmpty(); 0162 } 0163 0164 #include "moc_setavatarjob.cpp"