messageservice.cpp 23.7 KB
Newer Older
1

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/********************************************************************************************
 *                                                                                          *
 * Copyright (C) 2017 Armin Felder, Dennis Beier                                            *
 * This file is part of RocketChatMobileEngine <https://git.fairkom.net/chat/fairchat>.     *
 *                                                                                          *
 * RocketChatMobileEngine is free software: you can redistribute it and/or modify           *
 * it under the terms of the GNU General Public License as published by                     *
 * the Free Software Foundation, either version 3 of the License, or                        *
 * (at your option) any later version.                                                      *
 *                                                                                          *
 * RocketChatMobileEngine is distributed in the hope that it will be useful,                *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of                           *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                            *
 * GNU General Public License for more details.                                             *
 *                                                                                          *
 * You should have received a copy of the GNU General Public License                        *
 * along with RocketChatMobileEngine. If not, see <http://www.gnu.org/licenses/>.           *
 *                                                                                          *
 ********************************************************************************************/


armin's avatar
armin committed
23
#include <algorithm>
armin's avatar
armin committed
24
25
#include "messageservice.h"

armin's avatar
avatar    
armin committed
26
27
#include "repos/entities/rocketchatreplymessage.h"
#include "services/fileservice.h"
armin's avatar
armin committed
28
29


armin's avatar
armin committed
30
31
32
33
34
35
36
37
//MessageService::MessageService( PersistanceLayer *pPersistanceLayer,
//                                RocketChatServerData *pServer,
//                                QHash<QString, QString> &pEmojisMap ): mEmojisMap( pEmojisMap )
//{
//    this->mPersistanceLayer = pPersistanceLayer;
//    this->mServer = pServer;
//}

armin's avatar
ds    
armin committed
38
MessageService::MessageService( QObject *parent, PersistanceLayer *pPersistanceLayer,
armin's avatar
armin committed
39
                                RocketChatServerData *pServer,
armin's avatar
avatar    
armin committed
40
41
42
                                EmojiRepo *pEmojiRepo, FileService *pFileService ): QObject( parent ),
    mReplyRegeEx( "\\[ \\]\\(.*\\)</a>" ), mEmojiRepo( pEmojiRepo ), mMessagesModel( Models::getMessagesModel() ),
    mReplyReplyRegeEx( "\\[ \\]\\(.*\\)" ), mSearchResults( Models::getMessagesSearchModel() ), mFileService( pFileService )
armin's avatar
armin committed
43
44
45
{
    this->mPersistanceLayer = pPersistanceLayer;
    this->mServer = pServer;
armin's avatar
armin committed
46
    qRegisterMetaType<MessageList>( "MessageList" );
armin's avatar
armin committed
47
48
}

armin's avatar
cleanup    
armin committed
49
void MessageService::loadHistory( const QSharedPointer<LoadHistoryServiceRequest> &pRequest )
armin's avatar
armin committed
50
{
armin's avatar
armin committed
51
    if ( !pRequest.isNull() ) {
armin's avatar
armin committed
52
        switch ( pRequest->getSource() ) {
armin's avatar
cleanup    
armin committed
53
54
55
            case LoadHistoryServiceRequest::Source::DataBase:
                loadHistoryFromDb( pRequest );
                break;
armin's avatar
armin committed
56

armin's avatar
cleanup    
armin committed
57
58
59
            case LoadHistoryServiceRequest::Source::SERVER:
                loadHistoryFromServer( pRequest );
                break;
armin's avatar
armin committed
60

armin's avatar
cleanup    
armin committed
61
62
63
            default:
                loadHistoryFromAutoSource( pRequest );
                break;
armin's avatar
armin committed
64
        }
armin's avatar
armin committed
65
66
67
    }
}

armin's avatar
armin committed
68
69


armin's avatar
cleanup    
armin committed
70
71
void MessageService::checkForMissingMessages( const QSharedPointer<LoadMissedMessageServiceRequest>
        &pRequest )
armin's avatar
armin committed
72
{
armin's avatar
armin committed
73
    Q_UNUSED( pRequest )
armin's avatar
armin committed
74

armin's avatar
armin committed
75
76
}

