syncer.cpp 15.1 KB
Newer Older
1
#include "syncer.h"
2
#include "db/db.h"
3
#include "abstractnotesprovider.h"
4

5 6 7 8 9 10 11 12 13 14 15 16 17
#include <QUuid>

#ifdef STATIC_MAUIKIT
#include "tagging.h"
#include "fm.h"
#else
#include <MauiKit/tagging.h>
#include <MauiKit/fm.h>
#endif

Syncer::Syncer(QObject *parent) : QObject(parent),
    tag(Tagging::getInstance()),
    db(DB::getInstance()),
18
    provider(nullptr) {}
19

20 21 22 23
void Syncer::setAccount(const FMH::MODEL &account)
{
    if(this->provider)
        this->provider->setCredentials(account);
24 25
}

26
void Syncer::setProvider(AbstractNotesProvider *provider)
27
{
28 29 30 31
    this->provider = std::move(provider);
    this->provider->setParent(this);
    this->provider->disconnect();
    this->setConections();
32
}
33 34 35

void Syncer::insertNote(FMH::MODEL &note)
{
36
    if(!this->insertNoteLocal(note))
37
    {
38 39 40
        qWarning()<< "The note could not be inserted locally, "
                     "therefore it was not attempted to insert it to the remote provider server, "
                     "even if it existed.";
41 42
        return;
    }
43

44
    this->insertNoteRemote(note);
45 46
    emit this->noteInserted(note, {STATE::TYPE::LOCAL, STATE::STATUS::OK, "Note inserted on the DB locally"});
}
47

48 49
void Syncer::updateNote(const QString &id, const FMH::MODEL &note)
{
50
    if(!this->updateNoteLocal(id, note))
51 52 53 54 55 56 57 58
    {
        qWarning()<< "The note could not be updated locally, "
                     "therefore it was not attempted to update it on the remote server provider, "
                     "even if it existed.";
        return;
    }

    //to update remote note we need to pass the stamp as the id
59
    const auto stamp = Syncer::noteStampFromId(this->db, id);
60
    if(!stamp.isEmpty())
61
        this->updateNoteRemote(stamp, note);
62 63 64 65

    emit this->noteUpdated(note, {STATE::TYPE::LOCAL, STATE::STATUS::OK, "Note updated on the DB locally"});
}

camilo higuita's avatar
camilo higuita committed
66 67
void Syncer::removeNote(const QString &id)
{
68 69 70
    //to remove the remote note we need to pass the stamp as the id,
    //and before removing the note locally we need to retireved first

71
    const auto stamp = Syncer::noteStampFromId(this->db, id);
72
    if(!this->removeNoteLocal(id))
camilo higuita's avatar
camilo higuita committed
73 74 75 76 77 78
    {
        qWarning()<< "The note could not be inserted locally, "
                     "therefore it was not attempted to insert it to the remote provider server, "
                     "even if it existed.";
        return;
    }
79 80

    if(!stamp.isEmpty())
81
        this->removeNoteRemote(stamp);
82 83

    emit this->noteRemoved(FMH::MODEL(), {STATE::TYPE::LOCAL, STATE::STATUS::OK, "The note has been removed from the local DB"});
camilo higuita's avatar
camilo higuita committed
84 85
}

86 87
void Syncer::getNotes()
{
88
    const auto notes = this->collectAllNotes();
89 90

    if(this->provider && this->provider->isValid())
91
        this->provider->getNotes();
92 93 94
    else
        qWarning()<< "Credentials are missing to get notes or the provider has not been set";

95

96
    emit this->notesReady(notes);
97 98
}

99 100
void Syncer::getBooks()
{
camilo higuita's avatar
camilo higuita committed
101
    const auto books = this->collectAllBooks();
102 103

    // this service is still missing
104 105 106 107
    //    if(this->provider && this->provider->isValid())
    //        this->provider->getNotes();
    //    else
    //        qWarning()<< "Credentials are missing to get notes or the provider has not been set";
108 109 110 111 112


    emit this->booksReady(books);
}

113
void Syncer::insertBook(FMH::MODEL &book)
camilo higuita's avatar
camilo higuita committed
114
{
115
    if(!this->insertBookLocal(book))
camilo higuita's avatar
camilo higuita committed
116 117
    {
        qWarning()<< "Could not insert Book, Syncer::insertBook";
118
        return;
camilo higuita's avatar
camilo higuita committed
119
    }
120 121

    emit this->bookInserted(book, {STATE::TYPE::LOCAL, STATE::STATUS::OK, "Book inserted locally sucessfully"});
camilo higuita's avatar
camilo higuita committed
122 123
}

