File indexing completed on 2024-02-25 16:44:32

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"