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