rocketchatserver.cpp 79.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/********************************************************************************************
 *                                                                                          *
 * 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
22
23
#include "rocketchatserver.h"

armin's avatar
armin committed
24
#include "CustomModels/models.h"
armin's avatar
armin committed
25

Dennis Beier's avatar
Dennis Beier committed
26
27
28
RocketChatServerData::RocketChatServerData( QString pId, QString pBaseUrl, bool pUnsecure ): mBaseUrl( std::move( pBaseUrl ) ),
    mServerId( std::move( pId ) ), userModel( Models::getUsersModel() ), loginMethodsModel( Models::getLoginMethodsModel() ),
    channelsModel( Models::getPublicGroupsModel() ),
armin's avatar
ias    
armin committed
29
    directModel( Models::getDirectChannelsModel() ), groupsModel( Models::getPublicGroupsModel() )
armin's avatar
armin committed
30
{
armin's avatar
armin committed
31
    qRegisterMetaType<User>( "User" );
armin's avatar
d    
armin committed
32
    qRegisterMetaType<QList<QSharedPointer<Emoji>>>( "QList<QSharedPointer<Emoji>>" );
armin's avatar
armin committed
33
34
35
    mUnsecureConnection = pUnsecure;

    mApiUri = QStringLiteral( "/api/v1" );
armin's avatar
ds    
armin committed
36
    mEmojiRepo = new EmojiRepo( this );
armin's avatar
as    
armin committed
37
    mFilesRepo = new FilesRepo( this );
armin's avatar
armin committed
38

armin's avatar
armin committed
39
}
armin's avatar
armin committed
40

armin's avatar
armin committed
41
void RocketChatServerData::init()
armin's avatar
ds    
armin committed
42
43
44
{
    initDb();
}
armin's avatar
armin committed
45

armin's avatar
ds    
armin committed
46
void RocketChatServerData::initDb()
armin's avatar
armin committed
47
{
armin's avatar
armin committed
48
    mStorage = PersistanceLayer::instance();
armin's avatar
ds    
armin committed
49
50
51
    connect( mStorage, &PersistanceLayer::ready, this, &RocketChatServerData::initConnections, Qt::UniqueConnection );
    mStorage->init();
}
armin's avatar
armin committed
52

armin's avatar
ds    
armin committed
53
54
void RocketChatServerData::initConnections()
{
armin's avatar
armin committed
55
    historyLoaded = [ = ]( QMultiMap<QString, QSharedPointer<RocketChatMessage>> *messages ) {
armin's avatar
armin committed
56
        if ( messages ) {
armin's avatar
armin committed
57
58
            mStorage->transaction();

armin's avatar
as    
armin committed
59
            for ( auto it = messages->begin(); it != messages->end(); it++ ) {
60
61
62
                if ( Q_LIKELY( mChannels->contains( it.key() ) && !mChannels->get( it.key() ).isNull() ) ) {
                    MessageList messageList = messages->values( it.key() );
                    auto channel = mChannels->get( it.key() );
63
                    QList<QSharedPointer<RocketChatMessage>> newones = channel->addMessages( messageList );
64
65
66
                    mMessageService->deleteMessagesNotInList( messages, it.key(), true );

                    if ( newones.count() ) {
67
                        mMessageService->persistMessages( newones );
68
                    }
armin's avatar
armin committed
69
70
                }
            }
armin's avatar
armin committed
71

armin's avatar
ad    
armin committed
72
            mStorage->askForcommit();
armin's avatar
as    
armin committed
73
            delete messages;
armin's avatar
armin committed
74
75
        }
    };
armin's avatar
ds    
armin committed
76
    QString protocol = QStringLiteral( "https://" );
armin's avatar
armin committed
77

armin's avatar
armin committed
78
    if ( mUnsecureConnection ) {
armin's avatar
ds    
armin committed
79
80
        protocol = QStringLiteral( "http://" );
    }
armin's avatar
armin committed
81

armin's avatar
ad    
armin committed
82
83
84
85
86
87
88
89
90
91
92
93
94
95
    if ( mRestApi != nullptr ) {
        mRestApi->deleteLater();
    }

    if ( mFileService != nullptr ) {
        delete mFileService;
    }

    if ( mEmojiService != nullptr ) {
        delete mEmojiService;
    }

    if ( mDdpApi != nullptr ) {
        mDdpApi->deleteLater();
armin's avatar
armin committed
96
    }
97

armin's avatar
ad    
armin committed
98
99
100
101
102
103
104
105
106
107
108
109
    if ( mChannels != nullptr ) {
        mChannels->deleteLater();
    }

    if ( mMessageService != nullptr ) {
        mMessageService->deleteLater();
    }

    if ( mChannelService != nullptr ) {
        mChannelService->deleteLater();
    }

armin's avatar
ds    
armin committed
110
111
    setRestApi( new RestApi( this, protocol + mBaseUrl ) );
    mFileService = new FileService( this );
armin's avatar
as    
armin committed
112
    mEmojiService = new EmojiService( this, mFileService );
113

armin's avatar
ds    
armin committed
114
    mDdpApi = new MeteorDDP( this, mBaseUrl, mUnsecureConnection );
armin's avatar
armin committed
115

armin's avatar
armin committed
116
117
    mRestApi->moveToThread( QThread::currentThread() );
    mDdpApi->moveToThread( QThread::currentThread() );
armin's avatar
armin committed
118

armin's avatar
ds    
armin committed
119
    mChannels = new ChannelRepository( this );
armin's avatar
armin committed
120

121
122
    RocketChatServerConfig::init();

armin's avatar
as    
armin committed
123
124
    auto result = QMetaObject::invokeMethod( mRestApi, "init" );
    Q_ASSERT( result );
125

armin's avatar
iqw    
armin committed
126
    mDdpApi->registerMessageHandler( this );
armin's avatar
armin committed
127
    connect( mDdpApi, &MeteorDDP::ddpConnected, this, &RocketChatServerData::onDDPConnected, Qt::UniqueConnection );
armin's avatar
armin committed
128
    connect( mDdpApi, &MeteorDDP::ddpDisconnected, this, &RocketChatServerData::onDDPDisonnected, Qt::UniqueConnection );
armin's avatar
armin committed
129

Dennis Beier's avatar
Dennis Beier committed
130
131
132
    QPair<QString, uint> tokenDb = mStorage->getToken();
    QString token = tokenDb.first;
    QString userDb = mStorage->getUserName();
armin's avatar
armin committed
133

Dennis Beier's avatar
Dennis Beier committed
134
135
136
137
    if ( !token.isEmpty() && !userDb.isEmpty() ) {
        emit offlineMode();
    }

armin's avatar
ds    
armin committed
138
    setUserId( mStorage->getUserId() );
armin's avatar
armin committed
139
140
141
142
    mUsername = mStorage->getUserName();

    loadEmojis();

armin's avatar
avatar    
armin committed
143
    mMessageService = new MessageService( this, mStorage, this, mEmojiRepo, mFileService );
armin's avatar
armin committed
144
    mChannelService = new RocketChatChannelService( this, this, mMessageService, mFileService );
145
146
147
148
    mChannelService->setDdp( mDdpApi );
    mChannelService->setChannels( mChannels );
    connect( mChannelService, &RocketChatChannelService::channelsLoaded, this, &RocketChatServerData::onChannelsLoaded, Qt::UniqueConnection );
    connect( mChannelService, &RocketChatChannelService::usersLoaded, this, &RocketChatServerData::onUsersLoaded, Qt::UniqueConnection );
armin's avatar
ias    
armin committed
149
    connect( mChannelService, &RocketChatChannelService::directChannelReady, this, &RocketChatServerData::switchChannelByName, Qt::UniqueConnection );
armin's avatar
armin committed
150
151
152
    connect( channelsModel, &ChannelModel::unreadMessagesChanged, this, &RocketChatServerData::onUnreadCountChanged, Qt::UniqueConnection );
    connect( directModel, &ChannelModel::unreadMessagesChanged, this, &RocketChatServerData::onUnreadCountChanged, Qt::UniqueConnection );
    connect( groupsModel, &ChannelModel::unreadMessagesChanged, this, &RocketChatServerData::onUnreadCountChanged, Qt::UniqueConnection );
armin's avatar
armin committed
153

armin's avatar
armin committed
154

155
    QString lastServer = mStorage->getSetting( QStringLiteral( "currentServer" ) );
armin's avatar
armin committed
156
157
158
159
160
161

    if ( lastServer == mBaseUrl ) {
        QPair<QString, uint> tokenDb = mStorage->getToken();
        QString userDb = mStorage->getUserName();
        QDateTime currentTime = QDateTime::currentDateTime();

armin's avatar
as    
armin committed
162
        //TODO: needs more testing
armin's avatar
armin committed
163
164
165
        if ( !tokenDb.first.isEmpty() && tokenDb.second > currentTime.toTime_t() ) {
            loginWithToken( userDb, tokenDb.first );
        } else {
armin's avatar
ad    
armin committed
166
            wipeDbAndReconnect();
armin's avatar
sd    
armin committed
167
            emit loggedOut( mServerId );
armin's avatar
armin committed
168
        }
armin's avatar
ds    
armin committed
169
    } else if ( !lastServer.isEmpty() ) {
armin's avatar
ad    
armin committed
170
        wipeDbAndReconnect();
armin's avatar
ds    
armin committed
171
        emit loggedOut( mServerId );
armin's avatar
armin committed
172
173
    }

armin's avatar
armin committed
174
    emit readyToCheckForPendingNotification();
175
    mChannelService->loadJoinedChannelsFromDb();
armin's avatar
armin committed
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
}

void RocketChatServerData::setRestApi( RestApi *pNewRestApi )
{

    connect( pNewRestApi, &RestApi::loggedIn, this, &RocketChatServerData::onLoggedIn, Qt::UniqueConnection );
    connect( pNewRestApi, &RestApi::loginError, this, &RocketChatServerData::onLoginError, Qt::UniqueConnection );
    this->mRestApi = pNewRestApi;
    QPair<QString, uint> token = mStorage->getToken();

    if ( token.first.length() && token.second > 0 ) {
        mResumeToken = token.first;
        mTokenExpire = token.second;
    }
}

void RocketChatServerData::loadEmojis()
{

armin's avatar
armin committed
195
196
197
198
199
    /* QFile file(":/emoji.json");
     if(!file.open(QFile::ReadOnly)){
         qDebug()<<file.errorString();
         qDebug()<<file.error();
     }
armin's avatar
armin committed
200

armin's avatar
armin committed
201
     QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
armin's avatar
armin committed
202

armin's avatar
armin committed
203
     QJsonObject obj = doc.object();
armin's avatar
armin committed
204

armin's avatar
armin committed
205
206
207
208
209
210
211
212
213
214
215
216
     for(QString key: obj.keys()){
         QJsonObject emojiObj = obj[key].toObject();
         QString id = ":"+key+":";
         QString file = "qrc:/res/emojis/"+emojiObj["unicode"].toString()+".png";
         QString html = "<img height='20' width='20' src='"+file+"' />";
         QString unicode = Utils::escapeUnicodeEmoji(emojiObj["unicode"].toString());
         QString category = emojiObj["category"].toString();
         QString sort_order = emojiObj["emoji_order"].toString();
         int sort_orderInt = sort_order.toInt();
         qDebug()<<sort_orderInt;
         mStorage->addCustomEmoji(id,file,html,category,unicode,sort_orderInt);
     }*/