124 125 126 127 128
void Syncer::insertBooklet(const FMH::MODEL &booklet)
{

}

129
void Syncer::addId(FMH::MODEL &model)
130
{
131
    const auto id = QUuid::createUuid().toString();
132
    model[FMH::MODEL_KEY::ID] = id;
133
}
134

135

136
const QString Syncer::noteIdFromStamp(DB *_db, const QString &provider, const QString &stamp)
137 138 139 140 141
{
    return [&]() -> QString {
        const auto data = _db->getDBData(QString("select id from notes_sync where server = '%1' AND stamp = '%2'").arg(provider, stamp));
        return data.isEmpty() ? QString() : data.first()[FMH::MODEL_KEY::ID];
    }();
142 143
}

144
const QString Syncer::noteStampFromId(DB *_db, const QString &id)
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
{
    return [&]() -> QString {
        const auto data = _db->getDBData(QString("select stamp from notes_sync where id = '%1'").arg(id));
        return data.isEmpty() ? QString() : data.first()[FMH::MODEL_KEY::STAMP];
    }();
}

void Syncer::setConections()
{
    connect(this->provider, &AbstractNotesProvider::noteInserted, [&](FMH::MODEL note)
    {
        qDebug()<< "STAMP OF THE NEWLY INSERTED NOTE" << note[FMH::MODEL_KEY::ID] << note;
        this->db->insert(OWL::TABLEMAP[OWL::TABLE::NOTES_SYNC], FMH::toMap(FMH::filterModel(note, {FMH::MODEL_KEY::ID,
                                                                                                   FMH::MODEL_KEY::STAMP,
                                                                                                   FMH::MODEL_KEY::USER,
                                                                                                   FMH::MODEL_KEY::SERVER})));
        emit this->noteInserted(note, {STATE::TYPE::REMOTE, STATE::STATUS::OK, "Note inserted on server provider"});
    });

    connect(this->provider, &AbstractNotesProvider::notesReady, [&](FMH::MODEL_LIST notes)
    {
        //        qDebug()<< "SERVER NOETS READY "<< notes;

        //if there are no notes in the provider server, then just return
        if(notes.isEmpty())
            return;

        qDebug()<< "NOETS READY << " << notes;
        // there might be two case scenarios:
        // the note exists locally in the db, so it needs to be updated with the server version
        // the note does not exists locally, so it needs to be inserted into the db
        for(const auto &note : notes)
        {
178
            const auto id = Syncer::noteIdFromStamp(this->db, this->provider->provider(), note[FMH::MODEL_KEY::ID]);
179 180 181 182 183 184 185 186 187 188 189 190 191 192

            // if the id is empty then the note does nto exists, so ithe note is inserted into the local db
            if(id.isEmpty())
            {
                //here insert the note into the db
                auto __note = FMH::filterModel(note, {FMH::MODEL_KEY::TITLE,
                                                      FMH::MODEL_KEY::CONTENT,
                                                      FMH::MODEL_KEY::FAVORITE,
                                                      FMH::MODEL_KEY::MODIFIED,
                                                      FMH::MODEL_KEY::ADDDATE});

                __note[FMH::MODEL_KEY::MODIFIED] = QDateTime::fromSecsSinceEpoch(note[FMH::MODEL_KEY::MODIFIED].toInt()).toString(Qt::TextDate);
                __note[FMH::MODEL_KEY::ADDDATE] = __note[FMH::MODEL_KEY::MODIFIED];

193
                if(!this->insertNoteLocal(__note))
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
                {
                    qWarning()<< "Remote note could not be inserted to the local storage";
                    continue;
                }

                __note[FMH::MODEL_KEY::STAMP] = note[FMH::MODEL_KEY::ID];
                __note[FMH::MODEL_KEY::USER] = this->provider->user();
                __note[FMH::MODEL_KEY::SERVER] = this->provider->provider();


                this->db->insert(OWL::TABLEMAP[OWL::TABLE::NOTES_SYNC], FMH::toMap(FMH::filterModel(__note, {FMH::MODEL_KEY::ID,
                                                                                                             FMH::MODEL_KEY::STAMP,
                                                                                                             FMH::MODEL_KEY::USER,
                                                                                                             FMH::MODEL_KEY::SERVER})));

            }else
            {
                //the note exists in the db locally, so update it
                auto __note = FMH::filterModel(note, {FMH::MODEL_KEY::TITLE,
                                                      FMH::MODEL_KEY::CONTENT,
                                                      FMH::MODEL_KEY::MODIFIED,
                                                      FMH::MODEL_KEY::FAVORITE});
                __note[FMH::MODEL_KEY::MODIFIED] = QDateTime::fromSecsSinceEpoch(note[FMH::MODEL_KEY::MODIFIED].toInt()).toString(Qt::TextDate);
217
                this->updateNoteLocal(id, __note);
218 219 220 221
                emit this->noteInserted(note, {STATE::TYPE::LOCAL, STATE::STATUS::OK, "Note inserted on local db, from the server provider"});
            }
        }

222
        emit this->notesReady(this->collectAllNotes());
223 224 225 226
    });

    connect(this->provider, &AbstractNotesProvider::noteUpdated, [&](FMH::MODEL note)
    {
227
        const auto id = Syncer::noteIdFromStamp(this->db, this->provider->provider(), note[FMH::MODEL_KEY::ID]);
228
        if(!note.isEmpty())
229
            this->updateNoteLocal(id, FMH::filterModel(note, {FMH::MODEL_KEY::TITLE}));
230 231 232 233 234 235 236 237 238
        emit this->noteUpdated(note, {STATE::TYPE::REMOTE, STATE::STATUS::OK, "Note updated on server provider"});
    });

    connect(this->provider, &AbstractNotesProvider::noteRemoved, [&]()
    {
        emit this->noteRemoved(FMH::MODEL(), {STATE::TYPE::REMOTE, STATE::STATUS::OK, "The note has been removed from the remove server provider"});
    });
}

