2
* Copyright (C) 2016 Canonical Ltd
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authors: Michi Henning <michi.henning@canonical.com>
19
#include <unity/storage/internal/ItemMetadata.h>
21
#include <unity/storage/provider/metadata_keys.h>
22
#include <unity/storage/qt/client/Exceptions.h>
27
using namespace unity::storage::internal;
40
namespace remote_client
46
// Check that actual type and value match the expect type and value for a particular metadata entry.
48
void validate_type_and_value(QString const& prefix,
49
QMapIterator<QString, QVariant> actual,
50
unordered_map<string, provider::MetadataType>::const_iterator known)
52
using namespace unity::storage::provider;
54
switch (known->second)
56
case MetadataType::iso_8601_date_time:
58
if (actual.value().type() != QVariant::String)
60
throw LocalCommsException(prefix + actual.key() + ": expected value of type String, "
61
" but received value of type " + actual.value().typeName());
63
QDateTime dt = QDateTime::fromString(actual.value().toString(), Qt::ISODate);
66
throw LocalCommsException(prefix + actual.key() + ": value \"" + actual.value().toString()
67
+ "\" does not parse as ISO-8601 date");
69
auto timespec = dt.timeSpec();
70
if (timespec == Qt::LocalTime)
72
throw LocalCommsException(prefix + actual.key() + ": value \"" + actual.value().toString()
73
+ "\" lacks a time zone specification");
77
case MetadataType::int64:
79
if (actual.value().type() != QVariant::LongLong)
81
throw LocalCommsException(prefix + actual.key() + ": expected value of type LongLong, "
82
" but received value of type " + actual.value().typeName());
88
abort(); // Impossible. // LCOV_EXCL_LINE
95
void validate(QString const& method, ItemMetadata const& md)
97
using namespace unity::storage::provider;
99
QString prefix = method + ": received invalid metadata from server: ";
101
// Basic sanity checks for mandatory fields.
102
if (md.item_id.isEmpty())
104
throw LocalCommsException(prefix + "item_id cannot be empty");
106
if (md.parent_id.isEmpty() && md.type != ItemType::root)
108
throw LocalCommsException(prefix + "parent_id of file or folder cannot be empty");
110
if (!md.parent_id.isEmpty() && md.type == ItemType::root)
112
throw LocalCommsException(prefix + "metadata: parent_id of root cannot be non-empty");
114
if (md.name.isEmpty())
116
throw LocalCommsException(prefix + "name cannot be empty");
118
if (md.etag.isEmpty())
120
throw LocalCommsException(prefix + "etag cannot be empty");
123
// Sanity check metadata to make sure only known metadata keys appear.
124
QMapIterator<QString, QVariant> actual(md.metadata);
125
while (actual.hasNext())
128
auto known = known_metadata.find(actual.key().toStdString());
129
if (known == known_metadata.end())
131
throw LocalCommsException(prefix + "unknown metadata key:" + actual.key());
133
validate_type_and_value(prefix, actual, known);
136
// Sanity check metadata to make sure that mandatory fields are present.
137
if (md.type == ItemType::file)
139
if (!md.metadata.contains(SIZE_IN_BYTES))
141
throw LocalCommsException(prefix + "missing key " + SIZE_IN_BYTES + " in metadata for " + md.item_id);
143
if (!md.metadata.contains(LAST_MODIFIED_TIME))
145
throw LocalCommsException(prefix + "missing key " + LAST_MODIFIED_TIME + " in metadata for " + md.item_id);
150
} // namespace remote_client
151
} // namespace internal
152
} // namespace client
154
} // namespace storage