Skip to content

Commit

Permalink
[FEATURE] Add 'Copy as JSON' action to logged network requests
Browse files Browse the repository at this point in the history
Copies the tree values as a json string to the clipboard, for easy
pasting in bug reports or for remote assistance
  • Loading branch information
nyalldawson committed Mar 31, 2020
1 parent b3cf239 commit 16dc169
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 6 deletions.
116 changes: 110 additions & 6 deletions src/app/devtools/networklogger/qgsnetworkloggernode.cpp
Expand Up @@ -15,6 +15,7 @@

#include "qgsnetworkloggernode.h"
#include "qgis.h"
#include "qgsjsonutils.h"
#include <QUrlQuery>
#include <QColor>
#include <QBrush>
Expand All @@ -23,6 +24,8 @@
#include <QDesktopServices>
#include <QApplication>
#include <QClipboard>
#include <nlohmann/json.hpp>

//
// QgsNetworkLoggerNode
//
Expand Down Expand Up @@ -87,6 +90,19 @@ QVariant QgsNetworkLoggerGroup::data( int role ) const
return QVariant();
}

QVariant QgsNetworkLoggerGroup::toVariant() const
{
QVariantMap res;
for ( const std::unique_ptr< QgsNetworkLoggerNode > &child : mChildren )
{
if ( const QgsNetworkLoggerValueNode *valueNode = dynamic_cast< const QgsNetworkLoggerValueNode *>( child.get() ) )
{
res.insert( valueNode->key(), valueNode->value() );
}
}
return res;
}

//
// QgsNetworkLoggerRootNode
//
Expand All @@ -107,6 +123,14 @@ void QgsNetworkLoggerRootNode::removeRow( int row )
mChildren.erase( mChildren.begin() + row );
}

QVariant QgsNetworkLoggerRootNode::toVariant() const
{
QVariantList res;
for ( const std::unique_ptr< QgsNetworkLoggerNode > &child : mChildren )
res << child->toVariant();
return res;
}


//
// QgsNetworkLoggerValueNode
Expand Down Expand Up @@ -169,6 +193,7 @@ QgsNetworkLoggerRequestGroup::QgsNetworkLoggerRequestGroup( const QgsNetworkRequ
}

std::unique_ptr< QgsNetworkLoggerRequestDetailsGroup > detailsGroup = qgis::make_unique< QgsNetworkLoggerRequestDetailsGroup >( request );
mDetailsGroup = detailsGroup.get();
addChild( std::move( detailsGroup ) );

mTimer.start();
Expand Down Expand Up @@ -283,6 +308,41 @@ QList<QAction *> QgsNetworkLoggerRequestGroup::actions( QObject *parent )
} );
res << copyAsCurlAction;

QAction *copyJsonAction = new QAction( QObject::tr( "Copy as JSON" ), parent );
QObject::connect( copyJsonAction, &QAction::triggered, openUrlAction, [ = ]
{
const QVariant value = toVariant();
const QString json = QString::fromStdString( QgsJsonUtils::jsonFromVariant( value ).dump( 2 ) );
QApplication::clipboard()->setText( json );

} );
res << copyJsonAction;

return res;
}

QVariant QgsNetworkLoggerRequestGroup::toVariant() const
{
QVariantMap res;
res.insert( QStringLiteral( "URL" ), mUrl.url() );
res.insert( QStringLiteral( "Total time (ms)" ), mTotalTime );
res.insert( QStringLiteral( "Bytes Received" ), mBytesReceived );
res.insert( QStringLiteral( "Bytes Total" ), mBytesTotal );
res.insert( QStringLiteral( "Replies" ), mReplies );
if ( mDetailsGroup )
{
const QVariantMap detailsMap = mDetailsGroup->toVariant().toMap();
for ( auto it = detailsMap.constBegin(); it != detailsMap.constEnd(); ++it )
res.insert( it.key(), it.value() );
}
if ( mReplyGroup )
{
res.insert( QObject::tr( "Reply" ), mReplyGroup->toVariant() );
}
if ( mSslErrorsGroup )
{
res.insert( QObject::tr( "SSL Errors" ), mSslErrorsGroup->toVariant() );
}
return res;
}

Expand All @@ -307,7 +367,9 @@ void QgsNetworkLoggerRequestGroup::setReply( const QgsNetworkReplyContent &reply
mHttpStatus = reply.attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt();
mContentType = reply.rawHeader( "Content - Type" );

addChild( qgis::make_unique< QgsNetworkLoggerReplyGroup >( reply ) );
std::unique_ptr< QgsNetworkLoggerReplyGroup > replyGroup = qgis::make_unique< QgsNetworkLoggerReplyGroup >( reply ) ;
mReplyGroup = replyGroup.get();
addChild( std::move( replyGroup ) );
}

