1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <optional>
17 #include "remove.h"
18 #include "ans_inner_errors.h"
19
20 namespace OHOS {
21 namespace NotificationNapi {
22 const int REMOVE_MIN_PARA = 2;
23 const int REMOVE_OR_BUNDLE_MAX_PARA = 3;
24
25 const int REMOVE_ALL_MAX_PARA = 2;
26
27 const int REMOVE_BY_BUNDLE_AND_KEY_MIN_PARA = 3;
28 const int REMOVE_BY_BUNDLE_AND_KEY_MAX_PARA = 4;
29
30 const int REMOVE_GROUP_BY_BUNDLE_MIN_PARA = 2;
31 const int REMOVE_GROUP_BY_BUNDLE_MAX_PARA = 3;
32
ParseRemoveReason(const napi_env & env,const napi_value & value,RemoveParams & params)33 bool ParseRemoveReason(const napi_env &env, const napi_value &value, RemoveParams ¶ms)
34 {
35 napi_valuetype valueType = napi_undefined;
36 NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
37 if (valueType != napi_number) {
38 ANS_LOGE("RemoveReason valueType unexpected.");
39 return false;
40 }
41 int32_t removeReason = 0;
42 napi_get_value_int32(env, value, &removeReason);
43 if (!Common::IsValidRemoveReason(removeReason)) {
44 ANS_LOGE("RemoveReason value unexpected.");
45 return false;
46 }
47 params.removeReason = removeReason;
48 return true;
49 }
50
ParseCallbackFunc(const napi_env & env,const napi_value & value,RemoveParams & params)51 bool ParseCallbackFunc(const napi_env &env, const napi_value &value,
52 RemoveParams ¶ms)
53 {
54 napi_valuetype valueType = napi_undefined;
55 NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), false);
56 if (valueType != napi_function) {
57 ANS_LOGE("Callback is not function excute promise.");
58 return true;
59 }
60 napi_create_reference(env, value, 1, ¶ms.callback);
61 return true;
62 }
63
ParseHashcodeTypeParams(const napi_env & env,napi_value * argv,size_t argc,napi_valuetype valueType,RemoveParams & params)64 bool ParseHashcodeTypeParams(
65 const napi_env &env, napi_value* argv, size_t argc, napi_valuetype valueType, RemoveParams ¶ms)
66 {
67 // argv[0]: hashCode
68 bool isArray = false;
69 napi_is_array(env, argv[PARAM0], &isArray);
70 if (isArray) {
71 std::vector<std::string> hashcodes;
72 auto retValue = Common::GetHashCodes(env, argv[PARAM0], hashcodes);
73 if (retValue == nullptr) {
74 ANS_LOGE("GetHashCodes failed.");
75 return false;
76 }
77 params.hashcodes = hashcodes;
78 } else if (valueType == napi_string) {
79 size_t strLen = 0;
80 char str[STR_MAX_SIZE] = {0};
81 NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, argv[PARAM0], str, STR_MAX_SIZE - 1, &strLen), false);
82 params.hashcode = str;
83 } else if (valueType == napi_number) {
84 int64_t number = 0;
85 NAPI_CALL_BASE(env, napi_get_value_int64(env, argv[PARAM0], &number), false);
86 params.hashcode = std::to_string(number);
87 } else {
88 bool result = false;
89 NAPI_CALL_BASE(env, napi_get_value_bool(env, argv[PARAM0], &result), false);
90 params.hashcode = std::to_string(result);
91 }
92 // argv[1]:removeReason
93 if (!ParseRemoveReason(env, argv[PARAM1], params)) {
94 return false;
95 }
96 // argv[2]:callback
97 if (argc >= REMOVE_OR_BUNDLE_MAX_PARA) {
98 if (!ParseCallbackFunc(env, argv[PARAM2], params)) {
99 return false;
100 }
101 }
102 return true;
103 }
104
ParseBundleOptionTypeParams(const napi_env & env,napi_value * argv,size_t argc,RemoveParams & params)105 bool ParseBundleOptionTypeParams(const napi_env &env, napi_value* argv, size_t argc, RemoveParams ¶ms)
106 {
107 if (argc < REMOVE_BY_BUNDLE_AND_KEY_MIN_PARA) {
108 ANS_LOGE("Wrong number of arguments.");
109 return false;
110 }
111 BundleAndKeyInfo bundleInfo {};
112 // argv[0]: BundleOption argv[1]: NotificationKey
113 if (Common::GetBundleOption(env, argv[PARAM0], bundleInfo.option) == nullptr ||
114 Common::GetNotificationKey(env, argv[PARAM1], bundleInfo.key) == nullptr) {
115 ANS_LOGE("GetBundleOption failed.");
116 return false;
117 }
118 params.bundleAndKeyInfo = bundleInfo;
119 // argv[2]:removeReason
120 if (!ParseRemoveReason(env, argv[PARAM2], params)) {
121 return false;
122 }
123 // argv[3]:callback
124 if (argc >= REMOVE_BY_BUNDLE_AND_KEY_MAX_PARA) {
125 if (!ParseCallbackFunc(env, argv[PARAM3], params)) {
126 return false;
127 }
128 }
129 return true;
130 }
131
ParseParameters(const napi_env & env,const napi_callback_info & info,RemoveParams & params)132 bool ParseParameters(const napi_env &env, const napi_callback_info &info, RemoveParams ¶ms)
133 {
134 ANS_LOGD("enter");
135 size_t argc = REMOVE_BY_BUNDLE_AND_KEY_MAX_PARA;
136 napi_value argv[REMOVE_BY_BUNDLE_AND_KEY_MAX_PARA] = {nullptr};
137 napi_value thisVar = nullptr;
138 NAPI_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL), false);
139 if (argc < REMOVE_MIN_PARA) {
140 ANS_LOGE("Wrong number of arguments.");
141 Common::NapiThrow(env, ERROR_PARAM_INVALID, MANDATORY_PARAMETER_ARE_LEFT_UNSPECIFIED);
142 return false;
143 }
144 bool isArray = false;
145 napi_is_array(env, argv[PARAM0], &isArray);
146 napi_valuetype valueType = napi_undefined;
147 NAPI_CALL_BASE(env, napi_typeof(env, argv[PARAM0], &valueType), false);
148 if ((valueType != napi_string) && (valueType != napi_object) &&
149 (valueType != napi_number) && (valueType != napi_boolean) && !isArray) {
150 ANS_LOGE("Wrong argument type. String or object expected.");
151 std::string msg = "Incorrect parameter types.The type of param must be object or string.";
152 Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
153 return false;
154 }
155 if ((valueType == napi_string) || (valueType == napi_number) || (valueType == napi_boolean) || isArray) {
156 return ParseHashcodeTypeParams(env, argv, argc, valueType, params);
157 }
158 return ParseBundleOptionTypeParams(env, argv, argc, params);
159 }
160
ParseParametersByRemoveAll(const napi_env & env,const napi_callback_info & info,RemoveParams & params)161 napi_value ParseParametersByRemoveAll(const napi_env &env, const napi_callback_info &info, RemoveParams ¶ms)
162 {
163 ANS_LOGD("enter");
164
165 size_t argc = REMOVE_ALL_MAX_PARA;
166 napi_value argv[REMOVE_ALL_MAX_PARA] = {nullptr};
167 napi_value thisVar = nullptr;
168 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
169
170 if (argc == 0) {
171 return Common::NapiGetNull(env);
172 }
173
174 // argv[0]: bundle / userId / callback
175 napi_valuetype valuetype = napi_undefined;
176 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
177 if ((valuetype != napi_object) && (valuetype != napi_number) && (valuetype != napi_function)) {
178 ANS_LOGE("Wrong argument type. Function or object expected. Excute promise.");
179 return Common::NapiGetNull(env);
180 }
181 if (valuetype == napi_object) {
182 BundleAndKeyInfo bundleandKeyInfo {};
183 auto retValue = Common::GetBundleOption(env, argv[PARAM0], bundleandKeyInfo.option);
184 if (retValue == nullptr) {
185 ANS_LOGE("GetBundleOption failed.");
186 Common::NapiThrow(env, ERROR_PARAM_INVALID, PARAMETER_VERIFICATION_FAILED);
187 return nullptr;
188 }
189 params.bundleAndKeyInfo = bundleandKeyInfo;
190 } else if (valuetype == napi_number) {
191 NAPI_CALL(env, napi_get_value_int32(env, argv[PARAM0], ¶ms.userId));
192 params.hasUserId = true;
193 } else {
194 napi_create_reference(env, argv[PARAM0], 1, ¶ms.callback);
195 }
196
197 // argv[1]:callback
198 if (argc >= REMOVE_ALL_MAX_PARA) {
199 NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
200 if (valuetype != napi_function) {
201 ANS_LOGE("Callback is not function excute promise.");
202 return Common::NapiGetNull(env);
203 }
204 napi_create_reference(env, argv[PARAM1], 1, ¶ms.callback);
205 }
206
207 return Common::NapiGetNull(env);
208 }
209
ParseParameters(const napi_env & env,const napi_callback_info & info,RemoveParamsGroupByBundle & params)210 napi_value ParseParameters(
211 const napi_env &env, const napi_callback_info &info, RemoveParamsGroupByBundle ¶ms)
212 {
213 ANS_LOGD("enter");
214
215 size_t argc = REMOVE_GROUP_BY_BUNDLE_MAX_PARA;
216 napi_value argv[REMOVE_GROUP_BY_BUNDLE_MAX_PARA] = {nullptr};
217 napi_value thisVar = nullptr;
218 napi_valuetype valuetype = napi_undefined;
219 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
220 if (argc < REMOVE_GROUP_BY_BUNDLE_MIN_PARA) {
221 ANS_LOGE("Error number of arguments.");
222 Common::NapiThrow(env, ERROR_PARAM_INVALID, MANDATORY_PARAMETER_ARE_LEFT_UNSPECIFIED);
223 return nullptr;
224 }
225
226 // argv[0]: bundle
227 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
228 if (valuetype != napi_object) {
229 ANS_LOGE("Valuetype is not object.");
230 std::string msg = "Incorrect parameter types.The type of param must be object.";
231 Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
232 return nullptr;
233 }
234 auto retValue = Common::GetBundleOption(env, argv[PARAM0], params.option);
235 if (retValue == nullptr) {
236 ANS_LOGE("GetBundleOption failed.");
237 Common::NapiThrow(env, ERROR_PARAM_INVALID, PARAMETER_VERIFICATION_FAILED);
238 return nullptr;
239 }
240
241 // argv[1]: groupName: string
242 NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
243 if (valuetype != napi_string && valuetype != napi_number && valuetype != napi_boolean) {
244 ANS_LOGE("Error argument type. String number boolean anticipate.");
245 std::string msg = "Incorrect parameter types.The type of param must be string or number or boolean.";
246 Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
247 return nullptr;
248 }
249 if (valuetype == napi_string) {
250 char str[STR_MAX_SIZE] = {0};
251 size_t strLen = 0;
252 NAPI_CALL(env, napi_get_value_string_utf8(env, argv[PARAM1], str, STR_MAX_SIZE - 1, &strLen));
253 params.groupName = str;
254 } else if (valuetype == napi_number) {
255 ANS_LOGD("valuetype is number.");
256 int64_t number = 0;
257 NAPI_CALL(env, napi_get_value_int64(env, argv[PARAM1], &number));
258 params.groupName = std::to_string(number);
259 } else {
260 ANS_LOGD("valuetype is other types.");
261 bool result = false;
262 NAPI_CALL(env, napi_get_value_bool(env, argv[PARAM1], &result));
263 params.groupName = std::to_string(result);
264 }
265 // argv[2]:callback
266 if (argc >= REMOVE_GROUP_BY_BUNDLE_MAX_PARA) {
267 NAPI_CALL(env, napi_typeof(env, argv[PARAM2], &valuetype));
268 if (valuetype != napi_function) {
269 ANS_LOGW("Callback is not function.");
270 return Common::NapiGetNull(env);
271 }
272 napi_create_reference(env, argv[PARAM2], 1, ¶ms.callback);
273 }
274 return Common::NapiGetNull(env);
275 }
276
RemoveExecuteCallback(napi_env env,void * data)277 void RemoveExecuteCallback(napi_env env, void *data)
278 {
279 if (!data) {
280 ANS_LOGE("Invalid async callback data");
281 return;
282 }
283 auto removeInfo = static_cast<AsyncCallbackInfoRemove *>(data);
284 if (removeInfo) {
285 if (removeInfo->params.hashcode.has_value()) {
286 removeInfo->info.errorCode = NotificationHelper::RemoveNotification(removeInfo->params.hashcode.value(),
287 removeInfo->params.removeReason);
288 } else if (removeInfo->params.bundleAndKeyInfo.has_value()) {
289 auto &infos = removeInfo->params.bundleAndKeyInfo.value();
290 removeInfo->info.errorCode = NotificationHelper::RemoveNotification(infos.option,
291 infos.key.id, infos.key.label, removeInfo->params.removeReason);
292 }
293 }
294 }
295
RemoveCompleteCallback(napi_env env,napi_status status,void * data)296 void RemoveCompleteCallback(napi_env env, napi_status status, void *data)
297 {
298 if (!data) {
299 ANS_LOGE("Invalid async callback data");
300 return;
301 }
302 auto removeInfo = static_cast<AsyncCallbackInfoRemove *>(data);
303 if (removeInfo) {
304 Common::ReturnCallbackPromise(env, removeInfo->info, Common::NapiGetNull(env));
305 if (removeInfo->info.callback != nullptr) {
306 napi_delete_reference(env, removeInfo->info.callback);
307 }
308 napi_delete_async_work(env, removeInfo->asyncWork);
309 delete removeInfo;
310 removeInfo = nullptr;
311 }
312 }
313
Remove(napi_env env,napi_callback_info info)314 napi_value Remove(napi_env env, napi_callback_info info)
315 {
316 ANS_LOGD("enter");
317 RemoveParams params {};
318 if (!ParseParameters(env, info, params)) {
319 return Common::NapiGetUndefined(env);
320 }
321 auto removeInfo = new (std::nothrow) AsyncCallbackInfoRemove {.env = env, .asyncWork = nullptr, .params = params};
322 if (!removeInfo) {
323 ANS_LOGD("RemoveInfo is nullptr.");
324 return Common::JSParaError(env, params.callback);
325 }
326 napi_value promise = nullptr;
327 Common::PaddingCallbackPromiseInfo(env, params.callback, removeInfo->info, promise);
328
329 napi_value resourceName = nullptr;
330 napi_create_string_latin1(env, "remove", NAPI_AUTO_LENGTH, &resourceName);
331 // Asynchronous function call
332 napi_create_async_work(env, nullptr, resourceName, RemoveExecuteCallback, RemoveCompleteCallback,
333 (void *)removeInfo, &removeInfo->asyncWork);
334 NAPI_CALL(env, napi_queue_async_work_with_qos(env, removeInfo->asyncWork, napi_qos_user_initiated));
335 if (removeInfo->info.isCallback) {
336 return Common::NapiGetNull(env);
337 } else {
338 return promise;
339 }
340 }
341
RemoveAll(napi_env env,napi_callback_info info)342 napi_value RemoveAll(napi_env env, napi_callback_info info)
343 {
344 ANS_LOGD("enter");
345
346 RemoveParams params {};
347 if (ParseParametersByRemoveAll(env, info, params) == nullptr) {
348 return Common::NapiGetUndefined(env);
349 }
350
351 AsyncCallbackInfoRemove *asynccallbackinfo =
352 new (std::nothrow) AsyncCallbackInfoRemove {.env = env, .asyncWork = nullptr, .params = params};
353 if (!asynccallbackinfo) {
354 ANS_LOGD("Asynccallbackinfo is nullptr.");
355 return Common::JSParaError(env, params.callback);
356 }
357 napi_value promise = nullptr;
358 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
359
360 ANS_LOGD("Create removeAll string.");
361 napi_value resourceName = nullptr;
362 napi_create_string_latin1(env, "removeAll", NAPI_AUTO_LENGTH, &resourceName);
363 // Asynchronous function call
364 napi_create_async_work(env,
365 nullptr,
366 resourceName,
367 [](napi_env env, void *data) {
368 ANS_LOGI("RemoveAll napi_create_async_work start");
369 AsyncCallbackInfoRemove *asynccallbackinfo = static_cast<AsyncCallbackInfoRemove *>(data);
370 if (asynccallbackinfo) {
371 if (asynccallbackinfo->params.bundleAndKeyInfo.has_value()) {
372 auto &infos = asynccallbackinfo->params.bundleAndKeyInfo.value();
373 asynccallbackinfo->info.errorCode = NotificationHelper::RemoveAllNotifications(infos.option);
374 } else if (asynccallbackinfo->params.hasUserId) {
375 ANS_LOGD("hasUserId is true.");
376 asynccallbackinfo->info.errorCode = NotificationHelper::RemoveNotifications(
377 asynccallbackinfo->params.userId);
378 } else {
379 asynccallbackinfo->info.errorCode = NotificationHelper::RemoveNotifications();
380 }
381 }
382 },
383 [](napi_env env, napi_status status, void *data) {
384 ANS_LOGI("RemoveAll napi_create_async_work end");
385 AsyncCallbackInfoRemove *asynccallbackinfo = static_cast<AsyncCallbackInfoRemove *>(data);
386 if (asynccallbackinfo) {
387 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
388 if (asynccallbackinfo->info.callback != nullptr) {
389 ANS_LOGD("Delete removeAll callback reference.");
390 napi_delete_reference(env, asynccallbackinfo->info.callback);
391 }
392 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
393 delete asynccallbackinfo;
394 asynccallbackinfo = nullptr;
395 }
396 ANS_LOGD("RemoveAll work complete end.");
397 },
398 (void *)asynccallbackinfo,
399 &asynccallbackinfo->asyncWork);
400
401 napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
402
403 if (asynccallbackinfo->info.isCallback) {
404 ANS_LOGD("removeAll callback is nullptr.");
405 return Common::NapiGetNull(env);
406 } else {
407 return promise;
408 }
409 }
410
AsyncCompleteCallbackRemoveGroupByBundle(napi_env env,napi_status status,void * data)411 void AsyncCompleteCallbackRemoveGroupByBundle(napi_env env, napi_status status, void *data)
412 {
413 ANS_LOGD("enter");
414 if (!data) {
415 ANS_LOGE("Invalid async callback data");
416 return;
417 }
418 AsyncCallbackInfoRemoveGroupByBundle *asynccallbackinfo = static_cast<AsyncCallbackInfoRemoveGroupByBundle *>(data);
419 if (asynccallbackinfo) {
420 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
421 if (asynccallbackinfo->info.callback != nullptr) {
422 napi_delete_reference(env, asynccallbackinfo->info.callback);
423 }
424 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
425 delete asynccallbackinfo;
426 asynccallbackinfo = nullptr;
427 }
428 }
429
RemoveGroupByBundle(napi_env env,napi_callback_info info)430 napi_value RemoveGroupByBundle(napi_env env, napi_callback_info info)
431 {
432 ANS_LOGD("enter");
433
434 RemoveParamsGroupByBundle params {};
435 if (ParseParameters(env, info, params) == nullptr) {
436 return Common::NapiGetUndefined(env);
437 }
438
439 AsyncCallbackInfoRemoveGroupByBundle *asynccallbackinfo =
440 new (std::nothrow) AsyncCallbackInfoRemoveGroupByBundle {.env = env, .asyncWork = nullptr, .params = params};
441 if (!asynccallbackinfo) {
442 ANS_LOGD("Create asynccallbackinfo failed.");
443 return Common::JSParaError(env, params.callback);
444 }
445 napi_value promise = nullptr;
446 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
447
448 ANS_LOGD("Create removeGroupByBundle string.");
449 napi_value resourceName = nullptr;
450 napi_create_string_latin1(env, "removeGroupByBundle", NAPI_AUTO_LENGTH, &resourceName);
451 // Asynchronous function call
452 napi_create_async_work(env,
453 nullptr,
454 resourceName,
455 [](napi_env env, void *data) {
456 ANS_LOGI("RemoveGroupByBundle napi_create_async_work start");
457 AsyncCallbackInfoRemoveGroupByBundle *asynccallbackinfo =
458 static_cast<AsyncCallbackInfoRemoveGroupByBundle *>(data);
459 if (asynccallbackinfo) {
460 ANS_LOGI("option.bundle = %{public}s, option.uid = %{public}d, groupName = %{public}s",
461 asynccallbackinfo->params.option.GetBundleName().c_str(),
462 asynccallbackinfo->params.option.GetUid(),
463 asynccallbackinfo->params.groupName.c_str());
464 asynccallbackinfo->info.errorCode = NotificationHelper::RemoveGroupByBundle(
465 asynccallbackinfo->params.option, asynccallbackinfo->params.groupName);
466 }
467 },
468 AsyncCompleteCallbackRemoveGroupByBundle,
469 (void *)asynccallbackinfo,
470 &asynccallbackinfo->asyncWork);
471
472 napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
473
474 if (asynccallbackinfo->info.isCallback) {
475 ANS_LOGD("removeGroupByBundle callback is nullptr.");
476 return Common::NapiGetNull(env);
477 } else {
478 return promise;
479 }
480 }
481 } // namespace NotificationNapi
482 } // namespace OHOS