armin's avatar
d    
armin committed
217
    auto emojiModel = Models::getEmojisModel();
armin's avatar
armin committed
218

armin's avatar
armin committed
219
    auto emojiList = mEmojiService->loadEmojisFromDb();
armin's avatar
as    
armin committed
220
    QHash<QString, QList<QSharedPointer<Emoji>>> emojisByCategory;
armin's avatar
armin committed
221

222
    for ( auto &emoji : emojiList ) {
armin's avatar
armin committed
223
224
        if ( mEmojiRepo != nullptr && !emoji.isNull() ) {
            mEmojiRepo->add( emoji->getIdentifier(), emoji );
armin's avatar
armin committed
225
        }
armin's avatar
d    
armin committed
226
227
228
229
230

        auto category = emoji->getCategory();

        if ( !emojisByCategory.contains( category ) ) {
            emojisByCategory.insert( category, QList<QSharedPointer<Emoji>>() );
armin's avatar
armin committed
231
            emojisByCategory[category].reserve( 500 );
armin's avatar
armin committed
232
233
234
235

            if ( category == "custom" ) {
                mCustomEmojisReady = true;
            }
armin's avatar
d    
armin committed
236
237
        }

armin's avatar
sa    
armin committed
238
        emojisByCategory[category].append( std::move( emoji ) );
armin's avatar
d    
armin committed
239
240
    }