void QgsNetworkLoggerRequestGroup::setTimedOut()
Expand All @@ -327,7 +389,9 @@ void QgsNetworkLoggerRequestGroup::setSslErrors( const QList<QSslError> &errors
mHasSslErrors = !errors.empty();
if ( mHasSslErrors )
{
addChild( qgis::make_unique< QgsNetworkLoggerSslErrorGroup >( errors ) );
std::unique_ptr< QgsNetworkLoggerSslErrorGroup > errorGroup = qgis::make_unique< QgsNetworkLoggerSslErrorGroup >( errors );
mSslErrorsGroup = errorGroup.get();
addChild( std::move( errorGroup ) );
}
}

Expand Down Expand Up @@ -404,16 +468,26 @@ QgsNetworkLoggerRequestDetailsGroup::QgsNetworkLoggerRequestDetailsGroup( const
addKeyValueNode( QObject::tr( "Cache (save)" ), request.request().attribute( QNetworkRequest::CacheSaveControlAttribute ).toBool() ? QObject::tr( "Can store result in cache" ) : QObject::tr( "Result cannot be stored in cache" ) );

if ( !QUrlQuery( request.request().url() ).queryItems().isEmpty() )
addChild( qgis::make_unique< QgsNetworkLoggerRequestQueryGroup >( request.request().url() ) );
{
std::unique_ptr< QgsNetworkLoggerRequestQueryGroup > queryGroup = qgis::make_unique< QgsNetworkLoggerRequestQueryGroup >( request.request().url() );
mQueryGroup = queryGroup.get();
addChild( std::move( queryGroup ) );
}

addChild( qgis::make_unique< QgsNetworkLoggerRequestHeadersGroup >( request ) );
std::unique_ptr< QgsNetworkLoggerRequestHeadersGroup > requestHeadersGroup = qgis::make_unique< QgsNetworkLoggerRequestHeadersGroup >( request );
mRequestHeaders = requestHeadersGroup.get();
addChild( std::move( requestHeadersGroup ) );

switch ( request.operation() )
{
case QNetworkAccessManager::PostOperation:
case QNetworkAccessManager::PutOperation:
addChild( qgis::make_unique< QgsNetworkLoggerPostContentGroup >( request ) );
{
std::unique_ptr< QgsNetworkLoggerPostContentGroup > postContentGroup = qgis::make_unique< QgsNetworkLoggerPostContentGroup >( request );
mPostContent = postContentGroup.get();
addChild( std::move( postContentGroup ) );
break;
}

case QNetworkAccessManager::GetOperation:
case QNetworkAccessManager::HeadOperation:
Expand All @@ -424,6 +498,19 @@ QgsNetworkLoggerRequestDetailsGroup::QgsNetworkLoggerRequestDetailsGroup( const
}
}

QVariant QgsNetworkLoggerRequestDetailsGroup::toVariant() const
{
QVariantMap res = QgsNetworkLoggerGroup::toVariant().toMap();
if ( mQueryGroup )
res.insert( QObject::tr( "Query" ), mQueryGroup->toVariant() );
if ( mRequestHeaders )
res.insert( QObject::tr( "Headers" ), mRequestHeaders->toVariant() );
if ( mPostContent )
res.insert( QObject::tr( "Content" ), mPostContent->toVariant() );
return res;
}


//
// QgsNetworkLoggerRequestQueryGroup
//
Expand Down Expand Up @@ -480,7 +567,19 @@ QgsNetworkLoggerReplyGroup::QgsNetworkLoggerReplyGroup( const QgsNetworkReplyCon
}
addKeyValueNode( QObject::tr( "Cache (result)" ), reply.attribute( QNetworkRequest::SourceIsFromCacheAttribute ).toBool() ? QObject::tr( "Used entry from cache" ) : QObject::tr( "Read from network" ) );

addChild( qgis::make_unique< QgsNetworkLoggerReplyHeadersGroup >( reply ) );
std::unique_ptr< QgsNetworkLoggerReplyHeadersGroup > headersGroup = qgis::make_unique< QgsNetworkLoggerReplyHeadersGroup >( reply );
mReplyHeaders = headersGroup.get();
addChild( std::move( headersGroup ) );
}

QVariant QgsNetworkLoggerReplyGroup::toVariant() const
{
QVariantMap res = QgsNetworkLoggerGroup::toVariant().toMap();
if ( mReplyHeaders )
{
res.insert( QObject::tr( "Headers" ), mReplyHeaders->toVariant() );
}
return res;
}


