[Content] Add deprecation to some not frequently used members
[platform/core/api/webapi-plugins.git] / src / content / content_filter.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "content/content_filter.h"
18
19 #include <vector>
20
21 #include "common/converter.h"
22 #include "common/logger.h"
23 #include "common/tools.h"
24
25 using common::AttributeMatchFlag;
26 using common::CompositeFilterType;
27 using common::ErrorCode;
28 using common::JsonCast;
29 using common::PlatformResult;
30
31 namespace extension {
32 namespace content {
33
34 namespace {
35
36 std::map<std::string, std::string> const attributeNameMap = {
37     {"id", "MEDIA_ID"},
38     {"type", "MEDIA_TYPE"},
39     {"mimeType", "MEDIA_MIME_TYPE"},
40     {"name", "MEDIA_DISPLAY_NAME"},
41     {"title", "MEDIA_TITLE"},
42     {"contentURI", "MEDIA_PATH"},
43     {"thumbnailURIs", "MEDIA_THUMBNAIL_PATH"},
44     {"description", "MEDIA_DESCRIPTION"},
45     {"rating", "MEDIA_RATING"},
46     {"createdDate", "MEDIA_ADDED_TIME"},
47     {"releaseDate", "MEDIA_DATETAKEN"},
48     {"modifiedDate", "MEDIA_MODIFIED_TIME"},
49     {"geolocation.latitude",
50      "MEDIA_LATITUDE"},  // Deprecated since 9.0 //TODO remove after 2 versions
51     {"geolocation.longitude",
52      "MEDIA_LONGITUDE"},  // Deprecated since 9.0 //TODO remove after 2 versions
53     {"duration",
54      "MEDIA_DURATION"},  // Deprecated since 9.0 //TODO remove after 2 versions
55     {"album", "MEDIA_ALBUM"},
56     {"artists", "MEDIA_ARTIST"},
57     {"width", "MEDIA_WIDTH"},
58     {"height", "MEDIA_HEIGHT"},
59     {"genres", "MEDIA_GENRE"},
60     {"size", "MEDIA_SIZE"},
61 };
62
63 std::string escapeValueString(const std::string& data) {
64   ScopeLogger();
65   std::string out;
66   // If string won't be resized, then it will be faster
67   out.reserve(data.size());
68   for (auto c : data) {
69     if (c == '\\')
70       out += "\\\\";
71     else if (c == '\"')
72       out += "\\\"";
73     else if (c == '\'')
74       out += "\\\'";
75     else if (c == '\n')
76       out += "\\\n";
77     else if (c == '\r')
78       out += "\\\r";
79     else
80       out += c;
81   }
82   return out;
83 }
84
85 }  // namespace
86
87 PlatformResult ContentFilter::MapField(const std::string& name, std::string* result) {
88   ScopeLogger();
89   auto it = attributeNameMap.find(name);
90   if (it != attributeNameMap.end()) {
91     if (name == "rating" || name == "description" ||
92         name == "geolocation.latitude" || name == "geolocation.longitude" ||
93         name == "duration") {
94       std::string warning = "Filtering by attribute '" + name + "'";
95       common::tools::PrintDeprecationWarningFor(warning.c_str());
96     }
97     *result = it->second;
98   } else {
99     return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR);
100   }
101   return PlatformResult(ErrorCode::NO_ERROR);
102 }
103
104 PlatformResult ContentFilter::BuildQuery(const picojson::object& jsFilter,
105                                          std::string* queryToCall) {
106   ScopeLogger();
107   std::vector<std::vector<std::string>> partialqueries;
108   partialqueries.push_back(std::vector<std::string>());
109
110   visitor.SetOnAttributeFilter([&](const std::string& name, AttributeMatchFlag match_flag,
111                                    const picojson::value& match_value) {
112     ScopeLogger("Entered into asynchronous function, visitor.SetOnAttributeFilter's argument");
113
114     std::string query;
115     std::string matchValue;
116
117     PlatformResult result = MapField(name, &query);
118     if (!result) return result;
119
120     if (AttributeMatchFlag::kExactly == match_flag ||
121         AttributeMatchFlag::kFullString == match_flag) {
122       query += " = ";
123     } else if (AttributeMatchFlag::kContains == match_flag ||
124                AttributeMatchFlag::kStartsWith == match_flag ||
125                AttributeMatchFlag::kEndsWith == match_flag) {
126       query += " LIKE ";
127     } else if (AttributeMatchFlag::kExists == match_flag) {
128       query += " IS NOT NULL ";
129     } else {
130       return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR);
131     }
132     if (AttributeMatchFlag::kExists != match_flag) {
133       query.append("\"");
134       matchValue = escapeValueString(JsonCast<std::string>(match_value));
135       if (name == "type") {
136         if (matchValue == "IMAGE") {
137           matchValue = "0";
138         } else if (matchValue == "VIDEO") {
139           matchValue = "1";
140         } else if (matchValue == "AUDIO") {
141           matchValue = "3";
142         } else {  // OTHER
143           matchValue = "4";
144         }
145       } else if (name == "contentURI") {
146         const char* uri_prefix = "file://";
147         size_t found = matchValue.find(uri_prefix);
148         if (found != std::string::npos) {
149           // simple convertion of URI to globalpath
150           matchValue = matchValue.substr(found + strlen(uri_prefix));
151         }
152       }
153       switch (match_flag) {
154         case AttributeMatchFlag::kStartsWith:
155           query += matchValue + "%";
156           break;
157         case AttributeMatchFlag::kEndsWith:
158           query += "%" + matchValue;
159           break;
160         case AttributeMatchFlag::kContains:
161           query += "%" + matchValue + "%";
162           break;
163         default:
164           query += matchValue;
165       }
166       query.append("\"");
167     }
168
169     partialqueries.back().push_back(query);
170
171     return result;
172   });
173
174   visitor.SetOnCompositeFilterBegin([&](CompositeFilterType type) {
175     ScopeLogger("Entered into asynchronous function, visitor.SetOnCompositeFilterBegin's argument");
176     partialqueries.push_back(std::vector<std::string>());
177     return PlatformResult(ErrorCode::NO_ERROR);
178   });
179
180   visitor.SetOnCompositeFilterEnd([&](CompositeFilterType calType) {
181     ScopeLogger("Entered into asynchronous function, visitor.SetOnCompositeFilterEnd's argument");
182     std::string finalQuery;
183     std::string separator;
184
185     if (CompositeFilterType::kUnion == calType)
186       separator = " OR ";
187     else
188       separator = " AND ";
189
190     if (partialqueries.back().empty()) {
191       partialqueries.pop_back();
192       return PlatformResult(ErrorCode::NO_ERROR);
193     }
194     if (partialqueries.back().size() != 1) finalQuery.append("(");
195
196     for (unsigned long i = 0; i < partialqueries.back().size(); i++) {
197       finalQuery += partialqueries.back().at(i);
198       if (i != partialqueries.back().size() - 1) {
199         finalQuery += separator;
200       }
201     }
202
203     if (partialqueries.back().size() != 1) finalQuery.append(")");
204     partialqueries.pop_back();
205     partialqueries.back().push_back(finalQuery);
206
207     return PlatformResult(ErrorCode::NO_ERROR);
208   });
209
210   visitor.SetOnAttributeRangeFilter([&](const std::string& name,
211                                         const picojson::value& initial_value,
212                                         const picojson::value& end_value) {
213     ScopeLogger("Entered into asynchronous function, visitor.SetOnAttributeRangeFilter's argument");
214
215     std::string query = "";
216     std::string paramName;
217     PlatformResult result = MapField(name, &paramName);
218     if (!result) return result;
219
220     std::string initialValue = escapeValueString(JsonCast<std::string>(initial_value));
221     std::string endValue = escapeValueString(JsonCast<std::string>(end_value));
222     query += paramName;
223     query += " >= \"";
224     query += initialValue;
225     query += "\" AND ";
226     query += paramName;
227     query += " <= \"";
228     query += endValue;
229     query += "\"";
230     partialqueries.back().push_back(query);
231
232     return result;
233   });
234
235   if (!visitor.Visit(jsFilter)) {
236     return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR);
237   }
238
239   if (partialqueries.empty()) {
240     return LogAndCreateResult(ErrorCode::SYNTAX_ERR);
241   }
242   if (partialqueries.back().empty()) {
243     LoggerD("Resolved to empty string!");
244     *queryToCall = "";
245     return PlatformResult(ErrorCode::NO_ERROR);
246   }
247
248   *queryToCall = partialqueries.back().front();
249   return PlatformResult(ErrorCode::NO_ERROR);
250 }
251
252 }  // namespace content
253 }  // namespace extension