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
16 #include "album_data_handler.h"
17
18 #include "medialibrary_db_const.h"
19 #include "medialibrary_type_const.h"
20
21 #include "data_sync_const.h"
22 #include "data_sync_notifier.h"
23 #include "dfs_error.h"
24 #include "gallery_album_const.h"
25 #include "utils_log.h"
26
27 namespace OHOS {
28 namespace FileManagement {
29 namespace CloudSync {
30 using namespace std;
31 using namespace NativeRdb;
32 using namespace DriveKit;
33 using namespace Media;
34 using PAC = Media::PhotoAlbumColumns;
35 using ChangeType = OHOS::AAFwk::ChangeInfo::ChangeType;
36
AlbumDataHandler(int32_t userId,const std::string & bundleName,std::shared_ptr<RdbStore> rdb)37 AlbumDataHandler::AlbumDataHandler(int32_t userId, const std::string &bundleName, std::shared_ptr<RdbStore> rdb)
38 : RdbDataHandler(userId, bundleName, PAC::TABLE, rdb)
39 {
40 }
41
GetFetchCondition(FetchCondition & cond)42 void AlbumDataHandler::GetFetchCondition(FetchCondition &cond)
43 {
44 cond.limitRes = LIMIT_SIZE;
45 cond.recordType = recordType_;
46 cond.desiredKeys = desiredKeys_;
47 cond.fullKeys = desiredKeys_;
48 }
49
50
QueryLocalMatch(const std::string & recordId)51 tuple<shared_ptr<ResultSet>, int> AlbumDataHandler::QueryLocalMatch(const std::string &recordId)
52 {
53 NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(PAC::TABLE);
54 predicates.EqualTo(PAC::ALBUM_CLOUD_ID, recordId);
55 auto resultSet = Query(predicates, ALBUM_LOCAL_QUERY_COLUMNS);
56 if (resultSet == nullptr) {
57 LOGE("get nullptr query result");
58 return {nullptr, 0};
59 }
60 int rowCount = 0;
61 int ret = resultSet->GetRowCount(rowCount);
62 if (ret != 0) {
63 LOGE("result set get row count err %{public}d", ret);
64 return {nullptr, 0};
65 }
66 return { move(resultSet), rowCount };
67 }
68
InsertCloudAlbum(DKRecord & record)69 int32_t AlbumDataHandler::InsertCloudAlbum(DKRecord &record)
70 {
71 LOGI("insert of record %s", record.GetRecordId().c_str());
72
73 ValuesBucket values;
74 int32_t ret = createConvertor_.RecordToValueBucket(record, values);
75 if (ret != E_OK) {
76 LOGE("record to value bucket failed, ret = %{public}d", ret);
77 return ret;
78 }
79 values.PutInt(PAC::ALBUM_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED));
80 values.PutString(PAC::ALBUM_CLOUD_ID, record.GetRecordId());
81
82 /* update if a album with the same name exists? */
83 int64_t rowId;
84 ret = Insert(rowId, values);
85 if (ret != E_OK) {
86 LOGE("Insert pull record failed, rdb ret = %{public}d", ret);
87 return E_RDB;
88 }
89 return E_OK;
90 }
91
DeleteCloudAlbum(DKRecord & record)92 int32_t AlbumDataHandler::DeleteCloudAlbum(DKRecord &record)
93 {
94 int32_t deletedRows;
95 int ret = Delete(deletedRows, PAC::ALBUM_CLOUD_ID + " = ?", { record.GetRecordId() });
96 if (ret != E_OK) {
97 LOGE("delete in rdb failed, ret: %{public}d", ret);
98 return E_INVAL_ARG;
99 }
100 return E_OK;
101 }
102
UpdateCloudAlbum(DKRecord & record)103 int32_t AlbumDataHandler::UpdateCloudAlbum(DKRecord &record)
104 {
105 int32_t changedRows;
106 ValuesBucket values;
107 int32_t ret = createConvertor_.RecordToValueBucket(record, values);
108 if (ret != E_OK) {
109 LOGE("record to value bucket failed, ret = %{public}d", ret);
110 return ret;
111 }
112 values.PutInt(PAC::ALBUM_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED));
113
114 ret = Update(changedRows, values, PAC::ALBUM_CLOUD_ID + " = ?", { record.GetRecordId() });
115 if (ret != E_OK) {
116 LOGE("rdb update failed, err = %{public}d", ret);
117 return E_RDB;
118 }
119 return E_OK;
120 }
121
GetLocalMatchDirty(NativeRdb::ResultSet & resultSet)122 static int32_t GetLocalMatchDirty(NativeRdb::ResultSet &resultSet)
123 {
124 int32_t dirty;
125 int32_t ret = DataConvertor::GetInt(PAC::ALBUM_DIRTY, dirty, resultSet);
126 if (ret != E_OK) {
127 LOGE("fail to get album dirty value");
128 /* assume dirty so that no follow-up actions */
129 return static_cast<int32_t>(Media::DirtyType::TYPE_MDIRTY);
130 }
131 return dirty;
132 }
133
HandleLocalDirty(int32_t dirty,const DriveKit::DKRecord & record)134 int32_t AlbumDataHandler::HandleLocalDirty(int32_t dirty, const DriveKit::DKRecord &record)
135 {
136 /* new -> dirty: keep local info and update cloud's */
137 if (dirty == static_cast<int32_t>(Media::DirtyType::TYPE_NEW)) {
138 int32_t changedRows;
139 ValuesBucket values;
140 values.PutInt(PAC::ALBUM_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_MDIRTY));
141 int32_t ret = Update(changedRows, values, PAC::ALBUM_NAME + " = ?", { record.GetRecordId() });
142 if (ret != E_OK) {
143 LOGE("rdb update failed, err = %{public}d", ret);
144 return E_RDB;
145 }
146 return E_OK;
147 }
148 return E_OK;
149 }
150
OnFetchRecords(shared_ptr<vector<DKRecord>> & records,OnFetchParams & params)151 int32_t AlbumDataHandler::OnFetchRecords(shared_ptr<vector<DKRecord>> &records,
152 OnFetchParams ¶ms)
153 {
154 LOGI("on fetch %{public}zu records", records->size());
155 int32_t ret = E_OK;
156 for (auto &record : *records) {
157 auto [resultSet, rowCount] = QueryLocalMatch(record.GetRecordId());
158 if (resultSet == nullptr) {
159 LOGE("get nullptr query result");
160 continue;
161 }
162 /* need to handle album cover uri */
163 if (rowCount == 0) {
164 if (!record.GetIsDelete()) {
165 /* insert */
166 ret = InsertCloudAlbum(record);
167 }
168 } else if (rowCount == 1) {
169 resultSet->GoToNextRow();
170 int32_t dirty = GetLocalMatchDirty(*resultSet);
171 if (dirty != static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED)) {
172 /* local dirty */
173 ret = HandleLocalDirty(dirty, record);
174 } else if (record.GetIsDelete()) {
175 /* delete */
176 ret = DeleteCloudAlbum(record);
177 } else {
178 /* update */
179 ret = UpdateCloudAlbum(record);
180 }
181 } else {
182 /* invalid cases */
183 LOGE("recordId %s rowCount %{public}d", record.GetRecordId().c_str(), rowCount);
184 }
185
186 /* check ret */
187 if (ret != E_OK) {
188 LOGE("recordId %s error %{public}d", record.GetRecordId().c_str(), ret);
189 if (ret == E_STOP) {
190 return E_STOP;
191 }
192 continue;
193 } else {
194 /* notify */
195 (void)DataSyncNotifier::GetInstance().TryNotify(DataSyncConst::ALBUM_URI_PREFIX,
196 ChangeType::UPDATE, DataSyncConst::INVALID_ID);
197 }
198 }
199 (void)DataSyncNotifier::GetInstance().FinalNotify();
200 return E_OK;
201 }
202
GetRetryRecords(std::vector<DriveKit::DKRecordId> & records)203 int32_t AlbumDataHandler::GetRetryRecords(std::vector<DriveKit::DKRecordId> &records)
204 {
205 return E_OK;
206 }
207
Clean(const int action)208 int32_t AlbumDataHandler::Clean(const int action)
209 {
210 return E_OK;
211 }
212
GetCreatedRecords(vector<DKRecord> & records)213 int32_t AlbumDataHandler::GetCreatedRecords(vector<DKRecord> &records)
214 {
215 /* build predicates */
216 auto createPredicates = NativeRdb::AbsRdbPredicates(PAC::TABLE);
217 createPredicates.EqualTo(PAC::ALBUM_DIRTY, to_string(static_cast<int32_t>(Media::DirtyType::TYPE_NEW)));
218 /* skip system albums */
219 createPredicates.And()->EqualTo(PAC::ALBUM_SUBTYPE, to_string(Media::PhotoAlbumSubType::USER_GENERIC));
220 if (!createFailSet_.empty()) {
221 createPredicates.And()->NotIn(PAC::ALBUM_NAME, createFailSet_);
222 }
223 createPredicates.Limit(LIMIT_SIZE);
224
225 /* query */
226 auto results = Query(createPredicates, GALLERY_ALBUM_COLUMNS);
227 if (results == nullptr) {
228 LOGE("get nullptr created result");
229 return E_RDB;
230 }
231
232 /* results to records */
233 int ret = createConvertor_.ResultSetToRecords(move(results), records);
234 if (ret != 0) {
235 LOGE("result set to records err %{public}d", ret);
236 return ret;
237 }
238
239 return E_OK;
240 }
241
GetDeletedRecords(vector<DKRecord> & records)242 int32_t AlbumDataHandler::GetDeletedRecords(vector<DKRecord> &records)
243 {
244 /* build predicates */
245 auto createPredicates = NativeRdb::AbsRdbPredicates(PAC::TABLE);
246 createPredicates.EqualTo(PAC::ALBUM_DIRTY, to_string(static_cast<int32_t>(Media::DirtyType::TYPE_DELETED)));
247 /* skip system albums */
248 createPredicates.And()->EqualTo(PAC::ALBUM_SUBTYPE, to_string(Media::PhotoAlbumSubType::USER_GENERIC));
249 if (!modifyFailSet_.empty()) {
250 createPredicates.And()->NotIn(PAC::ALBUM_NAME, modifyFailSet_);
251 }
252 createPredicates.Limit(LIMIT_SIZE);
253
254 /* query */
255 auto results = Query(createPredicates, GALLERY_ALBUM_COLUMNS);
256 if (results == nullptr) {
257 LOGE("get nullptr created result");
258 return E_RDB;
259 }
260
261 /* results to records */
262 int ret = deleteConvertor_.ResultSetToRecords(move(results), records);
263 if (ret != 0) {
264 LOGE("result set to records err %{public}d", ret);
265 return ret;
266 }
267
268 return E_OK;
269 }
270
GetMetaModifiedRecords(vector<DKRecord> & records)271 int32_t AlbumDataHandler::GetMetaModifiedRecords(vector<DKRecord> &records)
272 {
273 /* build predicates */
274 auto createPredicates = NativeRdb::AbsRdbPredicates(PAC::TABLE);
275 createPredicates.EqualTo(PAC::ALBUM_DIRTY, to_string(static_cast<int32_t>(Media::DirtyType::TYPE_MDIRTY)));
276 /* skip system albums */
277 createPredicates.And()->EqualTo(PAC::ALBUM_SUBTYPE, to_string(Media::PhotoAlbumSubType::USER_GENERIC));
278 if (!modifyFailSet_.empty()) {
279 createPredicates.And()->NotIn(PAC::ALBUM_NAME, modifyFailSet_);
280 }
281 createPredicates.Limit(LIMIT_SIZE);
282
283 /* query */
284 auto results = Query(createPredicates, GALLERY_ALBUM_COLUMNS);
285 if (results == nullptr) {
286 LOGE("get nullptr created result");
287 return E_RDB;
288 }
289
290 /* results to records */
291 int ret = modifyConvertor_.ResultSetToRecords(move(results), records);
292 if (ret != 0) {
293 LOGE("result set to records err %{public}d", ret);
294 return ret;
295 }
296
297 return E_OK;
298 }
299
OnCreateRecords(const map<DKRecordId,DKRecordOperResult> & map)300 int32_t AlbumDataHandler::OnCreateRecords(const map<DKRecordId, DKRecordOperResult> &map)
301 {
302 int32_t ret = E_OK;
303 for (auto &entry : map) {
304 int32_t err;
305 const DKRecordOperResult &result = entry.second;
306 if (result.IsSuccess()) {
307 err = OnCreateSuccess(entry);
308 } else {
309 err = OnCreateFail(entry);
310 }
311 if (err == E_STOP) {
312 ret = E_STOP;
313 }
314 }
315 return ret;
316 }
317
OnDeleteRecords(const map<DKRecordId,DKRecordOperResult> & map)318 int32_t AlbumDataHandler::OnDeleteRecords(const map<DKRecordId, DKRecordOperResult> &map)
319 {
320 int32_t ret = E_OK;
321 for (auto &entry : map) {
322 int32_t err;
323 const DKRecordOperResult &result = entry.second;
324 if (result.IsSuccess()) {
325 err = OnDeleteSuccess(entry);
326 } else {
327 err = OnCreateFail(entry);
328 }
329 if (err == E_STOP) {
330 ret = E_STOP;
331 }
332 }
333 return ret;
334 }
335
OnModifyMdirtyRecords(const map<DKRecordId,DKRecordOperResult> & map)336 int32_t AlbumDataHandler::OnModifyMdirtyRecords(const map<DKRecordId, DKRecordOperResult> &map)
337 {
338 int32_t ret = E_OK;
339 for (auto &entry : map) {
340 int32_t err;
341 const DKRecordOperResult &result = entry.second;
342 if (result.IsSuccess()) {
343 err = OnUploadSuccess(entry);
344 } else {
345 err = OnCreateFail(entry);
346 }
347 if (err == E_STOP) {
348 ret = E_STOP;
349 }
350 }
351 return ret;
352 }
353
GetAlbumNameFromRecord(const DriveKit::DKRecordOperResult & result)354 static inline string GetAlbumNameFromRecord(const DriveKit::DKRecordOperResult &result)
355 {
356 auto record = result.GetDKRecord();
357 DKRecordData data;
358 record.GetRecordData(data);
359 return data[ALBUM_NAME];
360 }
361
OnCreateSuccess(const pair<DriveKit::DKRecordId,DriveKit::DKRecordOperResult> & entry)362 int32_t AlbumDataHandler::OnCreateSuccess(const pair<DriveKit::DKRecordId,
363 DriveKit::DKRecordOperResult> &entry)
364 {
365 ValuesBucket valuesBucket;
366 int32_t changedRows;
367 string whereClause = PAC::ALBUM_NAME + " = ?";
368 vector<string> whereArgs = { GetAlbumNameFromRecord(entry.second) };
369 valuesBucket.PutInt(PAC::ALBUM_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED));
370 valuesBucket.PutString(PAC::ALBUM_CLOUD_ID, entry.first);
371 int32_t ret = Update(changedRows, valuesBucket, whereClause, whereArgs);
372 if (ret != 0) {
373 LOGE("update local records err %{public}d", ret);
374 return ret;
375 }
376 return E_OK;
377 }
378
OnUploadSuccess(const pair<DriveKit::DKRecordId,DriveKit::DKRecordOperResult> & entry)379 int32_t AlbumDataHandler::OnUploadSuccess(const pair<DriveKit::DKRecordId,
380 DriveKit::DKRecordOperResult> &entry)
381 {
382 ValuesBucket valuesBucket;
383 int32_t changedRows;
384 string whereClause = PAC::ALBUM_CLOUD_ID + " = ?";
385 vector<string> whereArgs = { entry.first };
386 valuesBucket.PutInt(PAC::ALBUM_DIRTY, static_cast<int32_t>(Media::DirtyType::TYPE_SYNCED));
387 int32_t ret = Update(changedRows, valuesBucket, whereClause, whereArgs);
388 if (ret != 0) {
389 LOGE("update local records err %{public}d", ret);
390 return ret;
391 }
392 return E_OK;
393 }
394
OnDeleteSuccess(const pair<DriveKit::DKRecordId,DriveKit::DKRecordOperResult> & entry)395 int32_t AlbumDataHandler::OnDeleteSuccess(const pair<DriveKit::DKRecordId,
396 DriveKit::DKRecordOperResult> &entry)
397 {
398 int32_t deletedRows;
399 string whereClause = PAC::ALBUM_CLOUD_ID + " = ?";
400 vector<string> whereArgs = { entry.first };
401 int32_t ret = Delete(deletedRows, whereClause, whereArgs);
402 if (ret != 0) {
403 LOGE("delete local records err %{public}d", ret);
404 return ret;
405 }
406 return E_OK;
407 }
408
OnCreateFail(const pair<DriveKit::DKRecordId,DriveKit::DKRecordOperResult> & entry)409 int32_t AlbumDataHandler::OnCreateFail(const pair<DriveKit::DKRecordId,
410 DriveKit::DKRecordOperResult> &entry)
411 {
412 createFailSet_.push_back(entry.first);
413 return E_OK;
414 }
415
OnDeleteFail(const pair<DriveKit::DKRecordId,DriveKit::DKRecordOperResult> & entry)416 int32_t AlbumDataHandler::OnDeleteFail(const pair<DriveKit::DKRecordId,
417 DriveKit::DKRecordOperResult> &entry)
418 {
419 modifyFailSet_.push_back(entry.first);
420 return E_OK;
421 }
422
OnModifyFail(const pair<DriveKit::DKRecordId,DriveKit::DKRecordOperResult> & entry)423 int32_t AlbumDataHandler::OnModifyFail(const pair<DriveKit::DKRecordId,
424 DriveKit::DKRecordOperResult> &entry)
425 {
426 modifyFailSet_.push_back(entry.first);
427 return E_OK;
428 }
429
Reset()430 void AlbumDataHandler::Reset()
431 {
432 modifyFailSet_.clear();
433 createFailSet_.clear();
434 }
435
SetChecking()436 void AlbumDataHandler::SetChecking()
437 {
438 ClearCursor();
439 }
440 } // namespace CloudSync
441 } // namespace FileManagement
442 } // namespace OHOS
443