armin's avatar
cleanup    
armin committed
77
void MessageService::sendMessage( const QSharedPointer<RocketChatMessage> &pMessage )
armin's avatar
armin committed
78
{
armin's avatar
armin committed
79
    if ( !pMessage.isNull() ) {
armin's avatar
armin committed
80
        QJsonObject params;
81
82
        params[QStringLiteral( "rid" )] = pMessage->getRoomId();
        params[QStringLiteral( "msg" )] = pMessage->getMessageString();
83
        auto sendMessageRequest = QSharedPointer<DDPMethodRequest>::create( QStringLiteral( "sendMessage" ), QJsonArray( {params} ) );
armin's avatar
armin committed
84
85
        mServer->sendDdprequest( sendMessageRequest, true );
    }
armin's avatar
armin committed
86
87
}

armin's avatar
cleanup    
armin committed
88
void MessageService::persistMessage( const QSharedPointer<RocketChatMessage> &pMessage )
armin's avatar
armin committed
89
{
armin's avatar
armin committed
90
    if ( !pMessage.isNull() ) {
armin's avatar
armin committed
91
92
        QJsonDocument doc( pMessage->getData() );
        QString msg = doc.toJson();
armin's avatar
armin committed
93
94
        mPersistanceLayer->addMessage( pMessage->getId(), pMessage->getRoomId(), pMessage->getAuthor(),
                                       pMessage->getTimestamp(), msg, pMessage->getAuthorId() );
armin's avatar
armin committed
95
    }
armin's avatar
armin committed
96
97
}

armin's avatar
cleanup    
armin committed
98
void MessageService::persistMessages( const MessageList &pMessage )
armin's avatar
armin committed
99
100
101
{
    mPersistanceLayer->transaction();

armin's avatar
armin committed
102
    for ( const auto &currentMessage : pMessage ) {
armin's avatar
armin committed
103
        if ( !currentMessage.isNull() ) {
armin's avatar
armin committed
104
105
            persistMessage( currentMessage );
        }
armin's avatar
armin committed
106
107
    };

armin's avatar
ad    
armin committed
108
    mPersistanceLayer->askForcommit();
armin's avatar
armin committed
109
110
}

armin's avatar
as    
armin committed
111
112
void MessageService::persist()
{
armin's avatar
armin committed
113
114
115
    if ( mServer ) {
        mPersistanceLayer->transaction();
        auto channels = mServer->getChannels();
armin's avatar
as    
armin committed
116

armin's avatar
armin committed
117
118
119
        for ( const auto &channel : channels->getElements() ) {
            if ( channel.isNull() ) {
                auto messages = channel->getMessageRepo();
armin's avatar
as    
armin committed
120

armin's avatar
armin committed
121
122
123
124
                for ( const auto &message : messages->getElements() ) {
                    if ( !message.isNull() ) {
                        persistMessage( message );
                    }
armin's avatar
as    
armin committed
125
126
127
128
                }
            }
        }

armin's avatar
armin committed
129
        mPersistanceLayer->askForcommit();
Armin Felder's avatar
Armin Felder committed
130
    }
armin's avatar
as    
armin committed
131
132
}

armin's avatar
armin committed
133
QSharedPointer<RocketChatMessage> MessageService::parseMessage( const QJsonObject &pMessageData,
armin's avatar
cleanup    
armin committed
134
        bool linkify )
