Akonadi

tagcreatehandler.cpp
1/*
2 SPDX-FileCopyrightText: 2014 Daniel Vrátil <dvratil@redhat.com>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "tagcreatehandler.h"
8
9#include "connection.h"
10#include "storage/countquerybuilder.h"
11#include "storage/datastore.h"
12#include "storage/querybuilder.h"
13#include "storage/transaction.h"
14#include "tagfetchhelper.h"
15
16#include "private/scope_p.h"
17
18using namespace Akonadi;
19using namespace Akonadi::Server;
20
21TagCreateHandler::TagCreateHandler(AkonadiServer &akonadi)
22 : Handler(akonadi)
23{
24}
25
26bool TagCreateHandler::parseStream()
27{
28 const auto &cmd = Protocol::cmdCast<Protocol::CreateTagCommand>(m_command);
29
30 if (!cmd.remoteId().isEmpty() && !connection()->context().resource().isValid()) {
31 return failureResponse(QStringLiteral("Only resources can create tags with remote ID"));
32 }
33
34 Transaction trx(storageBackend(), QStringLiteral("TAGAPPEND"));
35
36 TagType tagType;
37 if (!cmd.type().isEmpty()) {
38 const QString typeName = QString::fromUtf8(cmd.type());
39 tagType = TagType::retrieveByNameOrCreate(typeName);
40 if (!tagType.isValid()) {
41 return failureResponse(QStringLiteral("Unable to create tagtype '") % typeName % QStringLiteral("'"));
42 }
43 }
44
45 qint64 tagId = -1;
46 const QString gid = QString::fromUtf8(cmd.gid());
47 if (cmd.merge()) {
48 QueryBuilder qb(Tag::tableName());
49 qb.addColumn(Tag::idColumn());
50 qb.addValueCondition(Tag::gidColumn(), Query::Equals, gid);
51 if (!qb.exec()) {
52 return failureResponse("Unable to list tags");
53 }
54 if (qb.query().next()) {
55 tagId = qb.query().value(0).toLongLong();
56 }
57 qb.query().finish();
58 }
59 if (tagId < 0) {
60 Tag insertedTag;
61 insertedTag.setGid(gid);
62 if (cmd.parentId() >= 0) {
63 insertedTag.setParentId(cmd.parentId());
64 }
65 if (tagType.isValid()) {
66 insertedTag.setTypeId(tagType.id());
67 }
68 if (!insertedTag.insert(&tagId)) {
69 return failureResponse("Failed to store tag");
70 }
71
72 const Protocol::Attributes attrs = cmd.attributes();
73 for (auto iter = attrs.cbegin(), end = attrs.cend(); iter != end; ++iter) {
74 TagAttribute attribute;
75 attribute.setTagId(tagId);
76 attribute.setType(iter.key());
77 attribute.setValue(iter.value());
78 if (!attribute.insert()) {
79 return failureResponse("Failed to store tag attribute");
80 }
81 }
82
83 storageBackend()->notificationCollector()->tagAdded(insertedTag);
84 }
85
86 if (!cmd.remoteId().isEmpty()) {
87 const qint64 resourceId = connection()->context().resource().id();
88
89 CountQueryBuilder qb(TagRemoteIdResourceRelation::tableName());
90 qb.addValueCondition(TagRemoteIdResourceRelation::tagIdColumn(), Query::Equals, tagId);
91 qb.addValueCondition(TagRemoteIdResourceRelation::resourceIdColumn(), Query::Equals, resourceId);
92 if (!qb.exec()) {
93 return failureResponse("Failed to query for existing TagRemoteIdResourceRelation entries");
94 }
95 const bool exists = (qb.result() > 0);
96
97 // If the relation is already existing simply update it (can happen if a resource simply creates the tag again while enabling merge)
98 bool ret = false;
99 if (exists) {
100 // Simply using update() doesn't work since TagRemoteIdResourceRelation only takes the tagId for identification of the column
101 QueryBuilder qb(TagRemoteIdResourceRelation::tableName(), QueryBuilder::Update);
102 qb.addValueCondition(TagRemoteIdResourceRelation::tagIdColumn(), Query::Equals, tagId);
103 qb.addValueCondition(TagRemoteIdResourceRelation::resourceIdColumn(), Query::Equals, resourceId);
104 qb.setColumnValue(TagRemoteIdResourceRelation::remoteIdColumn(), QString::fromUtf8(cmd.remoteId()));
105 ret = qb.exec();
106 } else {
107 TagRemoteIdResourceRelation rel;
108 rel.setTagId(tagId);
109 rel.setResourceId(resourceId);
110 rel.setRemoteId(QString::fromUtf8(cmd.remoteId()));
111 ret = rel.insert();
112 }
113 if (!ret) {
114 return failureResponse("Failed to store tag remote ID");
115 }
116 }
117
118 trx.commit();
119
120 Protocol::TagFetchScope fetchScope;
121 fetchScope.setFetchRemoteID(true);
122 fetchScope.setFetchAllAttributes(true);
123
124 TagFetchHelper helper(connection(), Scope(tagId), fetchScope);
125 if (!helper.fetchTags()) {
126 return failureResponse("Failed to fetch the new tag");
127 }
128
129 return successResponse<Protocol::CreateTagResponse>();
130}
Helper class for creating queries to count elements in a database.
NotificationCollector * notificationCollector()
Returns the notification collector of this DataStore object.
The handler interfaces describes an entity capable of handling an AkonadiIMAP command.
Definition handler.h:32
void tagAdded(const Tag &tag)
Notify about an added tag.
Helper class to construct arbitrary SQL queries.
Helper class for DataStore transaction handling.
Definition transaction.h:23
Attribute that stores the properties that are used to display a tag.
An Akonadi Tag.
Definition tag.h:26
Helper integration between Akonadi and Qt.
QString typeName(const QJsonObject &obj)
bool isValid(QStringView ifopt)
const QList< QKeySequence > & end()
QString fromUtf8(QByteArrayView str)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:13:38 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.