1 /*
2  * Copyright (c) 2021-2024 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 "cancel.h"
17 #include "js_native_api_types.h"
18 #include "ans_inner_errors.h"
19 
20 namespace OHOS {
21 namespace NotificationNapi {
22 constexpr int8_t CANCEL_MAX_PARA = 3;
23 constexpr int8_t CANCEL_GROUP_MAX_PARA = 2;
24 constexpr int8_t CANCEL_GROUP_MIN_PARA = 1;
25 constexpr int8_t CANCEL_AS_BUNDLE_MAX_PARA = 4;
26 constexpr int8_t CANCEL_AS_BUNDLEOPTION_MAX_PARA = 2;
27 
ParseParameters(const napi_env & env,const napi_callback_info & info,ParametersInfoCancel & paras)28 napi_value ParseParameters(const napi_env &env, const napi_callback_info &info, ParametersInfoCancel &paras)
29 {
30     ANS_LOGD("enter");
31 
32     size_t argc = CANCEL_MAX_PARA;
33     napi_value argv[CANCEL_MAX_PARA] = {nullptr};
34     napi_value thisVar = nullptr;
35     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
36     if (argc < 1) {
37         ANS_LOGW("Wrong number of arguments");
38         Common::NapiThrow(env, ERROR_PARAM_INVALID, MANDATORY_PARAMETER_ARE_LEFT_UNSPECIFIED);
39         return nullptr;
40     }
41 
42     napi_valuetype valuetype = napi_undefined;
43     // argv[0]: id: number / representativeBundle: BundleOption
44     NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
45     if (valuetype != napi_number && valuetype != napi_object) {
46         ANS_LOGW("Wrong argument type. Number object expected.");
47         std::string msg = "Incorrect parameter types.The type of param must be number or object.";
48         Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
49         return nullptr;
50     }
51 
52     if (valuetype == napi_number) {
53         NAPI_CALL(env, napi_get_value_int32(env, argv[PARAM0], &paras.id));
54     } else {
55         auto retValue = Common::GetBundleOption(env, argv[PARAM0], paras.option);
56         if (retValue == nullptr) {
57             ANS_LOGE("GetBundleOption failed.");
58             Common::NapiThrow(env, ERROR_PARAM_INVALID, PARAMETER_VERIFICATION_FAILED);
59             return nullptr;
60         }
61         paras.hasOption = true;
62     }
63 
64     // argv[1]: label: string / callback / id : number
65     if (argc >= CANCEL_MAX_PARA - 1 && !paras.hasOption) {
66         NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
67         if (valuetype == napi_undefined || valuetype == napi_null) {
68             return Common::NapiGetNull(env);
69         }
70         if (valuetype != napi_number && valuetype != napi_boolean &&
71             valuetype != napi_string && valuetype != napi_function) {
72             ANS_LOGW("Wrong argument type. String or function expected.");
73             std::string msg = "Incorrect parameter types.The type of param must be string or function.";
74             Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
75             return nullptr;
76         }
77         if (valuetype == napi_number) {
78             int64_t number = 0;
79             NAPI_CALL(env, napi_get_value_int64(env, argv[PARAM1], &number));
80             paras.label = std::to_string(number);
81         } else if (valuetype == napi_boolean) {
82             bool result = false;
83             NAPI_CALL(env, napi_get_value_bool(env, argv[PARAM1], &result));
84             paras.label = std::to_string(result);
85         } else if (valuetype == napi_string) {
86             char str[STR_MAX_SIZE] = {0};
87             size_t strLen = 0;
88             NAPI_CALL(env, napi_get_value_string_utf8(env, argv[PARAM1], str, STR_MAX_SIZE - 1, &strLen));
89             paras.label = str;
90         } else {
91             napi_create_reference(env, argv[PARAM1], 1, &paras.callback);
92         }
93     } else if (argc >= CANCEL_MAX_PARA - 1 && paras.hasOption) {
94         NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
95         if (valuetype != napi_number) {
96             ANS_LOGW("Wrong argument type. Number expected.");
97             std::string msg = "Incorrect parameter types.The type of param must be number.";
98             Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
99             return nullptr;
100         }
101         NAPI_CALL(env, napi_get_value_int32(env, argv[PARAM1], &paras.id));
102     }
103 
104     // argv[2]: callback
105     if (argc >= CANCEL_MAX_PARA) {
106         NAPI_CALL(env, napi_typeof(env, argv[PARAM2], &valuetype));
107         if (valuetype != napi_function) {
108             ANS_LOGW("Callback is not function excute promise.");
109             return Common::NapiGetNull(env);
110         }
111         napi_create_reference(env, argv[PARAM2], 1, &paras.callback);
112     }
113 
114     return Common::NapiGetNull(env);
115 }
116 
ParseParameters(const napi_env & env,const napi_callback_info & info,ParametersInfoCancelGroup & paras)117 napi_value ParseParameters(const napi_env &env, const napi_callback_info &info, ParametersInfoCancelGroup &paras)
118 {
119     ANS_LOGD("enter");
120 
121     size_t argc = CANCEL_GROUP_MAX_PARA;
122     napi_value argv[CANCEL_GROUP_MAX_PARA] = {nullptr};
123     napi_value thisVar = nullptr;
124     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
125     if (argc < CANCEL_GROUP_MIN_PARA) {
126         ANS_LOGW("Wrong number of arguments");
127         Common::NapiThrow(env, ERROR_PARAM_INVALID, MANDATORY_PARAMETER_ARE_LEFT_UNSPECIFIED);
128         return nullptr;
129     }
130 
131     napi_valuetype valuetype = napi_undefined;
132     // argv[0]: groupName: string
133     NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
134     if (valuetype != napi_string && valuetype != napi_number && valuetype != napi_boolean) {
135         ANS_LOGW("Wrong argument type. String number boolean expected.");
136         std::string msg = "Incorrect parameter types.The type of param must be number or string or boolean.";
137         Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
138         return nullptr;
139     }
140     if (valuetype == napi_string) {
141         char str[STR_MAX_SIZE] = {0};
142         size_t strLen = 0;
143         NAPI_CALL(env, napi_get_value_string_utf8(env, argv[PARAM0], str, STR_MAX_SIZE - 1, &strLen));
144         paras.groupName = str;
145     } else if (valuetype == napi_number) {
146         int64_t number = 0;
147         NAPI_CALL(env, napi_get_value_int64(env, argv[PARAM0], &number));
148         paras.groupName = std::to_string(number);
149     } else {
150         bool result = false;
151         NAPI_CALL(env, napi_get_value_bool(env, argv[PARAM0], &result));
152         paras.groupName = std::to_string(result);
153     }
154 
155     // argv[1]: callback
156     if (argc >= CANCEL_GROUP_MAX_PARA) {
157         NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
158         if (valuetype != napi_function) {
159             ANS_LOGW("Callback is not function excute promise.");
160             return Common::NapiGetNull(env);
161         }
162         napi_create_reference(env, argv[PARAM1], 1, &paras.callback);
163     }
164 
165     return Common::NapiGetNull(env);
166 }
167 
Cancel(napi_env env,napi_callback_info info)168 napi_value Cancel(napi_env env, napi_callback_info info)
169 {
170     ANS_LOGD("enter");
171 
172     ParametersInfoCancel paras;
173     if (ParseParameters(env, info, paras) == nullptr) {
174         return Common::NapiGetUndefined(env);
175     }
176 
177     AsyncCallbackInfoCancel *asynccallbackinfo = new (std::nothrow)
178         AsyncCallbackInfoCancel {.env = env, .asyncWork = nullptr, .id = paras.id, .label = paras.label};
179     if (!asynccallbackinfo) {
180         ANS_LOGD("AsyncCallbackinfo is nullptr.");
181         return Common::JSParaError(env, paras.callback);
182     }
183     napi_value promise = nullptr;
184     Common::PaddingCallbackPromiseInfo(env, paras.callback, asynccallbackinfo->info, promise);
185 
186     ANS_LOGD("Create cancel string.");
187     napi_value resourceName = nullptr;
188     napi_create_string_latin1(env, "cancel", NAPI_AUTO_LENGTH, &resourceName);
189     // Async function call
190     napi_create_async_work(env,
191         nullptr,
192         resourceName,
193         [](napi_env env, void *data) {
194             ANS_LOGD("Cancel work excute.");
195             AsyncCallbackInfoCancel *asynccallbackinfo = static_cast<AsyncCallbackInfoCancel *>(data);
196 
197             if (asynccallbackinfo) {
198                 asynccallbackinfo->info.errorCode =
199                     NotificationHelper::CancelNotification(asynccallbackinfo->label, asynccallbackinfo->id);
200             }
201         },
202         [](napi_env env, napi_status status, void *data) {
203             ANS_LOGD("Cancel work complete.");
204             AsyncCallbackInfoCancel *asynccallbackinfo = static_cast<AsyncCallbackInfoCancel *>(data);
205             if (asynccallbackinfo) {
206                 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
207                 if (asynccallbackinfo->info.callback != nullptr) {
208                     ANS_LOGD("Delete cancel callback reference.");
209                     napi_delete_reference(env, asynccallbackinfo->info.callback);
210                 }
211                 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
212                 delete asynccallbackinfo;
213                 asynccallbackinfo = nullptr;
214             }
215             ANS_LOGD("Cancel work complete end.");
216         },
217         (void *)asynccallbackinfo,
218         &asynccallbackinfo->asyncWork);
219 
220     napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
221 
222     if (asynccallbackinfo->info.isCallback) {
223         ANS_LOGD("cancel callback is nullptr.");
224         return Common::NapiGetNull(env);
225     } else {
226         return promise;
227     }
228 }
229 
CancelAll(napi_env env,napi_callback_info info)230 napi_value CancelAll(napi_env env, napi_callback_info info)
231 {
232     ANS_LOGD("enter");
233 
234     napi_ref callback = nullptr;
235     if (Common::ParseParaOnlyCallback(env, info, callback) == nullptr) {
236         return Common::NapiGetUndefined(env);
237     }
238 
239     auto asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoCancel {.env = env, .asyncWork = nullptr};
240     if (!asynccallbackinfo) {
241         ANS_LOGD("Asynccallbackinfo is nullptr.");
242         return Common::JSParaError(env, callback);
243     }
244     napi_value promise = nullptr;
245     Common::PaddingCallbackPromiseInfo(env, callback, asynccallbackinfo->info, promise);
246 
247     ANS_LOGD("Create cancelAll string.");
248     napi_value resourceName = nullptr;
249     napi_create_string_latin1(env, "cancelAll", NAPI_AUTO_LENGTH, &resourceName);
250     // Asynchronous function call
251     napi_create_async_work(env,
252         nullptr,
253         resourceName,
254         [](napi_env env, void *data) {
255             ANS_LOGD("CancelAll work excute.");
256             AsyncCallbackInfoCancel *asynccallbackinfo = static_cast<AsyncCallbackInfoCancel *>(data);
257             if (asynccallbackinfo) {
258                 asynccallbackinfo->info.errorCode = NotificationHelper::CancelAllNotifications();
259             }
260         },
261         [](napi_env env, napi_status status, void *data) {
262             ANS_LOGD("CancelAll work complete.");
263             AsyncCallbackInfoCancel *asynccallbackinfo = static_cast<AsyncCallbackInfoCancel *>(data);
264             if (asynccallbackinfo) {
265                 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
266                 if (asynccallbackinfo->info.callback != nullptr) {
267                     ANS_LOGD("Delete CancelAll callback reference.");
268                     napi_delete_reference(env, asynccallbackinfo->info.callback);
269                 }
270                 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
271                 delete asynccallbackinfo;
272                 asynccallbackinfo = nullptr;
273             }
274             ANS_LOGD("CancelAll work complete end.");
275         },
276         (void *)asynccallbackinfo,
277         &asynccallbackinfo->asyncWork);
278 
279     napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
280 
281     if (asynccallbackinfo->info.isCallback) {
282         ANS_LOGD("CancelAll callback is nullptr.");
283         return Common::NapiGetNull(env);
284     } else {
285         return promise;
286     }
287 }
288 
CancelGroup(napi_env env,napi_callback_info info)289 napi_value CancelGroup(napi_env env, napi_callback_info info)
290 {
291     ANS_LOGD("enter");
292 
293     ParametersInfoCancelGroup params {};
294     if (ParseParameters(env, info, params) == nullptr) {
295         return Common::NapiGetUndefined(env);
296     }
297 
298     AsyncCallbackInfoCancelGroup *asynccallbackinfo = new (std::nothrow)
299         AsyncCallbackInfoCancelGroup {.env = env, .asyncWork = nullptr, .params = params};
300     if (!asynccallbackinfo) {
301         ANS_LOGD("Create asynccallbackinfo fail.");
302         return Common::JSParaError(env, params.callback);
303     }
304     napi_value promise = nullptr;
305     Common::PaddingCallbackPromiseInfo(env, params.callback, asynccallbackinfo->info, promise);
306 
307     ANS_LOGD("Create cancelGroup string.");
308     napi_value resourceName = nullptr;
309     napi_create_string_latin1(env, "cancelGroup", NAPI_AUTO_LENGTH, &resourceName);
310     // Asynchronous function call
311     napi_create_async_work(env,
312         nullptr,
313         resourceName,
314         [](napi_env env, void *data) {
315             ANS_LOGD("CancelGroup work excute.");
316             AsyncCallbackInfoCancelGroup *asynccallbackinfo = static_cast<AsyncCallbackInfoCancelGroup *>(data);
317             if (asynccallbackinfo) {
318                 ANS_LOGI("asynccallbackinfo->params.groupName = %{public}s",
319                     asynccallbackinfo->params.groupName.c_str());
320                 asynccallbackinfo->info.errorCode =
321                     NotificationHelper::CancelGroup(asynccallbackinfo->params.groupName);
322             }
323         },
324         [](napi_env env, napi_status status, void *data) {
325             ANS_LOGD("CancelGroup work complete.");
326             AsyncCallbackInfoCancelGroup *asynccallbackinfo = static_cast<AsyncCallbackInfoCancelGroup *>(data);
327             if (asynccallbackinfo) {
328                 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
329                 if (asynccallbackinfo->info.callback != nullptr) {
330                     ANS_LOGD("Delete CancelGroup callback reference.");
331                     napi_delete_reference(env, asynccallbackinfo->info.callback);
332                 }
333                 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
334                 delete asynccallbackinfo;
335                 asynccallbackinfo = nullptr;
336             }
337             ANS_LOGD("CancelGroup work complete end.");
338         },
339         (void *)asynccallbackinfo,
340         &asynccallbackinfo->asyncWork);
341 
342     napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
343 
344     if (asynccallbackinfo->info.isCallback) {
345         ANS_LOGD("CancelGroup callback is nullptr.");
346         return Common::NapiGetNull(env);
347     } else {
348         return promise;
349     }
350 }
351 
ParseParameters(const napi_env & env,const napi_callback_info & info,ParametersInfoCancelAsBundle & paras)352 napi_value ParseParameters(const napi_env &env, const napi_callback_info &info, ParametersInfoCancelAsBundle &paras)
353 {
354     ANS_LOGD("enter");
355 
356     size_t argc = CANCEL_AS_BUNDLE_MAX_PARA;
357     napi_value argv[CANCEL_AS_BUNDLE_MAX_PARA] = {nullptr};
358     napi_value thisVar = nullptr;
359     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
360     if (argc < 1) {
361         ANS_LOGW("Wrong number of arguments");
362         Common::NapiThrow(env, ERROR_PARAM_INVALID, MANDATORY_PARAMETER_ARE_LEFT_UNSPECIFIED);
363         return nullptr;
364     }
365 
366     napi_valuetype valuetype = napi_undefined;
367     // argv[0]: id: number / bundleOption
368     NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
369     if (valuetype != napi_number && valuetype != napi_object) {
370         ANS_LOGW("Wrong argument type. Number object expected.");
371         std::string msg = "Incorrect parameter types.The type of param must be number.";
372         Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
373         return nullptr;
374     }
375     if (argc > CANCEL_AS_BUNDLEOPTION_MAX_PARA) {
376         NAPI_CALL(env, napi_get_value_int32(env, argv[PARAM0], &paras.id));
377     } else {
378         auto retValue = Common::GetBundleOption(env, argv[PARAM0], paras.option);
379         if (retValue == nullptr) {
380             ANS_LOGE("GetBundleOption failed.");
381             Common::NapiThrow(env, ERROR_PARAM_INVALID, PARAMETER_VERIFICATION_FAILED);
382             return nullptr;
383         }
384         paras.hasOption = true;
385     }
386     // argv[1]: representativeBundle: string / id
387     NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
388     if (valuetype != napi_string && valuetype != napi_number && valuetype != napi_boolean) {
389         ANS_LOGW("Wrong argument type. String number boolean expected.");
390         std::string msg = "Incorrect parameter types.The type of param must be number or string or boolean.";
391         Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
392         return nullptr;
393     }
394     if (argc > CANCEL_AS_BUNDLEOPTION_MAX_PARA) {
395         if (valuetype == napi_string) {
396             char str[STR_MAX_SIZE] = {0};
397             size_t strLen = 0;
398             napi_get_value_string_utf8(env, argv[PARAM1], str, STR_MAX_SIZE - 1, &strLen);
399             paras.representativeBundle = str;
400         } else if (valuetype == napi_number) {
401             int64_t number = 0;
402             NAPI_CALL(env, napi_get_value_int64(env, argv[PARAM1], &number));
403             paras.representativeBundle = std::to_string(number);
404         } else {
405             bool result = false;
406             NAPI_CALL(env, napi_get_value_bool(env, argv[PARAM1], &result));
407             paras.representativeBundle = std::to_string(result);
408         }
409     } else {
410         NAPI_CALL(env, napi_get_value_int32(env, argv[PARAM1], &paras.id));
411     }
412 
413     // argv[2] : userId
414     if (argc > CANCEL_AS_BUNDLEOPTION_MAX_PARA) {
415         NAPI_CALL(env, napi_typeof(env, argv[PARAM2], &valuetype));
416         if (valuetype != napi_number) {
417             ANS_LOGW("Wrong argument type. Number expected.");
418             std::string msg = "Incorrect parameter types.The type of param must be number.";
419             Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
420             return nullptr;
421         }
422         napi_get_value_int32(env, argv[PARAM2], &paras.userId);
423     }
424     // argv[3]: callback
425     if (argc >= CANCEL_AS_BUNDLE_MAX_PARA) {
426         NAPI_CALL(env, napi_typeof(env, argv[PARAM3], &valuetype));
427         if (valuetype != napi_function) {
428             ANS_LOGW("Callback is not function excute promise.");
429             return Common::NapiGetNull(env);
430         }
431         napi_create_reference(env, argv[PARAM3], 1, &paras.callback);
432     }
433 
434     return Common::NapiGetNull(env);
435 }
436 
CancelAsBundle(napi_env env,napi_callback_info info)437 napi_value CancelAsBundle(napi_env env, napi_callback_info info)
438 {
439     ANS_LOGD("enter");
440 
441     ParametersInfoCancelAsBundle paras;
442     if (ParseParameters(env, info, paras) == nullptr) {
443         return Common::NapiGetUndefined(env);
444     }
445 
446     AsyncCallbackInfoCancelAsBundle *asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoCancelAsBundle {
447         .env = env, .asyncWork = nullptr,
448         .id = paras.id,
449         .representativeBundle = paras.representativeBundle,
450         .userId = paras.userId
451     };
452     if (!asynccallbackinfo) {
453         ANS_LOGD("AsyncCallbackinfo is nullptr.");
454         return Common::JSParaError(env, paras.callback);
455     }
456     napi_value promise = nullptr;
457     Common::PaddingCallbackPromiseInfo(env, paras.callback, asynccallbackinfo->info, promise);
458 
459     ANS_LOGD("Create cancelasbundle string.");
460     napi_value resourceName = nullptr;
461     napi_create_string_latin1(env, "cancelasbundle", NAPI_AUTO_LENGTH, &resourceName);
462     // Asynchronous function call
463     napi_create_async_work(env,
464         nullptr,
465         resourceName,
466         [](napi_env env, void *data) {
467             ANS_LOGD("CancelAsBundle work excute.");
468             AsyncCallbackInfoCancelAsBundle *asynccallbackinfo = static_cast<AsyncCallbackInfoCancelAsBundle *>(data);
469 
470             if (asynccallbackinfo) {
471                 asynccallbackinfo->info.errorCode = NotificationHelper::CancelAsBundle(
472                     asynccallbackinfo->id, asynccallbackinfo->representativeBundle, asynccallbackinfo->userId);
473             }
474         },
475         [](napi_env env, napi_status status, void *data) {
476             ANS_LOGD("CancelAsBundle work complete");
477             AsyncCallbackInfoCancelAsBundle *asynccallbackinfo = static_cast<AsyncCallbackInfoCancelAsBundle *>(data);
478             if (asynccallbackinfo) {
479                 Common::ReturnCallbackPromise(env, asynccallbackinfo->info, Common::NapiGetNull(env));
480                 if (asynccallbackinfo->info.callback != nullptr) {
481                     ANS_LOGD("Delete CancelAsBundle callback reference.");
482                     napi_delete_reference(env, asynccallbackinfo->info.callback);
483                 }
484                 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
485                 delete asynccallbackinfo;
486                 asynccallbackinfo = nullptr;
487             }
488             ANS_LOGD("CancelAsBundle work complete end.");
489         },
490         (void *)asynccallbackinfo,
491         &asynccallbackinfo->asyncWork);
492 
493     napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
494 
495     if (asynccallbackinfo->info.isCallback) {
496         ANS_LOGD("CancelAsBundle callback is nullptr.");
497         return Common::NapiGetNull(env);
498     } else {
499         return promise;
500     }
501 }
502 }  // namespace NotificationNapi
503 }  // namespace OHOS
504