armin's avatar
armin committed
135
{
armin's avatar
armin committed
136
137
138
139
    if ( mServer ) {
        ChatMessage message( nullptr );
        QString userId = mServer->getUserId();
        bool blocked = false;
armin's avatar
armin committed
140

armin's avatar
armin committed
141
142
143
        if ( Q_LIKELY( pMessageData.contains( QStringLiteral( "msg" ) ) ) ) {
            //parse message String
            QString msgString = pMessageData[QStringLiteral( "msg" )].toString();
armin's avatar
armin committed
144

armin's avatar
armin committed
145
146
            if ( linkify ) {
                msgString = Utils::removeUtf8Emojis( msgString );
armin's avatar
armin committed
147

armin's avatar
armin committed
148
149
150
151
                msgString = Utils::linkiFy( msgString );
                msgString = msgString.replace( QStringLiteral( "\n" ), QStringLiteral( "<br>" ) );
                msgString = Utils::escapeHtml( msgString );
                msgString = Utils::emojiFy( msgString, mEmojiRepo );
152

armin's avatar
armin committed
153
            }
armin's avatar
armin committed
154

armin's avatar
armin committed
155
156
157
            QString msgType;
            QString author;
            QString authorId;
armin's avatar
armin committed
158

armin's avatar
armin committed
159
160
161
            if ( Q_LIKELY( pMessageData.contains( "t" ) ) ) {
                msgType = pMessageData["t"].toString();
            }
armin's avatar
cleanup    
armin committed
162

armin's avatar
armin committed
163
164
165
            if ( Q_UNLIKELY( mServer->getUsername() == "apple.store" ) && msgType == "jitsi_call_started" ) {
                return nullptr;
            }
armin's avatar
armin committed
166

armin's avatar
armin committed
167
            QJsonObject userObject = pMessageData["u"].toObject();
armin's avatar
armin committed
168

armin's avatar
armin committed
169
170
171
            if ( Q_LIKELY( userObject.contains( QStringLiteral( "username" ) ) ) ) {
                author = userObject[QStringLiteral( "username" )].toString();
            }
armin's avatar
armin committed
172

armin's avatar
armin committed
173
174
175
176
            // if alias given, us it instead of the username, required for bridges
            if ( Q_LIKELY( pMessageData.contains( QStringLiteral( "alias" ) ) ) ) {
                author = pMessageData[QStringLiteral( "alias" )].toString();
            }
armin's avatar
armin committed
177

armin's avatar
armin committed
178
179
180
            if ( Q_LIKELY( userObject.contains( "_id" ) ) ) {
                authorId = userObject[QStringLiteral( "_id" )].toString();
            }
armin's avatar
armin committed
181

armin's avatar
armin committed
182
            bool ownMessage = false;
armin's avatar
armin committed
183

armin's avatar
armin committed
184
185
186
            if ( authorId == userId ) {
                ownMessage = true;
            }
armin's avatar
cleanup    
armin committed
187

armin's avatar
armin committed
188
189
            QJsonObject timestampObject = pMessageData[QStringLiteral( "ts" )].toObject();
            qint64 timestamp = 0;
armin's avatar
armin committed
190

armin's avatar
armin committed
191
192
193
            if ( Q_LIKELY( timestampObject.contains( QStringLiteral( "$date" ) ) ) ) {
                timestamp = static_cast<qint64>( timestampObject[QStringLiteral( "$date" )].toDouble() );
            }
armin's avatar
armin committed
194

armin's avatar
armin committed
195
            QDateTime date = QDateTime::fromMSecsSinceEpoch( timestamp );
armin's avatar
armin committed
196

armin's avatar
armin committed
197
198
199
200
201
202
203
            QString formattedDate = date.toString( QStringLiteral( "dd.MM.yyyy" ) );
            QString formattedTime = date.toString( QStringLiteral( "hh:mm" ) );
            auto attachments = processAttachments( pMessageData );
            message = QSharedPointer<RocketChatMessage>::create( pMessageData );
            message->setAttachments( attachments );
            message->setOwnMessage( ownMessage );
            message->setAuthorId( authorId );
armin's avatar
armin committed
204

armin's avatar
armin committed
205
206
            if ( !attachments.isEmpty() ) {
                auto firstAttachment  = attachments.first();
207

armin's avatar
armin committed
208
209
210
211
212
213
214
215
                if ( !firstAttachment.isNull() ) {
                    if ( firstAttachment->getType() == "replyMessage" ) {
                        QString messageText = msgString;
                        messageText.replace( mReplyRegeEx, "" );
                        msgString  = messageText;
                    } else {
                        msgString = firstAttachment->getTitle();
                    }
216
                }
armin's avatar
armin committed
217
            }
armin's avatar
armin committed
218

armin's avatar
armin committed
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
            //TODO: place RocketChatUserObject inside Message instead...
            auto then = [ message ]( QSharedPointer<TempFile> tempfile, bool showInline ) {
                message->setAvatarImg( tempfile );
            };
            auto avatarUrl = "/avatar/" + author + ".jpg";
            auto avatarRequest = QSharedPointer<FileRequest>::create( avatarUrl, "temp", then, true );
            //mFileService->getFileRessource( avatarRequest );

            message->setAuthor( author );
            message->setFormattedDate( formattedDate );
            message->setFormattedTime( formattedTime );
            message->setMessageString( msgString );
            message->setMessageType( msgType );

            if ( mBlockedUsers.contains( author ) ) {
                blocked = true;
            }
armin's avatar
armin committed
236
        }
armin's avatar
armin committed
237

armin's avatar
armin committed
238
239
240
        if ( Q_UNLIKELY( message.isNull() ) ) {
            qDebug() << "invalid messag";
        }
armin's avatar
cleanup    
armin committed
241

armin's avatar
armin committed
242
        message->setServer( mServer->getBaseUrl() );
armin's avatar
cleanup    
armin committed
243

armin's avatar
armin committed
244
245
246
        if ( !blocked ) {
            return message;
        }
armin's avatar
armin committed
247
    }
armin's avatar
armin committed
248

armin's avatar
as    
armin committed
249
250
    return nullptr;

armin's avatar
armin committed
251
252
253
254
255
}

