Akonadi

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

KDE's Doxygen guidelines are available online.