1 /***************************************************************************
2 qgsnewarcgisrestconnection.cpp
3 -------------------
4 begin : December 2020
5 copyright : (C) 2020 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 #include "qgsnewarcgisrestconnection.h"
18 #include "qgsauthsettingswidget.h"
19 #include "qgssettings.h"
20 #include "qgshelp.h"
21 #include "qgsgui.h"
22 #include "fromencodedcomponenthelper.h"
23
24 #include <QMessageBox>
25 #include <QUrl>
26 #include <QPushButton>
27 #include <QRegularExpression>
28 #include <QRegularExpressionValidator>
29 #include <QUrlQuery>
30
QgsNewArcGisRestConnectionDialog(QWidget * parent,const QString & baseKey,const QString & connectionName,Qt::WindowFlags fl)31 QgsNewArcGisRestConnectionDialog::QgsNewArcGisRestConnectionDialog( QWidget *parent, const QString &baseKey, const QString &connectionName, Qt::WindowFlags fl )
32 : QDialog( parent, fl )
33 , mBaseKey( baseKey )
34 , mOriginalConnName( connectionName )
35 {
36 setupUi( this );
37
38 QgsGui::enableAutoGeometryRestore( this );
39
40 connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsNewArcGisRestConnectionDialog::showHelp );
41
42 const QRegularExpression rx( QStringLiteral( "/connections-([^/]+)/" ) );
43 const QRegularExpressionMatch match = rx.match( baseKey );
44 if ( match.hasMatch() )
45 {
46 const QString connectionType( match.captured( 1 ).toUpper() );
47 setWindowTitle( tr( "Create a New %1 Connection" ).arg( connectionType ) );
48 }
49
50 mCredentialsBaseKey = mBaseKey.split( '-' ).last().toUpper();
51
52 txtName->setValidator( new QRegularExpressionValidator( QRegularExpression( QStringLiteral( "[^\\/]+" ) ), txtName ) );
53
54 if ( !connectionName.isEmpty() )
55 {
56 // populate the dialog with the information stored for the connection
57 // populate the fields with the stored setting parameters
58
59 const QgsSettings settings;
60
61 const QString key = mBaseKey + connectionName;
62 const QString credentialsKey = "qgis/" + mCredentialsBaseKey + '/' + connectionName;
63 txtName->setText( connectionName );
64 txtUrl->setText( settings.value( key + "/url" ).toString() );
65 mRefererLineEdit->setText( settings.value( key + "/referer" ).toString() );
66
67 // portal
68 mContentEndPointLineEdit->setText( settings.value( key + "/content_endpoint" ).toString() );
69 mCommunityEndPointLineEdit->setText( settings.value( key + "/community_endpoint" ).toString() );
70
71 // Authentication
72 mAuthSettings->setUsername( settings.value( credentialsKey + "/username" ).toString() );
73 mAuthSettings->setPassword( settings.value( credentialsKey + "/password" ).toString() );
74 mAuthSettings->setConfigId( settings.value( credentialsKey + "/authcfg" ).toString() );
75 }
76
77 // Adjust height
78 const int w = width();
79 adjustSize();
80 resize( w, height() );
81
82 connect( txtName, &QLineEdit::textChanged, this, &QgsNewArcGisRestConnectionDialog::nameChanged );
83 connect( txtUrl, &QLineEdit::textChanged, this, &QgsNewArcGisRestConnectionDialog::urlChanged );
84
85 buttonBox->button( QDialogButtonBox::Ok )->setDisabled( true );
86 connect( txtName, &QLineEdit::textChanged, this, &QgsNewArcGisRestConnectionDialog::updateOkButtonState );
87 connect( txtUrl, &QLineEdit::textChanged, this, &QgsNewArcGisRestConnectionDialog::updateOkButtonState );
88
89 nameChanged( connectionName );
90 }
91
name() const92 QString QgsNewArcGisRestConnectionDialog::name() const
93 {
94 return txtName->text();
95 }
96
url() const97 QString QgsNewArcGisRestConnectionDialog::url() const
98 {
99 return txtUrl->text();
100 }
101
nameChanged(const QString & text)102 void QgsNewArcGisRestConnectionDialog::nameChanged( const QString &text )
103 {
104 Q_UNUSED( text )
105 buttonBox->button( QDialogButtonBox::Ok )->setDisabled( txtName->text().isEmpty() || txtUrl->text().isEmpty() );
106 }
107
urlChanged(const QString & text)108 void QgsNewArcGisRestConnectionDialog::urlChanged( const QString &text )
109 {
110 Q_UNUSED( text )
111 buttonBox->button( QDialogButtonBox::Ok )->setDisabled( txtName->text().isEmpty() || txtUrl->text().isEmpty() );
112 }
113
updateOkButtonState()114 void QgsNewArcGisRestConnectionDialog::updateOkButtonState()
115 {
116 const bool enabled = !txtName->text().isEmpty() && !txtUrl->text().isEmpty();
117 buttonBox->button( QDialogButtonBox::Ok )->setEnabled( enabled );
118 }
119
validate()120 bool QgsNewArcGisRestConnectionDialog::validate()
121 {
122 const QgsSettings settings;
123 const QString key = mBaseKey + txtName->text();
124
125 // warn if entry was renamed to an existing connection
126 if ( ( mOriginalConnName.isNull() || mOriginalConnName.compare( txtName->text(), Qt::CaseInsensitive ) != 0 ) &&
127 settings.contains( key + "/url" ) &&
128 QMessageBox::question( this,
129 tr( "Save Connection" ),
130 tr( "Should the existing connection %1 be overwritten?" ).arg( txtName->text() ),
131 QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel )
132 {
133 return false;
134 }
135
136 if ( ! mAuthSettings->password().isEmpty() &&
137 QMessageBox::question( this,
138 tr( "Saving Passwords" ),
139 tr( "WARNING: You have entered a password. It will be stored in unsecured plain text in your project files and your home directory (Unix-like OS) or user profile (Windows). If you want to avoid this, press Cancel and either:\n\na) Don't provide a password in the connection settings — it will be requested interactively when needed;\nb) Use the Configuration tab to add your credentials in an HTTP Basic Authentication method and store them in an encrypted database." ),
140 QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Cancel )
141 {
142 return false;
143 }
144
145 return true;
146 }
147
urlTrimmed() const148 QUrl QgsNewArcGisRestConnectionDialog::urlTrimmed() const
149 {
150 QUrl url( txtUrl->text().trimmed() );
151 const QUrlQuery query( url );
152 const QList<QPair<QString, QString> > items = query.queryItems( QUrl::FullyEncoded );
153 QHash< QString, QPair<QString, QString> > params;
154 for ( const QPair<QString, QString> &it : items )
155 {
156 params.insert( it.first.toUpper(), it );
157 }
158
159 url.setQuery( query );
160
161 if ( url.path( QUrl::FullyEncoded ).isEmpty() )
162 {
163 url.setPath( fromEncodedComponent_helper( "/" ) );
164 }
165 return url;
166 }
167
accept()168 void QgsNewArcGisRestConnectionDialog::accept()
169 {
170 QgsSettings settings;
171 const QString key = mBaseKey + txtName->text();
172 const QString credentialsKey = "qgis/" + mCredentialsBaseKey + '/' + txtName->text();
173
174 if ( !validate() )
175 return;
176
177 // on rename delete original entry first
178 if ( !mOriginalConnName.isNull() && mOriginalConnName != key )
179 {
180 settings.remove( mBaseKey + mOriginalConnName );
181 settings.remove( "qgis/" + mCredentialsBaseKey + '/' + mOriginalConnName );
182 settings.sync();
183 }
184
185 const QUrl url( urlTrimmed() );
186 settings.setValue( key + "/url", url.toString() );
187
188 settings.setValue( credentialsKey + "/username", mAuthSettings->username() );
189 settings.setValue( credentialsKey + "/password", mAuthSettings->password() );
190
191 settings.setValue( key + "/content_endpoint", mContentEndPointLineEdit->text() );
192 settings.setValue( key + "/community_endpoint", mCommunityEndPointLineEdit->text() );
193
194 settings.setValue( credentialsKey + "/authcfg", mAuthSettings->configId() );
195
196 if ( mHttpGroupBox->isVisible() )
197 settings.setValue( key + "/referer", mRefererLineEdit->text() );
198
199 settings.setValue( mBaseKey + "/selected", txtName->text() );
200
201 QDialog::accept();
202 }
203
showHelp()204 void QgsNewArcGisRestConnectionDialog::showHelp()
205 {
206 QgsHelp::openHelp( QStringLiteral( "working_with_ogc/index.html" ) );
207 }
208