void MessageService::addUserToBlockList( const QString &pId )
{
    mBlockedUsers.insert( pId );
armin's avatar
as    
armin committed
256
257
    auto result = QMetaObject::invokeMethod( mMessagesModel, "addBlockedUser", Q_ARG( QString, pId ) );
    Q_ASSERT( result );
armin's avatar
armin committed
258
259
260
261
}

void MessageService::addChannelToBlockList( const QString &pId )
{
armin's avatar
armin committed
262
263
264
265
266
    if ( mServer ) {
        QString roomId = pId;
        QString userId = mServer->getUserId();
        QString otherUserId = roomId.replace( userId, "" );
        addUserToBlockList( otherUserId );
Armin Felder's avatar
Armin Felder committed
267
    }
armin's avatar
armin committed
268
269
}

armin's avatar
cleanup    
armin committed
270
void MessageService::searchMessage( const QString &pTerm, const QString &pRoom )
armin's avatar
armin committed
271
{
armin's avatar
armin committed
272
273
274
275
    if ( mServer ) {
        DdpCallback ddpSuccess = [ = ]( const QJsonObject & pResponse,
        MeteorDDP * pDdp ) {
            Q_UNUSED( pDdp )
armin's avatar
cleanup    
armin committed
276

armin's avatar
armin committed
277
278
            if ( pResponse.contains( "result" ) ) {
                QJsonObject result = pResponse["result"].toObject();
armin's avatar
cleanup    
armin committed
279

armin's avatar
armin committed
280
281
282
                if ( result.contains( "messages" ) ) {
                    QJsonArray messagesArray = result["messages"].toArray();
                    MessageList messageList;
armin's avatar
cleanup    
armin committed
283

armin's avatar
armin committed
284
285
286
                    for ( const auto message : messagesArray ) {
                        messageList.append( parseMessage( message.toObject() ) );
                    }
armin's avatar
cleanup    
armin committed
287

armin's avatar
armin committed
288
289
290
291
                    if ( !messageList.isEmpty() ) {
                        auto result = QMetaObject::invokeMethod( mSearchResults, "setSearchResults", Q_ARG( MessageList, messageList ) );
                        Q_ASSERT( result );
                    }
armin's avatar
armin committed
292
293
                }
            }
armin's avatar
armin committed
294
        };
armin's avatar
armin committed
295

armin's avatar
armin committed
296
297
        auto request = QSharedPointer<RocketChatMessageSearchRequest>::create( pTerm, pRoom );
        request->setSuccess( ddpSuccess );
armin's avatar
armin committed
298

armin's avatar
armin committed
299
        mServer->sendDdprequest( request );
Armin Felder's avatar
Armin Felder committed
300
    }
armin's avatar
armin committed
301
302
}

