Skip to content

Commit

Permalink
Merge pull request #156 from gee-community/auth-and-set-project
Browse files Browse the repository at this point in the history
Authenticate and set project during initialize
  • Loading branch information
gena authored Nov 7, 2024
2 parents 30ecdc3 + 8c7dcc1 commit a4613df
Show file tree
Hide file tree
Showing 10 changed files with 604 additions and 788 deletions.
34 changes: 34 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 6 additions & 8 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
import site
import pkg_resources


def pre_init_plugin():

def add_ee_dependencies():
extra_libs_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'extlibs'))

if os.path.isdir(extra_libs_path):
Expand All @@ -23,12 +21,12 @@ def classFactory(iface): # pylint: disable=invalid-name
:type iface: QgsInterface
"""

# load extra python dependencies
pre_init_plugin()
# load EE python dependencies
add_ee_dependencies()

# Initialize the Earth Engine Python API
import ee
ee.Initialize()
# authenticate and initialize EE
from . import ee_auth
ee_auth.authenticate_and_set_project()

# start
from .ee_plugin import GoogleEarthEnginePlugin
Expand Down
121 changes: 121 additions & 0 deletions ee_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import pathlib
import json
import ee
from qgis.PyQt.QtWidgets import QMessageBox, QInputDialog, QLineEdit

CREDENTIALS_PATH = pathlib.Path('~/.config/earthengine/credentials').expanduser()

def ee_read_config():
"""Reads project name, return None if there is no EE config file detected"""
try:
with open(CREDENTIALS_PATH) as json_config_file:
config = json.load(json_config_file)
except FileNotFoundError:
# File may not exist if we initialized from default credentials.
return None

return config

def save_project_to_config(project):
"""Write new project name into the EE config file"""
config = ee_read_config()
config['project'] = project
ee.oauth.write_private_json(CREDENTIALS_PATH, config)

def ee_authenticate():
""" show a dialog to allow users to start or cancel the authentication process """

msg = """This plugin uses Google Earth Engine API and it looks like it is not yet authenticated on this machine.<br>
<br>
You need to have a Google account registered for Google Earth Engine access to continue.<br>
<br>
Make sure you can access Earth Engine Code Editor by visiting: <br>
<br>
<a href="https://code.earthengine.google.com">https://code.earthengine.google.com</a><br>
<br>
After validating that you can access Earth Engine, click OK to open a web browser
and follow the authentication process or click Cancel to skip"""

reply = QMessageBox.warning(None, 'Authenticate Google Earth Engine',
msg, QMessageBox.Cancel | QMessageBox.Ok)

if reply == QMessageBox.Cancel:
print('Cancel')
return False
else:
ee.Authenticate(auth_mode='localhost', force=True)

# bug: ee.Authenticate(force=True) returns None, check the auth status manually
config = ee_read_config()
if config is not None:
return True


def ee_initialize_with_project(project, force=False):
"""Initializes EE with a project or ask user to specify project if there is no project set"""

msg_no_project = """Google Cloud Project is empty.<br>
<br>
Starting November 13, 2024, users will need to use a Google Cloud Project to access the Earth Engine platform.<br>
See <a href="https://developers.google.com/earth-engine/guides/transition_to_cloud_projects">Transition to Cloud projects</a> for more info.<br>
<br>
Make sure your Google Cloud project is registered properly for Earth Engine access<br>
<br>
Then set the project name in the text field baloe and click OK or click Cancel to skip<br>
<br>
Google Cloud Project:"""

msg_with_project = """Change Google Cloud project field below to a new value.<br>
<br>
Make sure your project is registered properly for Earth Engine access and click OK or click Cancel to skip this step<br>
<br>
Google Cloud Project:"""

if project is None:
msg = msg_no_project
elif force:
msg = msg_with_project
else:
# project is set and no force - initialize and return
ee.Initialize(project=project)
return

(project, ok) = QInputDialog.getText(None, "Select Earth Engine project", msg, QLineEdit.Normal, project)

if not ok:
return # no project is configured and cancelled, you're on your own

ee.Initialize(project=project)
save_project_to_config(project)

def authenticate_and_set_project():
config = ee_read_config()

is_authenticated = False

if config is not None:
is_authenticated = True

if not is_authenticated: # not authenticated > start authentication process
is_authenticated = ee_authenticate()

# authentication failed
if not is_authenticated:
raise ee.EEException("Can not initialize Google Earth Engine. Please make sure you can access Earth Engine, restart QGIS, and re-enable EE plugin.")

# initialize EE with existing project or select a new one if there is no project
project = None
if config is not None:
project = config.get('project')
ee_initialize_with_project(project)

def select_project():
# read existing project
config = ee_read_config()

project = None
if config is not None:
project = config.get('project')

ee_initialize_with_project(project, force=True)

50 changes: 38 additions & 12 deletions ee_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def __init__(self, iface):
if qVersion() > '4.3.3':
QCoreApplication.installTranslator(self.translator)

self.menu_name_plugin = self.tr("Google Earth Engine Plugin")
self.menu_name_plugin = self.tr("Google Earth Engine")

# Create and register the EE data providers
provider.register_data_provider()
Expand All @@ -81,21 +81,45 @@ def tr(self, message):
def initGui(self):
### Main dockwidget menu
# Create action that will start plugin configuration
icon_path = ':/plugins/ee_plugin/icons/earth_engine.svg'
self.dockable_action = QAction(
QIcon(icon_path), "User Guide", self.iface.mainWindow())
# connect the action to the run method
self.dockable_action.triggered.connect(self.run)
ee_icon_path = ':/plugins/ee_plugin/icons/earth-engine.svg'
self.cmd_ee_user_guide = QAction(QIcon(ee_icon_path), "User Guide", self.iface.mainWindow())
self.cmd_ee_user_guide.triggered.connect(self.run_cmd_ee_user_guide)

gcp_icon_path = ':/plugins/ee_plugin/icons/google-cloud.svg'
self.cmd_sign_in = QAction(QIcon(gcp_icon_path), "Sign-in", self.iface.mainWindow())
self.cmd_sign_in.triggered.connect(self.run_cmd_sign_in)

gcp_project_icon_path = ':/plugins/ee_plugin/icons/google-cloud-project.svg'
self.cmd_set_cloud_project = QAction(QIcon(gcp_project_icon_path), "Set Project", self.iface.mainWindow())
self.cmd_set_cloud_project.triggered.connect(self.run_cmd_set_cloud_project)

# Add menu item
self.iface.addPluginToMenu(self.menu_name_plugin, self.dockable_action)
self.iface.addPluginToMenu(self.menu_name_plugin, self.cmd_ee_user_guide)
self.iface.addPluginToMenu(self.menu_name_plugin, self.cmd_sign_in)
self.iface.addPluginToMenu(self.menu_name_plugin, self.cmd_set_cloud_project)

# Register signal to initialize EE layers on project load
self.iface.projectRead.connect(self.updateLayers)


def run(self):
def run_cmd_ee_user_guide(self):
# open user guide in external web browser
webbrowser.open_new(
"http://qgis-ee-plugin.appspot.com/user-guide")
webbrowser.open_new("http://qgis-ee-plugin.appspot.com/user-guide")

def run_cmd_sign_in(self):
import ee
from . import ee_auth

# reset authentication by forcing sign in
ee.Authenticate(auth_mode='localhost', force=True)

# after resetting authentication, select Google Cloud project again
ee_auth.select_project()

def run_cmd_set_cloud_project(self):
from . import ee_auth

ee_auth.select_project()

def check_version(self):
global version_checked
Expand All @@ -118,8 +142,10 @@ def check_version(self):

def unload(self):
# Remove the plugin menu item and icon
self.iface.removePluginMenu(
self.menu_name_plugin, self.dockable_action)
self.iface.removePluginMenu(self.menu_name_plugin, self.cmd_ee_user_guide)
self.iface.removePluginMenu(self.menu_name_plugin, self.cmd_sign_in)
self.iface.removePluginMenu(self.menu_name_plugin, self.cmd_set_cloud_project)


def updateLayers(self):
import ee
Expand Down
14 changes: 14 additions & 0 deletions icons/earth-engine.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit a4613df

Please sign in to comment.