armin's avatar
as    
armin committed
241
242
243
    for ( auto it = emojisByCategory.begin(); it != emojisByCategory.end(); it++ ) {
        auto result = QMetaObject::invokeMethod( emojiModel, "addEmojisByCategory", Q_ARG( QString, it.key() ), Q_ARG( QList<QSharedPointer<Emoji>>, std::move( it.value() ) ) );
        Q_ASSERT( result );
armin's avatar
armin committed
244
245
246
    }
}

armin's avatar
armin committed
247
void RocketChatServerData::switchChannel( const QString &pServer, const QString &pRid, const QString &pName, const QString &pType )
armin's avatar
armin committed
248
{
armin's avatar
ias    
armin committed
249
    Q_UNUSED( pServer )
armin's avatar
armin committed
250
    qDebug() << "switch channel to: " << pRid;
armin's avatar
armin committed
251
    bool switchPossible = false;
armin's avatar
armin committed
252

253
254
    QSharedPointer<RocketChatChannel> channel = nullptr;

armin's avatar
armin committed
255
    if ( pRid.length() ) {
armin's avatar
armin committed
256
        if ( mChannels != nullptr && !mChannels->contains( pRid ) ) {
armin's avatar
armin committed
257
            if ( pType == "d" || pType == "c" || pType == "p" ) {
armin's avatar
armin committed
258
                qDebug() << "create new channel object to:" << pRid;
259
                mChannelService->createChannelObject( pRid, pName, pType );
armin's avatar
armin committed
260
261

                if ( mChannels->contains( pRid ) && !mChannels->get( pRid ).isNull() ) {
262
                    channel = mChannels->get( pRid );
armin's avatar
armin committed
263
264
                    switchPossible = true;
                }
armin's avatar
armin committed
265
            }
armin's avatar
armin committed
266
        } else if ( mChannels != nullptr ) {
267
            channel = mChannels->get( pRid );
armin's avatar
armin committed
268
269
270
            switchPossible = true;
        }
    }
armin's avatar
armin committed
271
272
273
274
275
276

    if ( switchPossible ) {
        qDebug() << "current Channel " << mCurrentChannel;
        qDebug() << "room " << pRid;

        if ( mCurrentChannel != pRid ) {
277
            emit channelSwitchRequest( channel );
armin's avatar
armin committed
278
279
280
281
        }
    }
}

armin's avatar
ias    
armin committed
282
void RocketChatServerData::switchChannelByName( const QString &pName, const QString &pType )
armin's avatar
armin committed
283
{
armin's avatar
armin committed
284
285
286
    if ( mLoggedIn ) {
        if ( mChannels->getChannelByName( pName ) ) {
            auto channel = mChannels->getChannelByName( pName );
287
            switchChannel( QStringLiteral( "default" ), channel->getRoomId(), pName, channel->getType() );
armin's avatar
armin committed
288
            mPendingSwitchRoomRequest.clear();
armin's avatar
ias    
armin committed
289
            mPendingSwitchRoomRequestType.clear();
armin's avatar
armin committed
290
        } else {
armin's avatar
ias    
armin committed
291
292
293
294
295
296
297
            DdpCallback success = [ = ]( QJsonObject pResponse, MeteorDDP * ) {
                if ( pResponse.contains( "result" ) ) {
                    QJsonObject result = pResponse["result"].toObject();
                    QString id = result["_id"].toString();
                    switchChannel( QStringLiteral( "default" ), id, pName, pType );
                }
            };
298
            auto request = QSharedPointer<RocketChatGetRoomByNameAndType>::create( pName, pType );
armin's avatar
ias    
armin committed
299
300
301
            request->setSuccess( success );
            sendDdprequest( request );
            //searchForRoomIdByName( pName );
armin's avatar
armin committed
302
        }
armin's avatar
armin committed
303
    } else {
armin's avatar
armin committed
304
        mPendingSwitchRoomRequest = pName;
armin's avatar
ias    
armin committed
305
        mPendingSwitchRoomRequestType = pType;
armin's avatar
armin committed
306
307
308
    }
}

armin's avatar
armin committed
309
void RocketChatServerData::requestGetChannelDetails( const QString &pChannelId )
armin's avatar
armin committed
310
311
312
{
    if ( mChannels->contains( pChannelId ) ) {
        auto channel = mChannels->get( pChannelId );
armin's avatar
armin committed
313
314

        if ( !channel.isNull() ) {
armin's avatar
as    
armin committed
315
316
317
318
            auto archived = channel->getArchived();
            auto readonly = channel->getReadOnly();
            auto muted = channel->getMuted();
            auto selfMuted = channel->getSelfMuted();
armin's avatar
armin committed
319

armin's avatar
armin committed
320

armin's avatar
armin committed
321
322
            QVariantList mutedList;

armin's avatar
armin committed
323
324
            for ( const auto &entry : muted ) {
                mutedList.append( entry );
armin's avatar
armin committed
325
            }
armin's avatar
armin committed
326

armin's avatar
armin committed
327
328
            QVariantMap details;

329
330
331
332
            details[QStringLiteral( "archived" )] = archived;
            details[QStringLiteral( "ro" )] = readonly;
            details[QStringLiteral( "muted" )] = mutedList;
            details[QStringLiteral( "selfMuted" )] = selfMuted;
333
            details[QStringLiteral( "type" )] = channel->getType();
334
            details[QStringLiteral( "name" )] = channel->getName();
335
336
            details[QStringLiteral( "ownerId" )] = channel->getOwnerId();
            details[QStringLiteral( "ownerName" )] = channel->getOwnerName();
337
            details[QStringLiteral( "blocked" )] = channel->getBlocked();
armin's avatar
armin committed
338

armin's avatar
armin committed
339
            emit channelDetailsReady( details, pChannelId );
armin's avatar
armin committed
340
        }
armin's avatar
armin committed
341
342
343
344
345
    }
}