armin's avatar
cleanup    
armin committed
303
void MessageService::loadHistoryFromServer( const QSharedPointer<LoadHistoryRequestContainer> &pContainer )
armin's avatar
armin committed
304
{
armin's avatar
armin committed
305
    if ( !pContainer.isNull() && mServer ) {
armin's avatar
armin committed
306
307
308
309
        auto requests = pContainer->getRequests();
        pContainer->mAlredayReceived = 0;

        //TODO: fix memory leak risk
310
        auto duplicateCheck = QSharedPointer<QSet<QString>>::create();
armin's avatar
armin committed
311

armin's avatar
armin committed
312
        if ( requests.length() ) {
armin's avatar
sa    
armin committed
313
            auto list = new QMultiMap<QString, ChatMessage>;
armin's avatar
armin committed
314
315
316
317
318
319

            //loop over all channels
            for ( const auto &currentChannelRequest : requests ) {
                if ( !currentChannelRequest.isNull() ) {
                    QString roomId = currentChannelRequest->getChannelIds().first();
                    QJsonObject startObj ;
320
                    startObj[QStringLiteral( "$date" )] = currentChannelRequest->getStart();
armin's avatar
armin committed
321
                    QJsonObject endObj ;
322
                    endObj[QStringLiteral( "$date" )] = currentChannelRequest->getEnd();
armin's avatar
armin committed
323
324
325
326
327
328
329
330
331
332
                    QJsonArray params;

                    int limit = currentChannelRequest->getLimit();

                    if ( currentChannelRequest->getEnd() < 0 ) {
                        if ( currentChannelRequest->getStart() < 0 ) {
                            params = {roomId, QJsonValue::Null, limit, QJsonValue::Null};
                        } else {
                            params = {roomId, QJsonValue::Null, limit, startObj};
                        }
armin's avatar
armin committed
333
                    } else {
armin's avatar
armin committed
334

armin's avatar
armin committed
335
                        params = {roomId, endObj, limit, startObj};
armin's avatar
armin committed
336
                    }
armin's avatar
armin committed
337

338
                    auto request = QSharedPointer<DDPMethodRequest>::create( QStringLiteral( "loadHistory" ), params );
armin's avatar
cleanup    
armin committed
339
                    DdpCallback ddpSuccess = [ = ]( const QJsonObject & pResponse,
armin's avatar
armin committed
340
                    MeteorDDP * pDdp ) {
armin's avatar
armin committed
341
                        Q_UNUSED( pDdp );
armin's avatar
armin committed
342

343
344
                        if ( Q_LIKELY( pResponse.contains( QStringLiteral( "result" ) ) ) ) {
                            QJsonObject result = pResponse[QStringLiteral( "result" )].toObject();
armin's avatar
armin committed
345

346
347
                            if ( Q_LIKELY( result.contains( QStringLiteral( "messages" ) ) ) ) {
                                QJsonArray messages  = result[QStringLiteral( "messages" )].toArray();
armin's avatar
armin committed
348

armin's avatar
armin committed
349
                                for ( auto currentMessage : messages ) {
armin's avatar
armin committed
350

armin's avatar
armin committed
351
                                    auto messageObject = parseMessage( currentMessage.toObject(), true );
armin's avatar
armin committed
352

armin's avatar
armin committed
353
                                    if ( !messageObject.isNull() && !duplicateCheck->contains( messageObject->getId() ) ) {
armin's avatar
armin committed
354
355
356
                                        list->insert( messageObject->getRoomId(), messageObject );
                                        duplicateCheck->insert( messageObject->getId() );
                                    }
armin's avatar
armin committed
357
358
                                }
                            }
armin's avatar
armin committed
359
360
                        }

armin's avatar
armin committed
361
                        pContainer->mAlredayReceived++;
armin's avatar
armin committed
362

armin's avatar
armin committed
363
364
                        if ( pContainer->mAlredayReceived == pContainer->mRequests.count() ) {
                            auto containerSuccess = pContainer->getSuccess();
armin's avatar
armin committed
365

armin's avatar
armin committed
366
367
368
                            if ( containerSuccess ) {
                                containerSuccess( list );
                            }
armin's avatar
armin committed
369
                        }
armin's avatar
armin committed
370
                    };
armin's avatar
armin committed
371

armin's avatar
armin committed
372
                    request->setSuccess( ddpSuccess );
armin's avatar
armin committed
373

armin's avatar
armin committed
374
375
                    mServer->sendDdprequest( request );
                }
armin's avatar
armin committed
376
377
            }
        }
armin's avatar
armin committed
378
379
380
    }
}

