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