File indexing completed on 2024-06-23 05:07:02
0001 /* 0002 SPDX-FileCopyrightText: 2014 Christian Mollekopf <mollekopf@kolabsys.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "relationmodifyhandler.h" 0008 0009 #include "connection.h" 0010 #include "storage/datastore.h" 0011 #include "storage/querybuilder.h" 0012 #include "storage/selectquerybuilder.h" 0013 0014 using namespace Akonadi; 0015 using namespace Akonadi::Server; 0016 0017 RelationModifyHandler::RelationModifyHandler(AkonadiServer &akonadi) 0018 : Handler(akonadi) 0019 { 0020 } 0021 0022 Relation RelationModifyHandler::fetchRelation(qint64 leftId, qint64 rightId, qint64 typeId) 0023 { 0024 SelectQueryBuilder<Relation> relationQuery; 0025 relationQuery.addValueCondition(Relation::leftIdFullColumnName(), Query::Equals, leftId); 0026 relationQuery.addValueCondition(Relation::rightIdFullColumnName(), Query::Equals, rightId); 0027 relationQuery.addValueCondition(Relation::typeIdFullColumnName(), Query::Equals, typeId); 0028 if (!relationQuery.exec()) { 0029 throw HandlerException("Failed to query for existing relation"); 0030 } 0031 const Relation::List existingRelations = relationQuery.result(); 0032 if (!existingRelations.isEmpty()) { 0033 if (existingRelations.size() == 1) { 0034 return existingRelations.at(0); 0035 } else { 0036 throw HandlerException("Matched more than 1 relation"); 0037 } 0038 } 0039 0040 return Relation(); 0041 } 0042 0043 bool RelationModifyHandler::parseStream() 0044 { 0045 const auto &cmd = Protocol::cmdCast<Protocol::ModifyRelationCommand>(m_command); 0046 0047 if (cmd.type().isEmpty()) { 0048 return failureResponse("Relation type not specified"); 0049 } 0050 0051 if (cmd.left() < 0 || cmd.right() < 0) { 0052 return failureResponse("Invalid relation specified"); 0053 } 0054 0055 if (!cmd.remoteId().isEmpty() && !connection()->context().resource().isValid()) { 0056 return failureResponse("RemoteID can only be set by Resources"); 0057 } 0058 0059 const QString typeName = QString::fromUtf8(cmd.type()); 0060 const RelationType relationType = RelationType::retrieveByNameOrCreate(typeName); 0061 if (!relationType.isValid()) { 0062 return failureResponse(QStringLiteral("Unable to create relation type '") % typeName % QStringLiteral("'")); 0063 } 0064 0065 Relation existingRelation = fetchRelation(cmd.left(), cmd.right(), relationType.id()); 0066 if (existingRelation.isValid()) { 0067 existingRelation.setRemoteId(QLatin1StringView(cmd.remoteId())); 0068 if (!existingRelation.update()) { 0069 return failureResponse("Failed to update relation"); 0070 } 0071 } 0072 0073 // Can't use insert(), does not work here (no "id" column) 0074 QueryBuilder inQb(Relation::tableName(), QueryBuilder::Insert); 0075 inQb.setIdentificationColumn(QString()); // omit "RETURNING xyz" with PSQL 0076 inQb.setColumnValue(Relation::leftIdColumn(), cmd.left()); 0077 inQb.setColumnValue(Relation::rightIdColumn(), cmd.right()); 0078 inQb.setColumnValue(Relation::typeIdColumn(), relationType.id()); 0079 if (!inQb.exec()) { 0080 throw HandlerException("Failed to store relation"); 0081 } 0082 0083 Relation insertedRelation = fetchRelation(cmd.left(), cmd.right(), relationType.id()); 0084 0085 // Get all PIM items that are part of the relation 0086 SelectQueryBuilder<PimItem> itemsQuery; 0087 itemsQuery.setSubQueryMode(Query::Or); 0088 itemsQuery.addValueCondition(PimItem::idColumn(), Query::Equals, cmd.left()); 0089 itemsQuery.addValueCondition(PimItem::idColumn(), Query::Equals, cmd.right()); 0090 0091 if (!itemsQuery.exec()) { 0092 return failureResponse("Adding relation failed"); 0093 } 0094 const PimItem::List items = itemsQuery.result(); 0095 0096 if (items.size() != 2) { 0097 return failureResponse("Couldn't find items for relation"); 0098 } 0099 0100 /* if (items[0].collection().resourceId() != items[1].collection().resourceId()) { 0101 throw HandlerException("Relations can only be created for items within the same resource"); 0102 } */ 0103 0104 auto collector = storageBackend()->notificationCollector(); 0105 collector->relationAdded(insertedRelation); 0106 collector->itemsRelationsChanged(items, {insertedRelation}, {}); 0107 0108 return successResponse<Protocol::ModifyRelationResponse>(); 0109 }