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