1 /*
2  * Copyright (C) 2024 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 "PhotoBurstOperation"
16 
17 #include "photo_burst_operation.h"
18 
19 #include <string>
20 #include <uuid.h>
21 #include <sstream>
22 #include <vector>
23 #include <numeric>
24 #include <algorithm>
25 
26 #include "rdb_store.h"
27 #include "result_set_utils.h"
28 #include "userfile_manager_types.h"
29 #include "media_column.h"
30 #include "media_log.h"
31 
32 namespace OHOS::Media {
SetTargetPhotoInfo(const PhotoAssetInfo & photoAssetInfo)33 PhotoBurstOperation &PhotoBurstOperation::SetTargetPhotoInfo(const PhotoAssetInfo &photoAssetInfo)
34 {
35     this->photoAssetInfo_ = photoAssetInfo;
36     this->photoAssetInfo_.burstGroupName = this->FindBurstGroupName(photoAssetInfo.displayName);
37     return *this;
38 }
39 
40 /**
41  * @brief Find burstKey from the given albumId, only for BURST photo.
42  * @return burstKey, if found; empty string, otherwise.
43  */
FindBurstKey(const std::shared_ptr<MediaLibraryRdbStore> & rdbStore)44 std::string PhotoBurstOperation::FindBurstKey(const std::shared_ptr<MediaLibraryRdbStore> &rdbStore)
45 {
46     return this->FindBurstKey(rdbStore, this->photoAssetInfo_);
47 }
48 
49 /**
50  * @brief Find burstKey from the given albumId, only for BURST photo.
51  * @return burstKey, if found; empty string, otherwise.
52  */
FindBurstKey(const std::shared_ptr<MediaLibraryRdbStore> & rdbStore,const PhotoAssetInfo & photoAssetInfo)53 std::string PhotoBurstOperation::FindBurstKey(
54     const std::shared_ptr<MediaLibraryRdbStore> &rdbStore, const PhotoAssetInfo &photoAssetInfo)
55 {
56     if (photoAssetInfo.ownerAlbumId <= 0 || photoAssetInfo.burstGroupName.empty() ||
57         photoAssetInfo.subtype != static_cast<int32_t>(PhotoSubType::BURST) || rdbStore == nullptr) {
58         return "";
59     }
60     std::string burstKey = this->QueryBurstKeyFromDB(rdbStore, photoAssetInfo);
61     if (burstKey.empty()) {
62         burstKey = this->GenerateUuid();
63         MEDIA_INFO_LOG("Media_Operation: burstKey is empty, create a new one [%{public}s]. Object: %{public}s",
64             burstKey.c_str(),
65             photoAssetInfo.ToString().c_str());
66     }
67     return burstKey;
68 }
69 
ToString(const std::vector<NativeRdb::ValueObject> & values)70 std::string PhotoBurstOperation::ToString(const std::vector<NativeRdb::ValueObject> &values)
71 {
72     std::vector<std::string> result;
73     for (auto &value : values) {
74         std::string str;
75         value.GetString(str);
76         result.emplace_back(str + ", ");
77     }
78     return std::accumulate(result.begin(), result.end(), std::string());
79 }
80 
81 /**
82  * @brief generate a uuid
83  *
84  * @return std::string uuid with 37 characters
85  */
GenerateUuid()86 std::string PhotoBurstOperation::GenerateUuid()
87 {
88     uuid_t uuid;
89     uuid_generate(uuid);
90     char str[UUID_STR_LENGTH] = {};
91     uuid_unparse(uuid, str);
92     return str;
93 }
94 
95 /**
96  * @brief find prefix contains "_BURST" of displayName
97  *
98  * @return std::string prefix including "_BURST" of displayName
99  */
FindBurstGroupName(const std::string & displayName)100 std::string PhotoBurstOperation::FindBurstGroupName(const std::string &displayName)
101 {
102     auto pos = displayName.find(this->TITLE_KEY_WORDS_OF_BURST);
103     if (pos == std::string::npos) {
104         MEDIA_ERR_LOG("Media_Operation: FindBurstGroupName: cannot find _BURST in displayName. displayName: %{public}s",
105             displayName.c_str());
106         return "";
107     }
108     return displayName.substr(0, std::min<int32_t>(pos, DISPLAY_NAME_PREFIX_LENGTH) + 1);
109 }
110 
QueryBurstKeyFromDB(const std::shared_ptr<MediaLibraryRdbStore> & rdbStore,const PhotoAssetInfo & photoAssetInfo)111 std::string PhotoBurstOperation::QueryBurstKeyFromDB(
112     const std::shared_ptr<MediaLibraryRdbStore> &rdbStore, const PhotoAssetInfo &photoAssetInfo)
113 {
114     int32_t ownerAlbumId = photoAssetInfo.ownerAlbumId;
115     std::string burstGroupName = photoAssetInfo.burstGroupName;
116     // Avoid full table scan: if the burstGroupName is empty, return empty string.
117     if (ownerAlbumId <= 0 || burstGroupName.empty() || rdbStore == nullptr) {
118         MEDIA_ERR_LOG("Media_Operation: object invalid. Object: %{public}s", photoAssetInfo.ToString().c_str());
119         return "";
120     }
121     std::string querySql = this->SQL_PHOTOS_TABLE_QUERY_BURST_KEY;
122     std::string burstGroupNameCondition = burstGroupName + "%";
123     const std::vector<NativeRdb::ValueObject> bindArgs = {ownerAlbumId, burstGroupNameCondition};
124     auto resultSet = rdbStore->QuerySql(querySql, bindArgs);
125     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
126         MEDIA_WARN_LOG("Media_Operation: resultSet is null or no data found! "
127                        "querySql: %{public}s, bindArgs: %{public}s",
128             querySql.c_str(),
129             this->ToString(bindArgs).c_str());
130         return "";
131     }
132     std::string burstKey = GetStringVal(PhotoColumn::PHOTO_BURST_KEY, resultSet);
133     return burstKey;
134 }
135 }  // namespace OHOS::Media