void RocketChatServerData::requestIsLoggedIn()
{
armin's avatar
armin committed
346
    if ( mLoggedIn ) {
347
        emit loggedIn( QStringLiteral( "default" ) );
armin's avatar
armin committed
348
349
350
    }
}

armin's avatar
armin committed
351
352
353
354
void RocketChatServerData::setUserPresenceDefaultStatus( int pStatus )
{
    if ( pStatus >= 0 && pStatus < 5 && isWebsocketValid() && diffToLastDDPPing() < 29 ) {

355
        auto request = QSharedPointer<RocketChatChangeUserPresenceDefaultStatus>::create( static_cast<RocketChatUser::status>( pStatus ) );
armin's avatar
armin committed
356
357
358
359
        sendDdprequest( request, true );
    }
}

armin's avatar
armin committed
360
void RocketChatServerData::setUserPresenceStatus( int pStatus )
armin's avatar
armin committed
361
{
armin's avatar
armin committed
362
    if ( pStatus >= 0 && pStatus < 5 && isWebsocketValid() && diffToLastDDPPing() < 29 ) {
armin's avatar
armin committed
363

364
        auto request = QSharedPointer<RocketChatChangeUserPresenceStatus>::create( static_cast<RocketChatUser::status>( pStatus ) );
armin's avatar
armin committed
365
        sendDdprequest( request, true );
armin's avatar
armin committed
366
367
    }
}
armin's avatar
armin committed
368

armin's avatar
armin committed
369
void RocketChatServerData::onStateChanged( const Qt::ApplicationState &pState )
armin's avatar
armin committed
370
{
armin's avatar
armin committed
371
372
    Q_UNUSED( pState )

armin's avatar
armin committed
373
374
375
    if ( !isWebsocketValid() || diffToLastDDPPing() > 29 ) {
        qDebug() << "call resume";
        resume();
armin's avatar
armin committed
376
    } else {
armin's avatar
armin committed
377
        setUserPresenceStatus( static_cast<int>( RocketChatUser::status::ONLINE ) );
armin's avatar
armin committed
378
    }
armin's avatar
as    
armin committed
379

armin's avatar
armin committed
380
381
}

armin's avatar
armin committed
382
void RocketChatServerData::createVideoCall( const QString &pRid )
armin's avatar
armin committed
383
{
armin's avatar
armin committed
384
    if ( !pRid.isEmpty() ) {
armin's avatar
armin committed
385

386
        auto request = QSharedPointer<RocketChatUpdateJitsiTimeout>::create( pRid );
armin's avatar
sad    
armin committed
387
        sendDdprequest( request );
armin's avatar
armin committed
388
        joinJitsiCall( pRid );
armin's avatar
armin committed
389
390
391
    }
}

armin's avatar
armin committed
392
//TODO: rename, as method is not really for searching only
armin's avatar
armin committed
393
void RocketChatServerData::searchForRoomIdByName( const QString &pName )
armin's avatar
armin committed
394
{
395
    auto request = QSharedPointer<RestSpotlightRequest>::create( pName );
armin's avatar
ias    
armin committed
396
    std::function<void ( QNetworkReply *, QJsonObject data, RestApi * )> success = [ = ]( QNetworkReply *, QJsonObject data, RestApi * ) {
armin's avatar
armin committed
397

armin's avatar
ias    
armin committed
398
399
        if ( data.contains( QStringLiteral( "result" ) ) ) {
            QJsonObject result = data[QStringLiteral( "result" )].toObject();
armin's avatar
armin committed
400

401
402
            if ( result.contains( QStringLiteral( "users" ) ) ) {
                QJsonArray users = result[QStringLiteral( "users" )].toArray();
armin's avatar
armin committed
403

armin's avatar
as    
armin committed
404
                for ( auto user : users ) {
armin's avatar
armin committed
405
                    QJsonObject userObj = user.toObject();
armin's avatar
armin committed
406

407
408
                    if ( userObj.contains( QStringLiteral( "username" ) ) && userObj.contains( QStringLiteral( "_id" ) ) ) {
                        QString username = userObj[QStringLiteral( "username" )].toString();
armin's avatar
armin committed
409
410

                        if ( !username.compare( pName, Qt::CaseInsensitive ) ) {
411
412
                            QString id = userObj[QStringLiteral( "_id" )].toString();
                            switchChannel( QStringLiteral( "default" ), id, pName, "d" );
armin's avatar
armin committed
413
414
415
                        }
                    }
                }
416
417
            } else if ( result.contains( QStringLiteral( "rooms" ) ) ) {
                QJsonArray rooms = result[QStringLiteral( "rooms" )].toArray();
armin's avatar
armin committed
418

armin's avatar
as    
armin committed
419
                for ( const auto room : rooms ) {
armin's avatar
armin committed
420
                    QJsonObject roomObj = room.toObject();
armin's avatar
armin committed
421

422
423
                    if ( roomObj.contains( QStringLiteral( "name" ) ) && roomObj.contains( QStringLiteral( "_id" ) ) ) {
                        QString roomname = roomObj[QStringLiteral( "name" )].toString();
armin's avatar
armin committed
424
425

                        if ( !roomname.compare( pName, Qt::CaseInsensitive ) ) {
426
427
                            QString id = roomObj[QStringLiteral( "_id" )].toString();
                            switchChannel( QStringLiteral( "default" ), id, pName, "c" );
armin's avatar
armin committed
428
429
430
431
432
                        }
                    }
                }
            }
        }
armin's avatar
armin committed
433

armin's avatar
armin committed
434
        mPendingSwitchRoomRequest.clear();
armin's avatar
ias    
armin committed
435
        mPendingSwitchRoomRequestType.clear();
armin's avatar
armin committed
436
437

    };
armin's avatar
armin committed
438
    request->setSuccess( success );
armin's avatar
ias    
armin committed
439
    sendApiRequest( request );
armin's avatar
armin committed
440
441
}