armin's avatar
cleanup    
armin committed
381
void MessageService::loadHistoryFromServer( const QSharedPointer<LoadHistoryServiceRequest> &pRequest )
armin's avatar
armin committed
382
{
armin's avatar
armin committed
383
    if ( !pRequest.isNull() ) {
armin's avatar
armin committed
384
385
        QList<QSharedPointer<LoadHistoryServiceRequest>> list;
        list.append( pRequest );
386
        auto container = QSharedPointer<LoadHistoryRequestContainer>::create( list, pRequest->getSuccess() );
armin's avatar
armin committed
387
388
389
        container->setSuccess( pRequest->getSuccess() );
        loadHistoryFromServer( container );
    }
armin's avatar
armin committed
390
391
}

armin's avatar
armin committed
392
QMultiMap<QString, ChatMessage> *MessageService::loadHistoryFromDb(
armin's avatar
cleanup    
armin committed
393
    const QSharedPointer<LoadHistoryServiceRequest> &pRequest )
armin's avatar
armin committed
394
{
armin's avatar
sa    
armin committed
395
    auto channelMap  = new QMultiMap<QString, ChatMessage>;
armin's avatar
armin committed
396

armin's avatar
armin committed
397
    if ( !pRequest.isNull() ) {
armin's avatar
armin committed
398
399
400
401
402
        QStringList channelIds = pRequest->getChannelIds();
        double start = pRequest->getStart();
        int limit = pRequest->getLimit();
        QList<QJsonObject> messages;
        messages.reserve( 100 );
armin's avatar
armin committed
403

armin's avatar
armin committed
404
        for ( const auto &channelId : channelIds ) {
armin's avatar
armin committed
405
            QList<QJsonObject> result = mPersistanceLayer->getMessagesByRid( channelId,
armin's avatar
cleanup    
armin committed
406
                                        static_cast<qint64>( start ), static_cast< int >( limit ) );
armin's avatar
armin committed
407
408
409
            messages.append( result );
        }

armin's avatar
armin committed
410
        for ( const auto &current : messages ) {
armin's avatar
armin committed
411
            auto parsedMessage = parseMessage( current, false );
armin's avatar
armin committed
412

armin's avatar
armin committed
413
414
415
            if ( Q_LIKELY( !parsedMessage.isNull() ) ) {
                channelMap->insert( parsedMessage->getRoomId(), parsedMessage );
            }
armin's avatar
armin committed
416
417
418
419
420
421
        }
    }

    return channelMap;
}

