1 /*
2  * Copyright (C) 2021-2022 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 #define MLOG_TAG "SmartAlbumNapi"
16 
17 #include "smart_album_napi.h"
18 
19 #include "media_file_asset_columns.h"
20 #include "media_library_napi.h"
21 #include "media_smart_album_column.h"
22 #include "media_smart_map_column.h"
23 #include "medialibrary_client_errno.h"
24 #include "medialibrary_napi_log.h"
25 #include "medialibrary_tracer.h"
26 #include "media_file_utils.h"
27 #include "userfile_client.h"
28 
29 using OHOS::HiviewDFX::HiLog;
30 using OHOS::HiviewDFX::HiLogLabel;
31 
32 namespace OHOS {
33 namespace Media {
34 using namespace std;
35 thread_local napi_ref SmartAlbumNapi::sConstructor_ = nullptr;
36 thread_local SmartAlbumAsset *SmartAlbumNapi::sAlbumData_ = nullptr;
37 using CompleteCallback = napi_async_complete_callback;
38 thread_local napi_ref SmartAlbumNapi::userFileMgrConstructor_ = nullptr;
39 constexpr int32_t INVALID_EXPIREDTIME = -1;
SmartAlbumNapi()40 SmartAlbumNapi::SmartAlbumNapi()
41     : env_(nullptr) {}
42 
43 SmartAlbumNapi::~SmartAlbumNapi() = default;
44 
SmartAlbumNapiDestructor(napi_env env,void * nativeObject,void * finalize_hint)45 void SmartAlbumNapi::SmartAlbumNapiDestructor(napi_env env, void *nativeObject, void *finalize_hint)
46 {
47     SmartAlbumNapi *album = reinterpret_cast<SmartAlbumNapi*>(nativeObject);
48     if (album != nullptr) {
49         delete album;
50         album = nullptr;
51     }
52 }
53 
Init(napi_env env,napi_value exports)54 napi_value SmartAlbumNapi::Init(napi_env env, napi_value exports)
55 {
56     napi_status status;
57     napi_value ctorObj;
58     int32_t refCount = 1;
59 
60     napi_property_descriptor album_props[] = {
61         DECLARE_NAPI_GETTER("albumId", JSGetSmartAlbumId),
62         DECLARE_NAPI_GETTER("albumUri", JSGetSmartAlbumUri),
63         DECLARE_NAPI_GETTER("albumType", JSGetSmartAlbumType),
64         DECLARE_NAPI_GETTER_SETTER("albumName", JSGetSmartAlbumName, JSSmartAlbumNameSetter),
65         DECLARE_NAPI_GETTER_SETTER("description", JSGetSmartAlbumDescription, JSSmartAlbumDescriptionSetter),
66         DECLARE_NAPI_GETTER("albumTag", JSGetSmartAlbumTag),
67         DECLARE_NAPI_GETTER("size", JSGetSmartAlbumCapacity),
68         DECLARE_NAPI_GETTER("categoryId", JSGetSmartAlbumCategoryId),
69         DECLARE_NAPI_GETTER("categoryName", JSGetSmartAlbumCategoryName),
70         DECLARE_NAPI_GETTER_SETTER("coverURI", JSGetSmartAlbumCoverUri, JSSmartAlbumCoverUriSetter),
71         DECLARE_NAPI_GETTER_SETTER("expiredTime", JSGetSmartAlbumExpiredTime, JSSmartAlbumExpiredTimeSetter),
72         DECLARE_NAPI_FUNCTION("commitModify", JSCommitModify),
73         DECLARE_NAPI_FUNCTION("addFileAssets", JSAddFileAssets),
74         DECLARE_NAPI_FUNCTION("removeFileAssets", JSRemoveFileAssets),
75         DECLARE_NAPI_FUNCTION("getFileAssets", JSGetSmartAlbumFileAssets)
76     };
77 
78     status = napi_define_class(env, SMART_ALBUM_NAPI_CLASS_NAME.c_str(), NAPI_AUTO_LENGTH,
79                                SmartAlbumNapiConstructor, nullptr,
80                                sizeof(album_props) / sizeof(album_props[PARAM0]),
81                                album_props, &ctorObj);
82     if (status == napi_ok) {
83         status = napi_create_reference(env, ctorObj, refCount, &sConstructor_);
84         if (status == napi_ok) {
85             status = napi_set_named_property(env, exports, SMART_ALBUM_NAPI_CLASS_NAME.c_str(), ctorObj);
86             if (status == napi_ok) {
87                 return exports;
88             }
89         }
90     }
91     NAPI_DEBUG_LOG("SmartAlbumNapi::Init nullptr, status: %{public}d", status);
92     return nullptr;
93 }
94 
UserFileMgrInit(napi_env env,napi_value exports)95 napi_value SmartAlbumNapi::UserFileMgrInit(napi_env env, napi_value exports)
96 {
97     NapiClassInfo info = {
98         .name = USERFILEMGR_SMART_ALBUM_NAPI_CLASS_NAME,
99         .ref = &userFileMgrConstructor_,
100         .constructor = SmartAlbumNapiConstructor,
101         .props = {
102             DECLARE_NAPI_GETTER_SETTER("albumName", JSGetSmartAlbumName, JSSmartAlbumNameSetter),
103             DECLARE_NAPI_GETTER("albumUri", JSGetSmartAlbumUri),
104             DECLARE_NAPI_GETTER("dateModified", JSGetSmartAlbumDateModified),
105             DECLARE_NAPI_GETTER("count", JSGetSmartAlbumCapacity),
106             DECLARE_NAPI_GETTER("coverUri", JSGetSmartAlbumCoverUri),
107             DECLARE_NAPI_FUNCTION("getPhotoAssets", UserFileMgrGetAssets),
108             DECLARE_NAPI_FUNCTION("delete", UserFileMgrDeleteAsset),
109             DECLARE_NAPI_FUNCTION("recover", UserFileMgrRecoverAsset),
110         }
111     };
112 
113     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
114     return exports;
115 }
116 
SetSmartAlbumNapiProperties()117 void SmartAlbumNapi::SetSmartAlbumNapiProperties()
118 {
119     smartAlbumAssetPtr = std::shared_ptr<SmartAlbumAsset>(sAlbumData_);
120     NAPI_INFO_LOG("SetSmartAlbumNapiProperties name = %{public}s",
121         smartAlbumAssetPtr->GetAlbumName().c_str());
122 }
123 
124 // Constructor callback
SmartAlbumNapiConstructor(napi_env env,napi_callback_info info)125 napi_value SmartAlbumNapi::SmartAlbumNapiConstructor(napi_env env, napi_callback_info info)
126 {
127     napi_status status;
128     napi_value result = nullptr;
129     napi_value thisVar = nullptr;
130     napi_get_undefined(env, &result);
131     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
132     if (status == napi_ok && thisVar != nullptr) {
133         std::unique_ptr<SmartAlbumNapi> obj = std::make_unique<SmartAlbumNapi>();
134         if (obj != nullptr) {
135             obj->env_ = env;
136             if (sAlbumData_ != nullptr) {
137                 obj->SetSmartAlbumNapiProperties();
138             }
139             status = napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
140                                SmartAlbumNapi::SmartAlbumNapiDestructor, nullptr, nullptr);
141             if (status == napi_ok) {
142                 obj.release();
143                 return thisVar;
144             } else {
145                 NAPI_ERR_LOG("Failure wrapping js to native napi, status: %{public}d", status);
146             }
147         }
148     }
149 
150     return result;
151 }
152 
CreateSmartAlbumNapi(napi_env env,unique_ptr<SmartAlbumAsset> & albumData)153 napi_value SmartAlbumNapi::CreateSmartAlbumNapi(napi_env env, unique_ptr<SmartAlbumAsset> &albumData)
154 {
155     if (albumData == nullptr) {
156         return nullptr;
157     }
158 
159     napi_value constructor;
160     napi_ref constructorRef = (albumData->GetResultNapiType() == ResultNapiType::TYPE_MEDIALIBRARY) ?
161         (sConstructor_) : (userFileMgrConstructor_);
162     NAPI_CALL(env, napi_get_reference_value(env, constructorRef, &constructor));
163 
164     napi_value result = nullptr;
165     sAlbumData_ = albumData.release();
166     NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
167     sAlbumData_ = nullptr;
168     return result;
169 }
170 
GetSmartAlbumName() const171 std::string SmartAlbumNapi::GetSmartAlbumName() const
172 {
173     return smartAlbumAssetPtr->GetAlbumName();
174 }
175 
GetAlbumPrivateType() const176 int32_t SmartAlbumNapi::GetAlbumPrivateType() const
177 {
178     return smartAlbumAssetPtr->GetAlbumPrivateType();
179 }
180 
GetSmartAlbumUri() const181 std::string SmartAlbumNapi::GetSmartAlbumUri() const
182 {
183     return smartAlbumAssetPtr->GetAlbumUri();
184 }
185 
GetSmartAlbumId() const186 int32_t SmartAlbumNapi::GetSmartAlbumId() const
187 {
188     return smartAlbumAssetPtr->GetAlbumId();
189 }
GetDescription() const190 std::string SmartAlbumNapi::GetDescription() const
191 {
192     return smartAlbumAssetPtr->GetDescription();
193 }
194 
GetCoverUri() const195 std::string SmartAlbumNapi::GetCoverUri() const
196 {
197     return smartAlbumAssetPtr->GetCoverUri();
198 }
199 
GetExpiredTime() const200 int32_t SmartAlbumNapi::GetExpiredTime() const
201 {
202     return smartAlbumAssetPtr->GetExpiredTime();
203 }
204 
SetAlbumCapacity(int32_t albumCapacity)205 void SmartAlbumNapi::SetAlbumCapacity(int32_t albumCapacity)
206 {
207     smartAlbumAssetPtr->SetAlbumCapacity(albumCapacity);
208 }
209 
GetNetworkId() const210 std::string SmartAlbumNapi::GetNetworkId() const
211 {
212     return MediaFileUtils::GetNetworkIdFromUri(GetSmartAlbumUri());
213 }
214 
SetCoverUri(string & coverUri)215 void SmartAlbumNapi::SetCoverUri(string &coverUri)
216 {
217     smartAlbumAssetPtr->SetCoverUri(coverUri);
218 }
219 
SetDescription(string & description)220 void SmartAlbumNapi::SetDescription(string &description)
221 {
222     smartAlbumAssetPtr->SetDescription(description);
223 }
224 
SetExpiredTime(int32_t expiredTime)225 void SmartAlbumNapi::SetExpiredTime(int32_t expiredTime)
226 {
227     smartAlbumAssetPtr->SetExpiredTime(expiredTime);
228 }
229 
JSGetSmartAlbumId(napi_env env,napi_callback_info info)230 napi_value SmartAlbumNapi::JSGetSmartAlbumId(napi_env env, napi_callback_info info)
231 {
232     napi_status status;
233     napi_value jsResult = nullptr;
234     napi_value undefinedResult = nullptr;
235     SmartAlbumNapi* obj = nullptr;
236     int32_t id;
237     napi_value thisVar = nullptr;
238 
239     napi_get_undefined(env, &undefinedResult);
240     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
241     if ((status != napi_ok) || (thisVar == nullptr)) {
242         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
243         return undefinedResult;
244     }
245 
246     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
247     if ((status == napi_ok) && (obj != nullptr)) {
248         id = obj->GetSmartAlbumId();
249         status = napi_create_int32(env, id, &jsResult);
250         if (status == napi_ok) {
251             return jsResult;
252         }
253     }
254 
255     return undefinedResult;
256 }
257 
JSGetSmartAlbumName(napi_env env,napi_callback_info info)258 napi_value SmartAlbumNapi::JSGetSmartAlbumName(napi_env env, napi_callback_info info)
259 {
260     napi_status status;
261     napi_value jsResult = nullptr;
262     napi_value undefinedResult = nullptr;
263     SmartAlbumNapi* obj = nullptr;
264     std::string name = "";
265     napi_value thisVar = nullptr;
266     napi_get_undefined(env, &undefinedResult);
267     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
268     if ((status != napi_ok) || (thisVar == nullptr)) {
269         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
270         return undefinedResult;
271     }
272     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
273     if ((status == napi_ok) && (obj != nullptr)) {
274         name = obj->GetSmartAlbumName();
275         NAPI_DEBUG_LOG("JSGetSmartAlbumName name = %{private}s", name.c_str());
276         status = napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &jsResult);
277         if (status == napi_ok) {
278             return jsResult;
279         }
280     }
281 
282     return undefinedResult;
283 }
284 
JSSmartAlbumNameSetter(napi_env env,napi_callback_info info)285 napi_value SmartAlbumNapi::JSSmartAlbumNameSetter(napi_env env, napi_callback_info info)
286 {
287     napi_status status;
288     napi_value jsResult = nullptr;
289     size_t argc = ARGS_ONE;
290     napi_value argv[ARGS_ONE] = {0};
291     size_t res = 0;
292     char buffer[FILENAME_MAX];
293     SmartAlbumNapi* obj = nullptr;
294     napi_value thisVar = nullptr;
295     napi_valuetype valueType = napi_undefined;
296 
297     napi_get_undefined(env, &jsResult);
298     GET_JS_ARGS(env, info, argc, argv, thisVar);
299     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
300 
301     if (thisVar == nullptr || napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
302         NAPI_ERR_LOG("Invalid arguments type! valueType: %{public}d", valueType);
303         return jsResult;
304     }
305 
306     napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res);
307 
308     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
309     if (status == napi_ok && obj != nullptr) {
310         obj->smartAlbumAssetPtr->SetAlbumName(std::string(buffer));
311     }
312 
313     return jsResult;
314 }
315 
JSGetSmartAlbumTag(napi_env env,napi_callback_info info)316 napi_value SmartAlbumNapi::JSGetSmartAlbumTag(napi_env env, napi_callback_info info)
317 {
318     napi_status status;
319     napi_value jsResult = nullptr;
320     napi_value undefinedResult = nullptr;
321     SmartAlbumNapi* obj = nullptr;
322     std::string albumTag = "";
323     napi_value thisVar = nullptr;
324 
325     napi_get_undefined(env, &undefinedResult);
326     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
327     if ((status != napi_ok) || (thisVar == nullptr)) {
328         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
329         return undefinedResult;
330     }
331 
332     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
333     if (status == napi_ok && obj != nullptr) {
334         albumTag = obj->smartAlbumAssetPtr->GetAlbumTag();
335         status = napi_create_string_utf8(env, albumTag.c_str(), NAPI_AUTO_LENGTH, &jsResult);
336         if (status == napi_ok) {
337             return jsResult;
338         }
339     }
340 
341     return undefinedResult;
342 }
343 
JSGetSmartAlbumCapacity(napi_env env,napi_callback_info info)344 napi_value SmartAlbumNapi::JSGetSmartAlbumCapacity(napi_env env, napi_callback_info info)
345 {
346     napi_status status;
347     napi_value jsResult = nullptr;
348     napi_value undefinedResult = nullptr;
349     SmartAlbumNapi* obj = nullptr;
350     int32_t albumCapacity;
351     napi_value thisVar = nullptr;
352 
353     napi_get_undefined(env, &undefinedResult);
354     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
355     if ((status != napi_ok) || (thisVar == nullptr)) {
356         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
357         return undefinedResult;
358     }
359 
360     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
361     if (status == napi_ok && obj != nullptr) {
362         albumCapacity = obj->smartAlbumAssetPtr->GetAlbumCapacity();
363         status = napi_create_int32(env, albumCapacity, &jsResult);
364         if (status == napi_ok) {
365             return jsResult;
366         }
367     }
368 
369     return undefinedResult;
370 }
371 
JSGetSmartAlbumCategoryId(napi_env env,napi_callback_info info)372 napi_value SmartAlbumNapi::JSGetSmartAlbumCategoryId(napi_env env, napi_callback_info info)
373 {
374     napi_status status;
375     napi_value jsResult = nullptr;
376     napi_value undefinedResult = nullptr;
377     SmartAlbumNapi* obj = nullptr;
378     int32_t categoryId;
379     napi_value thisVar = nullptr;
380 
381     napi_get_undefined(env, &undefinedResult);
382     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
383     if ((status != napi_ok) || (thisVar == nullptr)) {
384         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
385         return undefinedResult;
386     }
387 
388     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
389     if (status == napi_ok && obj != nullptr) {
390         categoryId = obj->smartAlbumAssetPtr->GetCategoryId();
391         status = napi_create_int32(env, categoryId, &jsResult);
392         if (status == napi_ok) {
393             return jsResult;
394         }
395     }
396 
397     return undefinedResult;
398 }
399 
JSGetSmartAlbumCategoryName(napi_env env,napi_callback_info info)400 napi_value SmartAlbumNapi::JSGetSmartAlbumCategoryName(napi_env env, napi_callback_info info)
401 {
402     napi_status status;
403     napi_value jsResult = nullptr;
404     napi_value undefinedResult = nullptr;
405     SmartAlbumNapi* obj = nullptr;
406     std::string categoryName = "";
407     napi_value thisVar = nullptr;
408 
409     napi_get_undefined(env, &undefinedResult);
410     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
411     if ((status != napi_ok) || (thisVar == nullptr)) {
412         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
413         return undefinedResult;
414     }
415 
416     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
417     if (status == napi_ok && obj != nullptr) {
418         categoryName = obj->smartAlbumAssetPtr->GetCategoryName();
419         status = napi_create_string_utf8(env, categoryName.c_str(), NAPI_AUTO_LENGTH, &jsResult);
420         if (status == napi_ok) {
421             return jsResult;
422         }
423     }
424 
425     return undefinedResult;
426 }
427 
JSGetSmartAlbumCoverUri(napi_env env,napi_callback_info info)428 napi_value SmartAlbumNapi::JSGetSmartAlbumCoverUri(napi_env env, napi_callback_info info)
429 {
430     napi_status status;
431     napi_value jsResult = nullptr;
432     napi_value undefinedResult = nullptr;
433     SmartAlbumNapi* obj = nullptr;
434     std::string coverUri = "";
435     napi_value thisVar = nullptr;
436 
437     napi_get_undefined(env, &undefinedResult);
438     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
439     if ((status != napi_ok) || (thisVar == nullptr)) {
440         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
441         return undefinedResult;
442     }
443 
444     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
445     if (status == napi_ok && obj != nullptr) {
446         coverUri = obj->smartAlbumAssetPtr->GetCoverUri();
447         status = napi_create_string_utf8(env, coverUri.c_str(), NAPI_AUTO_LENGTH, &jsResult);
448         if (status == napi_ok) {
449             return jsResult;
450         }
451     }
452 
453     return undefinedResult;
454 }
455 
JSSmartAlbumCoverUriSetter(napi_env env,napi_callback_info info)456 napi_value SmartAlbumNapi::JSSmartAlbumCoverUriSetter(napi_env env, napi_callback_info info)
457 {
458     napi_value jsResult = nullptr;
459     napi_get_undefined(env, &jsResult);
460     napi_value argv[ARGS_ONE] = {0};
461     size_t argc = ARGS_ONE;
462     napi_value thisVar = nullptr;
463     GET_JS_ARGS(env, info, argc, argv, thisVar);
464     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
465     napi_valuetype valueType = napi_undefined;
466     if (thisVar == nullptr || napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
467         NAPI_ERR_LOG("Invalid arguments type! valueType: %{private}d", valueType);
468         return jsResult;
469     }
470     SmartAlbumNapi* obj = nullptr;
471     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
472     if ((status != napi_ok) || (obj == nullptr)) {
473         NAPI_ERR_LOG("Unwrap object failed");
474         return jsResult;
475     }
476     size_t res = 0;
477     char buffer[FILENAME_MAX];
478     status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res);
479     if (status != napi_ok) {
480         NAPI_ERR_LOG("Get coverUri value string failed");
481         return jsResult;
482     }
483     obj->smartAlbumAssetPtr->SetCoverUri(std::string(buffer));
484     return jsResult;
485 }
486 
JSGetSmartAlbumUri(napi_env env,napi_callback_info info)487 napi_value SmartAlbumNapi::JSGetSmartAlbumUri(napi_env env, napi_callback_info info)
488 {
489     napi_value undefinedResult = nullptr;
490     napi_get_undefined(env, &undefinedResult);
491     napi_status status;
492     napi_value thisVar = nullptr;
493     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
494     if ((status != napi_ok) || (thisVar == nullptr)) {
495         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
496         return undefinedResult;
497     }
498     SmartAlbumNapi* obj = nullptr;
499     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
500     if ((status != napi_ok) || (obj == nullptr)) {
501         NAPI_ERR_LOG("Unwrap object failed");
502         return undefinedResult;
503     }
504     napi_value jsResult = nullptr;
505     status = napi_create_string_utf8(env, obj->smartAlbumAssetPtr->GetAlbumUri().c_str(), NAPI_AUTO_LENGTH, &jsResult);
506     if (status != napi_ok) {
507         NAPI_ERR_LOG("Create albumUri string failed");
508         return undefinedResult;
509     }
510     return jsResult;
511 }
512 
JSGetSmartAlbumDateModified(napi_env env,napi_callback_info info)513 napi_value SmartAlbumNapi::JSGetSmartAlbumDateModified(napi_env env, napi_callback_info info)
514 {
515     napi_status status;
516     napi_value undefinedResult = nullptr;
517     napi_value thisVar = nullptr;
518 
519     napi_get_undefined(env, &undefinedResult);
520     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
521     if ((status != napi_ok) || (thisVar == nullptr)) {
522         NAPI_ERR_LOG("Invalid arguments! status: %{public}d", status);
523         return undefinedResult;
524     }
525     SmartAlbumNapi* obj = nullptr;
526     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
527     if ((status == napi_ok) && (obj != nullptr)) {
528         int64_t dateModified = obj->smartAlbumAssetPtr->GetAlbumDateModified();
529         napi_value jsResult = nullptr;
530         status = napi_create_int64(env, dateModified, &jsResult);
531         if (status == napi_ok) {
532             return jsResult;
533         }
534     }
535     return undefinedResult;
536 }
537 
JSGetSmartAlbumType(napi_env env,napi_callback_info info)538 napi_value SmartAlbumNapi::JSGetSmartAlbumType(napi_env env, napi_callback_info info)
539 {
540     napi_value undefinedResult = nullptr;
541     napi_get_undefined(env, &undefinedResult);
542     napi_status status;
543     napi_value thisVar = nullptr;
544     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
545     if ((status != napi_ok) || (thisVar == nullptr)) {
546         NAPI_ERR_LOG("Invalid arguments! status: %{private}d", status);
547         return undefinedResult;
548     }
549     SmartAlbumNapi* obj = nullptr;
550     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
551     if ((status != napi_ok) || (obj == nullptr)) {
552         NAPI_ERR_LOG("Unwrap object failed");
553         return undefinedResult;
554     }
555     napi_value jsResult = nullptr;
556     status = napi_create_int32(env, obj->smartAlbumAssetPtr->GetAlbumPrivateType(), &jsResult);
557     if (status != napi_ok) {
558         NAPI_ERR_LOG("Create albumPrivateType int32 failed");
559         return undefinedResult;
560     }
561     return jsResult;
562 }
563 
JSGetSmartAlbumDescription(napi_env env,napi_callback_info info)564 napi_value SmartAlbumNapi::JSGetSmartAlbumDescription(napi_env env, napi_callback_info info)
565 {
566     napi_value undefinedResult = nullptr;
567     napi_get_undefined(env, &undefinedResult);
568     napi_status status;
569     napi_value thisVar = nullptr;
570     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
571     if ((status != napi_ok) || (thisVar == nullptr)) {
572         NAPI_ERR_LOG("Invalid arguments! status: %{private}d", status);
573         return undefinedResult;
574     }
575     SmartAlbumNapi* obj = nullptr;
576     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
577     if ((status != napi_ok) || (obj == nullptr)) {
578         NAPI_ERR_LOG("Unwrap object failed");
579         return undefinedResult;
580     }
581     napi_value jsResult = nullptr;
582     status = napi_create_string_utf8(env, obj->smartAlbumAssetPtr->GetDescription().c_str(), NAPI_AUTO_LENGTH,
583         &jsResult);
584     if (status != napi_ok) {
585         NAPI_ERR_LOG("Create description string failed");
586         return undefinedResult;
587     }
588     return jsResult;
589 }
590 
JSSmartAlbumDescriptionSetter(napi_env env,napi_callback_info info)591 napi_value SmartAlbumNapi::JSSmartAlbumDescriptionSetter(napi_env env, napi_callback_info info)
592 {
593     napi_value jsResult = nullptr;
594     napi_get_undefined(env, &jsResult);
595     size_t argc = ARGS_ONE;
596     napi_value argv[ARGS_ONE] = {0};
597     napi_value thisVar = nullptr;
598     GET_JS_ARGS(env, info, argc, argv, thisVar);
599     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
600     napi_valuetype valueType = napi_undefined;
601     if (thisVar == nullptr || napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_string) {
602         NAPI_ERR_LOG("Invalid arguments type! valueType: %{private}d", valueType);
603         return jsResult;
604     }
605     SmartAlbumNapi* obj = nullptr;
606     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
607     if ((status != napi_ok) || (obj == nullptr)) {
608         NAPI_ERR_LOG("Unwrap object failed");
609         return jsResult;
610     }
611     size_t res = 0;
612     char buffer[FILENAME_MAX];
613     status = napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res);
614     if (status != napi_ok) {
615         NAPI_ERR_LOG("Get description value string failed");
616         return jsResult;
617     }
618     obj->smartAlbumAssetPtr->SetDescription(std::string(buffer));
619     return jsResult;
620 }
621 
JSGetSmartAlbumExpiredTime(napi_env env,napi_callback_info info)622 napi_value SmartAlbumNapi::JSGetSmartAlbumExpiredTime(napi_env env, napi_callback_info info)
623 {
624     napi_value undefinedResult = nullptr;
625     napi_get_undefined(env, &undefinedResult);
626     napi_status status;
627     napi_value thisVar = nullptr;
628     GET_JS_OBJ_WITH_ZERO_ARGS(env, info, status, thisVar);
629     if ((status != napi_ok) || (thisVar == nullptr)) {
630         NAPI_ERR_LOG("Invalid arguments! status: %{private}d", status);
631         return undefinedResult;
632     }
633     SmartAlbumNapi* obj = nullptr;
634     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
635     if ((status != napi_ok) || (obj == nullptr)) {
636         NAPI_ERR_LOG("Unwrap object failed");
637         return undefinedResult;
638     }
639     napi_value jsResult = nullptr;
640     status = napi_create_int32(env, obj->smartAlbumAssetPtr->GetExpiredTime(), &jsResult);
641     if (status != napi_ok) {
642         NAPI_ERR_LOG("Create expiredTime int32 failed");
643         return undefinedResult;
644     }
645     return jsResult;
646 }
647 
JSSmartAlbumExpiredTimeSetter(napi_env env,napi_callback_info info)648 napi_value SmartAlbumNapi::JSSmartAlbumExpiredTimeSetter(napi_env env, napi_callback_info info)
649 {
650     napi_value undefinedResult = nullptr;
651     napi_get_undefined(env, &undefinedResult);
652     size_t argc = ARGS_ONE;
653     napi_value argv[ARGS_ONE] = {0};
654     napi_value thisVar = nullptr;
655     GET_JS_ARGS(env, info, argc, argv, thisVar);
656     NAPI_ASSERT(env, argc == ARGS_ONE, "requires 1 parameter");
657     SmartAlbumNapi* obj = nullptr;
658     napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
659     if ((status != napi_ok) || (obj == nullptr)) {
660         NAPI_ERR_LOG("Failed to get expiredTime obj");
661         return undefinedResult;
662     }
663     napi_valuetype valueType = napi_undefined;
664     if (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok || valueType != napi_number) {
665         NAPI_ERR_LOG("Invalid arguments type! valueType: %{private}d", valueType);
666         obj->smartAlbumAssetPtr->SetExpiredTime(INVALID_EXPIREDTIME);
667         return undefinedResult;
668     }
669     int32_t expiredTime;
670     status = napi_get_value_int32(env, argv[PARAM0], &expiredTime);
671     if (status != napi_ok) {
672         NAPI_ERR_LOG("Failed to get expiredTime");
673         return undefinedResult;
674     }
675     obj->smartAlbumAssetPtr->SetExpiredTime(expiredTime);
676     return undefinedResult;
677 }
678 
CommitModifyNative(const SmartAlbumNapiAsyncContext & albumContext)679 static void CommitModifyNative(const SmartAlbumNapiAsyncContext &albumContext)
680 {
681     SmartAlbumNapiAsyncContext *context = const_cast<SmartAlbumNapiAsyncContext *>(&albumContext);
682     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
683     NAPI_DEBUG_LOG("CommitModifyNative = %{private}s", context->objectInfo->GetSmartAlbumName().c_str());
684     if (MediaFileUtils::CheckAlbumName(context->objectInfo->GetSmartAlbumName()) < 0) {
685         context->error = JS_E_DISPLAYNAME;
686         NAPI_ERR_LOG("Failed to checkDisplayName");
687         return;
688     }
689     DataShare::DataShareValuesBucket valuesBucket;
690     valuesBucket.Put(SMARTALBUM_DB_DESCRIPTION, context->objectInfo->GetDescription());
691     string coverUri = context->objectInfo->GetCoverUri();
692     if (coverUri.empty() || (coverUri.find(MEDIALIBRARY_MEDIA_PREFIX) == string::npos)) {
693         context->error = E_VIOLATION_PARAMETERS;
694         NAPI_ERR_LOG("CoverUri is invalid");
695         return;
696     }
697     valuesBucket.Put(SMARTALBUM_DB_COVER_URI, coverUri);
698     if (context->objectInfo->GetExpiredTime() < 0) {
699         context->error = E_VIOLATION_PARAMETERS;
700         NAPI_ERR_LOG("ExpiredTime is invalid");
701         return;
702     }
703     valuesBucket.Put(SMARTALBUM_DB_EXPIRED_TIME, context->objectInfo->GetExpiredTime());
704     DataShare::DataSharePredicates predicates;
705     predicates.SetWhereClause(SMARTALBUM_DB_ID + " = " + std::to_string(context->objectInfo->GetSmartAlbumId()));
706     Uri commitModifyUri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMOPRN + "/" + MEDIA_SMARTALBUMOPRN_MODIFYALBUM);
707     context->changedRows = UserFileClient::Update(commitModifyUri, predicates, valuesBucket);
708     context->SaveError(context->changedRows);
709 }
710 
JSAddAssetExecute(SmartAlbumNapiAsyncContext * context)711 static void JSAddAssetExecute(SmartAlbumNapiAsyncContext *context)
712 {
713     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
714     int32_t smartAlbumId = context->objectInfo->GetSmartAlbumId();
715     if ((smartAlbumId == TRASH_ALBUM_ID_VALUES) || (smartAlbumId == FAVOURITE_ALBUM_ID_VALUES)) {
716         context->error = E_INVALID_VALUES;
717         NAPI_ERR_LOG("SmartAlbumId is invalid, smartAlbumId = %{private}d", smartAlbumId);
718         return;
719     }
720     vector<DataShare::DataShareValuesBucket> values;
721     for (int32_t id : context->assetIds) {
722         DataShare::DataShareValuesBucket valuesBucket;
723         valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, smartAlbumId);
724         valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, id);
725         values.push_back(valuesBucket);
726     }
727     Uri addAssetUri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/" +
728         MEDIA_SMARTALBUMMAPOPRN_ADDSMARTALBUM);
729     context->changedRows = UserFileClient::BatchInsert(addAssetUri, values);
730     if (context->changedRows != static_cast<int32_t>(context->assetIds.size())) {
731         context->error = E_INVALID_VALUES;
732     }
733 }
734 
JSRemoveAssetExecute(SmartAlbumNapiAsyncContext * context)735 static void JSRemoveAssetExecute(SmartAlbumNapiAsyncContext *context)
736 {
737     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
738     int32_t smartAlbumId = context->objectInfo->GetSmartAlbumId();
739     if ((smartAlbumId == TRASH_ALBUM_ID_VALUES) || (smartAlbumId == FAVOURITE_ALBUM_ID_VALUES)) {
740         NAPI_ERR_LOG("SmartAlbumId is invalid, smartAlbumId = %{private}d", smartAlbumId);
741         context->error = E_INVALID_VALUES;
742         return;
743     }
744     vector<DataShare::DataShareValuesBucket> values;
745     for (int32_t id : context->assetIds) {
746         DataShare::DataShareValuesBucket valuesBucket;
747         valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, smartAlbumId);
748         valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, id);
749         values.push_back(valuesBucket);
750     }
751     Uri removeAssetUri(MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/" +
752         MEDIA_SMARTALBUMMAPOPRN_REMOVESMARTALBUM);
753     context->changedRows = UserFileClient::BatchInsert(removeAssetUri, values);
754     if (context->changedRows != static_cast<int32_t>(context->assetIds.size())) {
755         context->error = E_INVALID_VALUES;
756     }
757 }
758 
JSCommitModifyCompleteCallback(napi_env env,napi_status status,SmartAlbumNapiAsyncContext * context)759 static void JSCommitModifyCompleteCallback(napi_env env, napi_status status, SmartAlbumNapiAsyncContext *context)
760 {
761     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
762     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
763     jsContext->status = false;
764     if (context->error == ERR_DEFAULT) {
765         napi_create_int32(env, context->changedRows, &jsContext->data);
766         napi_get_undefined(env, &jsContext->error);
767         jsContext->status = true;
768     } else {
769         context->HandleError(env, jsContext->error);
770         napi_get_undefined(env, &jsContext->data);
771         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, context->error,
772                                                      "Failed to commit smart album");
773     }
774 
775     if (context->work != nullptr) {
776         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
777                                                    context->work, *jsContext);
778     }
779     delete context;
780 }
781 
JSAddAssetCompleteCallback(napi_env env,napi_status status,SmartAlbumNapiAsyncContext * context)782 static void JSAddAssetCompleteCallback(napi_env env, napi_status status, SmartAlbumNapiAsyncContext *context)
783 {
784     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
785     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
786     jsContext->status = false;
787     if (context->error == ERR_DEFAULT) {
788         napi_create_int32(env, context->changedRows, &jsContext->data);
789         napi_get_undefined(env, &jsContext->error);
790         jsContext->status = true;
791     } else {
792         context->HandleError(env, jsContext->error);
793         napi_get_undefined(env, &jsContext->data);
794         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error,  context->error,
795                                                      "Failed to add smartalbum asset");
796     }
797 
798     if (context->work != nullptr) {
799         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
800                                                    context->work, *jsContext);
801     }
802     delete context;
803 }
804 
JSRemoveAssetCompleteCallback(napi_env env,napi_status status,SmartAlbumNapiAsyncContext * context)805 static void JSRemoveAssetCompleteCallback(napi_env env, napi_status status, SmartAlbumNapiAsyncContext *context)
806 {
807     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
808     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
809     jsContext->status = false;
810 
811     if (context->error == ERR_DEFAULT) {
812         napi_create_int32(env, context->changedRows, &jsContext->data);
813         napi_get_undefined(env, &jsContext->error);
814         jsContext->status = true;
815     } else {
816         context->HandleError(env, jsContext->error);
817         napi_get_undefined(env, &jsContext->data);
818         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error,  context->error,
819                                                      "Failed to remove smartalbum asset");
820     }
821 
822     if (context->work != nullptr) {
823         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
824                                                    context->work, *jsContext);
825     }
826     delete context;
827 }
828 
ConvertCommitJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],SmartAlbumNapiAsyncContext & asyncContext)829 static napi_value ConvertCommitJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
830     SmartAlbumNapiAsyncContext &asyncContext)
831 {
832     const int32_t refCount = 1;
833     napi_value result;
834     auto context = &asyncContext;
835 
836     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
837 
838     for (size_t i = PARAM0; i < argc; i++) {
839         napi_valuetype valueType = napi_undefined;
840         napi_typeof(env, argv[i], &valueType);
841         if (i == PARAM0 && valueType == napi_function) {
842             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
843         } else {
844             NAPI_ASSERT(env, false, "type mismatch");
845         }
846     }
847 
848     // Return true napi_value if params are successfully obtained
849     napi_get_boolean(env, true, &result);
850     return result;
851 }
852 
GetAssetIds(napi_env env,napi_value param,SmartAlbumNapiAsyncContext & context)853 static napi_value GetAssetIds(napi_env env, napi_value param, SmartAlbumNapiAsyncContext &context)
854 {
855     uint32_t arraySize = 0;
856     if (!MediaLibraryNapiUtils::IsArrayForNapiValue(env, param, arraySize)) {
857         NAPI_ERR_LOG("GetAssetIds get args fail, not array");
858         return nullptr;
859     }
860     string uri = "";
861     for (uint32_t i = 0; i < arraySize; i++) {
862         napi_value jsValue = nullptr;
863         int32_t result;
864         if ((napi_get_element(env, param, i, &jsValue)) != napi_ok) {
865             NAPI_ERR_LOG("GetAssetIds get args fail");
866             return nullptr;
867         }
868         if (napi_get_value_int32(env, jsValue, &result) != napi_ok) {
869             NAPI_ERR_LOG("Get ids value fail");
870             return nullptr;
871         } else {
872             if (result < 0) {
873                 NAPI_ERR_LOG("GetAssetIds < 0 is invalid , id = %{public}d", result);
874                 return nullptr;
875             }
876             context.assetIds.push_back(result);
877         }
878     }
879     napi_value res;
880     napi_get_undefined(env, &res);
881     return res;
882 }
883 
GetJSArgsForAsset(napi_env env,size_t argc,const napi_value argv[],SmartAlbumNapiAsyncContext & asyncContext)884 napi_value GetJSArgsForAsset(napi_env env, size_t argc,
885                              const napi_value argv[],
886                              SmartAlbumNapiAsyncContext &asyncContext)
887 {
888     const int32_t refCount = 1;
889     napi_value result = nullptr;
890     auto context = &asyncContext;
891 
892     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
893 
894     for (size_t i = PARAM0; i < argc; i++) {
895         napi_valuetype valueType = napi_undefined;
896         napi_typeof(env, argv[i], &valueType);
897         if (i == PARAM0) {
898             napi_value res = GetAssetIds(env, argv[PARAM0], asyncContext);
899             if (res == nullptr) {
900                 napi_throw_error(env, std::to_string(ERR_INVALID_OUTPUT).c_str(), "Failed to obtain arguments ids");
901                 return nullptr;
902             }
903         } else if (i == PARAM1 && valueType == napi_function) {
904             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
905             break;
906         } else {
907             NAPI_ASSERT(env, false, "type mismatch");
908         }
909     }
910     // Return true napi_value if params are successfully obtained
911     napi_get_boolean(env, true, &result);
912     return result;
913 }
914 
JSAddFileAssets(napi_env env,napi_callback_info info)915 napi_value SmartAlbumNapi::JSAddFileAssets(napi_env env, napi_callback_info info)
916 {
917     napi_status status;
918     napi_value result = nullptr;
919     size_t argc = ARGS_TWO;
920     napi_value argv[ARGS_TWO] = {0};
921     napi_value thisVar = nullptr;
922     napi_value resource = nullptr;
923     GET_JS_ARGS(env, info, argc, argv, thisVar);
924     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameter maximum");
925     napi_get_undefined(env, &result);
926     std::unique_ptr<SmartAlbumNapiAsyncContext> asyncContext = std::make_unique<SmartAlbumNapiAsyncContext>();
927 
928     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
929     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
930         result = GetJSArgsForAsset(env, argc, argv, *asyncContext);
931         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "JSAddFileAssets fail");
932         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
933         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSAddFileAssets", asyncContext);
934 
935         asyncContext->objectPtr = asyncContext->objectInfo->smartAlbumAssetPtr;
936         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "SmartAlbumAsset is nullptr");
937 
938         status = napi_create_async_work(
939             env, nullptr, resource, [](napi_env env, void *data) {
940                 auto context = static_cast<SmartAlbumNapiAsyncContext*>(data);
941                 JSAddAssetExecute(context);
942             },
943             reinterpret_cast<CompleteCallback>(JSAddAssetCompleteCallback),
944             static_cast<void *>(asyncContext.get()), &asyncContext->work);
945         if (status != napi_ok) {
946             napi_get_undefined(env, &result);
947         } else {
948             napi_queue_async_work(env, asyncContext->work);
949             asyncContext.release();
950         }
951     }
952 
953     return result;
954 }
955 
JSRemoveFileAssets(napi_env env,napi_callback_info info)956 napi_value SmartAlbumNapi::JSRemoveFileAssets(napi_env env, napi_callback_info info)
957 {
958     napi_status status;
959     napi_value result = nullptr;
960     size_t argc = ARGS_TWO;
961     napi_value argv[ARGS_TWO] = {0};
962     napi_value thisVar = nullptr;
963     napi_value resource = nullptr;
964     GET_JS_ARGS(env, info, argc, argv, thisVar);
965     NAPI_ASSERT(env, (argc == ARGS_ONE || argc == ARGS_TWO), "requires 2 parameter maximum");
966     napi_get_undefined(env, &result);
967     std::unique_ptr<SmartAlbumNapiAsyncContext> asyncContext = std::make_unique<SmartAlbumNapiAsyncContext>();
968 
969     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
970     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
971         result = GetJSArgsForAsset(env, argc, argv, *asyncContext);
972         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "JSRemoveFileAssets fail ");
973 
974         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
975         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSRemoveFileAssets", asyncContext);
976 
977         asyncContext->objectPtr = asyncContext->objectInfo->smartAlbumAssetPtr;
978         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "SmartAlbumAsset is nullptr");
979 
980         status = napi_create_async_work(
981             env, nullptr, resource, [](napi_env env, void *data) {
982                 auto context = static_cast<SmartAlbumNapiAsyncContext*>(data);
983                 JSRemoveAssetExecute(context);
984             },
985             reinterpret_cast<CompleteCallback>(JSRemoveAssetCompleteCallback),
986             static_cast<void *>(asyncContext.get()), &asyncContext->work);
987         if (status != napi_ok) {
988             napi_get_undefined(env, &result);
989         } else {
990             napi_queue_async_work(env, asyncContext->work);
991             asyncContext.release();
992         }
993     }
994 
995     return result;
996 }
997 
JSCommitModify(napi_env env,napi_callback_info info)998 napi_value SmartAlbumNapi::JSCommitModify(napi_env env, napi_callback_info info)
999 {
1000     napi_status status;
1001     napi_value result = nullptr;
1002     size_t argc = ARGS_ONE;
1003     napi_value argv[ARGS_ONE] = {0};
1004     napi_value thisVar = nullptr;
1005     napi_value resource = nullptr;
1006     GET_JS_ARGS(env, info, argc, argv, thisVar);
1007     NAPI_ASSERT(env, (argc == ARGS_ZERO || argc == ARGS_ONE), "requires 1 parameter maximum");
1008     napi_get_undefined(env, &result);
1009     std::unique_ptr<SmartAlbumNapiAsyncContext> asyncContext = std::make_unique<SmartAlbumNapiAsyncContext>();
1010 
1011     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1012     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1013         result = ConvertCommitJSArgsToNative(env, argc, argv, *asyncContext);
1014         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "JSCommitModify fail ");
1015 
1016         NAPI_CREATE_PROMISE(env, asyncContext->callbackRef, asyncContext->deferred, result);
1017         NAPI_CREATE_RESOURCE_NAME(env, resource, "JSCommitModify", asyncContext);
1018 
1019         asyncContext->objectPtr = asyncContext->objectInfo->smartAlbumAssetPtr;
1020         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "SmartAlbumAsset is nullptr");
1021 
1022         status = napi_create_async_work(
1023             env, nullptr, resource, [](napi_env env, void *data) {
1024                 auto context = static_cast<SmartAlbumNapiAsyncContext*>(data);
1025                 CommitModifyNative(*context);
1026             },
1027             reinterpret_cast<CompleteCallback>(JSCommitModifyCompleteCallback),
1028             static_cast<void *>(asyncContext.get()), &asyncContext->work);
1029         if (status != napi_ok) {
1030             napi_get_undefined(env, &result);
1031         } else {
1032             napi_queue_async_work(env, asyncContext->work);
1033             asyncContext.release();
1034         }
1035     }
1036 
1037     return result;
1038 }
1039 
GetFetchOptionsParam(napi_env env,napi_value arg,const SmartAlbumNapiAsyncContext & context,bool & err)1040 static void GetFetchOptionsParam(napi_env env, napi_value arg, const SmartAlbumNapiAsyncContext &context, bool &err)
1041 {
1042     SmartAlbumNapiAsyncContext *asyncContext = const_cast<SmartAlbumNapiAsyncContext *>(&context);
1043     CHECK_NULL_PTR_RETURN_VOID(asyncContext, "Async context is null");
1044     char buffer[PATH_MAX];
1045     size_t res;
1046     uint32_t len = 0;
1047     napi_value property = nullptr;
1048     napi_value stringItem = nullptr;
1049     bool present = false;
1050     bool boolResult = false;
1051 
1052     string propertyName = "selections";
1053     string tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
1054     if (!tmp.empty()) {
1055         asyncContext->selection = tmp;
1056     }
1057 
1058     propertyName = "order";
1059     tmp = MediaLibraryNapiUtils::GetStringFetchProperty(env, arg, err, present, propertyName);
1060     if (!tmp.empty()) {
1061         asyncContext->order = tmp;
1062     }
1063 
1064     napi_has_named_property(env, arg, "selectionArgs", &present);
1065     if (present && napi_get_named_property(env, arg, "selectionArgs", &property) == napi_ok &&
1066         napi_is_array(env, property, &boolResult) == napi_ok && boolResult) {
1067         napi_get_array_length(env, property, &len);
1068         for (size_t i = 0; i < len; i++) {
1069             napi_get_element(env, property, i, &stringItem);
1070             napi_get_value_string_utf8(env, stringItem, buffer, PATH_MAX, &res);
1071             asyncContext->selectionArgs.push_back(std::string(buffer));
1072             CHECK_IF_EQUAL(memset_s(buffer, PATH_MAX, 0, sizeof(buffer)) == 0, "Memset for buffer failed");
1073         }
1074     } else {
1075         NAPI_ERR_LOG("Could not get the string argument!");
1076         err = true;
1077     }
1078 }
1079 
ConvertJSArgsToNative(napi_env env,size_t argc,const napi_value argv[],SmartAlbumNapiAsyncContext & asyncContext)1080 static napi_value ConvertJSArgsToNative(napi_env env, size_t argc, const napi_value argv[],
1081     SmartAlbumNapiAsyncContext &asyncContext)
1082 {
1083     string str = "";
1084     std::vector<string> strArr;
1085     string order = "";
1086     bool err = false;
1087     const int32_t refCount = 1;
1088     napi_value result;
1089     auto context = &asyncContext;
1090 
1091     NAPI_ASSERT(env, argv != nullptr, "Argument list is empty");
1092 
1093     for (size_t i = PARAM0; i < argc; i++) {
1094         napi_valuetype valueType = napi_undefined;
1095         napi_typeof(env, argv[i], &valueType);
1096 
1097         if (i == PARAM0 && valueType == napi_object) {
1098             GetFetchOptionsParam(env, argv[PARAM0], asyncContext, err);
1099             if (err) {
1100                 NAPI_ASSERT(env, false, "type mismatch");
1101             }
1102         } else if (i == PARAM0 && valueType == napi_function) {
1103             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1104             break;
1105         } else if (i == PARAM1 && valueType == napi_function) {
1106             napi_create_reference(env, argv[i], refCount, &context->callbackRef);
1107             break;
1108         } else {
1109             NAPI_ASSERT(env, false, "type mismatch");
1110         }
1111     }
1112 
1113     // Return true napi_value if params are successfully obtained
1114     napi_get_boolean(env, true, &result);
1115     return result;
1116 }
1117 
UpdateSelection(SmartAlbumNapiAsyncContext * context)1118 static void UpdateSelection(SmartAlbumNapiAsyncContext *context)
1119 {
1120     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1121         context->predicates.EqualTo(SMARTALBUMMAP_DB_ALBUM_ID, context->objectPtr->GetAlbumId());
1122         context->predicates.EqualTo(MEDIA_DATA_DB_TIME_PENDING, to_string(0));
1123         if (context->objectPtr->GetAlbumId() == TRASH_ALBUM_ID_VALUES) {
1124             context->predicates.NotEqualTo(MEDIA_DATA_DB_DATE_TRASHED, "0");
1125         } else {
1126             context->predicates.EqualTo(MEDIA_DATA_DB_DATE_TRASHED, "0");
1127         }
1128         MediaLibraryNapiUtils::UpdateMediaTypeSelections(context);
1129     } else {
1130         string trashPrefix;
1131         if (context->objectPtr->GetAlbumId() == TRASH_ALBUM_ID_VALUES) {
1132             trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " <> ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
1133         } else {
1134             trashPrefix = MEDIA_DATA_DB_DATE_TRASHED + " = ? AND " + SMARTALBUMMAP_DB_ALBUM_ID + " = ? ";
1135         }
1136         MediaLibraryNapiUtils::AppendFetchOptionSelection(context->selection, trashPrefix);
1137         context->selectionArgs.emplace_back("0");
1138         context->selectionArgs.emplace_back(std::to_string(context->objectPtr->GetAlbumId()));
1139         MediaLibraryNapi::ReplaceSelection(context->selection, context->selectionArgs,
1140             MEDIA_DATA_DB_RELATIVE_PATH, MEDIA_DATA_DB_RELATIVE_PATH, ReplaceSelectionMode::ADD_DOCS_TO_RELATIVE_PATH);
1141     }
1142 }
1143 
GetFileAssetsNative(napi_env env,void * data)1144 static void GetFileAssetsNative(napi_env env, void *data)
1145 {
1146     MediaLibraryTracer tracer;
1147     tracer.Start("GetFileAssetsNative");
1148 
1149     auto context = static_cast<SmartAlbumNapiAsyncContext *>(data);
1150     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1151 
1152     UpdateSelection(context);
1153     MediaLibraryNapiUtils::FixSpecialDateType(context->selection);
1154     context->predicates.SetWhereClause(context->selection);
1155     context->predicates.SetWhereArgs(context->selectionArgs);
1156     context->predicates.SetOrder(context->order);
1157 
1158     if (context->resultNapiType == ResultNapiType::TYPE_MEDIALIBRARY) {
1159         context->fetchColumn = FILE_ASSET_COLUMNS;
1160     } else {
1161         context->fetchColumn.push_back(MEDIA_DATA_DB_ID);
1162         context->fetchColumn.push_back(MEDIA_DATA_DB_NAME);
1163         context->fetchColumn.push_back(MEDIA_DATA_DB_MEDIA_TYPE);
1164     }
1165 
1166     string queryUri = MEDIALIBRARY_DATA_ABILITY_PREFIX +
1167         (MediaFileUtils::GetNetworkIdFromUri(context->objectPtr->GetAlbumUri())) +
1168         MEDIALIBRARY_DATA_URI_IDENTIFIER + "/" + MEDIA_ALBUMOPRN_QUERYALBUM + "/" + ASSETMAP_VIEW_NAME;
1169     Uri uri(queryUri);
1170     int errCode = 0;
1171     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
1172     if (resultSet == nullptr) {
1173         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
1174         return;
1175     }
1176     context->fetchResult = std::make_unique<FetchResult<FileAsset>>(move(resultSet));
1177     context->fetchResult->SetNetworkId(
1178         MediaFileUtils::GetNetworkIdFromUri(context->objectPtr->GetAlbumUri()));
1179     if (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) {
1180         context->fetchResult->SetResultNapiType(context->resultNapiType);
1181     }
1182 }
1183 
JSGetFileAssetsCompleteCallback(napi_env env,napi_status status,void * data)1184 static void JSGetFileAssetsCompleteCallback(napi_env env, napi_status status, void *data)
1185 {
1186     MediaLibraryTracer tracer;
1187     tracer.Start("JSGetFileAssetsCompleteCallback");
1188 
1189     auto context = static_cast<SmartAlbumNapiAsyncContext *>(data);
1190     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1191 
1192     std::unique_ptr<JSAsyncContextOutput> jsContext = std::make_unique<JSAsyncContextOutput>();
1193     jsContext->status = false;
1194 
1195     if (context->fetchResult != nullptr) {
1196         if (context->fetchResult->GetCount() < 0) {
1197             napi_get_undefined(env, &jsContext->data);
1198             MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1199                 "Find no data by options");
1200         } else {
1201             napi_value fetchRes = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchResult));
1202             if (fetchRes == nullptr) {
1203                 NAPI_ERR_LOG("Failed to get file asset napi object");
1204                 napi_get_undefined(env, &jsContext->data);
1205                 MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1206                     "Failed to create js object for FetchFileResult");
1207             } else {
1208                 jsContext->data = fetchRes;
1209                 napi_get_undefined(env, &jsContext->error);
1210                 jsContext->status = true;
1211             }
1212         }
1213     } else {
1214         NAPI_ERR_LOG("No fetch file result found!");
1215         napi_get_undefined(env, &jsContext->data);
1216         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1217                                                      "Failed to get fetchFileResult from DB");
1218     }
1219 
1220     tracer.Finish();
1221     if (context->work != nullptr) {
1222         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1223                                                    context->work, *jsContext);
1224     }
1225     delete context;
1226 }
1227 
JSGetSmartAlbumFileAssets(napi_env env,napi_callback_info info)1228 napi_value SmartAlbumNapi::JSGetSmartAlbumFileAssets(napi_env env, napi_callback_info info)
1229 {
1230     napi_status status;
1231     napi_value result = nullptr;
1232     constexpr int maxArgs = 2;
1233     size_t argc = maxArgs;
1234     napi_value argv[maxArgs] = {0};
1235     napi_value thisVar = nullptr;
1236 
1237     GET_JS_ARGS(env, info, argc, argv, thisVar);
1238     NAPI_ASSERT(env, ((argc == ARGS_ZERO) || (argc == ARGS_ONE) || (argc == ARGS_TWO)),
1239                 "requires 2 parameter maximum");
1240 
1241     napi_get_undefined(env, &result);
1242     std::unique_ptr<SmartAlbumNapiAsyncContext> asyncContext = std::make_unique<SmartAlbumNapiAsyncContext>();
1243     status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&asyncContext->objectInfo));
1244     asyncContext->resultNapiType = ResultNapiType::TYPE_MEDIALIBRARY;
1245     if (status == napi_ok && asyncContext->objectInfo != nullptr) {
1246         result = ConvertJSArgsToNative(env, argc, argv, *asyncContext);
1247         CHECK_NULL_PTR_RETURN_UNDEFINED(env, result, result, "Failed to obtain arguments");
1248 
1249         asyncContext->objectPtr = asyncContext->objectInfo->smartAlbumAssetPtr;
1250         CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, result, "SmartAlbumAsset is nullptr");
1251 
1252         result = MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetSmartAlbumFileAssets",
1253             GetFileAssetsNative, JSGetFileAssetsCompleteCallback);
1254     }
1255 
1256     return result;
1257 }
1258 
UserFileMgrGetAssets(napi_env env,napi_callback_info info)1259 napi_value SmartAlbumNapi::UserFileMgrGetAssets(napi_env env, napi_callback_info info)
1260 {
1261     napi_value ret = nullptr;
1262     unique_ptr<SmartAlbumNapiAsyncContext> asyncContext = make_unique<SmartAlbumNapiAsyncContext>();
1263     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "AsyncContext context is null");
1264 
1265     asyncContext->mediaTypes.push_back(MEDIA_TYPE_IMAGE);
1266     asyncContext->mediaTypes.push_back(MEDIA_TYPE_VIDEO);
1267     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseAssetFetchOptCallback(env, info, asyncContext),
1268         JS_ERR_PARAMETER_INVALID);
1269     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1270 
1271     asyncContext->objectPtr = asyncContext->objectInfo->smartAlbumAssetPtr;
1272     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "SmartAlbumAsset is nullptr");
1273 
1274     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrGetAssets", GetFileAssetsNative,
1275         JSGetFileAssetsCompleteCallback);
1276 }
1277 
JSRecoverAssetExecute(napi_env env,void * data)1278 static void JSRecoverAssetExecute(napi_env env, void *data)
1279 {
1280     MediaLibraryTracer tracer;
1281     tracer.Start("JSRecoverAssetExecute");
1282 
1283     auto context = static_cast<SmartAlbumNapiAsyncContext *>(data);
1284     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1285 
1286     string recoverUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_SMARTALBUMMAPOPRN + "/" +
1287         MEDIA_SMARTALBUMMAPOPRN_REMOVESMARTALBUM;
1288     Uri recoverAssetUri(recoverUri);
1289     DataShare::DataShareValuesBucket valuesBucket;
1290     valuesBucket.Put(SMARTALBUMMAP_DB_ALBUM_ID, context->objectPtr->GetAlbumId());
1291     valuesBucket.Put(SMARTALBUMMAP_DB_CHILD_ASSET_ID, stoi(MediaLibraryNapiUtils::GetFileIdFromUri(context->uri)));
1292     int retVal = UserFileClient::Insert(recoverAssetUri, valuesBucket);
1293     context->SaveError(retVal);
1294 }
1295 
JSRecoverAssetCompleteCallback(napi_env env,napi_status status,void * data)1296 static void JSRecoverAssetCompleteCallback(napi_env env, napi_status status, void *data)
1297 {
1298     MediaLibraryTracer tracer;
1299     tracer.Start("JSRecoverAssetCompleteCallback");
1300 
1301     SmartAlbumNapiAsyncContext *context = static_cast<SmartAlbumNapiAsyncContext*>(data);
1302     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1303     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1304     CHECK_NULL_PTR_RETURN_VOID(jsContext, "jsContext context is null");
1305     jsContext->status = false;
1306     napi_get_undefined(env, &jsContext->data);
1307     if (context->error == ERR_DEFAULT) {
1308         jsContext->status = true;
1309         Media::MediaType mediaType = MediaLibraryNapiUtils::GetMediaTypeFromUri(context->uri);
1310         string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
1311         Uri modifyNotify(notifyUri);
1312         UserFileClient::NotifyChange(modifyNotify);
1313     } else {
1314         context->HandleError(env, jsContext->error);
1315     }
1316     if (context->work != nullptr) {
1317         tracer.Finish();
1318         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1319             context->work, *jsContext);
1320     }
1321 
1322     delete context;
1323 }
1324 
UserFileMgrRecoverAsset(napi_env env,napi_callback_info info)1325 napi_value SmartAlbumNapi::UserFileMgrRecoverAsset(napi_env env, napi_callback_info info)
1326 {
1327     napi_value ret = nullptr;
1328     unique_ptr<SmartAlbumNapiAsyncContext> asyncContext = make_unique<SmartAlbumNapiAsyncContext>();
1329     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "AsyncContext context is null");
1330 
1331     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->uri),
1332         JS_ERR_PARAMETER_INVALID);
1333     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1334     asyncContext->objectPtr = asyncContext->objectInfo->smartAlbumAssetPtr;
1335     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext->objectPtr, ret, "SmartAlbumAsset is nullptr");
1336 
1337     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrRecoverAsset",
1338         JSRecoverAssetExecute, JSRecoverAssetCompleteCallback);
1339 }
1340 
JSDeleteAssetExecute(napi_env env,void * data)1341 static void JSDeleteAssetExecute(napi_env env, void *data)
1342 {
1343     MediaLibraryTracer tracer;
1344     tracer.Start("JSDeleteAssetExecute");
1345 
1346     auto context = static_cast<SmartAlbumNapiAsyncContext *>(data);
1347     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1348 
1349     string deleteUri = MEDIALIBRARY_DATA_URI + "/" + MEDIA_FILEOPRN + "/" + MEDIA_FILEOPRN_DELETEASSET;
1350     Uri deleteAssetUri(deleteUri);
1351     DataShare::DataSharePredicates predicates;
1352     predicates.EqualTo(MEDIA_DATA_DB_ID, MediaLibraryNapiUtils::GetFileIdFromUri(context->uri));
1353     int retVal = UserFileClient::Delete(deleteAssetUri, {});
1354     context->SaveError(retVal);
1355 }
1356 
JSDeleteAssetCompleteCallback(napi_env env,napi_status status,void * data)1357 static void JSDeleteAssetCompleteCallback(napi_env env, napi_status status, void *data)
1358 {
1359     MediaLibraryTracer tracer;
1360     tracer.Start("JSDeleteAssetCompleteCallback");
1361 
1362     SmartAlbumNapiAsyncContext *context = static_cast<SmartAlbumNapiAsyncContext*>(data);
1363     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1364     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1365     CHECK_NULL_PTR_RETURN_VOID(jsContext, "JsContext context is null");
1366     jsContext->status = false;
1367     napi_get_undefined(env, &jsContext->data);
1368     if (context->error == ERR_DEFAULT) {
1369         jsContext->status = true;
1370         Media::MediaType mediaType = MediaLibraryNapiUtils::GetMediaTypeFromUri(context->uri);
1371         string notifyUri = MediaFileUtils::GetMediaTypeUri(mediaType);
1372         Uri modifyNotify(notifyUri);
1373         UserFileClient::NotifyChange(modifyNotify);
1374     } else {
1375         context->HandleError(env, jsContext->error);
1376     }
1377     if (context->work != nullptr) {
1378         tracer.Finish();
1379         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1380             context->work, *jsContext);
1381     }
1382 
1383     delete context;
1384 }
1385 
UserFileMgrDeleteAsset(napi_env env,napi_callback_info info)1386 napi_value SmartAlbumNapi::UserFileMgrDeleteAsset(napi_env env, napi_callback_info info)
1387 {
1388     napi_value ret = nullptr;
1389     unique_ptr<SmartAlbumNapiAsyncContext> asyncContext = make_unique<SmartAlbumNapiAsyncContext>();
1390     CHECK_NULL_PTR_RETURN_UNDEFINED(env, asyncContext, ret, "AsyncContext context is null");
1391 
1392     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, asyncContext, asyncContext->uri),
1393         JS_ERR_PARAMETER_INVALID);
1394     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1395 
1396     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "UserFileMgrDeleteAsset", JSDeleteAssetExecute,
1397         JSDeleteAssetCompleteCallback);
1398 }
1399 } // namespace Media
1400 } // namespace OHOS
1401