Expand Down Expand Up @@ -521,3 +620,8 @@ QList<QAction *> QgsNetworkLoggerNode::actions( QObject * )
{
return QList< QAction * >();
}

QVariant QgsNetworkLoggerNode::toVariant() const
{
return QVariant();
}
42 changes: 42 additions & 0 deletions src/app/devtools/networklogger/qgsnetworkloggernode.h
Expand Up @@ -69,6 +69,11 @@ class QgsNetworkLoggerNode
*/
virtual QList< QAction * > actions( QObject *parent );

/**
* Converts the node's contents to a variant.
*/
virtual QVariant toVariant() const;

protected:

QgsNetworkLoggerNode();
Expand Down Expand Up @@ -114,6 +119,7 @@ class QgsNetworkLoggerGroup : public QgsNetworkLoggerNode

int childCount() const override final { return mChildren.size(); }
QVariant data( int role = Qt::DisplayRole ) const override;
QVariant toVariant() const override;

protected:

Expand Down Expand Up @@ -151,6 +157,16 @@ class QgsNetworkLoggerValueNode : public QgsNetworkLoggerNode
*/
QgsNetworkLoggerValueNode( const QString &key, const QString &value, const QColor &color = QColor() );

/**
* Returns the node's key.
*/
QString key() const { return mKey; }

/**
* Returns the node's value.
*/
QString value() const { return mValue; }

QVariant data( int role = Qt::DisplayRole ) const override final;
int childCount() const override final { return 0; }

Expand Down Expand Up @@ -179,8 +195,13 @@ class QgsNetworkLoggerRootNode final : public QgsNetworkLoggerGroup
* Removes a \a row from the root group.
*/
void removeRow( int row );

QVariant toVariant() const override;
};

class QgsNetworkLoggerRequestDetailsGroup;
class QgsNetworkLoggerReplyGroup;
class QgsNetworkLoggerSslErrorGroup;

/**
* \ingroup app
Expand Down Expand Up @@ -229,6 +250,7 @@ class QgsNetworkLoggerRequestGroup final : public QgsNetworkLoggerGroup
QgsNetworkLoggerRequestGroup( const QgsNetworkRequestParameters &request );
QVariant data( int role = Qt::DisplayRole ) const override;
QList< QAction * > actions( QObject *parent ) override final;
QVariant toVariant() const override;

/**
* Returns the request's status.
Expand Down Expand Up @@ -293,8 +315,15 @@ class QgsNetworkLoggerRequestGroup final : public QgsNetworkLoggerGroup
Status mStatus = Status::Pending;
bool mHasSslErrors = false;
QList< QPair< QString, QString > > mHeaders;
QgsNetworkLoggerRequestDetailsGroup *mDetailsGroup = nullptr;
QgsNetworkLoggerReplyGroup *mReplyGroup = nullptr;
QgsNetworkLoggerSslErrorGroup *mSslErrorsGroup = nullptr;
};

class QgsNetworkLoggerRequestQueryGroup;
class QgsNetworkLoggerRequestHeadersGroup;
class QgsNetworkLoggerPostContentGroup;

/**
* \ingroup app
* \class QgsNetworkLoggerRequestGroup
Expand Down Expand Up @@ -329,7 +358,13 @@ class QgsNetworkLoggerRequestDetailsGroup final : public QgsNetworkLoggerGroup
* specified \a request details.
*/
QgsNetworkLoggerRequestDetailsGroup( const QgsNetworkRequestParameters &request );
QVariant toVariant() const override;

private:

QgsNetworkLoggerRequestQueryGroup *mQueryGroup = nullptr;
QgsNetworkLoggerRequestHeadersGroup *mRequestHeaders = nullptr;
QgsNetworkLoggerPostContentGroup *mPostContent = nullptr;
};


Expand Down Expand Up @@ -407,6 +442,8 @@ class QgsNetworkLoggerPostContentGroup final : public QgsNetworkLoggerGroup
QgsNetworkLoggerPostContentGroup( const QgsNetworkRequestParameters &parameters );
};

class QgsNetworkLoggerReplyHeadersGroup;

/**
* \ingroup app
* \class QgsNetworkLoggerReplyGroup
Expand All @@ -432,6 +469,11 @@ class QgsNetworkLoggerReplyGroup final : public QgsNetworkLoggerGroup
* specified \a reply details.
*/
QgsNetworkLoggerReplyGroup( const QgsNetworkReplyContent &reply );
QVariant toVariant() const override;

private:

QgsNetworkLoggerReplyHeadersGroup *mReplyHeaders = nullptr;

};

Expand Down

0 comments on commit 16dc169

Please sign in to comment.