1 /*
2  * Copyright (C) 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 #define MLOG_TAG "PhotoAlbumNapi"
16 
17 #include "photo_album_napi.h"
18 #include <nlohmann/json.hpp>
19 
20 #include "fetch_file_result_napi.h"
21 #include "file_asset_napi.h"
22 #include "media_file_utils.h"
23 #include "medialibrary_client_errno.h"
24 #include "medialibrary_napi_log.h"
25 #include "medialibrary_tracer.h"
26 #include "photo_map_column.h"
27 #include "result_set_utils.h"
28 #include "userfile_client.h"
29 
30 using namespace std;
31 using namespace OHOS::DataShare;
32 
33 namespace OHOS::Media {
34 thread_local PhotoAlbum *PhotoAlbumNapi::pAlbumData_ = nullptr;
35 thread_local napi_ref PhotoAlbumNapi::constructor_ = nullptr;
36 thread_local napi_ref PhotoAlbumNapi::photoAccessConstructor_ = nullptr;
37 static const string PHOTO_ALBUM_CLASS = "UserFileMgrPhotoAlbum";
38 static const string PHOTOACCESS_PHOTO_ALBUM_CLASS = "PhotoAccessPhotoAlbum";
39 static const string COUNT_GROUP_BY = "count(*) AS count";
40 
41 struct TrashAlbumExecuteOpt {
42     napi_env env;
43     void *data;
44     string tracerLabel;
45     string uri;
46 };
47 
48 using CompleteCallback = napi_async_complete_callback;
49 
PhotoAlbumNapi()50 PhotoAlbumNapi::PhotoAlbumNapi() : env_(nullptr) {}
51 
52 PhotoAlbumNapi::~PhotoAlbumNapi() = default;
53 
Init(napi_env env,napi_value exports)54 napi_value PhotoAlbumNapi::Init(napi_env env, napi_value exports)
55 {
56     NapiClassInfo info = {
57         .name = PHOTO_ALBUM_CLASS,
58         .ref = &constructor_,
59         .constructor = PhotoAlbumNapiConstructor,
60         .props = {
61             DECLARE_NAPI_GETTER_SETTER("albumName", JSGetAlbumName, JSSetAlbumName),
62             DECLARE_NAPI_GETTER("albumUri", JSGetAlbumUri),
63             DECLARE_NAPI_GETTER("count", JSGetAlbumCount),
64             DECLARE_NAPI_GETTER("albumType", JSGetPhotoAlbumType),
65             DECLARE_NAPI_GETTER("albumSubType", JSGetPhotoAlbumSubType),
66             DECLARE_NAPI_GETTER_SETTER("coverUri", JSGetCoverUri, JSSetCoverUri),
67             DECLARE_NAPI_GETTER("dateModified", JSGetDateModified),
68             DECLARE_NAPI_FUNCTION("commitModify", JSCommitModify),
69             DECLARE_NAPI_FUNCTION("addPhotoAssets", JSPhotoAlbumAddAssets),
70             DECLARE_NAPI_FUNCTION("removePhotoAssets", JSPhotoAlbumRemoveAssets),
71             DECLARE_NAPI_FUNCTION("getPhotoAssets", JSGetPhotoAssets),
72             DECLARE_NAPI_FUNCTION("recoverPhotoAssets", JSRecoverPhotos),
73             DECLARE_NAPI_FUNCTION("deletePhotoAssets", JSDeletePhotos),
74             // PrivateAlbum.recover
75             DECLARE_NAPI_FUNCTION("recover", PrivateAlbumRecoverPhotos),
76             // PrivateAlbum.delete
77             DECLARE_NAPI_FUNCTION("delete", PrivateAlbumDeletePhotos),
78         }
79     };
80 
81     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
82     return exports;
83 }
84 
PhotoAccessInit(napi_env env,napi_value exports)85 napi_value PhotoAlbumNapi::PhotoAccessInit(napi_env env, napi_value exports)
86 {
87     NapiClassInfo info = {
88         .name = PHOTOACCESS_PHOTO_ALBUM_CLASS,
89         .ref = &photoAccessConstructor_,
90         .constructor = PhotoAlbumNapiConstructor,
91         .props = {
92             DECLARE_NAPI_GETTER_SETTER("albumName", JSPhotoAccessGetAlbumName, JSPhotoAccessSetAlbumName),
93             DECLARE_NAPI_GETTER("albumUri", JSPhotoAccessGetAlbumUri),
94             DECLARE_NAPI_GETTER("count", JSPhotoAccessGetAlbumCount),
95             DECLARE_NAPI_GETTER("imageCount", JSPhotoAccessGetAlbumImageCount),
96             DECLARE_NAPI_GETTER("videoCount", JSPhotoAccessGetAlbumVideoCount),
97             DECLARE_NAPI_GETTER("albumType", JSGetPhotoAlbumType),
98             DECLARE_NAPI_GETTER("albumSubtype", JSGetPhotoAlbumSubType),
99             DECLARE_NAPI_GETTER("coverUri", JSGetCoverUri),
100             DECLARE_NAPI_GETTER("latitude", JSGetLatitude),
101             DECLARE_NAPI_GETTER("longitude", JSGetLongitude),
102             DECLARE_NAPI_FUNCTION("commitModify", PhotoAccessHelperCommitModify),
103             DECLARE_NAPI_FUNCTION("addAssets", PhotoAccessHelperAddAssets),
104             DECLARE_NAPI_FUNCTION("removeAssets", PhotoAccessHelperRemoveAssets),
105             DECLARE_NAPI_FUNCTION("getAssets", JSPhotoAccessGetPhotoAssets),
106             DECLARE_NAPI_FUNCTION("recoverAssets", PhotoAccessHelperRecoverPhotos),
107             DECLARE_NAPI_FUNCTION("deleteAssets", PhotoAccessHelperDeletePhotos),
108             DECLARE_NAPI_FUNCTION("setCoverUri", PhotoAccessHelperSetCoverUri),
109             DECLARE_NAPI_FUNCTION("getAssetsSync", JSPhotoAccessGetPhotoAssetsSync),
110             DECLARE_NAPI_FUNCTION("getSharedPhotoAssets", JSPhotoAccessGetSharedPhotoAssets),
111             DECLARE_NAPI_FUNCTION("getFaceId", PhotoAccessHelperGetFaceId),
112         }
113     };
114 
115     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
116     return exports;
117 }
118 
CreatePhotoAlbumNapi(napi_env env,unique_ptr<PhotoAlbum> & albumData)119 napi_value PhotoAlbumNapi::CreatePhotoAlbumNapi(napi_env env, unique_ptr<PhotoAlbum> &albumData)
120 {
121     if (albumData == nullptr) {
122         return nullptr;
123     }
124 
125     napi_value constructor;
126     napi_ref constructorRef;
127     if (albumData->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
128         constructorRef = photoAccessConstructor_;
129     } else {
130         constructorRef = constructor_;
131     }
132     CHECK_ARGS(env, napi_get_reference_value(env, constructorRef, &constructor), JS_INNER_FAIL);
133 
134     napi_value result = nullptr;
135     pAlbumData_ = albumData.release();
136     CHECK_ARGS(env, napi_new_instance(env, constructor, 0, nullptr, &result), JS_INNER_FAIL);
137     pAlbumData_ = nullptr;
138     return result;
139 }
140 
CreatePhotoAlbumNapi(napi_env env,shared_ptr<PhotoAlbum> & albumData)141 napi_value PhotoAlbumNapi::CreatePhotoAlbumNapi(napi_env env, shared_ptr<PhotoAlbum>& albumData)
142 {
143     if (albumData == nullptr || albumData->GetResultNapiType() != ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
144         NAPI_ERR_LOG("Unsupported photo album data");
145         return nullptr;
146     }
147 
148     napi_value constructor = nullptr;
149     napi_value result = nullptr;
150     CHECK_ARGS(env, napi_get_reference_value(env, photoAccessConstructor_, &constructor), JS_INNER_FAIL);
151     CHECK_ARGS(env, napi_new_instance(env, constructor, 0, nullptr, &result), JS_INNER_FAIL);
152     CHECK_COND(env, result != nullptr, JS_INNER_FAIL);
153 
154     PhotoAlbumNapi* photoAlbumNapi = nullptr;
155     CHECK_ARGS(env, napi_unwrap(env, result, reinterpret_cast<void**>(&photoAlbumNapi)), JS_INNER_FAIL);
156     CHECK_COND(env, photoAlbumNapi != nullptr, JS_INNER_FAIL);
157     photoAlbumNapi->photoAlbumPtr = albumData;
158     return result;
159 }
160 
GetAlbumId() const161 int32_t PhotoAlbumNapi::GetAlbumId() const
162 {
163     return photoAlbumPtr->GetAlbumId();
164 }
165 
GetCount() const166 int32_t PhotoAlbumNapi::GetCount() const
167 {
168     return photoAlbumPtr->GetCount();
169 }
170 
SetCount(int32_t count)171 void PhotoAlbumNapi::SetCount(int32_t count)
172 {
173     return photoAlbumPtr->SetCount(count);
174 }
175 
GetImageCount() const176 int32_t PhotoAlbumNapi::GetImageCount() const
177 {
178     return photoAlbumPtr->GetImageCount();
179 }
180 
SetImageCount(int32_t count)181 void PhotoAlbumNapi::SetImageCount(int32_t count)
182 {
183     return photoAlbumPtr->SetImageCount(count);
184 }
185 
GetVideoCount() const186 int32_t PhotoAlbumNapi::GetVideoCount() const
187 {
188     return photoAlbumPtr->GetVideoCount();
189 }
190 
SetVideoCount(int32_t count)191 void PhotoAlbumNapi::SetVideoCount(int32_t count)
192 {
193     return photoAlbumPtr->SetVideoCount(count);
194 }
195 
GetAlbumUri() const196 const string& PhotoAlbumNapi::GetAlbumUri() const
197 {
198     return photoAlbumPtr->GetAlbumUri();
199 }
200 
GetCoverUri() const201 const string& PhotoAlbumNapi::GetCoverUri() const
202 {
203     return photoAlbumPtr->GetCoverUri();
204 }
205 
GetDateModified() const206 int64_t PhotoAlbumNapi::GetDateModified() const
207 {
208     return photoAlbumPtr->GetDateModified();
209 }
210 
GetAlbumName() const211 const string& PhotoAlbumNapi::GetAlbumName() const
212 {
213     return photoAlbumPtr->GetAlbumName();
214 }
215 
GetPhotoAlbumType() const216 PhotoAlbumType PhotoAlbumNapi::GetPhotoAlbumType() const
217 {
218     return photoAlbumPtr->GetPhotoAlbumType();
219 }
220 
GetPhotoAlbumSubType() const221 PhotoAlbumSubType PhotoAlbumNapi::GetPhotoAlbumSubType() const
222 {
223     return photoAlbumPtr->GetPhotoAlbumSubType();
224 }
225 
GetLatitude() const226 double PhotoAlbumNapi::GetLatitude() const
227 {
228     return photoAlbumPtr->GetLatitude();
229 }
230 
GetLongitude() const231 double PhotoAlbumNapi::GetLongitude() const
232 {
233     return photoAlbumPtr->GetLongitude();
234 }
235 
GetPhotoAlbumInstance() const236 shared_ptr<PhotoAlbum> PhotoAlbumNapi::GetPhotoAlbumInstance() const
237 {
238     return photoAlbumPtr;
239 }
240 
GetHiddenOnly() const241 bool PhotoAlbumNapi::GetHiddenOnly() const
242 {
243     return photoAlbumPtr->GetHiddenOnly();
244 }
245 
SetHiddenOnly(const bool hiddenOnly_)246 void PhotoAlbumNapi::SetHiddenOnly(const bool hiddenOnly_)
247 {
248     return photoAlbumPtr->SetHiddenOnly(hiddenOnly_);
249 }
250 
SetPhotoAlbumNapiProperties()251 void PhotoAlbumNapi::SetPhotoAlbumNapiProperties()
252 {
253     photoAlbumPtr = shared_ptr<PhotoAlbum>(pAlbumData_);
254 }
255 
256 // Constructor callback
PhotoAlbumNapiConstructor(napi_env env,napi_callback_info info)257 napi_value PhotoAlbumNapi::PhotoAlbumNapiConstructor(napi_env env, napi_callback_info info)
258 {
259     napi_value result = nullptr;
260     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
261 
262     napi_value thisVar = nullptr;
263     CHECK_ARGS(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), JS_INNER_FAIL);
264     if (thisVar == nullptr) {
265         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
266         return result;
267     }
268 
269     unique_ptr<PhotoAlbumNapi> obj = make_unique<PhotoAlbumNapi>();
270     obj->env_ = env;
271     if (pAlbumData_ != nullptr) {
272         obj->SetPhotoAlbumNapiProperties();
273     }
274     CHECK_ARGS(env, napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
275         PhotoAlbumNapi::PhotoAlbumNapiDestructor, nullptr, nullptr), JS_INNER_FAIL);
276     obj.release();
277     return thisVar;
278 }
279 
PhotoAlbumNapiDestructor(napi_env env,void * nativeObject,void * finalizeHint)280 void PhotoAlbumNapi::PhotoAlbumNapiDestructor(napi_env env, void *nativeObject, void *finalizeHint)
281 {
282     auto *album = reinterpret_cast<PhotoAlbumNapi*>(nativeObject);
283     if (album != nullptr) {
284         delete album;
285         album = nullptr;
286     }
287 }
288 
UnwrapPhotoAlbumObject(napi_env env,napi_callback_info info,PhotoAlbumNapi ** obj)289 napi_value UnwrapPhotoAlbumObject(napi_env env, napi_callback_info info, PhotoAlbumNapi** obj)
290 {
291     napi_value result = nullptr;
292     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
293 
294     napi_value thisVar = nullptr;
295     CHECK_ARGS(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), JS_INNER_FAIL);
296     if (thisVar == nullptr) {
297         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
298         return result;
299     }
300 
301     CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void **>(obj)), JS_INNER_FAIL);
302     if (obj == nullptr) {
303         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
304         return result;
305     }
306 
307     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
308     return result;
309 }
310 
JSGetAlbumName(napi_env env,napi_callback_info info)311 napi_value PhotoAlbumNapi::JSGetAlbumName(napi_env env, napi_callback_info info)
312 {
313     PhotoAlbumNapi *obj = nullptr;
314     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
315 
316     napi_value jsResult = nullptr;
317     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumName().c_str(), NAPI_AUTO_LENGTH, &jsResult),
318         JS_INNER_FAIL);
319     return jsResult;
320 }
321 
JSPhotoAccessGetAlbumName(napi_env env,napi_callback_info info)322 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumName(napi_env env, napi_callback_info info)
323 {
324     PhotoAlbumNapi *obj = nullptr;
325     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
326 
327     napi_value jsResult = nullptr;
328     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumName().c_str(), NAPI_AUTO_LENGTH, &jsResult),
329         JS_INNER_FAIL);
330     return jsResult;
331 }
332 
JSGetAlbumUri(napi_env env,napi_callback_info info)333 napi_value PhotoAlbumNapi::JSGetAlbumUri(napi_env env, napi_callback_info info)
334 {
335     PhotoAlbumNapi *obj = nullptr;
336     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
337 
338     napi_value jsResult = nullptr;
339     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
340         JS_INNER_FAIL);
341     return jsResult;
342 }
343 
JSPhotoAccessGetAlbumUri(napi_env env,napi_callback_info info)344 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumUri(napi_env env, napi_callback_info info)
345 {
346     PhotoAlbumNapi *obj = nullptr;
347     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
348 
349     napi_value jsResult = nullptr;
350     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
351         JS_INNER_FAIL);
352     return jsResult;
353 }
354 
JSGetAlbumCount(napi_env env,napi_callback_info info)355 napi_value PhotoAlbumNapi::JSGetAlbumCount(napi_env env, napi_callback_info info)
356 {
357     PhotoAlbumNapi *obj = nullptr;
358     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
359 
360     napi_value jsResult = nullptr;
361     CHECK_ARGS(env, napi_create_int32(env, obj->GetCount(), &jsResult), JS_INNER_FAIL);
362     return jsResult;
363 }
364 
JSPhotoAccessGetAlbumCount(napi_env env,napi_callback_info info)365 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumCount(napi_env env, napi_callback_info info)
366 {
367     PhotoAlbumNapi *obj = nullptr;
368     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
369 
370     napi_value jsResult = nullptr;
371     CHECK_ARGS(env, napi_create_int32(env, obj->GetCount(), &jsResult), JS_INNER_FAIL);
372     return jsResult;
373 }
374 
JSPhotoAccessGetAlbumImageCount(napi_env env,napi_callback_info info)375 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumImageCount(napi_env env, napi_callback_info info)
376 {
377     PhotoAlbumNapi *obj = nullptr;
378     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
379 
380     napi_value jsResult = nullptr;
381     CHECK_ARGS(env, napi_create_int32(env, obj->GetImageCount(), &jsResult), JS_INNER_FAIL);
382     return jsResult;
383 }
384 
JSPhotoAccessGetAlbumVideoCount(napi_env env,napi_callback_info info)385 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumVideoCount(napi_env env, napi_callback_info info)
386 {
387     PhotoAlbumNapi *obj = nullptr;
388     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
389 
390     napi_value jsResult = nullptr;
391     CHECK_ARGS(env, napi_create_int32(env, obj->GetVideoCount(), &jsResult), JS_INNER_FAIL);
392     return jsResult;
393 }
394 
JSGetPhotoAlbumType(napi_env env,napi_callback_info info)395 napi_value PhotoAlbumNapi::JSGetPhotoAlbumType(napi_env env, napi_callback_info info)
396 {
397     PhotoAlbumNapi *obj = nullptr;
398     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
399 
400     napi_value jsResult = nullptr;
401     CHECK_ARGS(env, napi_create_int32(env, obj->GetPhotoAlbumType(), &jsResult), JS_INNER_FAIL);
402     return jsResult;
403 }
404 
JSGetPhotoAlbumSubType(napi_env env,napi_callback_info info)405 napi_value PhotoAlbumNapi::JSGetPhotoAlbumSubType(napi_env env, napi_callback_info info)
406 {
407     PhotoAlbumNapi *obj = nullptr;
408     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
409 
410     napi_value jsResult = nullptr;
411     CHECK_ARGS(env, napi_create_int32(env, obj->GetPhotoAlbumSubType(), &jsResult), JS_INNER_FAIL);
412     return jsResult;
413 }
414 
JSGetCoverUri(napi_env env,napi_callback_info info)415 napi_value PhotoAlbumNapi::JSGetCoverUri(napi_env env, napi_callback_info info)
416 {
417     PhotoAlbumNapi *obj = nullptr;
418     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
419 
420     napi_value jsResult = nullptr;
421     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetCoverUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
422         JS_INNER_FAIL);
423     return jsResult;
424 }
425 
JSGetLatitude(napi_env env,napi_callback_info info)426 napi_value PhotoAlbumNapi::JSGetLatitude(napi_env env, napi_callback_info info)
427 {
428     PhotoAlbumNapi *obj = nullptr;
429     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
430 
431     napi_value jsResult = nullptr;
432     CHECK_ARGS(env, napi_create_double(env, obj->GetLatitude(), &jsResult), JS_INNER_FAIL);
433     return jsResult;
434 }
435 
JSGetLongitude(napi_env env,napi_callback_info info)436 napi_value PhotoAlbumNapi::JSGetLongitude(napi_env env, napi_callback_info info)
437 {
438     PhotoAlbumNapi *obj = nullptr;
439     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
440 
441     napi_value jsResult = nullptr;
442     CHECK_ARGS(env, napi_create_double(env, obj->GetLongitude(), &jsResult), JS_INNER_FAIL);
443     return jsResult;
444 }
445 
GetStringArg(napi_env env,napi_callback_info info,PhotoAlbumNapi ** obj,string & output)446 napi_value GetStringArg(napi_env env, napi_callback_info info, PhotoAlbumNapi **obj, string &output)
447 {
448     size_t argc = ARGS_ONE;
449     napi_value argv[ARGS_ONE];
450     napi_value thisVar = nullptr;
451     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
452     CHECK_COND(env, argc == ARGS_ONE, JS_ERR_PARAMETER_INVALID);
453 
454     napi_value result = nullptr;
455     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
456     napi_valuetype valueType = napi_undefined;
457     if ((thisVar == nullptr) || (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok) || (valueType != napi_string)) {
458         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
459         return result;
460     }
461 
462     size_t res = 0;
463     char buffer[FILENAME_MAX];
464     CHECK_ARGS(env, napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res), JS_INNER_FAIL);
465     output = string(buffer);
466 
467     CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void **>(obj)), JS_INNER_FAIL);
468     if (obj == nullptr) {
469         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
470         return result;
471     }
472 
473     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
474     return result;
475 }
476 
JSSetAlbumName(napi_env env,napi_callback_info info)477 napi_value PhotoAlbumNapi::JSSetAlbumName(napi_env env, napi_callback_info info)
478 {
479     PhotoAlbumNapi *obj = nullptr;
480     string albumName;
481     CHECK_NULLPTR_RET(GetStringArg(env, info, &obj, albumName));
482     obj->photoAlbumPtr->SetAlbumName(albumName);
483 
484     napi_value result = nullptr;
485     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
486     return result;
487 }
488 
JSPhotoAccessSetAlbumName(napi_env env,napi_callback_info info)489 napi_value PhotoAlbumNapi::JSPhotoAccessSetAlbumName(napi_env env, napi_callback_info info)
490 {
491     PhotoAlbumNapi *obj = nullptr;
492     string albumName;
493     CHECK_NULLPTR_RET(GetStringArg(env, info, &obj, albumName));
494     obj->photoAlbumPtr->SetAlbumName(albumName);
495 
496     napi_value result = nullptr;
497     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
498     return result;
499 }
500 
JSSetCoverUri(napi_env env,napi_callback_info info)501 napi_value PhotoAlbumNapi::JSSetCoverUri(napi_env env, napi_callback_info info)
502 {
503     PhotoAlbumNapi *obj = nullptr;
504     string coverUri;
505     CHECK_NULLPTR_RET(GetStringArg(env, info, &obj, coverUri));
506     obj->photoAlbumPtr->SetCoverUri(coverUri);
507 
508     napi_value result = nullptr;
509     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
510     return result;
511 }
512 
JSGetDateModified(napi_env env,napi_callback_info info)513 napi_value PhotoAlbumNapi::JSGetDateModified(napi_env env, napi_callback_info info)
514 {
515     PhotoAlbumNapi *obj = nullptr;
516     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
517 
518     napi_value jsResult = nullptr;
519     CHECK_ARGS(env, napi_create_int64(env, obj->GetDateModified(), &jsResult),
520         JS_INNER_FAIL);
521     return jsResult;
522 }
523 
ParseArgsCommitModify(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)524 static napi_value ParseArgsCommitModify(napi_env env, napi_callback_info info,
525     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
526 {
527     constexpr size_t minArgs = ARGS_ZERO;
528     constexpr size_t maxArgs = ARGS_ONE;
529     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
530         JS_ERR_PARAMETER_INVALID);
531 
532     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
533     if (photoAlbum == nullptr) {
534         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
535         return nullptr;
536     }
537     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
538         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
539         return nullptr;
540     }
541 
542     if (MediaFileUtils::CheckAlbumName(photoAlbum->GetAlbumName()) < 0) {
543         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
544         return nullptr;
545     }
546     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
547     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, photoAlbum->GetAlbumName());
548     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_COVER_URI, photoAlbum->GetCoverUri());
549 
550     napi_value result = nullptr;
551     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
552     return result;
553 }
554 
JSCommitModifyExecute(napi_env env,void * data)555 static void JSCommitModifyExecute(napi_env env, void *data)
556 {
557     MediaLibraryTracer tracer;
558     tracer.Start("JSCommitModifyExecute");
559 
560     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
561     string commitModifyUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
562         UFM_UPDATE_PHOTO_ALBUM : PAH_UPDATE_PHOTO_ALBUM;
563     Uri uri(commitModifyUri);
564     int changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
565     context->SaveError(changedRows);
566     context->changedRows = changedRows;
567 }
568 
JSCommitModifyCompleteCallback(napi_env env,napi_status status,void * data)569 static void JSCommitModifyCompleteCallback(napi_env env, napi_status status, void *data)
570 {
571     MediaLibraryTracer tracer;
572     tracer.Start("JSCommitModifyCompleteCallback");
573 
574     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
575     auto jsContext = make_unique<JSAsyncContextOutput>();
576     jsContext->status = false;
577     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
578     if (context->error == ERR_DEFAULT) {
579         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
580         jsContext->status = true;
581     } else {
582         context->HandleError(env, jsContext->error);
583     }
584 
585     tracer.Finish();
586     if (context->work != nullptr) {
587         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
588                                                    context->work, *jsContext);
589     }
590     delete context;
591 }
592 
JSCommitModify(napi_env env,napi_callback_info info)593 napi_value PhotoAlbumNapi::JSCommitModify(napi_env env, napi_callback_info info)
594 {
595     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
596     CHECK_NULLPTR_RET(ParseArgsCommitModify(env, info, asyncContext));
597     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
598 
599     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
600         JSCommitModifyCompleteCallback);
601 }
602 
PhotoAccessHelperCommitModify(napi_env env,napi_callback_info info)603 napi_value PhotoAlbumNapi::PhotoAccessHelperCommitModify(napi_env env, napi_callback_info info)
604 {
605     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
606     CHECK_NULLPTR_RET(ParseArgsCommitModify(env, info, asyncContext));
607     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
608 
609     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
610         JSCommitModifyCompleteCallback);
611 }
612 
GetAssetsIdArray(napi_env env,napi_value arg,vector<string> & assetsArray)613 static napi_value GetAssetsIdArray(napi_env env, napi_value arg, vector<string> &assetsArray)
614 {
615     bool isArray = false;
616     CHECK_ARGS(env, napi_is_array(env, arg, &isArray), JS_INNER_FAIL);
617     if (!isArray) {
618         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check array type");
619         return nullptr;
620     }
621 
622     uint32_t len = 0;
623     CHECK_ARGS(env, napi_get_array_length(env, arg, &len), JS_INNER_FAIL);
624     if (len < 0) {
625         NAPI_ERR_LOG("Failed to check array length: %{public}u", len);
626         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check array length");
627         return nullptr;
628     }
629     if (len == 0) {
630         napi_value result = nullptr;
631         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
632         return result;
633     }
634 
635     for (uint32_t i = 0; i < len; i++) {
636         napi_value asset = nullptr;
637         CHECK_ARGS(env, napi_get_element(env, arg, i, &asset), JS_INNER_FAIL);
638         if (asset == nullptr) {
639             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to get asset element");
640             return nullptr;
641         }
642 
643         FileAssetNapi *obj = nullptr;
644         CHECK_ARGS(env, napi_unwrap(env, asset, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
645         if (obj == nullptr) {
646             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to get asset napi object");
647             return nullptr;
648         }
649         if ((obj->GetMediaType() != MEDIA_TYPE_IMAGE && obj->GetMediaType() != MEDIA_TYPE_VIDEO)) {
650             NAPI_INFO_LOG("Skip invalid asset, mediaType: %{public}d", obj->GetMediaType());
651             continue;
652         }
653         assetsArray.push_back(obj->GetFileUri());
654     }
655 
656     napi_value result = nullptr;
657     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
658     return result;
659 }
660 
ParseArgsAddAssets(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)661 static napi_value ParseArgsAddAssets(napi_env env, napi_callback_info info,
662     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
663 {
664     constexpr size_t minArgs = ARGS_ONE;
665     constexpr size_t maxArgs = ARGS_TWO;
666     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
667         JS_ERR_PARAMETER_INVALID);
668 
669     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
670     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
671         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
672         return nullptr;
673     }
674 
675     /* Parse the first argument */
676     vector<string> assetsArray;
677     CHECK_NULLPTR_RET(GetAssetsIdArray(env, context->argv[PARAM0], assetsArray));
678     if (assetsArray.empty()) {
679         napi_value result = nullptr;
680         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
681         return result;
682     }
683     int32_t albumId = photoAlbum->GetAlbumId();
684     for (const auto &assetId : assetsArray) {
685         DataShareValuesBucket valuesBucket;
686         valuesBucket.Put(PhotoColumn::PHOTO_OWNER_ALBUM_ID, albumId);
687         valuesBucket.Put(PhotoColumn::MEDIA_ID, assetId);
688         context->valuesBuckets.push_back(valuesBucket);
689     }
690 
691     napi_value result = nullptr;
692     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
693     return result;
694 }
695 
FetchNewCount(PhotoAlbumNapiAsyncContext * context)696 static int32_t FetchNewCount(PhotoAlbumNapiAsyncContext *context)
697 {
698     string queryUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
699         UFM_QUERY_PHOTO_ALBUM : PAH_QUERY_PHOTO_ALBUM;
700     Uri qUri(queryUri);
701     int errCode = 0;
702     DataSharePredicates predicates;
703     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, context->objectInfo->GetAlbumId());
704     vector<string> fetchColumn = {
705         PhotoAlbumColumns::ALBUM_ID,
706         PhotoAlbumColumns::ALBUM_COUNT,
707     };
708     bool isSmartAlbum = (context->objectInfo->GetPhotoAlbumType() == PhotoAlbumType::SMART);
709     if (!isSmartAlbum) {
710         fetchColumn.push_back(PhotoAlbumColumns::ALBUM_IMAGE_COUNT);
711         fetchColumn.push_back(PhotoAlbumColumns::ALBUM_VIDEO_COUNT);
712     }
713     auto resultSet = UserFileClient::Query(qUri, predicates, fetchColumn, errCode);
714     if (resultSet == nullptr) {
715         NAPI_ERR_LOG("resultSet == nullptr, errCode is %{public}d", errCode);
716         return -1;
717     }
718     if (resultSet->GoToFirstRow() != 0) {
719         NAPI_ERR_LOG("go to first row failed");
720         return -1;
721     }
722     bool hiddenOnly = context->objectInfo->GetHiddenOnly();
723     int imageCount = (hiddenOnly || isSmartAlbum) ? -1 :
724             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_IMAGE_COUNT, resultSet, TYPE_INT32));
725     int videoCount = (hiddenOnly || isSmartAlbum) ? -1 :
726             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_VIDEO_COUNT, resultSet, TYPE_INT32));
727     context->newCount =
728             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_COUNT, resultSet, TYPE_INT32));
729     context->newImageCount = imageCount;
730     context->newVideoCount = videoCount;
731     return 0;
732 }
733 
JSPhotoAlbumAddAssetsExecute(napi_env env,void * data)734 static void JSPhotoAlbumAddAssetsExecute(napi_env env, void *data)
735 {
736     MediaLibraryTracer tracer;
737     tracer.Start("JSPhotoAlbumAddAssetsExecute");
738     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
739     if (context->valuesBuckets.empty()) {
740         return;
741     }
742     string addAssetsUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
743         UFM_PHOTO_ALBUM_ADD_ASSET : PAH_PHOTO_ALBUM_ADD_ASSET;
744     Uri uri(addAssetsUri);
745 
746     auto changedRows = UserFileClient::BatchInsert(uri, context->valuesBuckets);
747     if (changedRows < 0) {
748         context->SaveError(changedRows);
749         return;
750     }
751     context->changedRows = changedRows;
752     int32_t ret = FetchNewCount(context);
753     if (ret < 0) {
754         NAPI_ERR_LOG("Update count failed");
755         context->SaveError(E_HAS_DB_ERROR);
756     }
757 }
758 
JSPhotoAlbumAddAssetsCompleteCallback(napi_env env,napi_status status,void * data)759 static void JSPhotoAlbumAddAssetsCompleteCallback(napi_env env, napi_status status, void *data)
760 {
761     MediaLibraryTracer tracer;
762     tracer.Start("JSPhotoAlbumAddAssetsCompleteCallback");
763 
764     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
765     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
766     jsContext->status = false;
767     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
768     if (context->error == ERR_DEFAULT) {
769         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
770         jsContext->status = true;
771         context->objectInfo->SetCount(context->newCount);
772         context->objectInfo->SetImageCount(context->newImageCount);
773         context->objectInfo->SetVideoCount(context->newVideoCount);
774     } else {
775         context->HandleError(env, jsContext->error);
776     }
777 
778     tracer.Finish();
779     if (context->work != nullptr) {
780         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
781                                                    context->work, *jsContext);
782     }
783     delete context;
784 }
785 
JSPhotoAlbumAddAssets(napi_env env,napi_callback_info info)786 napi_value PhotoAlbumNapi::JSPhotoAlbumAddAssets(napi_env env, napi_callback_info info)
787 {
788     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
789     CHECK_NULLPTR_RET(ParseArgsAddAssets(env, info, asyncContext));
790     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
791 
792     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumAddAssets",
793         JSPhotoAlbumAddAssetsExecute, JSPhotoAlbumAddAssetsCompleteCallback);
794 }
795 
PhotoAccessHelperAddAssets(napi_env env,napi_callback_info info)796 napi_value PhotoAlbumNapi::PhotoAccessHelperAddAssets(napi_env env, napi_callback_info info)
797 {
798     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
799     CHECK_NULLPTR_RET(ParseArgsAddAssets(env, info, asyncContext));
800     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
801 
802     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumAddAssets",
803         JSPhotoAlbumAddAssetsExecute, JSPhotoAlbumAddAssetsCompleteCallback);
804 }
805 
ParseArgsRemoveAssets(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)806 static napi_value ParseArgsRemoveAssets(napi_env env, napi_callback_info info,
807     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
808 {
809     constexpr size_t minArgs = ARGS_ONE;
810     constexpr size_t maxArgs = ARGS_TWO;
811     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
812         JS_ERR_PARAMETER_INVALID);
813 
814     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
815     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
816         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
817         return nullptr;
818     }
819 
820     /* Parse the first argument */
821     vector<string> assetsArray;
822     CHECK_NULLPTR_RET(GetAssetsIdArray(env, context->argv[PARAM0], assetsArray));
823     if (assetsArray.empty()) {
824         napi_value result = nullptr;
825         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
826         return result;
827     }
828     context->predicates.EqualTo(PhotoColumn::PHOTO_OWNER_ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
829     context->predicates.And()->In(PhotoColumn::MEDIA_ID, assetsArray);
830 
831     napi_value result = nullptr;
832     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
833     return result;
834 }
835 
JSPhotoAlbumRemoveAssetsExecute(napi_env env,void * data)836 static void JSPhotoAlbumRemoveAssetsExecute(napi_env env, void *data)
837 {
838     MediaLibraryTracer tracer;
839     tracer.Start("JSPhotoAlbumRemoveAssetsExecute");
840 
841     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
842     if (context->predicates.GetOperationList().empty()) {
843         NAPI_ERR_LOG("Invalid input: operation list is empty");
844         return;
845     }
846 
847     string removeAssetsUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
848         UFM_PHOTO_ALBUM_REMOVE_ASSET : PAH_PHOTO_ALBUM_REMOVE_ASSET;
849     Uri uri(removeAssetsUri);
850     auto deletedRows = UserFileClient::Delete(uri, context->predicates);
851     if (deletedRows < 0) {
852         NAPI_ERR_LOG("Remove assets failed: %{public}d", deletedRows);
853         context->SaveError(deletedRows);
854         return;
855     }
856     context->changedRows = deletedRows;
857     int32_t ret = FetchNewCount(context);
858     if (ret < 0) {
859         NAPI_ERR_LOG("Update count failed");
860         context->SaveError(E_HAS_DB_ERROR);
861     }
862 }
863 
JSPhotoAlbumRemoveAssetsCompleteCallback(napi_env env,napi_status status,void * data)864 static void JSPhotoAlbumRemoveAssetsCompleteCallback(napi_env env, napi_status status, void *data)
865 {
866     MediaLibraryTracer tracer;
867     tracer.Start("JSPhotoAlbumRemoveAssetsCompleteCallback");
868 
869     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
870     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
871     jsContext->status = false;
872     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
873     if (context->error == ERR_DEFAULT) {
874         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
875         jsContext->status = true;
876         context->objectInfo->SetCount(context->newCount);
877         context->objectInfo->SetImageCount(context->newImageCount);
878         context->objectInfo->SetVideoCount(context->newVideoCount);
879     } else {
880         context->HandleError(env, jsContext->error);
881     }
882 
883     tracer.Finish();
884     if (context->work != nullptr) {
885         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
886                                                    context->work, *jsContext);
887     }
888     delete context;
889 }
890 
JSPhotoAlbumRemoveAssets(napi_env env,napi_callback_info info)891 napi_value PhotoAlbumNapi::JSPhotoAlbumRemoveAssets(napi_env env, napi_callback_info info)
892 {
893     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
894     CHECK_NULLPTR_RET(ParseArgsRemoveAssets(env, info, asyncContext));
895     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
896 
897     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumRemoveAssets",
898         JSPhotoAlbumRemoveAssetsExecute, JSPhotoAlbumRemoveAssetsCompleteCallback);
899 }
900 
PhotoAccessHelperRemoveAssets(napi_env env,napi_callback_info info)901 napi_value PhotoAlbumNapi::PhotoAccessHelperRemoveAssets(napi_env env, napi_callback_info info)
902 {
903     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
904     CHECK_NULLPTR_RET(ParseArgsRemoveAssets(env, info, asyncContext));
905     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
906 
907     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumRemoveAssets",
908         JSPhotoAlbumRemoveAssetsExecute, JSPhotoAlbumRemoveAssetsCompleteCallback);
909 }
910 
GetPredicatesByAlbumTypes(const shared_ptr<PhotoAlbum> & photoAlbum,DataSharePredicates & predicates,const bool hiddenOnly)911 static int32_t GetPredicatesByAlbumTypes(const shared_ptr<PhotoAlbum> &photoAlbum,
912     DataSharePredicates &predicates, const bool hiddenOnly)
913 {
914     auto albumId = photoAlbum->GetAlbumId();
915     auto subType = photoAlbum->GetPhotoAlbumSubType();
916     bool isLocationAlbum = subType == PhotoAlbumSubType::GEOGRAPHY_LOCATION;
917     if (albumId <= 0 && !isLocationAlbum) {
918         return E_INVALID_ARGUMENTS;
919     }
920     auto type = photoAlbum->GetPhotoAlbumType();
921     if ((!PhotoAlbum::CheckPhotoAlbumType(type)) || (!PhotoAlbum::CheckPhotoAlbumSubType(subType))) {
922         return E_INVALID_ARGUMENTS;
923     }
924 
925     if (type == PhotoAlbumType::SMART && subType == PhotoAlbumSubType::PORTRAIT) {
926         return MediaLibraryNapiUtils::GetPortraitAlbumPredicates(photoAlbum->GetAlbumId(), predicates);
927     }
928 
929     if (PhotoAlbum::IsUserPhotoAlbum(type, subType)) {
930         return MediaLibraryNapiUtils::GetUserAlbumPredicates(photoAlbum->GetAlbumId(), predicates, hiddenOnly);
931     }
932 
933     if (PhotoAlbum::IsSourceAlbum(type, subType)) {
934         return MediaLibraryNapiUtils::GetSourceAlbumPredicates(photoAlbum->GetAlbumId(), predicates, hiddenOnly);
935     }
936 
937     if (type == PhotoAlbumType::SMART) {
938         if (isLocationAlbum) {
939             return MediaLibraryNapiUtils::GetAllLocationPredicates(predicates);
940         }
941         auto albumName = photoAlbum->GetAlbumName();
942         if (MediaLibraryNapiUtils::IsFeaturedSinglePortraitAlbum(albumName, predicates)) {
943             return MediaLibraryNapiUtils::GetFeaturedSinglePortraitAlbumPredicates(
944                 photoAlbum->GetAlbumId(), predicates);
945         }
946         return MediaLibraryNapiUtils::GetAnalysisAlbumPredicates(photoAlbum->GetAlbumId(), predicates);
947     }
948 
949     if ((type != PhotoAlbumType::SYSTEM) || (subType == PhotoAlbumSubType::USER_GENERIC) ||
950         (subType == PhotoAlbumSubType::ANY)) {
951         return E_INVALID_ARGUMENTS;
952     }
953     return MediaLibraryNapiUtils::GetSystemAlbumPredicates(subType, predicates, hiddenOnly);
954 }
955 
ParseArgsGetPhotoAssets(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)956 static napi_value ParseArgsGetPhotoAssets(napi_env env, napi_callback_info info,
957     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
958 {
959     constexpr size_t minArgs = ARGS_ONE;
960     constexpr size_t maxArgs = ARGS_TWO;
961     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
962         JS_ERR_PARAMETER_INVALID);
963 
964     /* Parse the first argument */
965     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM0], ASSET_FETCH_OPT, context),
966         JS_INNER_FAIL);
967 
968     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
969     auto ret = GetPredicatesByAlbumTypes(photoAlbum, context->predicates, photoAlbum->GetHiddenOnly());
970     if (ret != E_SUCCESS) {
971         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
972         return nullptr;
973     }
974     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
975         PhotoColumn::IsPhotoColumn, NapiAssetType::TYPE_PHOTO));
976     if (photoAlbum->GetHiddenOnly() || photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::HIDDEN) {
977         if (!MediaLibraryNapiUtils::IsSystemApp()) {
978             NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
979             return nullptr;
980         }
981         // sort by hidden time desc if is hidden asset
982         context->predicates.IndexedBy(PhotoColumn::PHOTO_HIDDEN_TIME_INDEX);
983     }
984 
985     napi_value result = nullptr;
986     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
987     return result;
988 }
989 
JSGetPhotoAssetsExecute(napi_env env,void * data)990 static void JSGetPhotoAssetsExecute(napi_env env, void *data)
991 {
992     MediaLibraryTracer tracer;
993     tracer.Start("JSGetPhotoAssetsExecute");
994 
995     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
996     string queryUri = UFM_QUERY_PHOTO_MAP;
997     Uri uri(queryUri);
998     int32_t errCode = 0;
999     std::vector<DataShare::OperationItem> operationItems = context->predicates.GetOperationList();
1000     for (DataShare::OperationItem item : operationItems) {
1001         if (item.operation == DataShare::OperationType::GROUP_BY) {
1002             context->fetchColumn.insert(context->fetchColumn.begin(), COUNT_GROUP_BY);
1003         }
1004     }
1005     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
1006     if (resultSet == nullptr) {
1007         context->SaveError(E_HAS_DB_ERROR);
1008         return;
1009     }
1010     context->fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1011     context->fetchResult->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
1012 }
1013 
IsFeaturedSinglePortraitAlbum(const shared_ptr<PhotoAlbum> & photoAlbum)1014 static bool IsFeaturedSinglePortraitAlbum(const shared_ptr<PhotoAlbum>& photoAlbum)
1015 {
1016     constexpr int portraitAlbumId = 0;
1017     return photoAlbum->GetPhotoAlbumSubType() == PhotoAlbumSubType::CLASSIFY &&
1018         photoAlbum->GetAlbumName().compare(to_string(portraitAlbumId)) == 0;
1019 }
1020 
ConvertColumnsForPortrait(PhotoAlbumNapiAsyncContext * context)1021 static void ConvertColumnsForPortrait(PhotoAlbumNapiAsyncContext *context)
1022 {
1023     if (context == nullptr || context->objectInfo == nullptr) {
1024         NAPI_ERR_LOG("context is null or PhotoAlbumNapi is null");
1025         return;
1026     }
1027 
1028     shared_ptr<PhotoAlbum> photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1029     if (photoAlbum == nullptr || (photoAlbum->GetPhotoAlbumSubType() != PhotoAlbumSubType::PORTRAIT &&
1030         !IsFeaturedSinglePortraitAlbum(photoAlbum))) {
1031         return;
1032     }
1033 
1034     for (size_t i = 0; i < context->fetchColumn.size(); i++) {
1035         if (context->fetchColumn[i] != "count(*)") {
1036             context->fetchColumn[i] = PhotoColumn::PHOTOS_TABLE + "." + context->fetchColumn[i];
1037         }
1038     }
1039 }
1040 
JSPhotoAccessGetPhotoAssetsExecute(napi_env env,void * data)1041 static void JSPhotoAccessGetPhotoAssetsExecute(napi_env env, void *data)
1042 {
1043     MediaLibraryTracer tracer;
1044     tracer.Start("JSPhotoAccessGetPhotoAssetsExecute");
1045 
1046     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1047     Uri uri(PAH_QUERY_PHOTO_MAP);
1048     ConvertColumnsForPortrait(context);
1049     int32_t errCode = 0;
1050     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
1051     if (resultSet == nullptr) {
1052         context->SaveError(E_HAS_DB_ERROR);
1053         return;
1054     }
1055     context->fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1056     context->fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1057 }
1058 
JSPhotoAccessGetPhotoAssetsExecuteSync(napi_env env,PhotoAlbumNapiAsyncContext & asyncContext)1059 static napi_value JSPhotoAccessGetPhotoAssetsExecuteSync(napi_env env, PhotoAlbumNapiAsyncContext& asyncContext)
1060 {
1061     auto context = &asyncContext;
1062     Uri uri(PAH_QUERY_PHOTO_MAP);
1063     ConvertColumnsForPortrait(context);
1064     int32_t errCode = 0;
1065     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
1066     CHECK_NULLPTR_RET(resultSet);
1067     auto fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
1068     fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
1069 
1070     std::vector<std::unique_ptr<FileAsset>> fileAssetArray;
1071     auto file = fetchResult->GetFirstObject();
1072     while (file != nullptr) {
1073         fileAssetArray.push_back(move(file));
1074         file = fetchResult->GetNextObject();
1075     }
1076     napi_value jsFileArray = nullptr;
1077     size_t len = fileAssetArray.size();
1078     napi_create_array_with_length(env, len, &jsFileArray);
1079     size_t i = 0;
1080     for (i = 0; i < len; i++) {
1081         napi_value jsFileAsset = FileAssetNapi::CreateFileAsset(env, fileAssetArray[i]);
1082         if ((jsFileAsset == nullptr) || (napi_set_element(env, jsFileArray, i, jsFileAsset) != napi_ok)) {
1083             NAPI_ERR_LOG("Failed to get file asset napi object");
1084             break;
1085         }
1086     }
1087     return (i == len) ? jsFileArray : nullptr;
1088 }
1089 
GetPhotoMapQueryResult(napi_env env,PhotoAlbumNapiAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)1090 static void GetPhotoMapQueryResult(napi_env env, PhotoAlbumNapiAsyncContext *context,
1091     unique_ptr<JSAsyncContextOutput> &jsContext)
1092 {
1093     napi_value fetchRes = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchResult));
1094     if (fetchRes == nullptr) {
1095         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
1096             "Failed to create js object for FetchFileResult");
1097         return;
1098     }
1099     jsContext->data = fetchRes;
1100     jsContext->status = true;
1101 }
1102 
JSGetPhotoAssetsCallbackComplete(napi_env env,napi_status status,void * data)1103 static void JSGetPhotoAssetsCallbackComplete(napi_env env, napi_status status, void *data)
1104 {
1105     MediaLibraryTracer tracer;
1106     tracer.Start("JSGetPhotoAssetsCallbackComplete");
1107 
1108     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1109 
1110     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1111     jsContext->status = false;
1112 
1113     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
1114     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
1115     if (context->fetchResult != nullptr) {
1116         GetPhotoMapQueryResult(env, context, jsContext);
1117     } else {
1118         NAPI_ERR_LOG("No fetch file result found!");
1119         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
1120             "Failed to get fetchFileResult from DB");
1121     }
1122 
1123     tracer.Finish();
1124     if (context->work != nullptr) {
1125         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1126                                                    context->work, *jsContext);
1127     }
1128     delete context;
1129 }
1130 
JSGetPhotoAssets(napi_env env,napi_callback_info info)1131 napi_value PhotoAlbumNapi::JSGetPhotoAssets(napi_env env, napi_callback_info info)
1132 {
1133     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1134     CHECK_NULLPTR_RET(ParseArgsGetPhotoAssets(env, info, asyncContext));
1135 
1136     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", JSGetPhotoAssetsExecute,
1137         JSGetPhotoAssetsCallbackComplete);
1138 }
1139 
JSPhotoAccessGetPhotoAssets(napi_env env,napi_callback_info info)1140 napi_value PhotoAlbumNapi::JSPhotoAccessGetPhotoAssets(napi_env env, napi_callback_info info)
1141 {
1142     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1143     CHECK_NULLPTR_RET(ParseArgsGetPhotoAssets(env, info, asyncContext));
1144 
1145     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
1146         JSPhotoAccessGetPhotoAssetsExecute, JSGetPhotoAssetsCallbackComplete);
1147 }
1148 
JSPhotoAccessGetPhotoAssetsSync(napi_env env,napi_callback_info info)1149 napi_value PhotoAlbumNapi::JSPhotoAccessGetPhotoAssetsSync(napi_env env, napi_callback_info info)
1150 {
1151     MediaLibraryTracer tracer;
1152     tracer.Start("JSPhotoAccessGetPhotoAssetsSync");
1153 
1154     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1155     CHECK_NULLPTR_RET(ParseArgsGetPhotoAssets(env, info, asyncContext));
1156     return JSPhotoAccessGetPhotoAssetsExecuteSync(env, *asyncContext);
1157 }
1158 
TrashAlbumParseArgs(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)1159 static napi_value TrashAlbumParseArgs(napi_env env, napi_callback_info info,
1160     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
1161 {
1162     if (!MediaLibraryNapiUtils::IsSystemApp()) {
1163         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "This interface can be called only by system apps");
1164         return nullptr;
1165     }
1166 
1167     napi_value result = nullptr;
1168     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1169     constexpr size_t minArgs = ARGS_ONE;
1170     constexpr size_t maxArgs = ARGS_TWO;
1171     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
1172         JS_ERR_PARAMETER_INVALID);
1173     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1174     if (!PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
1175         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check trash album type");
1176         return nullptr;
1177     }
1178 
1179     /* Parse the first argument */
1180     vector<napi_value> napiValues;
1181     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetNapiValueArray(env, context->argv[PARAM0], napiValues));
1182     if (napiValues.empty()) {
1183         return result;
1184     }
1185     napi_valuetype valueType = napi_undefined;
1186     vector<string> uris;
1187     CHECK_ARGS(env, napi_typeof(env, napiValues.front(), &valueType), JS_ERR_PARAMETER_INVALID);
1188     if (valueType == napi_string) {
1189         // The input should be an array of asset uri.
1190         CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetStringArray(env, napiValues, uris));
1191     } else if (valueType == napi_object) {
1192         // The input should be an array of asset object.
1193         CHECK_NULLPTR_RET(MediaLibraryNapiUtils::GetUriArrayFromAssets(env, napiValues, uris));
1194     }
1195     if (uris.empty()) {
1196         return result;
1197     }
1198 
1199     context->predicates.In(MediaColumn::MEDIA_ID, uris);
1200     context->valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, 0);
1201 
1202     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1203     return result;
1204 }
1205 
TrashAlbumExecute(const TrashAlbumExecuteOpt & opt)1206 static void TrashAlbumExecute(const TrashAlbumExecuteOpt &opt)
1207 {
1208     MediaLibraryTracer tracer;
1209     tracer.Start(opt.tracerLabel);
1210 
1211     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(opt.data);
1212     if (context->predicates.GetOperationList().empty()) {
1213         return;
1214     }
1215     Uri uri(opt.uri);
1216     int changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
1217     if (changedRows < 0) {
1218         context->SaveError(changedRows);
1219         return;
1220     }
1221     context->changedRows = changedRows;
1222 }
1223 
TrashAlbumComplete(napi_env env,napi_status status,void * data)1224 static void TrashAlbumComplete(napi_env env, napi_status status, void *data)
1225 {
1226     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
1227     auto jsContext = make_unique<JSAsyncContextOutput>();
1228     jsContext->status = false;
1229     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
1230     if (context->error == ERR_DEFAULT) {
1231         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
1232         jsContext->status = true;
1233     } else {
1234         context->HandleError(env, jsContext->error);
1235     }
1236 
1237     if (context->work != nullptr) {
1238         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1239                                                    context->work, *jsContext);
1240     }
1241     delete context;
1242 }
1243 
RecoverPhotosExecute(napi_env env,void * data)1244 static void RecoverPhotosExecute(napi_env env, void *data)
1245 {
1246     TrashAlbumExecuteOpt opt = {
1247         .env = env,
1248         .data = data,
1249         .tracerLabel = "RecoverPhotosExecute",
1250         .uri = (static_cast<PhotoAlbumNapiAsyncContext *>(data)->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
1251             UFM_RECOVER_PHOTOS : PAH_RECOVER_PHOTOS,
1252     };
1253     TrashAlbumExecute(opt);
1254 }
1255 
RecoverPhotosComplete(napi_env env,napi_status status,void * data)1256 static void RecoverPhotosComplete(napi_env env, napi_status status, void *data)
1257 {
1258     TrashAlbumComplete(env, status, data);
1259 }
1260 
JSRecoverPhotos(napi_env env,napi_callback_info info)1261 napi_value PhotoAlbumNapi::JSRecoverPhotos(napi_env env, napi_callback_info info)
1262 {
1263     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1264     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
1265     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1266 
1267     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRecoverPhotos", RecoverPhotosExecute,
1268         RecoverPhotosComplete);
1269 }
1270 
PrivateAlbumParseArgs(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)1271 static napi_value PrivateAlbumParseArgs(napi_env env, napi_callback_info info,
1272     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
1273 {
1274     string uri;
1275     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, uri),
1276         JS_ERR_PARAMETER_INVALID);
1277     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1278     if (photoAlbum == nullptr) {
1279         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to get photo album instance");
1280         return nullptr;
1281     }
1282     if (!PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
1283         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check trash album type");
1284         return nullptr;
1285     }
1286 
1287     context->predicates.EqualTo(MediaColumn::MEDIA_ID, MediaFileUtils::GetIdFromUri(uri));
1288     context->valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, 0);
1289 
1290     napi_value result = nullptr;
1291     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1292     return result;
1293 }
1294 
PrivateAlbumRecoverPhotos(napi_env env,napi_callback_info info)1295 napi_value PhotoAlbumNapi::PrivateAlbumRecoverPhotos(napi_env env, napi_callback_info info)
1296 {
1297     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1298     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1299     CHECK_NULLPTR_RET(PrivateAlbumParseArgs(env, info, asyncContext));
1300 
1301     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PrivateAlbumRecoverPhotos",
1302         RecoverPhotosExecute, RecoverPhotosComplete);
1303 }
1304 
PhotoAccessHelperRecoverPhotos(napi_env env,napi_callback_info info)1305 napi_value PhotoAlbumNapi::PhotoAccessHelperRecoverPhotos(napi_env env, napi_callback_info info)
1306 {
1307     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1308     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
1309     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1310 
1311     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRecoverPhotos", RecoverPhotosExecute,
1312         RecoverPhotosComplete);
1313 }
1314 
DeletePhotosExecute(napi_env env,void * data)1315 static void DeletePhotosExecute(napi_env env, void *data)
1316 {
1317     TrashAlbumExecuteOpt opt = {
1318         .env = env,
1319         .data = data,
1320         .tracerLabel = "DeletePhotosExecute",
1321         .uri = (static_cast<PhotoAlbumNapiAsyncContext *>(data)->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
1322             UFM_DELETE_PHOTOS : PAH_DELETE_PHOTOS,
1323     };
1324     TrashAlbumExecute(opt);
1325 }
1326 
DeletePhotosComplete(napi_env env,napi_status status,void * data)1327 static void DeletePhotosComplete(napi_env env, napi_status status, void *data)
1328 {
1329     TrashAlbumComplete(env, status, data);
1330 }
1331 
JSDeletePhotos(napi_env env,napi_callback_info info)1332 napi_value PhotoAlbumNapi::JSDeletePhotos(napi_env env, napi_callback_info info)
1333 {
1334     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1335     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
1336     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1337 
1338     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeletePhotos", DeletePhotosExecute,
1339         DeletePhotosComplete);
1340 }
1341 
PrivateAlbumDeletePhotos(napi_env env,napi_callback_info info)1342 napi_value PhotoAlbumNapi::PrivateAlbumDeletePhotos(napi_env env, napi_callback_info info)
1343 {
1344     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1345     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1346     CHECK_NULLPTR_RET(PrivateAlbumParseArgs(env, info, asyncContext));
1347 
1348     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PrivateAlbumDeletePhotos",
1349         DeletePhotosExecute, DeletePhotosComplete);
1350 }
1351 
PhotoAccessHelperDeletePhotos(napi_env env,napi_callback_info info)1352 napi_value PhotoAlbumNapi::PhotoAccessHelperDeletePhotos(napi_env env, napi_callback_info info)
1353 {
1354     NAPI_INFO_LOG("enter");
1355     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1356     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
1357     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1358 
1359     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeletePhotos", DeletePhotosExecute,
1360         DeletePhotosComplete);
1361 }
1362 
ParseArgsSetCoverUri(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)1363 static napi_value ParseArgsSetCoverUri(napi_env env, napi_callback_info info,
1364     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
1365 {
1366     string coverUri;
1367     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, coverUri),
1368         JS_ERR_PARAMETER_INVALID);
1369     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1370     if (!MediaLibraryNapiUtils::IsSystemApp()) {
1371         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Only system apps can update album cover");
1372         return nullptr;
1373     }
1374 
1375     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
1376     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_COVER_URI, coverUri);
1377 
1378     napi_value result = nullptr;
1379     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1380     return result;
1381 }
1382 
PhotoAccessHelperSetCoverUri(napi_env env,napi_callback_info info)1383 napi_value PhotoAlbumNapi::PhotoAccessHelperSetCoverUri(napi_env env, napi_callback_info info)
1384 {
1385     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1386     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1387     CHECK_NULLPTR_RET(ParseArgsSetCoverUri(env, info, asyncContext));
1388 
1389     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
1390         JSCommitModifyCompleteCallback);
1391 }
1392 
PhotoAccessHelperGetFaceIdExec(napi_env env,void * data)1393 static void PhotoAccessHelperGetFaceIdExec(napi_env env, void *data)
1394 {
1395     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1396     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1397 
1398     auto *objectInfo = context->objectInfo;
1399     CHECK_NULL_PTR_RETURN_VOID(objectInfo, "objectInfo is null");
1400 
1401     auto photoAlbumInstance = objectInfo->GetPhotoAlbumInstance();
1402     CHECK_NULL_PTR_RETURN_VOID(photoAlbumInstance, "photoAlbumInstance is null");
1403 
1404     PhotoAlbumSubType albumSubType = photoAlbumInstance->GetPhotoAlbumSubType();
1405     if (albumSubType != PhotoAlbumSubType::PORTRAIT && albumSubType != PhotoAlbumSubType::GROUP_PHOTO) {
1406         NAPI_WARN_LOG("albumSubType: %{public}d, not support getFaceId", albumSubType);
1407         return;
1408     }
1409 
1410     Uri uri(PAH_QUERY_ANA_PHOTO_ALBUM);
1411     DataShare::DataSharePredicates predicates;
1412     predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, objectInfo->GetAlbumId());
1413     vector<string> fetchColumn = { GROUP_TAG };
1414     int errCode = 0;
1415 
1416     auto resultSet = UserFileClient::Query(uri, predicates, fetchColumn, errCode);
1417     if (resultSet == nullptr || resultSet->GoToFirstRow() != 0) {
1418         if (errCode == E_PERMISSION_DENIED) {
1419             context->error = OHOS_PERMISSION_DENIED_CODE;
1420         } else {
1421             context->SaveError(E_FAIL);
1422         }
1423         NAPI_ERR_LOG("get face id failed, errCode is %{public}d", errCode);
1424         return;
1425     }
1426 
1427     context->faceTag = GetStringVal(GROUP_TAG, resultSet);
1428 }
1429 
GetFaceIdCompleteCallback(napi_env env,napi_status status,void * data)1430 static void GetFaceIdCompleteCallback(napi_env env, napi_status status, void *data)
1431 {
1432     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
1433     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1434     auto jsContext = make_unique<JSAsyncContextOutput>();
1435     jsContext->status = false;
1436 
1437     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
1438     if (context->error != ERR_DEFAULT) {
1439         context->HandleError(env, jsContext->error);
1440     } else {
1441         CHECK_ARGS_RET_VOID(env,
1442             napi_create_string_utf8(env, context->faceTag.c_str(), NAPI_AUTO_LENGTH, &jsContext->data), JS_INNER_FAIL);
1443         jsContext->status = true;
1444     }
1445 
1446     if (context->work != nullptr) {
1447         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef, context->work,
1448             *jsContext);
1449     }
1450     delete context;
1451 }
1452 
PhotoAccessHelperGetFaceId(napi_env env,napi_callback_info info)1453 napi_value PhotoAlbumNapi::PhotoAccessHelperGetFaceId(napi_env env, napi_callback_info info)
1454 {
1455     if (!MediaLibraryNapiUtils::IsSystemApp()) {
1456         NapiError::ThrowError(env, E_CHECK_SYSTEMAPP_FAIL, "Only system apps can get the Face ID of the album");
1457         return nullptr;
1458     }
1459 
1460     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1461 
1462     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, asyncContext, 0, 0),
1463         JS_ERR_PARAMETER_INVALID);
1464 
1465     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSAnalysisAlbumGetFaceId",
1466         PhotoAccessHelperGetFaceIdExec, GetFaceIdCompleteCallback);
1467 }
1468 
JSPhotoAccessGetSharedPhotoAssets(napi_env env,napi_callback_info info)1469 napi_value PhotoAlbumNapi::JSPhotoAccessGetSharedPhotoAssets(napi_env env, napi_callback_info info)
1470 {
1471     MediaLibraryTracer tracer;
1472     tracer.Start("JSPhotoAccessGetSharedPhotoAssets");
1473     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext =
1474         make_unique<PhotoAlbumNapiAsyncContext>();
1475     CHECK_NULLPTR_RET(ParseArgsGetPhotoAssets(env, info, asyncContext));
1476 
1477     PhotoAlbumNapiAsyncContext* context =
1478         static_cast<PhotoAlbumNapiAsyncContext*>((asyncContext.get()));
1479 
1480     Uri uri(PAH_QUERY_PHOTO_MAP);
1481     ConvertColumnsForPortrait(context);
1482     shared_ptr<NativeRdb::ResultSet> resultSet = UserFileClient::QueryRdb(uri,
1483         context->predicates, context->fetchColumn);
1484     CHECK_NULLPTR_RET(resultSet);
1485 
1486     napi_value jsFileArray = 0;
1487     napi_create_array(env, &jsFileArray);
1488 
1489     int count = 0;
1490     int err = resultSet->GoToFirstRow();
1491     if (err != napi_ok) {
1492         NAPI_ERR_LOG("Failed GoToFirstRow %{public}d", err);
1493         return jsFileArray;
1494     }
1495     do {
1496         napi_value item = MediaLibraryNapiUtils::GetNextRowObject(env, resultSet, true);
1497         napi_set_element(env, jsFileArray, count++, item);
1498     } while (!resultSet->GoToNextRow());
1499     resultSet->Close();
1500     return jsFileArray;
1501 }
1502 } // namespace OHOS::Media
1503