442
443
void RocketChatServerData::blockUser( const QString &pChannelId )
{
armin's avatar
armin committed
444
445
    auto userId = pChannelId;
    userId.replace( mUserId, "" );
armin's avatar
armin committed
446
447
448
449

    if ( userId == pChannelId ) {
        QString possibleRoom1 = userId + mUserId;
        QString possibleRoom2 = mUserId + userId;
450

451
452
453
        auto blockRequest1 = QSharedPointer<RocketChatBlockUserRequest>::create( possibleRoom1, userId );
        auto blockRequest2 = QSharedPointer<RocketChatBlockUserRequest>::create( possibleRoom2, userId );

armin's avatar
sad    
armin committed
454
455
        sendDdprequest( blockRequest1 );
        sendDdprequest( blockRequest2 );
456
457


armin's avatar
armin committed
458
    } else {
459
        auto blockRequest = QSharedPointer<RocketChatBlockUserRequest>::create( pChannelId, userId );
armin's avatar
sad    
armin committed
460
        sendDdprequest( blockRequest );
armin's avatar
armin committed
461
    }
462
463
464
465
}

void RocketChatServerData::unBlockUser( const QString &pChannelId )
{
armin's avatar
armin committed
466
467
    auto userId = pChannelId;
    userId.replace( mUserId, "" );
armin's avatar
armin committed
468
469
470
471

    if ( userId == pChannelId ) {
        QString possibleRoom1 = userId + mUserId;
        QString possibleRoom2 = mUserId + userId;
472
473
        auto unBlockRequest1 = QSharedPointer<RocketChatUnblockUserRequest>::create( possibleRoom1, userId );
        auto unBlockRequest2 = QSharedPointer<RocketChatUnblockUserRequest>::create( possibleRoom2, userId );
armin's avatar
sad    
armin committed
474
475
        sendDdprequest( unBlockRequest1 );
        sendDdprequest( unBlockRequest2 );
armin's avatar
armin committed
476
    } else {
477
        auto unBlockRequest = QSharedPointer<RocketChatUnblockUserRequest>::create( pChannelId, userId );
armin's avatar
sad    
armin committed
478
        sendDdprequest( unBlockRequest );
armin's avatar
armin committed
479
    }
480
481
}

armin's avatar
armin committed
482
483
484
485
486
QString RocketChatServerData::getUserId() const
{
    return mUserId;
}

armin's avatar
armin committed
487
void RocketChatServerData::setUserId( const QString &userId )
armin's avatar
armin committed
488
{
armin's avatar
armin committed
489
490
    auto users = Models::getUsersModel();
    auto user = users->getUserById( userId );
armin's avatar
armin committed
491

armin's avatar
sd    
armin committed
492
    if ( user.isNull() && !userId.isEmpty() ) {
493
        user = QSharedPointer<RocketChatUser>::create( userId ) ; //QSharedPointer<RocketChatUser>( new RocketChatUser( userId ) );
armin's avatar
as    
armin committed
494
495
        auto result = QMetaObject::invokeMethod( userModel, "addUser", Q_ARG( User, user ) );
        Q_ASSERT( result );
armin's avatar
armin committed
496
497
    }

armin's avatar
ds    
armin committed
498
499
    if ( !user.isNull() && !userId.isEmpty() ) {
        mUserId = userId;
armin's avatar
armin committed
500

armin's avatar
ds    
armin committed
501
502
503
504
        connect( user.data(), &RocketChatUser::statusChanged, this, [ = ]() {
            emit userStatusChanged( static_cast<int>( user->getStatus() ) );
        } );
    }
armin's avatar
armin committed
505
506
}

armin's avatar
armin committed
507
508
void RocketChatServerData::disconnectFromServer()
{
armin's avatar
armin committed
509
    mConnectionState = ConnectionState::OFFLINE;
510
    emit offline();
armin's avatar
armin committed
511
512
513
    mDdpApi->disconnectFromServer();
}

armin's avatar
armin committed
514
515
516
517
void RocketChatServerData::loadHistories()
{
    QStringList channelIds;

armin's avatar
armin committed
518
519
    for ( const auto &currentChannel : mChannels->getElements() ) {
        if ( Q_LIKELY( !currentChannel.isNull() && currentChannel->getJoined() ) ) {
armin's avatar
armin committed
520
521
522
523
            //joinChannel( currentChannel->getRoomId() );
            channelIds.append( currentChannel->getRoomId() );
        }
    }
armin's avatar
armin committed
524

525
526
    auto request = QSharedPointer<LoadHistoryServiceRequest>::create( channelIds, 1 );

armin's avatar
armin committed
527
    request->setLimit( 1 );
armin's avatar
armin committed
528
    request->setSuccess( historyLoaded );
armin's avatar
armin committed
529
    request->setNoLastThreeDays( true );
armin's avatar
armin committed
530
531
532
    mMessageService->loadHistory( request );
}

armin's avatar
ias    
armin committed
533
void RocketChatServerData::loadHistoryTill( const QString &pChannelId, qint64 pTs )
armin's avatar
armin committed
534
535
536
{

    std::function<void ( QMultiMap<QString, QSharedPointer<RocketChatMessage>> *messages )> success = [ = ]( QMultiMap<QString, QSharedPointer<RocketChatMessage>> *messages ) {
armin's avatar
ias    
armin committed
537
        historyLoaded( messages );
armin's avatar
armin committed
538
    };
539
    auto request = QSharedPointer<LoadHistoryServiceRequest>::create( pChannelId );
armin's avatar
ias    
armin committed
540
541
542
543
544
545
    request->setEnd( pTs );
    request->setLimit( 0 );
    request->setSuccess( success );
    request->setNoLastThreeDays( true );
    request->setStart( 0 );
    request->setSource( LoadHistoryServiceRequest::Source::SERVER );
armin's avatar
armin committed
546

armin's avatar
ias    
armin committed
547
    mMessageService->loadHistory( request );
armin's avatar
armin committed
548
549
}

