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

0001 /***************************************************************************
0002  *   SPDX-FileCopyrightText: 2006 Ingo Kloecker <kloecker@kde.org>         *
0003  *                                                                         *
0004  *   SPDX-License-Identifier: LGPL-2.0-or-later                            *
0005  ***************************************************************************/
0006 #include "collectioncreatehandler.h"
0007 
0008 #include "connection.h"
0009 #include "handlerhelper.h"
0010 #include "shared/akranges.h"
0011 #include "storage/datastore.h"
0012 #include "storage/selectquerybuilder.h"
0013 #include "storage/transaction.h"
0014 
0015 #include "private/scope_p.h"
0016 
0017 using namespace Akonadi;
0018 using namespace Akonadi::Server;
0019 using namespace AkRanges;
0020 
0021 CollectionCreateHandler::CollectionCreateHandler(AkonadiServer &akonadi)
0022     : Handler(akonadi)
0023 {
0024 }
0025 
0026 bool CollectionCreateHandler::parseStream()
0027 {
0028     const auto &cmd = Protocol::cmdCast<Protocol::CreateCollectionCommand>(m_command);
0029 
0030     if (cmd.name().isEmpty()) {
0031         return failureResponse(QStringLiteral("Invalid collection name"));
0032     }
0033 
0034     Collection parent;
0035     qint64 resourceId = 0;
0036     bool forceVirtual = false;
0037     MimeType::List parentContentTypes;
0038 
0039     // Invalid or empty scope means we refer to root collection
0040     if (cmd.parent().scope() != Scope::Invalid && !cmd.parent().isEmpty()) {
0041         parent = HandlerHelper::collectionFromScope(cmd.parent(), connection()->context());
0042         if (!parent.isValid()) {
0043             return failureResponse(QStringLiteral("Invalid parent collection"));
0044         }
0045 
0046         // check if parent can contain a sub-folder
0047         parentContentTypes = parent.mimeTypes();
0048         const auto hasMimeType = [](const QString &mimeType) {
0049             return [mimeType](const MimeType &mt) {
0050                 return mt.name() == mimeType;
0051             };
0052         };
0053         const bool canContainCollections = parentContentTypes | Actions::any(hasMimeType(CollectionMimeType));
0054         const bool canContainVirtualCollections = parentContentTypes | Actions::any(hasMimeType(VirtualCollectionMimeType));
0055 
0056         if (!canContainCollections && !canContainVirtualCollections) {
0057             return failureResponse(QStringLiteral("Parent collection can not contain sub-collections"));
0058         }
0059 
0060         // If only virtual collections are supported, force every new collection to
0061         // be virtual. Otherwise depend on VIRTUAL attribute in the command
0062         if (canContainVirtualCollections && !canContainCollections) {
0063             forceVirtual = true;
0064         }
0065 
0066         // inherit resource
0067         resourceId = parent.resourceId();
0068     } else {
0069         const QString sessionId = QString::fromUtf8(connection()->sessionId());
0070         Resource res = Resource::retrieveByName(sessionId);
0071         if (!res.isValid()) {
0072             return failureResponse(QStringLiteral("Cannot create top-level collection"));
0073         }
0074         resourceId = res.id();
0075     }
0076 
0077     Collection collection;
0078     if (parent.isValid()) {
0079         collection.setParentId(parent.id());
0080     }
0081     collection.setName(cmd.name());
0082     collection.setResourceId(resourceId);
0083     collection.setRemoteId(cmd.remoteId());
0084     collection.setRemoteRevision(cmd.remoteRevision());
0085     collection.setIsVirtual(cmd.isVirtual() || forceVirtual);
0086     collection.setEnabled(cmd.enabled());
0087     collection.setSyncPref(static_cast<Collection::Tristate>(cmd.syncPref()));
0088     collection.setDisplayPref(static_cast<Collection::Tristate>(cmd.displayPref()));
0089     collection.setIndexPref(static_cast<Collection::Tristate>(cmd.indexPref()));
0090     const Protocol::CachePolicy &cp = cmd.cachePolicy();
0091     collection.setCachePolicyCacheTimeout(cp.cacheTimeout());
0092     collection.setCachePolicyCheckInterval(cp.checkInterval());
0093     collection.setCachePolicyInherit(cp.inherit());
0094     collection.setCachePolicyLocalParts(cp.localParts().join(QLatin1Char(' ')));
0095     collection.setCachePolicySyncOnDemand(cp.syncOnDemand());
0096 
0097     DataStore *db = connection()->storageBackend();
0098     Transaction transaction(db, QStringLiteral("CREATE"));
0099 
0100     QStringList effectiveMimeTypes = cmd.mimeTypes();
0101     if (effectiveMimeTypes.isEmpty()) {
0102         effectiveMimeTypes = parentContentTypes | Views::transform(&MimeType::name) | Actions::toQList;
0103     }
0104 
0105     if (!db->appendCollection(collection, effectiveMimeTypes, cmd.attributes())) {
0106         return failureResponse(QStringLiteral("Could not create collection %1, resourceId %2").arg(cmd.name()).arg(resourceId));
0107     }
0108 
0109     if (!transaction.commit()) {
0110         return failureResponse(QStringLiteral("Unable to commit transaction."));
0111     }
0112 
0113     db->activeCachePolicy(collection);
0114 
0115     sendResponse<Protocol::FetchCollectionsResponse>(HandlerHelper::fetchCollectionsResponse(akonadi(), collection));
0116 
0117     return successResponse<Protocol::CreateCollectionResponse>();
0118 }