armin's avatar
cleanup    
armin committed
422
void MessageService::loadHistoryFromAutoSource( const QSharedPointer<LoadHistoryServiceRequest> &pRequest )
armin's avatar
armin committed
423
{
armin's avatar
armin committed
424
    int limit = pRequest->getLimit();
armin's avatar
armin committed
425
426
    auto channelMap = loadHistoryFromDb( pRequest );
    QList<QSharedPointer<LoadHistoryServiceRequest>> requestList;
armin's avatar
armin committed
427
    requestList.reserve( 50 );
armin's avatar
armin committed
428
    auto serverSuccess = [ = ]( QMultiMap<QString, QSharedPointer<RocketChatMessage>> *messages ) {
armin's avatar
armin committed
429
        if ( messages != nullptr ) {
armin's avatar
armin committed
430
431
432
            auto success = pRequest->getSuccess();
            success( messages );
        }
armin's avatar
armin committed
433
434
    };

armin's avatar
armin committed
435
    for ( const auto &key :  pRequest->getChannelIds() ) {
armin's avatar
armin committed
436
        if ( Q_LIKELY( channelMap->contains( key ) ) ) {
armin's avatar
armin committed
437
438
            MessageList currentList = channelMap->values( key );

armin's avatar
armin committed
439
            if ( currentList.count() < limit ) {
armin's avatar
armin committed
440
                std::sort( currentList.begin(), currentList.end() );
armin's avatar
armin committed
441
442
443
444
445
446
447
448
449
                double timestamp;

                if ( !currentList.empty() ) {
                    auto latestMessage = currentList.last();
                    timestamp = latestMessage->getTimestamp();
                } else {
                    timestamp = QDateTime::currentDateTime().toMSecsSinceEpoch();
                }

450
                auto newrequest = QSharedPointer<LoadHistoryServiceRequest>::create( key );
armin's avatar
armin committed
451
                newrequest->setStart( timestamp );
armin's avatar
armin committed
452
                newrequest->setLimit( limit - currentList.count() );
armin's avatar
armin committed
453
454
455
456
457
458
459
460

                if ( pRequest->getEnd() > -1 ) {
                    newrequest->setEnd( pRequest->getEnd() );
                }

                requestList.append( newrequest );
            }
        } else {
461
            auto newrequest =  QSharedPointer<LoadHistoryServiceRequest>::create( key );
armin's avatar
armin committed
462
463
464
465
466
467
468
469
470
471
472
473
            double timestamp = QDateTime::currentDateTime().toMSecsSinceEpoch();

            if ( pRequest->getStart() > -1 ) {
                timestamp = pRequest->getStart();
            }

            newrequest->setStart( timestamp );

            if ( pRequest->getEnd() > - 1 ) {
                newrequest->setEnd( pRequest->getEnd() );
            }

armin's avatar
armin committed
474
            newrequest->setLimit( limit );
armin's avatar
armin committed
475
476
477
478
479
480
481
            requestList.append( newrequest );
        }

        //in all cases load the last three days
        if ( !pRequest->getNoLastThreeDays() ) {
            double end = QDateTime::currentMSecsSinceEpoch();
            double start = end - ( 86400 * 3 * 1000 );
482
            auto lastThreeDays = QSharedPointer<LoadHistoryServiceRequest>::create( key );
armin's avatar
armin committed
483
484
485
486
487
488
489
490
491
            pRequest->setStart( start );
            pRequest->setStart( start );
            requestList.append( lastThreeDays );
        }
    }

    auto success = pRequest->getSuccess();
    success( channelMap );
    qDebug() << "loaded from database now loading from sever with " << requestList.size() << "requests";
492
    auto requests = QSharedPointer<LoadHistoryRequestContainer>::create( requestList, serverSuccess );
armin's avatar
armin committed
493
494
495
    loadHistoryFromServer( requests );
}

armin's avatar
armin committed
496
QList<QSharedPointer<RocketChatAttachment>> MessageService::processAttachments(
armin's avatar
cleanup    
armin committed
497
            const QJsonObject &pMessageObj )