armin's avatar
armin committed
550
void RocketChatServerData::onUsersLoaded( const QString &pChannelId, const QVector<QSharedPointer<RocketChatUser> > &pUserList )
armin's avatar
armin committed
551
552
553
{
    if ( Q_LIKELY( mChannels->contains( pChannelId ) ) ) {
        auto channel = mChannels->get( pChannelId );
armin's avatar
armin committed
554
555
556
557

        if ( !channel.isNull() ) {
            for ( const auto &user : pUserList ) {
                if ( !user.isNull() ) {
armin's avatar
armin committed
558
                    channel->addUser( user );
armin's avatar
as    
armin committed
559
560
                    auto result = QMetaObject::invokeMethod( userModel, "insertUser", Q_ARG( QString, pChannelId ), Q_ARG( User, user ) );
                    Q_ASSERT( result );
armin's avatar
armin committed
561
562
563
564
565
                }
            }
        }
    }
}
armin's avatar
armin committed
566

armin's avatar
armin committed
567
568
void RocketChatServerData::onUnreadCountChanged()
{
569
570
    static  int lastUnreadCount = -1;

armin's avatar
armin committed
571
    uint number = 0;
armin's avatar
armin committed
572
573
574
575
    qDebug() << "on Unread count changed";

    for ( const auto &channel : mChannels->getElements() ) {
        if ( !channel.isNull() ) {
armin's avatar
armin committed
576
            number += channel->getUnreadMessages();
armin's avatar
armin committed
577
578
        }
    }
579
580
581
582
583
       if ( lastUnreadCount != number ) {
           lastUnreadCount = number;
           emit unreadCountChanged( QStringLiteral( "default" ), number );

       }
armin's avatar
armin committed
584

armin's avatar
armin committed
585
586
}

armin's avatar
cleanup    
armin committed
587
bool RocketChatServerData::handlesMessage( const QJsonObject &message )
588
589
{
    qDebug() << "RocketChatServerData message handler";
armin's avatar
iqw    
armin committed
590
    onDDPMessageReceived( message );
591
592
593
    return true;
}

armin's avatar
armin committed
594
595
596
597
598
EmojiRepo *RocketChatServerData::getEmojiRepo() const
{
    return mEmojiRepo;
}

armin's avatar
armin committed
599
void RocketChatServerData::setEmojiRepo( EmojiRepo *emojiRepo )
armin's avatar
armin committed
600
601
602
603
{
    mEmojiRepo = emojiRepo;
}

armin's avatar
armin committed
604
void RocketChatServerData::createAccount( const QString &username, const QString &email, const QString &password )
605
{
606
    auto request = QSharedPointer<RocketChatCreateAccount>::create( username, email, password );
armin's avatar
armin committed
607
    sendDdprequest( request );
608
609
}

armin's avatar
armin committed
610
611
612
613
void RocketChatServerData::offlineLogin()
{
    QString userId = mStorage->getUserId();
    QString userName = mStorage->getUserName();
armin's avatar
armin committed
614
615

    if ( !userId.isEmpty() && !userName.isEmpty() ) {
armin's avatar
isad    
armin committed
616
        setUserId( userId );
617
        emit loggedIn( QStringLiteral( "default" ) );
armin's avatar
armin committed
618
619
620
    }
}

armin's avatar
ad    
armin committed
621
void RocketChatServerData::wipeDbAndReconnect()
Dennis Beier's avatar
Dennis Beier committed
622
{
armin's avatar
ad    
armin committed
623
624
625
626
    disconnectFromServer();
    mStorage->wipeDb();
    resume();
}
armin's avatar
iqw    
armin committed
627

628
629
630
631
632
void RocketChatServerData::reconnect()
{
    disconnectFromServer();;
    resume();
}
armin's avatar
iqw    
armin committed
633

634
void RocketChatServerData::deleteMessage( QString rid, QString id )
635
{
636
637
    QJsonArray params = { QJsonObject( {{"_id", id }} )};
    auto request = QSharedPointer<DDPMethodRequest>::create( "deleteMessage", params );
638
639
    DdpCallback success = [ = ]( QJsonObject, MeteorDDP * ) {
        try {
640
641
642
            auto room = mChannels->get( rid );
            mStorage->deleteMessage( id );
            room->deleteMessage( id );
643

644
        } catch ( std::logic_error error ) {
645
646
647
648
            qDebug() << error.what();
        }

    };
649
650
    request->setSuccess( success );
    sendDdprequest( request );
651
652
}

armin's avatar
isad    
armin committed
653
654
655
QSharedPointer<RocketChatUser> RocketChatServerData::getOwnUser() const
{
    return mOwnUser;
Dennis Beier's avatar
Dennis Beier committed
656
657
}

armin's avatar
isad    
armin committed
658
void RocketChatServerData::setOwnUser( const QSharedPointer<RocketChatUser> &ownUser )
armin's avatar
armin committed
659
{
armin's avatar
isad    
armin committed
660
661
662
    mOwnUser = ownUser;
}

Dennis Beier's avatar
Dennis Beier committed
663
664
QString RocketChatServerData::getBaseUrl() const
{
armin's avatar
armin committed
665
    QString protocol = "https://";
armin's avatar
armin committed
666

armin's avatar
armin committed
667
668
    if ( mDdpApi->getUnsecure() ) {
        protocol = "http://";
armin's avatar
armin committed
669
    }
armin's avatar
armin committed
670

armin's avatar
armin committed
671
    return protocol + mBaseUrl;
armin's avatar
armin committed
672
673
}

armin's avatar
armin committed
674
void RocketChatServerData::login( const QString &pUsername, const QString &pPassword )
armin's avatar
armin committed
675
{
armin's avatar
ad    
armin committed
676
    QString pass;
armin's avatar
armin committed
677

armin's avatar
ad    
armin committed
678
679
    QByteArray hashArray = QCryptographicHash::hash( pPassword.toUtf8(), QCryptographicHash::Sha256 );
    pass = hashArray.toHex();
armin's avatar
armin committed
680

armin's avatar
ad    
armin committed
681
    loginWithHash( pUsername, pass );
armin's avatar
armin committed
682
683
}

