• 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 
19 #include "fetch_file_result_napi.h"
20 #include "file_asset_napi.h"
21 #include "media_file_utils.h"
22 #include "medialibrary_client_errno.h"
23 #include "medialibrary_napi_log.h"
24 #include "medialibrary_tracer.h"
25 #include "photo_map_column.h"
26 #include "userfile_client.h"
27 
28 using namespace std;
29 using namespace OHOS::DataShare;
30 
31 namespace OHOS::Media {
32 thread_local PhotoAlbum *PhotoAlbumNapi::pAlbumData_ = nullptr;
33 thread_local napi_ref PhotoAlbumNapi::constructor_ = nullptr;
34 thread_local napi_ref PhotoAlbumNapi::photoAccessConstructor_ = nullptr;
35 static const string PHOTO_ALBUM_CLASS = "UserFileMgrPhotoAlbum";
36 static const string PHOTOACCESS_PHOTO_ALBUM_CLASS = "PhotoAccessPhotoAlbum";
37 
38 struct TrashAlbumExecuteOpt {
39     napi_env env;
40     void *data;
41     string tracerLabel;
42     string uri;
43 };
44 
45 using CompleteCallback = napi_async_complete_callback;
46 
PhotoAlbumNapi()47 PhotoAlbumNapi::PhotoAlbumNapi() : env_(nullptr) {}
48 
49 PhotoAlbumNapi::~PhotoAlbumNapi() = default;
50 
Init(napi_env env,napi_value exports)51 napi_value PhotoAlbumNapi::Init(napi_env env, napi_value exports)
52 {
53     NapiClassInfo info = {
54         .name = PHOTO_ALBUM_CLASS,
55         .ref = &constructor_,
56         .constructor = PhotoAlbumNapiConstructor,
57         .props = {
58             DECLARE_NAPI_GETTER_SETTER("albumName", JSGetAlbumName, JSSetAlbumName),
59             DECLARE_NAPI_GETTER("albumUri", JSGetAlbumUri),
60             DECLARE_NAPI_GETTER("count", JSGetAlbumCount),
61             DECLARE_NAPI_GETTER("albumType", JSGetPhotoAlbumType),
62             DECLARE_NAPI_GETTER("albumSubType", JSGetPhotoAlbumSubType),
63             DECLARE_NAPI_GETTER_SETTER("coverUri", JSGetCoverUri, JSSetCoverUri),
64             DECLARE_NAPI_GETTER("dateModified", JSGetDateModified),
65             DECLARE_NAPI_FUNCTION("commitModify", JSCommitModify),
66             DECLARE_NAPI_FUNCTION("addPhotoAssets", JSPhotoAlbumAddAssets),
67             DECLARE_NAPI_FUNCTION("removePhotoAssets", JSPhotoAlbumRemoveAssets),
68             DECLARE_NAPI_FUNCTION("getPhotoAssets", JSGetPhotoAssets),
69             DECLARE_NAPI_FUNCTION("recoverPhotoAssets", JSRecoverPhotos),
70             DECLARE_NAPI_FUNCTION("deletePhotoAssets", JSDeletePhotos),
71             // PrivateAlbum.recover
72             DECLARE_NAPI_FUNCTION("recover", PrivateAlbumRecoverPhotos),
73             // PrivateAlbum.delete
74             DECLARE_NAPI_FUNCTION("delete", PrivateAlbumDeletePhotos),
75         }
76     };
77 
78     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
79     return exports;
80 }
81 
PhotoAccessInit(napi_env env,napi_value exports)82 napi_value PhotoAlbumNapi::PhotoAccessInit(napi_env env, napi_value exports)
83 {
84     NapiClassInfo info = {
85         .name = PHOTOACCESS_PHOTO_ALBUM_CLASS,
86         .ref = &photoAccessConstructor_,
87         .constructor = PhotoAlbumNapiConstructor,
88         .props = {
89             DECLARE_NAPI_GETTER_SETTER("albumName", JSPhotoAccessGetAlbumName, JSPhotoAccessSetAlbumName),
90             DECLARE_NAPI_GETTER("albumUri", JSPhotoAccessGetAlbumUri),
91             DECLARE_NAPI_GETTER("count", JSPhotoAccessGetAlbumCount),
92             DECLARE_NAPI_GETTER("albumType", JSGetPhotoAlbumType),
93             DECLARE_NAPI_GETTER("albumSubtype", JSGetPhotoAlbumSubType),
94             DECLARE_NAPI_GETTER("coverUri", JSGetCoverUri),
95             DECLARE_NAPI_FUNCTION("commitModify", PhotoAccessHelperCommitModify),
96             DECLARE_NAPI_FUNCTION("addAssets", PhotoAccessHelperAddAssets),
97             DECLARE_NAPI_FUNCTION("removeAssets", PhotoAccessHelperRemoveAssets),
98             DECLARE_NAPI_FUNCTION("getAssets", JSPhoteAccessGetPhotoAssets),
99             DECLARE_NAPI_FUNCTION("recoverAssets", PhotoAccessHelperRecoverPhotos),
100             DECLARE_NAPI_FUNCTION("deleteAssets", PhotoAccessHelperDeletePhotos),
101             DECLARE_NAPI_FUNCTION("setCoverUri", PhotoAccessHelperSetCoverUri),
102         }
103     };
104 
105     MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
106     return exports;
107 }
108 
CreatePhotoAlbumNapi(napi_env env,unique_ptr<PhotoAlbum> & albumData)109 napi_value PhotoAlbumNapi::CreatePhotoAlbumNapi(napi_env env, unique_ptr<PhotoAlbum> &albumData)
110 {
111     if (albumData == nullptr) {
112         return nullptr;
113     }
114 
115     napi_value constructor;
116     napi_ref constructorRef;
117     if (albumData->GetResultNapiType() == ResultNapiType::TYPE_PHOTOACCESS_HELPER) {
118         constructorRef = photoAccessConstructor_;
119     } else {
120         constructorRef = constructor_;
121     }
122     CHECK_ARGS(env, napi_get_reference_value(env, constructorRef, &constructor), JS_INNER_FAIL);
123 
124     napi_value result = nullptr;
125     pAlbumData_ = albumData.release();
126     CHECK_ARGS(env, napi_new_instance(env, constructor, 0, nullptr, &result), JS_INNER_FAIL);
127     pAlbumData_ = nullptr;
128     return result;
129 }
130 
GetAlbumId() const131 int32_t PhotoAlbumNapi::GetAlbumId() const
132 {
133     return photoAlbumPtr->GetAlbumId();
134 }
135 
GetCount() const136 int32_t PhotoAlbumNapi::GetCount() const
137 {
138     return photoAlbumPtr->GetCount();
139 }
140 
SetCount(int32_t count)141 void PhotoAlbumNapi::SetCount(int32_t count)
142 {
143     return photoAlbumPtr->SetCount(count);
144 }
145 
GetAlbumUri() const146 const string& PhotoAlbumNapi::GetAlbumUri() const
147 {
148     return photoAlbumPtr->GetAlbumUri();
149 }
150 
GetCoverUri() const151 const string& PhotoAlbumNapi::GetCoverUri() const
152 {
153     return photoAlbumPtr->GetCoverUri();
154 }
155 
GetDateModified() const156 int64_t PhotoAlbumNapi::GetDateModified() const
157 {
158     return photoAlbumPtr->GetDateModified();
159 }
160 
GetAlbumName() const161 const string& PhotoAlbumNapi::GetAlbumName() const
162 {
163     return photoAlbumPtr->GetAlbumName();
164 }
165 
GetPhotoAlbumType() const166 PhotoAlbumType PhotoAlbumNapi::GetPhotoAlbumType() const
167 {
168     return photoAlbumPtr->GetPhotoAlbumType();
169 }
170 
GetPhotoAlbumSubType() const171 PhotoAlbumSubType PhotoAlbumNapi::GetPhotoAlbumSubType() const
172 {
173     return photoAlbumPtr->GetPhotoAlbumSubType();
174 }
175 
GetPhotoAlbumInstance() const176 shared_ptr<PhotoAlbum> PhotoAlbumNapi::GetPhotoAlbumInstance() const
177 {
178     return photoAlbumPtr;
179 }
180 
SetPhotoAlbumNapiProperties()181 void PhotoAlbumNapi::SetPhotoAlbumNapiProperties()
182 {
183     photoAlbumPtr = shared_ptr<PhotoAlbum>(pAlbumData_);
184 }
185 
186 // Constructor callback
PhotoAlbumNapiConstructor(napi_env env,napi_callback_info info)187 napi_value PhotoAlbumNapi::PhotoAlbumNapiConstructor(napi_env env, napi_callback_info info)
188 {
189     napi_value result = nullptr;
190     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
191 
192     napi_value thisVar = nullptr;
193     CHECK_ARGS(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), JS_INNER_FAIL);
194     if (thisVar == nullptr) {
195         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
196         return result;
197     }
198 
199     unique_ptr<PhotoAlbumNapi> obj = make_unique<PhotoAlbumNapi>();
200     obj->env_ = env;
201     if (pAlbumData_ == nullptr) {
202         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
203         return result;
204     }
205     obj->SetPhotoAlbumNapiProperties();
206     CHECK_ARGS(env, napi_wrap(env, thisVar, reinterpret_cast<void *>(obj.get()),
207         PhotoAlbumNapi::PhotoAlbumNapiDestructor, nullptr, nullptr), JS_INNER_FAIL);
208     obj.release();
209     return thisVar;
210 }
211 
PhotoAlbumNapiDestructor(napi_env env,void * nativeObject,void * finalizeHint)212 void PhotoAlbumNapi::PhotoAlbumNapiDestructor(napi_env env, void *nativeObject, void *finalizeHint)
213 {
214     auto *album = reinterpret_cast<PhotoAlbumNapi*>(nativeObject);
215     if (album != nullptr) {
216         delete album;
217         album = nullptr;
218     }
219 }
220 
UnwrapPhotoAlbumObject(napi_env env,napi_callback_info info,PhotoAlbumNapi ** obj)221 napi_value UnwrapPhotoAlbumObject(napi_env env, napi_callback_info info, PhotoAlbumNapi** obj)
222 {
223     napi_value result = nullptr;
224     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
225 
226     napi_value thisVar = nullptr;
227     CHECK_ARGS(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr), JS_INNER_FAIL);
228     if (thisVar == nullptr) {
229         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
230         return result;
231     }
232 
233     CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void **>(obj)), JS_INNER_FAIL);
234     if (obj == nullptr) {
235         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
236         return result;
237     }
238 
239     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
240     return result;
241 }
242 
JSGetAlbumName(napi_env env,napi_callback_info info)243 napi_value PhotoAlbumNapi::JSGetAlbumName(napi_env env, napi_callback_info info)
244 {
245     PhotoAlbumNapi *obj = nullptr;
246     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
247 
248     napi_value jsResult = nullptr;
249     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumName().c_str(), NAPI_AUTO_LENGTH, &jsResult),
250         JS_INNER_FAIL);
251     return jsResult;
252 }
253 
JSPhotoAccessGetAlbumName(napi_env env,napi_callback_info info)254 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumName(napi_env env, napi_callback_info info)
255 {
256     PhotoAlbumNapi *obj = nullptr;
257     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
258 
259     napi_value jsResult = nullptr;
260     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumName().c_str(), NAPI_AUTO_LENGTH, &jsResult),
261         JS_INNER_FAIL);
262     return jsResult;
263 }
264 
JSGetAlbumUri(napi_env env,napi_callback_info info)265 napi_value PhotoAlbumNapi::JSGetAlbumUri(napi_env env, napi_callback_info info)
266 {
267     PhotoAlbumNapi *obj = nullptr;
268     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
269 
270     napi_value jsResult = nullptr;
271     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
272         JS_INNER_FAIL);
273     return jsResult;
274 }
275 
JSPhotoAccessGetAlbumUri(napi_env env,napi_callback_info info)276 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumUri(napi_env env, napi_callback_info info)
277 {
278     PhotoAlbumNapi *obj = nullptr;
279     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
280 
281     napi_value jsResult = nullptr;
282     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetAlbumUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
283         JS_INNER_FAIL);
284     return jsResult;
285 }
286 
JSGetAlbumCount(napi_env env,napi_callback_info info)287 napi_value PhotoAlbumNapi::JSGetAlbumCount(napi_env env, napi_callback_info info)
288 {
289     PhotoAlbumNapi *obj = nullptr;
290     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
291 
292     napi_value jsResult = nullptr;
293     CHECK_ARGS(env, napi_create_int32(env, obj->GetCount(), &jsResult), JS_INNER_FAIL);
294     return jsResult;
295 }
296 
JSPhotoAccessGetAlbumCount(napi_env env,napi_callback_info info)297 napi_value PhotoAlbumNapi::JSPhotoAccessGetAlbumCount(napi_env env, napi_callback_info info)
298 {
299     PhotoAlbumNapi *obj = nullptr;
300     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
301 
302     napi_value jsResult = nullptr;
303     CHECK_ARGS(env, napi_create_int32(env, obj->GetCount(), &jsResult), JS_INNER_FAIL);
304     return jsResult;
305 }
306 
JSGetPhotoAlbumType(napi_env env,napi_callback_info info)307 napi_value PhotoAlbumNapi::JSGetPhotoAlbumType(napi_env env, napi_callback_info info)
308 {
309     PhotoAlbumNapi *obj = nullptr;
310     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
311 
312     napi_value jsResult = nullptr;
313     CHECK_ARGS(env, napi_create_int32(env, obj->GetPhotoAlbumType(), &jsResult), JS_INNER_FAIL);
314     return jsResult;
315 }
316 
JSGetPhotoAlbumSubType(napi_env env,napi_callback_info info)317 napi_value PhotoAlbumNapi::JSGetPhotoAlbumSubType(napi_env env, napi_callback_info info)
318 {
319     PhotoAlbumNapi *obj = nullptr;
320     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
321 
322     napi_value jsResult = nullptr;
323     CHECK_ARGS(env, napi_create_int32(env, obj->GetPhotoAlbumSubType(), &jsResult), JS_INNER_FAIL);
324     return jsResult;
325 }
326 
JSGetCoverUri(napi_env env,napi_callback_info info)327 napi_value PhotoAlbumNapi::JSGetCoverUri(napi_env env, napi_callback_info info)
328 {
329     PhotoAlbumNapi *obj = nullptr;
330     CHECK_NULLPTR_RET(UnwrapPhotoAlbumObject(env, info, &obj));
331 
332     napi_value jsResult = nullptr;
333     CHECK_ARGS(env, napi_create_string_utf8(env, obj->GetCoverUri().c_str(), NAPI_AUTO_LENGTH, &jsResult),
334         JS_INNER_FAIL);
335     return jsResult;
336 }
337 
GetStringArg(napi_env env,napi_callback_info info,PhotoAlbumNapi ** obj,string & output)338 napi_value GetStringArg(napi_env env, napi_callback_info info, PhotoAlbumNapi **obj, string &output)
339 {
340     size_t argc = ARGS_ONE;
341     napi_value argv[ARGS_ONE];
342     napi_value thisVar = nullptr;
343     CHECK_ARGS(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr), JS_INNER_FAIL);
344     CHECK_COND(env, argc == ARGS_ONE, JS_ERR_PARAMETER_INVALID);
345 
346     napi_value result = nullptr;
347     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
348     napi_valuetype valueType = napi_undefined;
349     if ((thisVar == nullptr) || (napi_typeof(env, argv[PARAM0], &valueType) != napi_ok) || (valueType != napi_string)) {
350         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
351         return result;
352     }
353 
354     size_t res = 0;
355     char buffer[FILENAME_MAX];
356     CHECK_ARGS(env, napi_get_value_string_utf8(env, argv[PARAM0], buffer, FILENAME_MAX, &res), JS_INNER_FAIL);
357     output = string(buffer);
358 
359     CHECK_ARGS(env, napi_unwrap(env, thisVar, reinterpret_cast<void **>(obj)), JS_INNER_FAIL);
360     if (obj == nullptr) {
361         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
362         return result;
363     }
364 
365     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
366     return result;
367 }
368 
JSSetAlbumName(napi_env env,napi_callback_info info)369 napi_value PhotoAlbumNapi::JSSetAlbumName(napi_env env, napi_callback_info info)
370 {
371     PhotoAlbumNapi *obj = nullptr;
372     string albumName;
373     CHECK_NULLPTR_RET(GetStringArg(env, info, &obj, albumName));
374     obj->photoAlbumPtr->SetAlbumName(albumName);
375 
376     napi_value result = nullptr;
377     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
378     return result;
379 }
380 
JSPhotoAccessSetAlbumName(napi_env env,napi_callback_info info)381 napi_value PhotoAlbumNapi::JSPhotoAccessSetAlbumName(napi_env env, napi_callback_info info)
382 {
383     PhotoAlbumNapi *obj = nullptr;
384     string albumName;
385     CHECK_NULLPTR_RET(GetStringArg(env, info, &obj, albumName));
386     obj->photoAlbumPtr->SetAlbumName(albumName);
387 
388     napi_value result = nullptr;
389     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
390     return result;
391 }
392 
JSSetCoverUri(napi_env env,napi_callback_info info)393 napi_value PhotoAlbumNapi::JSSetCoverUri(napi_env env, napi_callback_info info)
394 {
395     PhotoAlbumNapi *obj = nullptr;
396     string coverUri;
397     CHECK_NULLPTR_RET(GetStringArg(env, info, &obj, coverUri));
398     obj->photoAlbumPtr->SetCoverUri(coverUri);
399 
400     napi_value result = nullptr;
401     CHECK_ARGS(env, napi_get_undefined(env, &result), JS_INNER_FAIL);
402     return result;
403 }
404 
JSGetDateModified(napi_env env,napi_callback_info info)405 napi_value PhotoAlbumNapi::JSGetDateModified(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_int64(env, obj->GetDateModified(), &jsResult),
412         JS_INNER_FAIL);
413     return jsResult;
414 }
415 
ParseArgsCommitModify(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)416 static napi_value ParseArgsCommitModify(napi_env env, napi_callback_info info,
417     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
418 {
419     constexpr size_t minArgs = ARGS_ZERO;
420     constexpr size_t maxArgs = ARGS_ONE;
421     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
422         JS_ERR_PARAMETER_INVALID);
423 
424     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
425     if (photoAlbum == nullptr) {
426         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
427         return nullptr;
428     }
429     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
430         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
431         return nullptr;
432     }
433 
434     if (MediaFileUtils::CheckAlbumName(photoAlbum->GetAlbumName()) < 0) {
435         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
436         return nullptr;
437     }
438     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
439     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_NAME, photoAlbum->GetAlbumName());
440     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_COVER_URI, photoAlbum->GetCoverUri());
441 
442     napi_value result = nullptr;
443     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
444     return result;
445 }
446 
JSCommitModifyExecute(napi_env env,void * data)447 static void JSCommitModifyExecute(napi_env env, void *data)
448 {
449     MediaLibraryTracer tracer;
450     tracer.Start("JSCommitModifyExecute");
451 
452     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
453     string commitModifyUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
454         UFM_UPDATE_PHOTO_ALBUM : PAH_UPDATE_PHOTO_ALBUM;
455     Uri uri(commitModifyUri);
456     int changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
457     context->SaveError(changedRows);
458     context->changedRows = changedRows;
459 }
460 
JSCommitModifyCompleteCallback(napi_env env,napi_status status,void * data)461 static void JSCommitModifyCompleteCallback(napi_env env, napi_status status, void *data)
462 {
463     MediaLibraryTracer tracer;
464     tracer.Start("JSCommitModifyCompleteCallback");
465 
466     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
467     auto jsContext = make_unique<JSAsyncContextOutput>();
468     jsContext->status = false;
469     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
470     if (context->error == ERR_DEFAULT) {
471         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
472         jsContext->status = true;
473     } else {
474         context->HandleError(env, jsContext->error);
475     }
476 
477     tracer.Finish();
478     if (context->work != nullptr) {
479         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
480                                                    context->work, *jsContext);
481     }
482     delete context;
483 }
484 
JSCommitModify(napi_env env,napi_callback_info info)485 napi_value PhotoAlbumNapi::JSCommitModify(napi_env env, napi_callback_info info)
486 {
487     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
488     CHECK_NULLPTR_RET(ParseArgsCommitModify(env, info, asyncContext));
489     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
490 
491     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
492         JSCommitModifyCompleteCallback);
493 }
494 
PhotoAccessHelperCommitModify(napi_env env,napi_callback_info info)495 napi_value PhotoAlbumNapi::PhotoAccessHelperCommitModify(napi_env env, napi_callback_info info)
496 {
497     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
498     CHECK_NULLPTR_RET(ParseArgsCommitModify(env, info, asyncContext));
499     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
500 
501     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
502         JSCommitModifyCompleteCallback);
503 }
504 
GetAssetsUriArray(const FileAssetNapi * obj)505 static std::string GetAssetsUriArray(const FileAssetNapi *obj)
506 {
507     string displayName = obj->GetFileDisplayName();
508     string filePath = obj->GetFilePath();
509     return MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(obj->GetFileId()),
510         MediaFileUtils::GetExtraUri(displayName, filePath));
511 }
512 
GetAssetsIdArray(napi_env env,napi_value arg,vector<string> & assetsArray)513 static napi_value GetAssetsIdArray(napi_env env, napi_value arg, vector<string> &assetsArray)
514 {
515     bool isArray = false;
516     CHECK_ARGS(env, napi_is_array(env, arg, &isArray), JS_INNER_FAIL);
517     if (!isArray) {
518         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check array type");
519         return nullptr;
520     }
521 
522     uint32_t len = 0;
523     CHECK_ARGS(env, napi_get_array_length(env, arg, &len), JS_INNER_FAIL);
524     if (len < 0) {
525         NAPI_ERR_LOG("Failed to check array length: %{public}u", len);
526         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check array length");
527         return nullptr;
528     }
529     if (len == 0) {
530         napi_value result = nullptr;
531         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
532         return result;
533     }
534 
535     for (uint32_t i = 0; i < len; i++) {
536         napi_value asset = nullptr;
537         CHECK_ARGS(env, napi_get_element(env, arg, i, &asset), JS_INNER_FAIL);
538         if (asset == nullptr) {
539             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to get asset element");
540             return nullptr;
541         }
542 
543         FileAssetNapi *obj = nullptr;
544         CHECK_ARGS(env, napi_unwrap(env, asset, reinterpret_cast<void **>(&obj)), JS_INNER_FAIL);
545         if (obj == nullptr) {
546             NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to get asset napi object");
547             return nullptr;
548         }
549         if ((obj->GetMediaType() != MEDIA_TYPE_IMAGE && obj->GetMediaType() != MEDIA_TYPE_VIDEO)) {
550             NAPI_INFO_LOG("Skip invalid asset, mediaType: %{public}d", obj->GetMediaType());
551             continue;
552         }
553         assetsArray.push_back(GetAssetsUriArray(obj));
554     }
555 
556     napi_value result = nullptr;
557     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
558     return result;
559 }
560 
ParseArgsAddAssets(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)561 static napi_value ParseArgsAddAssets(napi_env env, napi_callback_info info,
562     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
563 {
564     constexpr size_t minArgs = ARGS_ONE;
565     constexpr size_t maxArgs = ARGS_TWO;
566     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
567         JS_ERR_PARAMETER_INVALID);
568 
569     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
570     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
571         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
572         return nullptr;
573     }
574 
575     /* Parse the first argument */
576     vector<string> assetsArray;
577     CHECK_NULLPTR_RET(GetAssetsIdArray(env, context->argv[PARAM0], assetsArray));
578     if (assetsArray.empty()) {
579         napi_value result = nullptr;
580         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
581         return result;
582     }
583     int32_t albumId = photoAlbum->GetAlbumId();
584     for (const auto &assetId : assetsArray) {
585         DataShareValuesBucket valuesBucket;
586         valuesBucket.Put(PhotoMap::ALBUM_ID, albumId);
587         valuesBucket.Put(PhotoMap::ASSET_ID, assetId);
588         context->valuesBuckets.push_back(valuesBucket);
589     }
590 
591     napi_value result = nullptr;
592     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
593     return result;
594 }
595 
JSPhotoAlbumAddAssetsExecute(napi_env env,void * data)596 static void JSPhotoAlbumAddAssetsExecute(napi_env env, void *data)
597 {
598     MediaLibraryTracer tracer;
599     tracer.Start("JSPhotoAlbumAddAssetsExecute");
600 
601     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
602     if (context->valuesBuckets.empty()) {
603         return;
604     }
605 
606     string addAssetsUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
607         UFM_PHOTO_ALBUM_ADD_ASSET : PAH_PHOTO_ALBUM_ADD_ASSET;
608     Uri uri(addAssetsUri);
609     auto changedRows = UserFileClient::BatchInsert(uri, context->valuesBuckets);
610     if (changedRows < 0) {
611         context->SaveError(changedRows);
612         return;
613     }
614     context->changedRows = changedRows;
615 }
616 
JSPhotoAlbumAddAssetsCompleteCallback(napi_env env,napi_status status,void * data)617 static void JSPhotoAlbumAddAssetsCompleteCallback(napi_env env, napi_status status, void *data)
618 {
619     MediaLibraryTracer tracer;
620     tracer.Start("JSPhotoAlbumAddAssetsCompleteCallback");
621 
622     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
623     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
624     jsContext->status = false;
625     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
626     if (context->error == ERR_DEFAULT) {
627         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
628         jsContext->status = true;
629         context->objectInfo->SetCount(context->objectInfo->GetCount() + context->changedRows);
630     } else {
631         context->HandleError(env, jsContext->error);
632     }
633 
634     tracer.Finish();
635     if (context->work != nullptr) {
636         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
637                                                    context->work, *jsContext);
638     }
639     delete context;
640 }
641 
JSPhotoAlbumAddAssets(napi_env env,napi_callback_info info)642 napi_value PhotoAlbumNapi::JSPhotoAlbumAddAssets(napi_env env, napi_callback_info info)
643 {
644     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
645     CHECK_NULLPTR_RET(ParseArgsAddAssets(env, info, asyncContext));
646     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
647 
648     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumAddAssets",
649         JSPhotoAlbumAddAssetsExecute, JSPhotoAlbumAddAssetsCompleteCallback);
650 }
651 
PhotoAccessHelperAddAssets(napi_env env,napi_callback_info info)652 napi_value PhotoAlbumNapi::PhotoAccessHelperAddAssets(napi_env env, napi_callback_info info)
653 {
654     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
655     CHECK_NULLPTR_RET(ParseArgsAddAssets(env, info, asyncContext));
656     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
657 
658     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumAddAssets",
659         JSPhotoAlbumAddAssetsExecute, JSPhotoAlbumAddAssetsCompleteCallback);
660 }
661 
ParseArgsRemoveAssets(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)662 static napi_value ParseArgsRemoveAssets(napi_env env, napi_callback_info info,
663     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
664 {
665     constexpr size_t minArgs = ARGS_ONE;
666     constexpr size_t maxArgs = ARGS_TWO;
667     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
668         JS_ERR_PARAMETER_INVALID);
669 
670     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
671     if (!PhotoAlbum::IsUserPhotoAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
672         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
673         return nullptr;
674     }
675 
676     /* Parse the first argument */
677     vector<string> assetsArray;
678     CHECK_NULLPTR_RET(GetAssetsIdArray(env, context->argv[PARAM0], assetsArray));
679     if (assetsArray.empty()) {
680         napi_value result = nullptr;
681         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
682         return result;
683     }
684     context->predicates.EqualTo(PhotoMap::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
685     context->predicates.And()->In(PhotoMap::ASSET_ID, assetsArray);
686 
687     napi_value result = nullptr;
688     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
689     return result;
690 }
691 
JSPhotoAlbumRemoveAssetsExecute(napi_env env,void * data)692 static void JSPhotoAlbumRemoveAssetsExecute(napi_env env, void *data)
693 {
694     MediaLibraryTracer tracer;
695     tracer.Start("JSPhotoAlbumRemoveAssetsExecute");
696 
697     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
698     if (context->predicates.GetOperationList().empty()) {
699         return;
700     }
701 
702     string removeAssetsUri = (context->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
703         UFM_PHOTO_ALBUM_REMOVE_ASSET : PAH_PHOTO_ALBUM_REMOVE_ASSET;
704     Uri uri(removeAssetsUri);
705     auto deletedRows = UserFileClient::Delete(uri, context->predicates);
706     if (deletedRows < 0) {
707         context->SaveError(deletedRows);
708         return;
709     }
710     context->changedRows = deletedRows;
711 }
712 
JSPhotoAlbumRemoveAssetsCompleteCallback(napi_env env,napi_status status,void * data)713 static void JSPhotoAlbumRemoveAssetsCompleteCallback(napi_env env, napi_status status, void *data)
714 {
715     MediaLibraryTracer tracer;
716     tracer.Start("JSPhotoAlbumRemoveAssetsCompleteCallback");
717 
718     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
719     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
720     jsContext->status = false;
721     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
722     if (context->error == ERR_DEFAULT) {
723         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
724         jsContext->status = true;
725         int32_t count = context->objectInfo->GetCount() - context->changedRows;
726         context->objectInfo->SetCount((count > 0) ? count : 0);
727     } else {
728         context->HandleError(env, jsContext->error);
729     }
730 
731     tracer.Finish();
732     if (context->work != nullptr) {
733         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
734                                                    context->work, *jsContext);
735     }
736     delete context;
737 }
738 
JSPhotoAlbumRemoveAssets(napi_env env,napi_callback_info info)739 napi_value PhotoAlbumNapi::JSPhotoAlbumRemoveAssets(napi_env env, napi_callback_info info)
740 {
741     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
742     CHECK_NULLPTR_RET(ParseArgsRemoveAssets(env, info, asyncContext));
743     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
744 
745     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumRemoveAssets",
746         JSPhotoAlbumRemoveAssetsExecute, JSPhotoAlbumRemoveAssetsCompleteCallback);
747 }
748 
PhotoAccessHelperRemoveAssets(napi_env env,napi_callback_info info)749 napi_value PhotoAlbumNapi::PhotoAccessHelperRemoveAssets(napi_env env, napi_callback_info info)
750 {
751     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
752     CHECK_NULLPTR_RET(ParseArgsRemoveAssets(env, info, asyncContext));
753     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
754 
755     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSPhotoAlbumRemoveAssets",
756         JSPhotoAlbumRemoveAssetsExecute, JSPhotoAlbumRemoveAssetsCompleteCallback);
757 }
758 
GetPredicatesByAlbumTypes(const shared_ptr<PhotoAlbum> & photoAlbum,DataSharePredicates & predicates)759 static int32_t GetPredicatesByAlbumTypes(const shared_ptr<PhotoAlbum> &photoAlbum,
760     DataSharePredicates &predicates)
761 {
762     auto albumId = photoAlbum->GetAlbumId();
763     if (albumId <= 0) {
764         return E_INVALID_ARGUMENTS;
765     }
766     auto type = photoAlbum->GetPhotoAlbumType();
767     auto subType = photoAlbum->GetPhotoAlbumSubType();
768     if ((!PhotoAlbum::CheckPhotoAlbumType(type)) || (!PhotoAlbum::CheckPhotoAlbumSubType(subType))) {
769         return E_INVALID_ARGUMENTS;
770     }
771 
772     if (PhotoAlbum::IsUserPhotoAlbum(type, subType)) {
773         return MediaLibraryNapiUtils::GetUserAlbumPredicates(photoAlbum->GetAlbumId(), predicates);
774     }
775 
776     if ((type != PhotoAlbumType::SYSTEM) || (subType == PhotoAlbumSubType::USER_GENERIC) ||
777         (subType == PhotoAlbumSubType::ANY)) {
778         return E_INVALID_ARGUMENTS;
779     }
780     return MediaLibraryNapiUtils::GetSystemAlbumPredicates(subType, predicates);
781 }
782 
ParseArgsGetPhotoAssets(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)783 static napi_value ParseArgsGetPhotoAssets(napi_env env, napi_callback_info info,
784     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
785 {
786     constexpr size_t minArgs = ARGS_ONE;
787     constexpr size_t maxArgs = ARGS_TWO;
788     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
789         JS_ERR_PARAMETER_INVALID);
790 
791     /* Parse the first argument */
792     CHECK_ARGS(env, MediaLibraryNapiUtils::GetFetchOption(env, context->argv[PARAM0], ASSET_FETCH_OPT, context),
793         JS_INNER_FAIL);
794 
795     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
796     auto ret = GetPredicatesByAlbumTypes(photoAlbum, context->predicates);
797     if (ret != E_SUCCESS) {
798         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID);
799         return nullptr;
800     }
801     CHECK_NULLPTR_RET(MediaLibraryNapiUtils::AddDefaultAssetColumns(env, context->fetchColumn,
802         PhotoColumn::IsPhotoColumn));
803 
804     napi_value result = nullptr;
805     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
806     return result;
807 }
808 
JSGetPhotoAssetsExecute(napi_env env,void * data)809 static void JSGetPhotoAssetsExecute(napi_env env, void *data)
810 {
811     MediaLibraryTracer tracer;
812     tracer.Start("JSGetPhotoAssetsExecute");
813 
814     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
815     string queryUri = UFM_QUERY_PHOTO_MAP;
816     Uri uri(queryUri);
817     int32_t errCode = 0;
818     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
819     if (resultSet == nullptr) {
820         context->SaveError(E_HAS_DB_ERROR);
821         return;
822     }
823     context->fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
824     context->fetchResult->SetResultNapiType(ResultNapiType::TYPE_USERFILE_MGR);
825 }
826 
JSPhotoAccessGetPhotoAssetsExecute(napi_env env,void * data)827 static void JSPhotoAccessGetPhotoAssetsExecute(napi_env env, void *data)
828 {
829     MediaLibraryTracer tracer;
830     tracer.Start("JSPhotoAccessGetPhotoAssetsExecute");
831 
832     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
833     Uri uri(PAH_QUERY_PHOTO_MAP);
834     int32_t errCode = 0;
835     auto resultSet = UserFileClient::Query(uri, context->predicates, context->fetchColumn, errCode);
836     if (resultSet == nullptr) {
837         context->SaveError(E_HAS_DB_ERROR);
838         return;
839     }
840     context->fetchResult = make_unique<FetchResult<FileAsset>>(move(resultSet));
841     context->fetchResult->SetResultNapiType(ResultNapiType::TYPE_PHOTOACCESS_HELPER);
842 }
843 
GetPhotoMapQueryResult(napi_env env,PhotoAlbumNapiAsyncContext * context,unique_ptr<JSAsyncContextOutput> & jsContext)844 static void GetPhotoMapQueryResult(napi_env env, PhotoAlbumNapiAsyncContext *context,
845     unique_ptr<JSAsyncContextOutput> &jsContext)
846 {
847     napi_value fetchRes = FetchFileResultNapi::CreateFetchFileResult(env, move(context->fetchResult));
848     if (fetchRes == nullptr) {
849         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_MEM_ALLOCATION,
850             "Failed to create js object for FetchFileResult");
851         return;
852     }
853     jsContext->data = fetchRes;
854     jsContext->status = true;
855 }
856 
JSGetPhotoAssetsCallbackComplete(napi_env env,napi_status status,void * data)857 static void JSGetPhotoAssetsCallbackComplete(napi_env env, napi_status status, void *data)
858 {
859     MediaLibraryTracer tracer;
860     tracer.Start("JSGetPhotoAssetsCallbackComplete");
861 
862     auto *context = static_cast<PhotoAlbumNapiAsyncContext *>(data);
863 
864     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
865     jsContext->status = false;
866 
867     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
868     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
869     if (context->fetchResult != nullptr) {
870         GetPhotoMapQueryResult(env, context, jsContext);
871     } else {
872         NAPI_ERR_LOG("No fetch file result found!");
873         MediaLibraryNapiUtils::CreateNapiErrorObject(env, jsContext->error, ERR_INVALID_OUTPUT,
874             "Failed to get fetchFileResult from DB");
875     }
876 
877     tracer.Finish();
878     if (context->work != nullptr) {
879         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
880                                                    context->work, *jsContext);
881     }
882     delete context;
883 }
884 
JSGetPhotoAssets(napi_env env,napi_callback_info info)885 napi_value PhotoAlbumNapi::JSGetPhotoAssets(napi_env env, napi_callback_info info)
886 {
887     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
888     CHECK_NULLPTR_RET(ParseArgsGetPhotoAssets(env, info, asyncContext));
889 
890     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets", JSGetPhotoAssetsExecute,
891         JSGetPhotoAssetsCallbackComplete);
892 }
893 
JSPhoteAccessGetPhotoAssets(napi_env env,napi_callback_info info)894 napi_value PhotoAlbumNapi::JSPhoteAccessGetPhotoAssets(napi_env env, napi_callback_info info)
895 {
896     unique_ptr<PhotoAlbumNapiAsyncContext> asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
897     CHECK_NULLPTR_RET(ParseArgsGetPhotoAssets(env, info, asyncContext));
898 
899     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSGetPhotoAssets",
900         JSPhotoAccessGetPhotoAssetsExecute, JSGetPhotoAssetsCallbackComplete);
901 }
902 
TrashAlbumParseArgs(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)903 static napi_value TrashAlbumParseArgs(napi_env env, napi_callback_info info,
904     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
905 {
906     constexpr size_t minArgs = ARGS_ONE;
907     constexpr size_t maxArgs = ARGS_TWO;
908     CHECK_ARGS(env, MediaLibraryNapiUtils::AsyncContextSetObjectInfo(env, info, context, minArgs, maxArgs),
909         JS_ERR_PARAMETER_INVALID);
910     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
911     if (!PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
912         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check trash album type");
913         return nullptr;
914     }
915 
916     /* Parse the first argument */
917     vector<string> assetsArray;
918     CHECK_NULLPTR_RET(GetAssetsIdArray(env, context->argv[PARAM0], assetsArray));
919     if (assetsArray.empty()) {
920         napi_value result = nullptr;
921         CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
922         return result;
923     }
924     context->predicates.In(MediaColumn::MEDIA_ID, assetsArray);
925     context->valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, 0);
926 
927     napi_value result = nullptr;
928     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
929     return result;
930 }
931 
TrashAlbumExecute(const TrashAlbumExecuteOpt & opt)932 static void TrashAlbumExecute(const TrashAlbumExecuteOpt &opt)
933 {
934     MediaLibraryTracer tracer;
935     tracer.Start(opt.tracerLabel);
936 
937     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(opt.data);
938     if (context->predicates.GetOperationList().empty()) {
939         return;
940     }
941     Uri uri(opt.uri);
942     int changedRows = UserFileClient::Update(uri, context->predicates, context->valuesBucket);
943     if (changedRows < 0) {
944         context->SaveError(changedRows);
945         return;
946     }
947     context->changedRows = changedRows;
948 }
949 
TrashAlbumComplete(napi_env env,napi_status status,void * data)950 static void TrashAlbumComplete(napi_env env, napi_status status, void *data)
951 {
952     auto *context = static_cast<PhotoAlbumNapiAsyncContext*>(data);
953     auto jsContext = make_unique<JSAsyncContextOutput>();
954     jsContext->status = false;
955     CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->data), JS_INNER_FAIL);
956     if (context->error == ERR_DEFAULT) {
957         CHECK_ARGS_RET_VOID(env, napi_get_undefined(env, &jsContext->error), JS_INNER_FAIL);
958         jsContext->status = true;
959     } else {
960         context->HandleError(env, jsContext->error);
961     }
962 
963     if (context->work != nullptr) {
964         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
965                                                    context->work, *jsContext);
966     }
967     delete context;
968 }
969 
RecoverPhotosExecute(napi_env env,void * data)970 static void RecoverPhotosExecute(napi_env env, void *data)
971 {
972     TrashAlbumExecuteOpt opt = {
973         .env = env,
974         .data = data,
975         .tracerLabel = "RecoverPhotosExecute",
976         .uri = (static_cast<PhotoAlbumNapiAsyncContext *>(data)->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
977             UFM_RECOVER_PHOTOS : PAH_RECOVER_PHOTOS,
978     };
979     TrashAlbumExecute(opt);
980 }
981 
RecoverPhotosComplete(napi_env env,napi_status status,void * data)982 static void RecoverPhotosComplete(napi_env env, napi_status status, void *data)
983 {
984     TrashAlbumComplete(env, status, data);
985 }
986 
JSRecoverPhotos(napi_env env,napi_callback_info info)987 napi_value PhotoAlbumNapi::JSRecoverPhotos(napi_env env, napi_callback_info info)
988 {
989     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
990     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
991     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
992 
993     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRecoverPhotos", RecoverPhotosExecute,
994         RecoverPhotosComplete);
995 }
996 
PrivateAlbumParseArgs(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)997 static napi_value PrivateAlbumParseArgs(napi_env env, napi_callback_info info,
998     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
999 {
1000     string uri;
1001     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, uri),
1002         JS_ERR_PARAMETER_INVALID);
1003     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1004     if (photoAlbum == nullptr) {
1005         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to get photo album instance");
1006         return nullptr;
1007     }
1008     if (!PhotoAlbum::IsTrashAlbum(photoAlbum->GetPhotoAlbumType(), photoAlbum->GetPhotoAlbumSubType())) {
1009         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Failed to check trash album type");
1010         return nullptr;
1011     }
1012 
1013     context->predicates.EqualTo(MediaColumn::MEDIA_ID, MediaFileUtils::GetIdFromUri(uri));
1014     context->valuesBucket.Put(MediaColumn::MEDIA_DATE_TRASHED, 0);
1015 
1016     napi_value result = nullptr;
1017     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1018     return result;
1019 }
1020 
PrivateAlbumRecoverPhotos(napi_env env,napi_callback_info info)1021 napi_value PhotoAlbumNapi::PrivateAlbumRecoverPhotos(napi_env env, napi_callback_info info)
1022 {
1023     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1024     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1025     CHECK_NULLPTR_RET(PrivateAlbumParseArgs(env, info, asyncContext));
1026 
1027     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PrivateAlbumRecoverPhotos",
1028         RecoverPhotosExecute, RecoverPhotosComplete);
1029 }
1030 
PhotoAccessHelperRecoverPhotos(napi_env env,napi_callback_info info)1031 napi_value PhotoAlbumNapi::PhotoAccessHelperRecoverPhotos(napi_env env, napi_callback_info info)
1032 {
1033     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1034     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
1035     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1036 
1037     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRecoverPhotos", RecoverPhotosExecute,
1038         RecoverPhotosComplete);
1039 }
1040 
DeletePhotosExecute(napi_env env,void * data)1041 static void DeletePhotosExecute(napi_env env, void *data)
1042 {
1043     TrashAlbumExecuteOpt opt = {
1044         .env = env,
1045         .data = data,
1046         .tracerLabel = "DeletePhotosExecute",
1047         .uri = (static_cast<PhotoAlbumNapiAsyncContext *>(data)->resultNapiType == ResultNapiType::TYPE_USERFILE_MGR) ?
1048             UFM_DELETE_PHOTOS : PAH_DELETE_PHOTOS,
1049     };
1050     TrashAlbumExecute(opt);
1051 }
1052 
DeletePhotosComplete(napi_env env,napi_status status,void * data)1053 static void DeletePhotosComplete(napi_env env, napi_status status, void *data)
1054 {
1055     TrashAlbumComplete(env, status, data);
1056 }
1057 
JSDeletePhotos(napi_env env,napi_callback_info info)1058 napi_value PhotoAlbumNapi::JSDeletePhotos(napi_env env, napi_callback_info info)
1059 {
1060     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1061     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
1062     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1063 
1064     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeletePhotos", DeletePhotosExecute,
1065         DeletePhotosComplete);
1066 }
1067 
PrivateAlbumDeletePhotos(napi_env env,napi_callback_info info)1068 napi_value PhotoAlbumNapi::PrivateAlbumDeletePhotos(napi_env env, napi_callback_info info)
1069 {
1070     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1071     asyncContext->resultNapiType = ResultNapiType::TYPE_USERFILE_MGR;
1072     CHECK_NULLPTR_RET(PrivateAlbumParseArgs(env, info, asyncContext));
1073 
1074     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "PrivateAlbumDeletePhotos",
1075         DeletePhotosExecute, DeletePhotosComplete);
1076 }
1077 
PhotoAccessHelperDeletePhotos(napi_env env,napi_callback_info info)1078 napi_value PhotoAlbumNapi::PhotoAccessHelperDeletePhotos(napi_env env, napi_callback_info info)
1079 {
1080     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1081     CHECK_NULLPTR_RET(TrashAlbumParseArgs(env, info, asyncContext));
1082     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1083 
1084     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSDeletePhotos", DeletePhotosExecute,
1085         DeletePhotosComplete);
1086 }
1087 
ParseArgsSetCoverUri(napi_env env,napi_callback_info info,unique_ptr<PhotoAlbumNapiAsyncContext> & context)1088 static napi_value ParseArgsSetCoverUri(napi_env env, napi_callback_info info,
1089     unique_ptr<PhotoAlbumNapiAsyncContext> &context)
1090 {
1091     string coverUri;
1092     CHECK_ARGS(env, MediaLibraryNapiUtils::ParseArgsStringCallback(env, info, context, coverUri),
1093         JS_ERR_PARAMETER_INVALID);
1094     auto photoAlbum = context->objectInfo->GetPhotoAlbumInstance();
1095     if (!MediaLibraryNapiUtils::IsSystemApp()) {
1096         NapiError::ThrowError(env, JS_ERR_PARAMETER_INVALID, "Only system apps can update album cover");
1097         return nullptr;
1098     }
1099 
1100     context->predicates.EqualTo(PhotoAlbumColumns::ALBUM_ID, to_string(photoAlbum->GetAlbumId()));
1101     context->valuesBucket.Put(PhotoAlbumColumns::ALBUM_COVER_URI, coverUri);
1102 
1103     napi_value result = nullptr;
1104     CHECK_ARGS(env, napi_get_boolean(env, true, &result), JS_INNER_FAIL);
1105     return result;
1106 }
1107 
PhotoAccessHelperSetCoverUri(napi_env env,napi_callback_info info)1108 napi_value PhotoAlbumNapi::PhotoAccessHelperSetCoverUri(napi_env env, napi_callback_info info)
1109 {
1110     auto asyncContext = make_unique<PhotoAlbumNapiAsyncContext>();
1111     asyncContext->resultNapiType = ResultNapiType::TYPE_PHOTOACCESS_HELPER;
1112     CHECK_NULLPTR_RET(ParseArgsSetCoverUri(env, info, asyncContext));
1113 
1114     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCommitModify", JSCommitModifyExecute,
1115         JSCommitModifyCompleteCallback);
1116 }
1117 } // namespace OHOS::Media
1118