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_LOGW("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_LOGW("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_LOGW("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_LOGW("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_LOGW("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_LOGW("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_LOGW("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_LOGW("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_LOGW("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_LOGW("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_LOGW("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_LOGW("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_LOGW("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 ANS_LOGI("Remove napi_create_async_work start");
280 if (!data) {
281 ANS_LOGE("Invalid async callback data");
282 return;
283 }
284 auto removeInfo = static_cast<AsyncCallbackInfoRemove *>(data);
285 if (removeInfo) {
286 if (removeInfo->params.hashcode.has_value()) {
287 removeInfo->info.errorCode = NotificationHelper::RemoveNotification(removeInfo->params.hashcode.value(),
288 removeInfo->params.removeReason);
289 } else if (removeInfo->params.bundleAndKeyInfo.has_value()) {
290 auto &infos = removeInfo->params.bundleAndKeyInfo.value();
291 removeInfo->info.errorCode = NotificationHelper::RemoveNotification(infos.option,
292 infos.key.id, infos.key.label, removeInfo->params.removeReason);
293 }
294 }
295 }
296
RemoveCompleteCallback(napi_env env,napi_status status,void * data)297 void RemoveCompleteCallback(napi_env env, napi_status status, void *data)
298 {
299 ANS_LOGI("Remove napi_create_async_work end");
300 if (!data) {
301 ANS_LOGE("Invalid async callback data");
302 return;
303 }
304 auto removeInfo = static_cast<AsyncCallbackInfoRemove *>(data);
305 if (removeInfo) {
306 Common::ReturnCallbackPromise(env, removeInfo->info, Common::NapiGetNull(env));
307 if (removeInfo->info.callback != nullptr) {
308 napi_delete_reference(env, removeInfo->info.callback);
309 }
310 napi_delete_async_work(env, removeInfo->asyncWork);
311 delete removeInfo;
312 removeInfo = nullptr;
313 }
314 }
315
Remove(napi_env env,napi_callback_info info)316 napi_value Remove(napi_env env, napi_callback_info info)
317 {
318 ANS_LOGD("enter");
319 RemoveParams params {};
320 if (!ParseParameters(env, info, params)) {
321 return Common::NapiGetUndefined(env);
322 }
323 auto removeInfo = new (std::nothrow) AsyncCallbackInfoRemove {.env = env, .asyncWork = nullptr, .params = params};
324 if (!removeInfo) {
325 ANS_LOGD("RemoveInfo is nullptr.");
326 return Common::JSParaError(env, params.callback);
327 }
328 napi_value promise = nullptr;
329 Common::PaddingCallbackPromiseInfo(env, params.callback, removeInfo->info, promise);
330
331 napi_value resourceName = nullptr;
332 napi_create_string_latin1(env, "remove", NAPI_AUTO_LENGTH, &resourceName);
333 // Asynchronous function call
334 napi_create_async_work(env, nullptr, resourceName, RemoveExecuteCallback, RemoveCompleteCallback,
335 (void *)removeInfo, &removeInfo->asyncWork);
336 NAPI_CALL(env, napi_queue_async_work_with_qos(env, removeInfo->asyncWork, napi_qos_user_initiated));
337 if (removeInfo->info.isCallback) {
338 return Common::NapiGetNull(env);
339 } else {
340 return promise;
341 }
342 }
343
RemoveAll(napi_env env,napi_callback_info info)344 napi_value RemoveAll(napi_env env, napi_callback_info info)
345 {
346 ANS_LOGD("enter");
347
348 RemoveParams params {};
349 if (ParseParametersByRemoveAll(env, info, params) == nullptr) {
350 return Common::NapiGetUndefined(env);
351 }
352
353 AsyncCallbackInfoRemove *asynccallbackinfo =
354 new (std::nothrow) AsyncCallbackInfoRemove {.env = env, .asyncWork = nullptr, .params = params};
355 if (!asynccallbackinfo) {
356 ANS_LOGD("Asynccallbackinfo is nullptr.");
357 return Common::JSParaError(env, params.callback);
358 }
359 napi_value promise = nullptr;
360 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
361
362 ANS_LOGD("Create removeAll string.");
363 napi_value resourceName = nullptr;
364 napi_create_string_latin1(env, "removeAll", NAPI_AUTO_LENGTH, &resourceName);
365 // Asynchronous function call
366 napi_create_async_work(env,
367 nullptr,
368 resourceName,
369 [](napi_env env, void *data) {
370 ANS_LOGI("RemoveAll napi_create_async_work start");
371 AsyncCallbackInfoRemove *asynccallbackinfo = static_cast<AsyncCallbackInfoRemove *>(data);
372 if (asynccallbackinfo) {
373 if (asynccallbackinfo->params.bundleAndKeyInfo.has_value()) {
374 auto &infos = asynccallbackinfo->params.bundleAndKeyInfo.value();
375 asynccallbackinfo->info.errorCode = NotificationHelper::RemoveAllNotifications(infos.option);
376 } else if (asynccallbackinfo->params.hasUserId) {
377 ANS_LOGD("hasUserId is true.");
378 asynccallbackinfo->info.errorCode = NotificationHelper::RemoveNotifications(
379 asynccallbackinfo->params.userId);
380 } else {
381 asynccallbackinfo->info.errorCode = NotificationHelper::RemoveNotifications();
382 }
383 }
384 },
385 [](napi_env env, napi_status status, void *data) {
386 ANS_LOGI("RemoveAll napi_create_async_work end");
387 AsyncCallbackInfoRemove *asynccallbackinfo = static_cast<AsyncCallbackInfoRemove *>(data);
388 if (asynccallbackinfo) {
389 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
390 if (asynccallbackinfo->info.callback != nullptr) {
391 ANS_LOGD("Delete removeAll callback reference.");
392 napi_delete_reference(env, asynccallbackinfo->info.callback);
393 }
394 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
395 delete asynccallbackinfo;
396 asynccallbackinfo = nullptr;
397 }
398 ANS_LOGD("RemoveAll work complete end.");
399 },
400 (void *)asynccallbackinfo,
401 &asynccallbackinfo->asyncWork);
402
403 napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
404
405 if (asynccallbackinfo->info.isCallback) {
406 ANS_LOGD("removeAll callback is nullptr.");
407 return Common::NapiGetNull(env);
408 } else {
409 return promise;
410 }
411 }
412
AsyncCompleteCallbackRemoveGroupByBundle(napi_env env,napi_status status,void * data)413 void AsyncCompleteCallbackRemoveGroupByBundle(napi_env env, napi_status status, void *data)
414 {
415 ANS_LOGD("enter");
416 if (!data) {
417 ANS_LOGE("Invalid async callback data");
418 return;
419 }
420 AsyncCallbackInfoRemoveGroupByBundle *asynccallbackinfo = static_cast<AsyncCallbackInfoRemoveGroupByBundle *>(data);
421 if (asynccallbackinfo) {
422 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
423 if (asynccallbackinfo->info.callback != nullptr) {
424 napi_delete_reference(env, asynccallbackinfo->info.callback);
425 }
426 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
427 delete asynccallbackinfo;
428 asynccallbackinfo = nullptr;
429 }
430 }
431
RemoveGroupByBundle(napi_env env,napi_callback_info info)432 napi_value RemoveGroupByBundle(napi_env env, napi_callback_info info)
433 {
434 ANS_LOGD("enter");
435
436 RemoveParamsGroupByBundle params {};
437 if (ParseParameters(env, info, params) == nullptr) {
438 return Common::NapiGetUndefined(env);
439 }
440
441 AsyncCallbackInfoRemoveGroupByBundle *asynccallbackinfo =
442 new (std::nothrow) AsyncCallbackInfoRemoveGroupByBundle {.env = env, .asyncWork = nullptr, .params = params};
443 if (!asynccallbackinfo) {
444 ANS_LOGD("Create asynccallbackinfo failed.");
445 return Common::JSParaError(env, params.callback);
446 }
447 napi_value promise = nullptr;
448 Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
449
450 ANS_LOGD("Create removeGroupByBundle string.");
451 napi_value resourceName = nullptr;
452 napi_create_string_latin1(env, "removeGroupByBundle", NAPI_AUTO_LENGTH, &resourceName);
453 // Asynchronous function call
454 napi_create_async_work(env,
455 nullptr,
456 resourceName,
457 [](napi_env env, void *data) {
458 ANS_LOGI("RemoveGroupByBundle napi_create_async_work start");
459 AsyncCallbackInfoRemoveGroupByBundle *asynccallbackinfo =
460 static_cast<AsyncCallbackInfoRemoveGroupByBundle *>(data);
461 if (asynccallbackinfo) {
462 ANS_LOGI("option.bundle = %{public}s, option.uid = %{public}d, groupName = %{public}s",
463 asynccallbackinfo->params.option.GetBundleName().c_str(),
464 asynccallbackinfo->params.option.GetUid(),
465 asynccallbackinfo->params.groupName.c_str());
466 asynccallbackinfo->info.errorCode = NotificationHelper::RemoveGroupByBundle(
467 asynccallbackinfo->params.option, asynccallbackinfo->params.groupName);
468 }
469 },
470 AsyncCompleteCallbackRemoveGroupByBundle,
471 (void *)asynccallbackinfo,
472 &asynccallbackinfo->asyncWork);
473
474 napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
475
476 if (asynccallbackinfo->info.isCallback) {
477 ANS_LOGD("removeGroupByBundle callback is nullptr.");
478 return Common::NapiGetNull(env);
479 } else {
480 return promise;
481 }
482 }
483 } // namespace NotificationNapi
484 } // namespace OHOS