File indexing completed on 2024-06-23 05:07:03

0001 /*
0002     SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "tagcreatehandler.h"
0008 
0009 #include "connection.h"
0010 #include "storage/countquerybuilder.h"
0011 #include "storage/datastore.h"
0012 #include "storage/querybuilder.h"
0013 #include "storage/transaction.h"
0014 #include "tagfetchhelper.h"
0015 
0016 #include "private/imapset_p.h"
0017 #include "private/scope_p.h"
0018 
0019 using namespace Akonadi;
0020 using namespace Akonadi::Server;
0021 
0022 TagCreateHandler::TagCreateHandler(AkonadiServer &akonadi)
0023     : Handler(akonadi)
0024 {
0025 }
0026 
0027 bool TagCreateHandler::parseStream()
0028 {
0029     const auto &cmd = Protocol::cmdCast<Protocol::CreateTagCommand>(m_command);
0030 
0031     if (!cmd.remoteId().isEmpty() && !connection()->context().resource().isValid()) {
0032         return failureResponse(QStringLiteral("Only resources can create tags with remote ID"));
0033     }
0034 
0035     Transaction trx(storageBackend(), QStringLiteral("TAGAPPEND"));
0036 
0037     TagType tagType;
0038     if (!cmd.type().isEmpty()) {
0039         const QString typeName = QString::fromUtf8(cmd.type());
0040         tagType = TagType::retrieveByNameOrCreate(typeName);
0041         if (!tagType.isValid()) {
0042             return failureResponse(QStringLiteral("Unable to create tagtype '") % typeName % QStringLiteral("'"));
0043         }
0044     }
0045 
0046     qint64 tagId = -1;
0047     const QString gid = QString::fromUtf8(cmd.gid());
0048     if (cmd.merge()) {
0049         QueryBuilder qb(Tag::tableName());
0050         qb.addColumn(Tag::idColumn());
0051         qb.addValueCondition(Tag::gidColumn(), Query::Equals, gid);
0052         if (!qb.exec()) {
0053             return failureResponse("Unable to list tags");
0054         }
0055         if (qb.query().next()) {
0056             tagId = qb.query().value(0).toLongLong();
0057         }
0058         qb.query().finish();
0059     }
0060     if (tagId < 0) {
0061         Tag insertedTag;
0062         insertedTag.setGid(gid);
0063         if (cmd.parentId() >= 0) {
0064             insertedTag.setParentId(cmd.parentId());
0065         }
0066         if (tagType.isValid()) {
0067             insertedTag.setTypeId(tagType.id());
0068         }
0069         if (!insertedTag.insert(&tagId)) {
0070             return failureResponse("Failed to store tag");
0071         }
0072 
0073         const Protocol::Attributes attrs = cmd.attributes();
0074         for (auto iter = attrs.cbegin(), end = attrs.cend(); iter != end; ++iter) {
0075             TagAttribute attribute;
0076             attribute.setTagId(tagId);
0077             attribute.setType(iter.key());
0078             attribute.setValue(iter.value());
0079             if (!attribute.insert()) {
0080                 return failureResponse("Failed to store tag attribute");
0081             }
0082         }
0083 
0084         storageBackend()->notificationCollector()->tagAdded(insertedTag);
0085     }
0086 
0087     if (!cmd.remoteId().isEmpty()) {
0088         const qint64 resourceId = connection()->context().resource().id();
0089 
0090         CountQueryBuilder qb(TagRemoteIdResourceRelation::tableName());
0091         qb.addValueCondition(TagRemoteIdResourceRelation::tagIdColumn(), Query::Equals, tagId);
0092         qb.addValueCondition(TagRemoteIdResourceRelation::resourceIdColumn(), Query::Equals, resourceId);
0093         if (!qb.exec()) {
0094             return failureResponse("Failed to query for existing TagRemoteIdResourceRelation entries");
0095         }
0096         const bool exists = (qb.result() > 0);
0097 
0098         // If the relation is already existing simply update it (can happen if a resource simply creates the tag again while enabling merge)
0099         bool ret = false;
0100         if (exists) {
0101             // Simply using update() doesn't work since TagRemoteIdResourceRelation only takes the tagId for identification of the column
0102             QueryBuilder qb(TagRemoteIdResourceRelation::tableName(), QueryBuilder::Update);
0103             qb.addValueCondition(TagRemoteIdResourceRelation::tagIdColumn(), Query::Equals, tagId);
0104             qb.addValueCondition(TagRemoteIdResourceRelation::resourceIdColumn(), Query::Equals, resourceId);
0105             qb.setColumnValue(TagRemoteIdResourceRelation::remoteIdColumn(), QString::fromUtf8(cmd.remoteId()));
0106             ret = qb.exec();
0107         } else {
0108             TagRemoteIdResourceRelation rel;
0109             rel.setTagId(tagId);
0110             rel.setResourceId(resourceId);
0111             rel.setRemoteId(QString::fromUtf8(cmd.remoteId()));
0112             ret = rel.insert();
0113         }
0114         if (!ret) {
0115             return failureResponse("Failed to store tag remote ID");
0116         }
0117     }
0118 
0119     trx.commit();
0120 
0121     Scope scope;
0122     ImapSet set;
0123     set.add(QList<qint64>() << tagId);
0124     scope.setUidSet(set);
0125 
0126     Protocol::TagFetchScope fetchScope;
0127     fetchScope.setFetchRemoteID(true);
0128     fetchScope.setFetchAllAttributes(true);
0129 
0130     TagFetchHelper helper(connection(), scope, fetchScope);
0131     if (!helper.fetchTags()) {
0132         return failureResponse("Failed to fetch the new tag");
0133     }
0134 
0135     return successResponse<Protocol::CreateTagResponse>();
0136 }