armin's avatar
armin committed
498
499
500
501
{

    QList<QSharedPointer<RocketChatAttachment> > attachmentsList;

502
503
    if ( Q_LIKELY( pMessageObj.contains( QStringLiteral( "file" ) ) ) ) {
        QJsonObject fileObj = pMessageObj[QStringLiteral( "file" )].toObject();
armin's avatar
armin committed
504

505
506
        if ( Q_LIKELY( fileObj.contains( QStringLiteral( "_id" ) ) ) ) {
            QJsonArray attachments = pMessageObj[QStringLiteral( "attachments" )].toArray();
armin's avatar
armin committed
507

armin's avatar
armin committed
508
            if ( Q_LIKELY( attachments.size() ) ) {
armin's avatar
armin committed
509
510
511
                QString type;
                QString url;
                QString title;
armin's avatar
armin committed
512
513
                int width = 100;
                int height = 100;
armin's avatar
armin committed
514
515
                QJsonObject attachment = attachments[0].toObject();

516
517
518
                if ( Q_LIKELY( attachment.contains( QStringLiteral( "image_url" ) ) ) ) {
                    type = QStringLiteral( "image" );
                    url = attachment[QStringLiteral( "image_url" )].toString();
armin's avatar
armin committed
519

520
521
                    if ( attachment.contains( QStringLiteral( "image_dimensions" ) ) ) {
                        QJsonObject imageDimensions = attachment[QStringLiteral( "image_dimensions" )].toObject();
armin's avatar
armin committed
522

armin's avatar
armin committed
523
524
                        if ( imageDimensions.contains( QStringLiteral( "height" ) )
                                && imageDimensions.contains( QStringLiteral( "width" ) ) ) {
525
526
                            height = imageDimensions[QStringLiteral( "height" )].toDouble();
                            width = imageDimensions[QStringLiteral( "width" )].toDouble();
armin's avatar
armin committed
527
528
                        }
                    }
529
530
531
532
533
534
535
536
537
                } else if ( attachment.contains( QStringLiteral( "video_url" ) ) ) {
                    type = QStringLiteral( "video" );
                    url = attachment[QStringLiteral( "video_url" )].toString();
                } else if ( attachment.contains( QStringLiteral( "audio_url" ) ) ) {
                    type = QStringLiteral( "audio" );
                    url = attachment[QStringLiteral( "audio_url" )].toString();
                } else if ( attachment.contains( QStringLiteral( "title_link" ) ) ) {
                    type = QStringLiteral( "file" );
                    url = attachment[QStringLiteral( "title_link" )].toString();
armin's avatar
armin committed
538
539
                }

540
541
                if ( Q_LIKELY( attachment.contains( QStringLiteral( "title" ) ) ) ) {
                    title = attachment[QStringLiteral( "title" )].toString();
armin's avatar
armin committed
542
543
                }

544
                auto attachmentObject = QSharedPointer<RocketChatAttachment>::create( url, type, title );
armin's avatar
armin committed
545
546
547
548
549
550
551
                attachmentObject->setHeight( height );
                attachmentObject->setWidth( width );

                attachmentsList.append( attachmentObject );
            }
        }
    }
armin's avatar
cleanup    
armin committed
552
553

    if ( pMessageObj.contains( "urls" ) ) {
554
        QJsonArray attachments = pMessageObj[QStringLiteral( "attachments" )].toArray();
armin's avatar
cleanup    
armin committed
555
556

        for ( QJsonValueRef attachment : attachments ) {
557
            QJsonObject attachmentObject  = attachment.toObject();
armin's avatar
cleanup    
armin committed
558
559

            if ( attachmentObject.contains( "text" ) ) {
560
561
                QString text = attachmentObject["text"].toString();
                QString url = "";
armin's avatar
cleanup    
armin committed
562
563

                if ( attachmentObject.contains( "message_link" ) ) {
564
565
                    url = attachmentObject["message_link"].toString();
                }
armin's avatar
cleanup    
armin committed
566

567
                QString author = attachmentObject["author_name"].toString();
armin's avatar
cleanup    
armin committed
568
569
                text = text.replace( mReplyRegeEx, "" );
                text = text.replace( mReplyReplyRegeEx, "" );
570
                auto reply = QSharedPointer<RocketChatReplyMessage>::create( text, author );
armin's avatar
cleanup    
armin committed
571
                attachmentsList.append( reply );
572
573
574
            }
        }
    }
armin's avatar
armin committed
575
576
577

    return attachmentsList;
}
578

armin's avatar
armin committed
579
void MessageService::deleteMessagesNotInList( MessageMap *pMessages, QString pChannelId, bool pCheckForYounger )
580
{
armin's avatar
armin committed
581
    QMap<qint64, QSharedPointer<RocketChatMessage>> timeIndex;
582
583
    QList<QString> ids;

armin's avatar
armin committed
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
    if ( mServer ) {
        auto channel = mServer->getChannels()->get( pChannelId );

        for ( const auto message : pMessages->values( pChannelId ) ) {
            timeIndex[message->getTimestamp()] = message;
            ids.append( message->getId() );
        }

        qint64 oldest = timeIndex.first()->getTimestamp();
        qint64 newest = timeIndex.last()->getTimestamp();
        qint64 youngest = channel->getYoungestMessage()->getTimestamp();

        if ( pCheckForYounger ) {
            newest = newest < youngest ? youngest : newest;
        }

        auto blacklist = channel->whiteList( ids, newest, oldest );

        for ( QString messageId : blacklist ) {
            mPersistanceLayer->deleteMessage( messageId );
        }
Armin Felder's avatar
Armin Felder committed
605
    }
606
}