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