armin's avatar
armin committed
684
void RocketChatServerData::loginWithHash( const QString &pUsername, const QString &pPswHash )
armin's avatar
armin committed
685
686
687
{
    qDebug() << "login with hash";

armin's avatar
ad    
armin committed
688
    RestRequestCallback meCallBackSuccess = [ = ]( QNetworkReply *, QJsonObject data, RestApi * ) {
689

armin's avatar
ad    
armin committed
690
691
692
693
694
695
696
697
698
699
        if ( data.contains( QStringLiteral( "username" ) ) ) {
            mUsername = data[QStringLiteral( "username" )].toString();
            mStorage->transaction();
            mStorage->setUserData( mUsername, "" );
            mStorage->setToken( mResumeToken, mTokenExpire );
            mStorage->setUserId( mUserId );
            mStorage->askForcommit();
            onResume();
            onDDPAuthenticated();
        }
700

armin's avatar
ad    
armin committed
701
    };
702
703
    auto request = QSharedPointer<DDPLoginRequest>::create( pUsername, pPswHash );

armin's avatar
ad    
armin committed
704
    DdpCallback success = [ = ]( QJsonObject pResponse, MeteorDDP * ) {
armin's avatar
armin committed
705
706
        qDebug() << "authenticated";

707
708
        if ( pResponse.contains( QStringLiteral( "result" ) ) ) {
            QJsonObject result = pResponse[QStringLiteral( "result" )].toObject();
armin's avatar
armin committed
709

710
            if ( result.contains( QStringLiteral( "token" ) ) && result.contains( QStringLiteral( "id" ) ) ) {
armin's avatar
ad    
armin committed
711
712
                mConnectionState = ConnectionState::ONLINE;
                mResumeToken = result[QStringLiteral( "token" )].toString();
armin's avatar
as    
armin committed
713
                QJsonObject expireObject = result[QStringLiteral( "tokenExpires" )].toObject();
714
                double expireDouble = expireObject[QStringLiteral( "$date" )].toDouble();
armin's avatar
ad    
armin committed
715
                mTokenExpire = static_cast<uint>( expireDouble / 1000 );
716
                QString userId = result[QStringLiteral( "id" )].toString();
armin's avatar
ad    
armin committed
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731

                setUserId( userId );
                mStorage->transaction();
                mStorage->setUserData( pUsername, pPswHash );

                mRestApi->setToken( mResumeToken );
                mRestApi->setUserId( userId );
                mStorage->askForcommit();
                mDdpApi->setToken( mResumeToken );
                mDdpApi->unsetResponseBinding( request->getFrame() );

                RestApiRequest meRequest
                    = RestApiRequest( new restMeRequest( meCallBackSuccess ) );

                mRestApi->sendRequest( meRequest );
armin's avatar
armin committed
732
733
734
735
736
737
738
739
740
741
            }
        }
    };
    DdpCallback error = [ = ]( QJsonObject pResponse, MeteorDDP * ) {
        Q_UNUSED( pResponse );
        onLoginError();
    };

    request->setSuccess( success );
    request->setError( error );
armin's avatar
armin committed
742
    sendDdprequest( request, true, true );
armin's avatar
armin committed
743
    emit loggingIn();
armin's avatar
armin committed
744
745
746
    this->mUsername = pUsername;
}

armin's avatar
armin committed
747
void RocketChatServerData::loginWithToken( const QString &pUsername, const QString &pToken, bool pResume )
armin's avatar
armin committed
748
749
750
751
752
753
754
{
    Q_UNUSED( pResume );
    qDebug() << "login with token";

    qDebug() << "token from db: " << pToken;

    if ( !pToken.isEmpty() ) {
755
        auto self = this;
armin's avatar
iqw    
armin committed
756

757
        RestRequestCallback meCallBackSuccess = [ self ]( QNetworkReply *, QJsonObject data, RestApi * ) {
armin's avatar
armin committed
758

armin's avatar
iqw    
armin committed
759
760
            QString username;

761
            if ( data.contains( QStringLiteral( "username" ) ) ) {
armin's avatar
iqw    
armin committed
762
763
764
765
766
767
768
769
770
771
772
773
774
                username = data[QStringLiteral( "username" )].toString();
            } else if ( data.contains( "name" ) ) {
                QString name = data["name"].toString().toLower();
                QStringList nameParts = name.split( " " );
                username = nameParts.join( "." );
            }

            if ( username.length() ) {
                self->mUsername = username;
                self->mStorage->transaction();
                self->mStorage->setUserData( self->mUsername, "" );
                self->mStorage->setToken( self->mResumeToken, self->mTokenExpire );
                self->mStorage->setUserId( self->mUserId );
775
776
                self->onResume();
                self->onDDPAuthenticated();
armin's avatar
iqw    
armin committed
777
778
            } else {
                qWarning() << "no valid user information, check message from server";
armin's avatar
armin committed
779
780
781
            }
        };

782
        auto request = QSharedPointer<DDPLoginRequest>::create( pToken );
armin's avatar
sd    
armin committed
783
        DdpCallback success = [ = ]( QJsonObject pResponse, MeteorDDP * ) {
armin's avatar
armin committed
784
            qDebug() << "authenticated";
armin's avatar
sd    
armin committed
785
            mConnectionState = ConnectionState::ONLINE;
armin's avatar
armin committed
786

787
788
            if ( pResponse.contains( QStringLiteral( "result" ) ) ) {
                QJsonObject result = pResponse[QStringLiteral( "result" )].toObject();
armin's avatar
armin committed
789

790
                if ( result.contains( QStringLiteral( "token" ) ) && result.contains( QStringLiteral( "id" ) ) ) {
armin's avatar
sd    
armin committed
791
                    mResumeToken = result[QStringLiteral( "token" )].toString();
792
793
                    QJsonObject expireObject = result[QStringLiteral( "tokenExpires" )].toObject();
                    double expireDouble = expireObject[QStringLiteral( "$date" )].toDouble();
armin's avatar
sd    
armin committed
794
                    mTokenExpire = static_cast<uint>( expireDouble / 1000 );
armin's avatar
armin committed
795

796
                    QString userId = result[QStringLiteral( "id" )].toString();
armin's avatar
sd    
armin committed
797
798
799
800
801
802
803
                    setUserId( userId );
                    mStorage->setToken( self->mResumeToken, self->mTokenExpire );
                    mStorage->setUserId( userId );
                    mRestApi->setToken( self->mResumeToken );
                    mRestApi->setUserId( userId );
                    mDdpApi->setToken( self-> mResumeToken );
                    mDdpApi->unsetResponseBinding( request->getFrame() );
armin's avatar
armin committed
804

armin's avatar
armin committed
805
                    RestApiRequest meRequest
armin's avatar
armin committed
806
                        = RestApiRequest( new restMeRequest( meCallBackSuccess ) );
armin's avatar
armin committed
807

armin's avatar
sd    
armin committed
808
                    mRestApi->sendRequest( meRequest );
armin's avatar
armin committed
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
                }
            }
        };
        DdpCallback error = [ = ]( QJsonObject pResponse, MeteorDDP * ) {
            Q_UNUSED( pResponse );
            qDebug() << "login error";
            //onLoginError();
            //try again with hash

            QString userDb = mStorage->getUserName();
            QString passDb = mStorage->getPassword();

            if ( !userDb.isEmpty() && !passDb.isEmpty() ) {

                loginWithHash( userDb, passDb );
            } else {
                qWarning() << "token rejected and no user+hash information present";
                onLoginError();
            }
        };

        request->setSuccess( success );
        request->setError( error );
832
#ifdef Q_OS_IOS
armin's avatar
armin committed
833
        mDdpApi->sendRequest( request );
834
#else
armin's avatar
armin committed
835
        sendDdprequest( request, true, true );
836
#endif
armin's avatar
armin committed
837
838
        emit loggingIn();

armin's avatar
armin committed
839
840
        this->mUsername = pUsername;
    } else {
841
        emit loginError();
armin's avatar
armin committed
842
843
844
845
        qDebug() << "empty token";
    }
}