239
bool Syncer::insertNoteLocal(FMH::MODEL &note)
240 241 242
{
    qDebug()<<"TAGS"<< note[FMH::MODEL_KEY::TAG];

243
    Syncer::addId(note); //adds a local id to the note
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258

    // create a file for the note
    const auto __notePath = Syncer::saveNoteFile(note);
    note[FMH::MODEL_KEY::URL] = __notePath.toString();
    qDebug()<< "note saved to <<" << __notePath;

    auto __noteMap = FMH::toMap(FMH::filterModel(note, {FMH::MODEL_KEY::ID,
                                                        FMH::MODEL_KEY::TITLE,
                                                        FMH::MODEL_KEY::COLOR,
                                                        FMH::MODEL_KEY::URL,
                                                        FMH::MODEL_KEY::PIN,
                                                        FMH::MODEL_KEY::FAVORITE,
                                                        FMH::MODEL_KEY::MODIFIED,
                                                        FMH::MODEL_KEY::ADDDATE}));

259 260 261 262 263 264 265 266 267 268 269 270

    if(this->db->insert(OWL::TABLEMAP[OWL::TABLE::NOTES], __noteMap))
    {
        for(const auto &tg : note[FMH::MODEL_KEY::TAG].split(",", QString::SplitBehavior::SkipEmptyParts))
            this->tag->tagAbstract(tg, OWL::TABLEMAP[OWL::TABLE::NOTES], note[FMH::MODEL_KEY::ID], note[FMH::MODEL_KEY::COLOR]);

        return true;
    }

    return false;
}

271
void Syncer::insertNoteRemote(FMH::MODEL &note)
272
{
273
    if(this->provider && this->provider->isValid())
274
        this->provider->insertNote(note);
275
}
276

277
bool Syncer::updateNoteLocal(const QString &id, const FMH::MODEL &note)
278 279 280 281
{
    for(const auto &tg : note[FMH::MODEL_KEY::TAG])
        this->tag->tagAbstract(tg, OWL::TABLEMAP[OWL::TABLE::NOTES], id);

282 283
    this->saveNoteFile(note);

284 285
    return this->db->update(OWL::TABLEMAP[OWL::TABLE::NOTES],
            FMH::toMap(FMH::filterModel(note, {FMH::MODEL_KEY::TITLE,
286 287 288 289
                                               FMH::MODEL_KEY::COLOR,
                                               FMH::MODEL_KEY::PIN,
                                               FMH::MODEL_KEY::MODIFIED,
                                               FMH::MODEL_KEY::FAVORITE})), QVariantMap {{FMH::MODEL_NAME[FMH::MODEL_KEY::ID], id}});
290 291
}

292
void Syncer::updateNoteRemote(const QString &id, const FMH::MODEL &note)
293
{
294
    if(this->provider && this->provider->isValid())
295 296
        this->provider->updateNote(id, note);
}
camilo higuita's avatar
camilo higuita committed
297

