File indexing completed on 2024-10-06 04:34:01
0001 /* 0002 SPDX-FileCopyrightText: 2017-2024 Laurent Montel <montel@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "messageattachment.h" 0008 #include "ruqolaglobalconfig.h" 0009 0010 #include <KLocalizedString> 0011 #include <QJsonArray> 0012 #include <QJsonObject> 0013 0014 MessageAttachment::MessageAttachment() = default; 0015 0016 void MessageAttachment::parseAttachment(const QJsonObject &attachment) 0017 { 0018 const QJsonValue description = attachment.value(QLatin1String("description")); 0019 if (!description.isUndefined()) { 0020 setDescription(description.toString()); 0021 } 0022 const QJsonValue title = attachment.value(QLatin1String("title")); 0023 if (!title.isUndefined()) { 0024 setTitle(title.toString()); 0025 } 0026 AttachmentType attType = AttachmentType::Unknown; 0027 if (attachment.contains(QLatin1String("audio_url"))) { 0028 setLink(attachment.value(QLatin1String("audio_url")).toString()); 0029 attType = AttachmentType::Audio; 0030 } else if (attachment.contains(QLatin1String("video_url"))) { 0031 setLink(attachment.value(QLatin1String("video_url")).toString()); 0032 attType = AttachmentType::Video; 0033 } else if (attachment.contains(QLatin1String("image_url"))) { 0034 // prefer the title_link as the image_url may just serve us the tiny preview image 0035 setLink(attachment.value(QLatin1String("title_link")).toString()); 0036 mImageUrlPreview = attachment.value(QLatin1String("image_url")).toString(); 0037 if (link().isEmpty()) // fallback to the image_url otherwise 0038 setLink(mImageUrlPreview); 0039 attType = AttachmentType::Image; 0040 } else if (attachment.contains(QLatin1String("author_link"))) { 0041 setLink(attachment.value(QLatin1String("author_link")).toString()); 0042 attType = AttachmentType::NormalText; 0043 // TODO implement it. 0044 // } else if (attachment.contains(QLatin1String("message_link"))) { 0045 // setLink(attachment.value(QLatin1String("message_link")).toString()); 0046 // attType = AttachmentType::NormalText; 0047 } else if (attachment.contains(QLatin1String("title_link"))) { // Last as an image_url can have a title_link 0048 setLink(attachment.value(QLatin1String("title_link")).toString()); 0049 attType = AttachmentType::File; 0050 } 0051 // Add image dimension 0052 if (attType == AttachmentType::Image) { 0053 const QJsonValue imageDimensions = attachment.value(QLatin1String("image_dimensions")); 0054 if (!imageDimensions.isUndefined()) { 0055 const QJsonObject imageDimensionsParams = imageDimensions.toObject(); 0056 0057 setImageHeight(imageDimensionsParams.value(QLatin1String("height")).toInt()); 0058 setImageWidth(imageDimensionsParams.value(QLatin1String("width")).toInt()); 0059 // TODO validate image size 0060 } else { 0061 // Use default value 0062 setImageHeight(120); 0063 setImageWidth(120); 0064 } 0065 } 0066 0067 setAuthorName(attachment.value(QLatin1String("author_name")).toString()); 0068 setAuthorIcon(attachment.value(QLatin1String("author_icon")).toString()); 0069 // Color 0070 const QJsonValue color = attachment.value(QLatin1String("color")); 0071 if (!color.isUndefined()) { 0072 setColor(color.toString()); 0073 } 0074 // MimeType 0075 setMimeType(attachment.value(QLatin1String("image_type")).toString()); 0076 0077 // Text 0078 const QJsonValue text = attachment.value(QLatin1String("text")); 0079 if (!text.isUndefined()) { 0080 const QJsonValue messagelink = attachment.value(QLatin1String("message_link")); 0081 if (messagelink.isUndefined()) { // Don't show attachment if we have message_link. We already implement message preview 0082 attType = AttachmentType::NormalText; 0083 setText(text.toString()); 0084 } 0085 } 0086 const QJsonArray fieldsArray = attachment.value(QLatin1String("fields")).toArray(); 0087 QVector<MessageAttachmentField> messageFields; 0088 messageFields.reserve(fieldsArray.size()); 0089 for (int i = 0, total = fieldsArray.size(); i < total; ++i) { 0090 messageFields.append(MessageAttachmentField::deserialize(fieldsArray.at(i).toObject())); 0091 } 0092 if (!messageFields.isEmpty()) { 0093 setAttachmentFields(messageFields); 0094 if (attType == AttachmentType::Unknown) { 0095 attType = AttachmentType::NormalText; 0096 } 0097 } 0098 setAttachmentType(attType); 0099 mCollapsed = attachment.value(QLatin1String("collapsed")).toBool(); 0100 } 0101 0102 QJsonObject MessageAttachment::serialize(const MessageAttachment &messageAttach) 0103 { 0104 QJsonObject obj; 0105 if (!messageAttach.description().isEmpty()) { 0106 obj[QLatin1String("description")] = messageAttach.description(); 0107 } 0108 if (!messageAttach.title().isEmpty()) { 0109 obj[QLatin1String("title")] = messageAttach.title(); 0110 } 0111 obj[QLatin1String("url")] = messageAttach.link(); 0112 if (!messageAttach.imageUrlPreview().isEmpty()) { 0113 obj[QLatin1String("image_preview")] = messageAttach.imageUrlPreview(); 0114 } 0115 0116 const QString authorname = messageAttach.authorName(); 0117 if (!authorname.isEmpty()) { 0118 obj[QLatin1String("authorname")] = authorname; 0119 } 0120 const QString authorIcon = messageAttach.authorIcon(); 0121 if (!authorIcon.isEmpty()) { 0122 obj[QLatin1String("authoricon")] = authorIcon; 0123 } 0124 const QString mimeType = messageAttach.mimeType(); 0125 if (!mimeType.isEmpty()) { 0126 obj[QLatin1String("mimetype")] = mimeType; 0127 } 0128 if ((messageAttach.imageHeight() != -1) && (messageAttach.imageWidth() != -1)) { 0129 obj[QLatin1String("image_height")] = messageAttach.imageHeight(); 0130 obj[QLatin1String("image_width")] = messageAttach.imageWidth(); 0131 } 0132 const QString color = messageAttach.color(); 0133 if (!color.isEmpty()) { 0134 obj[QLatin1String("color")] = color; 0135 } 0136 const QString text = messageAttach.text(); 0137 if (!text.isEmpty()) { 0138 obj[QLatin1String("text")] = text; 0139 } 0140 0141 QJsonArray fieldArray; 0142 for (int i = 0, total = messageAttach.attachmentFields().count(); i < total; ++i) { 0143 const QJsonObject fields = MessageAttachmentField::serialize(messageAttach.attachmentFields().at(i)); 0144 fieldArray.append(std::move(fields)); 0145 } 0146 if (!fieldArray.isEmpty()) { 0147 obj[QLatin1String("fields")] = fieldArray; 0148 } 0149 if (messageAttach.collapsed()) { 0150 obj[QLatin1String("collapsed")] = true; 0151 } 0152 obj[QLatin1String("attachmentType")] = QJsonValue::fromVariant(QVariant::fromValue<MessageAttachment::AttachmentType>(messageAttach.attachmentType())); 0153 if (bool show = messageAttach.showAttachment()) { 0154 obj[QLatin1String("show_attachment")] = show; 0155 } 0156 return obj; 0157 } 0158 0159 MessageAttachment MessageAttachment::deserialize(const QJsonObject &o) 0160 { 0161 MessageAttachment att; 0162 att.setDescription(o.value(QLatin1String("description")).toString()); 0163 att.setTitle(o.value(QLatin1String("title")).toString()); 0164 att.setText(o.value(QLatin1String("text")).toString()); 0165 att.setLink(o.value(QLatin1String("url")).toString()); 0166 att.setImageUrlPreview(o.value(QLatin1String("image_preview")).toString()); 0167 att.setAuthorName(o.value(QLatin1String("authorname")).toString()); 0168 att.setAuthorIcon(o.value(QLatin1String("authoricon")).toString()); 0169 att.setMimeType(o.value(QLatin1String("mimetype")).toString()); 0170 const QJsonValue valHeight = o.value(QLatin1String("image_height")); 0171 if (!valHeight.isUndefined()) { 0172 att.setImageHeight(valHeight.toInt()); 0173 } 0174 const QJsonValue valWidth = o.value(QLatin1String("image_width")); 0175 if (!valWidth.isUndefined()) { 0176 att.setImageWidth(valWidth.toInt()); 0177 } 0178 att.setColor(o.value(QLatin1String("color")).toString()); 0179 const QJsonArray fieldsArray = o.value(QLatin1String("fields")).toArray(); 0180 QVector<MessageAttachmentField> messageFields; 0181 messageFields.reserve(fieldsArray.size()); 0182 for (int i = 0, total = fieldsArray.size(); i < total; ++i) { 0183 messageFields.append(MessageAttachmentField::deserialize(fieldsArray.at(i).toObject())); 0184 } 0185 att.setAttachmentFields(messageFields); 0186 att.setCollapsed(o.value(QLatin1String("collapsed")).toBool()); 0187 att.setAttachmentType(o[QLatin1String("attachmentType")].toVariant().value<AttachmentType>()); 0188 att.setShowAttachment(o[QLatin1String("show_attachment")].toBool()); 0189 return att; 0190 } 0191 0192 int MessageAttachment::imageWidth() const 0193 { 0194 return mImageWidth; 0195 } 0196 0197 void MessageAttachment::setImageWidth(int imageWidth) 0198 { 0199 mImageWidth = imageWidth; 0200 } 0201 0202 int MessageAttachment::imageHeight() const 0203 { 0204 return mImageHeight; 0205 } 0206 0207 void MessageAttachment::setImageHeight(int imageHeight) 0208 { 0209 mImageHeight = imageHeight; 0210 } 0211 0212 QString MessageAttachment::color() const 0213 { 0214 return mColor; 0215 } 0216 0217 void MessageAttachment::setColor(const QString &color) 0218 { 0219 mColor = color; 0220 } 0221 0222 QString MessageAttachment::authorName() const 0223 { 0224 return mAuthorName; 0225 } 0226 0227 void MessageAttachment::setAuthorName(const QString &authorName) 0228 { 0229 mAuthorName = authorName; 0230 } 0231 0232 bool MessageAttachment::isValid() const 0233 { 0234 return !mAttachmentId.isEmpty() && (!mLink.isEmpty() || !mText.isEmpty() || !mAttachmentFields.isEmpty()); 0235 } 0236 0237 bool MessageAttachment::canDownloadAttachment() const 0238 { 0239 // Improve it ! 0240 if (mLink.startsWith(QLatin1String("http://")) || mLink.startsWith(QLatin1String("https://"))) { 0241 return false; 0242 } 0243 return true; 0244 } 0245 0246 QString MessageAttachment::imageTitle() const 0247 { 0248 return QStringLiteral("%1 <a href=\'%2'>%2</a>").arg(i18n("File Uploaded:"), title()); 0249 } 0250 0251 QString MessageAttachment::mimeType() const 0252 { 0253 return mMimeType; 0254 } 0255 0256 void MessageAttachment::setMimeType(const QString &type) 0257 { 0258 mMimeType = type; 0259 if (mMimeType == QLatin1String("image/gif")) { 0260 mIsAnimatedImage = true; 0261 } 0262 } 0263 0264 bool MessageAttachment::isAnimatedImage() const 0265 { 0266 return mIsAnimatedImage; 0267 } 0268 0269 QString MessageAttachment::text() const 0270 { 0271 return mText; 0272 } 0273 0274 void MessageAttachment::setText(const QString &text) 0275 { 0276 mText = text; 0277 } 0278 0279 MessageAttachment::AttachmentType MessageAttachment::attachmentType() const 0280 { 0281 return mAttachmentType; 0282 } 0283 0284 void MessageAttachment::setAttachmentType(AttachmentType attachmentType) 0285 { 0286 mAttachmentType = attachmentType; 0287 if (mAttachmentType == Image) { 0288 // By default use false for showing it or using settings for image 0289 mShowAttachment = RuqolaGlobalConfig::self()->showImage(); 0290 } 0291 } 0292 0293 QVector<MessageAttachmentField> MessageAttachment::attachmentFields() const 0294 { 0295 return mAttachmentFields; 0296 } 0297 0298 void MessageAttachment::setAttachmentFields(const QVector<MessageAttachmentField> &attachmentFields) 0299 { 0300 mAttachmentFields = attachmentFields; 0301 generateAttachmentFieldsText(); 0302 } 0303 0304 void MessageAttachment::generateAttachmentFieldsText() 0305 { 0306 QString result = QStringLiteral(R"(<qt><table width="100%"><tr>)"); 0307 QStringList values; 0308 values.reserve(mAttachmentFields.count()); 0309 for (const MessageAttachmentField &field : std::as_const(mAttachmentFields)) { 0310 result += QStringLiteral("<th><b>%1</b></th>").arg(field.title()); 0311 values << field.value(); 0312 } 0313 result += QStringLiteral("</tr><tr>"); 0314 for (const QString &res : std::as_const(values)) { 0315 result += QStringLiteral("<td>%1</td>").arg(res); 0316 } 0317 result += QStringLiteral("</tr></table></qt>"); 0318 mAttachmentFieldsText += result; 0319 } 0320 0321 const QString &MessageAttachment::imageUrlPreview() const 0322 { 0323 return mImageUrlPreview; 0324 } 0325 0326 void MessageAttachment::setImageUrlPreview(const QString &newImageUrlPreview) 0327 { 0328 mImageUrlPreview = newImageUrlPreview; 0329 } 0330 0331 QString MessageAttachment::attachmentFieldsText() const 0332 { 0333 return mAttachmentFieldsText; 0334 } 0335 0336 bool MessageAttachment::collapsed() const 0337 { 0338 return mCollapsed; 0339 } 0340 0341 void MessageAttachment::setCollapsed(bool collapsed) 0342 { 0343 mCollapsed = collapsed; 0344 } 0345 0346 QString MessageAttachment::attachmentId() const 0347 { 0348 return mAttachmentId; 0349 } 0350 0351 void MessageAttachment::setAttachmentId(const QString &attachementId) 0352 { 0353 mAttachmentId = attachementId; 0354 } 0355 0356 bool MessageAttachment::showAttachment() const 0357 { 0358 return mShowAttachment; 0359 } 0360 0361 void MessageAttachment::setShowAttachment(bool showAttachment) 0362 { 0363 mShowAttachment = showAttachment; 0364 } 0365 0366 QString MessageAttachment::authorIcon() const 0367 { 0368 return mAuthorIcon; 0369 } 0370 0371 void MessageAttachment::setAuthorIcon(const QString &authorIcon) 0372 { 0373 mAuthorIcon = authorIcon; 0374 } 0375 0376 QString MessageAttachment::displayTitle() const 0377 { 0378 if (canDownloadAttachment()) { 0379 return i18n("File Uploaded: %1", title()); 0380 } 0381 return QStringLiteral("<a href=\'%1'>%2</a>").arg(link(), title()); 0382 } 0383 0384 bool MessageAttachment::hasDescription() const 0385 { 0386 return !mDescription.isEmpty(); 0387 } 0388 0389 QString MessageAttachment::description() const 0390 { 0391 return mDescription; 0392 } 0393 0394 void MessageAttachment::setDescription(const QString &description) 0395 { 0396 mDescription = description; 0397 } 0398 0399 QString MessageAttachment::title() const 0400 { 0401 return mTitle; 0402 } 0403 0404 void MessageAttachment::setTitle(const QString &title) 0405 { 0406 mTitle = title; 0407 } 0408 0409 QString MessageAttachment::link() const 0410 { 0411 return mLink; 0412 } 0413 0414 void MessageAttachment::setLink(const QString &link) 0415 { 0416 mLink = link; 0417 if (link.endsWith(QLatin1String(".gif"))) { // Gify doesn't set mimetype 0418 mIsAnimatedImage = true; 0419 } else { 0420 QUrl url(link); 0421 if (url.fileName().endsWith(QLatin1String( 0422 ".gif"))) { // Gify can return 0423 // https://media2.giphy.com/media/Id66GDfKacJzxSvhqV/giphy.gif?cid=e1bb72ffh1nt4tll6fw7bab09yqqznaupcxewcw2av5m59yi&rid=giphy.gif&ct=g 0424 mIsAnimatedImage = true; 0425 } 0426 } 0427 } 0428 0429 bool MessageAttachment::operator==(const MessageAttachment &other) const 0430 { 0431 return (mDescription == other.description()) && (mTitle == other.title()) && (mLink == other.link()) && (mColor == other.color()) 0432 && (mImageHeight == other.imageHeight()) && (mImageWidth == other.imageWidth()) && (mAuthorName == other.authorName()) 0433 && (mMimeType == other.mimeType()) && (mText == other.text()) && (mAttachmentFields == other.attachmentFields()) && (mCollapsed == other.collapsed()) 0434 && (mAuthorIcon == other.authorIcon()) && (mImageUrlPreview == other.imageUrlPreview()); 0435 } 0436 0437 QDebug operator<<(QDebug d, const MessageAttachment &t) 0438 { 0439 d << "Title : " << t.title(); 0440 d << "Description: " << t.description(); 0441 d << "Link: " << t.link(); 0442 d << "image dimension: width: " << t.imageWidth() << " height: " << t.imageHeight(); 0443 d << "color: " << t.color(); 0444 d << "authorname: " << t.authorName(); 0445 d << "mimeType: " << t.mimeType(); 0446 d << "text: " << t.text(); 0447 d << "collapsed " << t.collapsed(); 0448 d << "attachmentfields " << t.attachmentFields(); 0449 d << "showAttachment " << t.showAttachment(); 0450 d << "AttachmentType: " << t.attachmentType(); 0451 d << "mAuthorIcon: " << t.authorIcon(); 0452 d << "imageUrlPreview " << t.imageUrlPreview(); 0453 return d; 0454 } 0455 0456 #include "moc_messageattachment.cpp"