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