298
bool Syncer::removeNoteLocal(const QString &id)
camilo higuita's avatar
camilo higuita committed
299 300 301 302 303
{
    this->db->remove(OWL::TABLEMAP[OWL::TABLE::NOTES_SYNC], {{FMH::MODEL_NAME[FMH::MODEL_KEY::ID], id}});
    return this->db->remove(OWL::TABLEMAP[OWL::TABLE::NOTES], {{FMH::MODEL_NAME[FMH::MODEL_KEY::ID], id}});
}

304
void Syncer::removeNoteRemote(const QString &id)
camilo higuita's avatar
camilo higuita committed
305
{
306
    if(this->provider && this->provider->isValid())
camilo higuita's avatar
camilo higuita committed
307 308
        this->provider->removeNote(id);
}
309

310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
bool Syncer::insertBookLocal(FMH::MODEL &book)
{
    const auto __path = QUrl::fromLocalFile(OWL::BooksPath+book[FMH::MODEL_KEY::TITLE]);
    if(FMH::fileExists(__path))
    {
        qWarning()<< "The directory for the book already exists. Syncer::insertBookLocal" << book[FMH::MODEL_KEY::TITLE];
        return false;

    }

    if(!FM::createDir(QUrl::fromLocalFile(OWL::BooksPath), book[FMH::MODEL_KEY::TITLE]))
    {
        qWarning() << "Could not create directory for the given book name. Syncer::insertBookLocal" << book[FMH::MODEL_KEY::TITLE];
        return false;
    }

    Syncer::addId(book);
    book[FMH::MODEL_KEY::URL] = __path.toString();

    return(this->db->insert(OWL::TABLEMAP[OWL::TABLE::BOOKS], FMH::toMap(FMH::filterModel(book,{FMH::MODEL_KEY::ID,
                                                                                                FMH::MODEL_KEY::URL,
                                                                                                FMH::MODEL_KEY::TITLE,
                                                                                                FMH::MODEL_KEY::FAVORITE,
                                                                                                FMH::MODEL_KEY::ADDDATE,
                                                                                                FMH::MODEL_KEY::MODIFIED}
                                                                                          ))));
}

void Syncer::insertBookRemote(FMH::MODEL &book)
{

}

bool Syncer::updateBookLocal(const QString &id, const FMH::MODEL &book)
{
    return false;
}

void Syncer::updateBookRemote(const QString &id, const FMH::MODEL &book)
{

}

bool Syncer::removeBookLocal(const QString &id)
{
    return false;
}

void Syncer::removeBookRemote(const QString &id)
{

}

bool Syncer::insertBookletLocal(FMH::MODEL &booklet)
{
    return false;
}

void Syncer::insertBookletRemote(FMH::MODEL &booklet)
{

}

bool Syncer::updateBookletLocal(const QString &id, const FMH::MODEL &booklet)
{
    return false;
}

void Syncer::updateBookletRemote(const QString &id, const FMH::MODEL &booklet)
{

}

bool Syncer::removeBookletLocal(const QString &id)
{
    return false;
}

void Syncer::removeBookletRemote(const QString &id)
{

}

393 394 395 396 397 398 399 400 401
const FMH::MODEL_LIST Syncer::collectAllNotes()
{
    FMH::MODEL_LIST __notes = this->db->getDBData("select * from notes");
    for(auto &note : __notes)
        note[FMH::MODEL_KEY::CONTENT] = this->noteFileContent(note[FMH::MODEL_KEY::URL]);

    return __notes;
}

402 403 404 405 406
const FMH::MODEL_LIST Syncer::collectAllBooks()
{
    return this->db->getDBData("select * from books");
}

407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
const QUrl Syncer::saveNoteFile(const FMH::MODEL &note)
{
    if(note.isEmpty() || !note.contains(FMH::MODEL_KEY::CONTENT))
    {
        qWarning() << "the note is empty, therefore it could not be saved into a file";
        return QUrl();
    }

    QFile file(OWL::NotesPath+note[FMH::MODEL_KEY::ID]+QStringLiteral(".txt"));
    file.open(QFile::WriteOnly);
    file.write(note[FMH::MODEL_KEY::CONTENT].toUtf8());
    file.close();

    return QUrl::fromLocalFile(file.fileName());
}

const QString Syncer::noteFileContent(const QUrl &path)
{
    if(!path.isLocalFile())
    {
        qWarning()<< "Can not open note file, the url is not a local path";
        return QString();
    }
    QFile file(path.toLocalFile());
    file.open(QFile::ReadOnly);
    const auto content = file.readAll();
    file.close();

    return QString(content);
}