armin's avatar
armin committed
846
847
void RocketChatServerData::loginWtihSamlToken( const QString &pToken )
{
armin's avatar
armin committed
848
    if ( !pToken.isEmpty() ) {
armin's avatar
armin committed
849
        qDebug() << pToken;
armin's avatar
armin committed
850
        
armin's avatar
iqw    
armin committed
851
852
853
854
        auto self = this;
        RestRequestCallback meCallBackSuccess = [ self ]( QNetworkReply *, QJsonObject data, RestApi * ) {

            QString username;
armin's avatar
armin committed
855

856
            if ( data.contains( QStringLiteral( "username" ) ) ) {
armin's avatar
iqw    
armin committed
857
858
859
860
861
862
863
864
865
866
867
868
869
                username = data[QStringLiteral( "username" )].toString();
            } else if ( data.contains( "name" ) ) {
                QString name = data["name"].toString().toLower();
                QStringList nameParts = name.split( " " );
                username = nameParts.join( "." );
            }

            if ( username.length() ) {
                self->mUsername = username;
                self->mStorage->transaction();
                self->mStorage->setUserData( self->mUsername, "" );
                self->mStorage->setToken( self->mResumeToken, self->mTokenExpire );
                self->mStorage->setUserId( self->mUserId );
armin's avatar
armin committed
870
                self->mStorage->askForcommit();
armin's avatar
iqw    
armin committed
871
872
873
874
                self->onResume();
                self->onDDPAuthenticated();
            } else {
                qWarning() << "no valid user information, check message from server";
armin's avatar
armin committed
875
876
877
            }
        };
        
878
        auto request = QSharedPointer<ddpSamlLoginRequest>::create( pToken );
armin's avatar
ias    
armin committed
879
        DdpCallback success = [ = ]( QJsonObject pResponse, MeteorDDP * ) {
armin's avatar
armin committed
880
881
882
            qDebug() << "authenticated";
            mConnectionState = ConnectionState::ONLINE;
            
883
884
            if ( pResponse.contains( QStringLiteral( "result" ) ) ) {
                QJsonObject result = pResponse[QStringLiteral( "result" )].toObject();
armin's avatar
armin committed
885
                
886
887
888
889
                if ( result.contains( QStringLiteral( "token" ) ) && result.contains( QStringLiteral( "id" ) ) ) {
                    this->mResumeToken = result[QStringLiteral( "token" )].toString();
                    QJsonObject expireObject = result[QStringLiteral( "tokenExpires" )].toObject();
                    double expireDouble = expireObject[QStringLiteral( "$date" )].toDouble();
armin's avatar
armin committed
890
                    mTokenExpire = static_cast<uint>( expireDouble / 1000 );
armin's avatar
armin committed
891
                    
892
                    QString userId = result[QStringLiteral( "id" )].toString();
armin's avatar
armin committed
893
                    setUserId( userId );
armin's avatar
armin committed
894
895
896
897
898
899
900
901
902
                    mStorage->setToken( mResumeToken, mTokenExpire );
                    mStorage->setUserId( userId );
                    mRestApi->setToken( mResumeToken );
                    mRestApi->setUserId( userId );
                    mDdpApi->setToken( mResumeToken );
                    mDdpApi->unsetResponseBinding( request->getFrame() );
                    
                    
                    RestApiRequest meRequest
armin's avatar
armin committed
903
904
                        = RestApiRequest( new restMeRequest( meCallBackSuccess ) );

armin's avatar
iqw    
armin committed
905
                    self->sendApiRequest( meRequest, true );
armin's avatar
armin committed
906
907
908
909
910
911
912
913
914
915
916
917
918
                    
                }
            }
        };
        DdpCallback error = [ = ]( QJsonObject pResponse, MeteorDDP * ) {
            Q_UNUSED( pResponse );
            qDebug() << "login error";
            qWarning() << "SAML2 token rejected";
            onLoginError();
        };
        
        request->setSuccess( success );
        request->setError( error );
armin's avatar
armin committed
919
        sendDdprequest( request, true, true );
armin's avatar
armin committed
920
921
        emit loggingIn();

armin's avatar
armin committed
922