google_auth_service.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. # -*- coding: utf-8 -*-
  2. import logging
  3. import requests
  4. from odoo import models, api
  5. from odoo.exceptions import UserError
  6. from odoo.tools.translate import _
  7. _logger = logging.getLogger(__name__)
  8. class GoogleAuthService(models.AbstractModel):
  9. _name = 'google.auth.service'
  10. _description = 'Google Authentication Service'
  11. def test_connection(self):
  12. """Test Google Drive API connection"""
  13. try:
  14. access_token = self._get_access_token()
  15. if not access_token:
  16. return False
  17. headers = {
  18. 'Authorization': f'Bearer {access_token}',
  19. 'Content-Type': 'application/json'
  20. }
  21. response = requests.get(
  22. 'https://www.googleapis.com/drive/v3/about',
  23. headers=headers,
  24. params={'fields': 'user'},
  25. timeout=10
  26. )
  27. if response.status_code == 200:
  28. return True
  29. elif response.status_code == 401:
  30. _logger.warning("Google Drive access token is invalid (401)")
  31. # Try to refresh the token
  32. if self.refresh_access_token():
  33. return self.test_connection()
  34. return False
  35. else:
  36. _logger.warning(f"Google Drive API test failed with status {response.status_code}")
  37. return False
  38. except requests.exceptions.Timeout:
  39. _logger.error("Google Drive API test timeout")
  40. return False
  41. except requests.exceptions.ConnectionError:
  42. _logger.error("Google Drive API connection error")
  43. return False
  44. except Exception as e:
  45. _logger.error(f"Google Drive API test error: {str(e)}")
  46. return False
  47. def refresh_access_token(self):
  48. """Refresh the access token using the refresh token"""
  49. try:
  50. refresh_token = self.env['ir.config_parameter'].sudo().get_param('google_api.refresh_token')
  51. client_id = self.env['ir.config_parameter'].sudo().get_param('google_api.client_id')
  52. client_secret = self.env['ir.config_parameter'].sudo().get_param('google_api.client_secret')
  53. if not all([refresh_token, client_id, client_secret]):
  54. _logger.error("Missing OAuth2 credentials")
  55. return False
  56. # Exchange refresh token for new access token
  57. token_url = 'https://oauth2.googleapis.com/token'
  58. data = {
  59. 'client_id': client_id,
  60. 'client_secret': client_secret,
  61. 'refresh_token': refresh_token,
  62. 'grant_type': 'refresh_token'
  63. }
  64. response = requests.post(token_url, data=data, timeout=30)
  65. if response.status_code == 200:
  66. token_data = response.json()
  67. new_access_token = token_data.get('access_token')
  68. if new_access_token:
  69. # Store the new access token
  70. self.env['ir.config_parameter'].sudo().set_param('google_api.access_token', new_access_token)
  71. _logger.info("Access token refreshed successfully")
  72. return True
  73. else:
  74. _logger.error("No access token in response")
  75. return False
  76. else:
  77. _logger.error(f"Failed to refresh token: {response.status_code} - {response.text}")
  78. return False
  79. except Exception as e:
  80. _logger.error(f"Failed to refresh access token: {str(e)}")
  81. return False
  82. def get_access_token(self, user=None):
  83. """Get a valid access token for the specified user, refreshing if necessary"""
  84. if not user:
  85. user = self.env.user
  86. try:
  87. # Get user's Google Drive settings
  88. user_settings = user.res_users_settings_id
  89. if not user_settings:
  90. return None
  91. # Get access token from user settings
  92. return user_settings._get_google_access_token()
  93. except Exception as e:
  94. _logger.error(f"Error getting access token for user {user.name}: {str(e)}")
  95. return None
  96. def _test_token_validity(self, access_token):
  97. """Test if an access token is still valid"""
  98. try:
  99. headers = {
  100. 'Authorization': f'Bearer {access_token}',
  101. 'Content-Type': 'application/json'
  102. }
  103. response = requests.get(
  104. 'https://www.googleapis.com/drive/v3/about',
  105. headers=headers,
  106. params={'fields': 'user'},
  107. timeout=5
  108. )
  109. return response.status_code == 200
  110. except Exception as e:
  111. _logger.error(f"Error testing token validity: {str(e)}")
  112. return False
  113. def validate_credentials(self):
  114. """Validate that all required OAuth2 credentials are configured"""
  115. try:
  116. client_id = self.env['ir.config_parameter'].sudo().get_param('google_api.client_id')
  117. client_secret = self.env['ir.config_parameter'].sudo().get_param('google_api.client_secret')
  118. refresh_token = self.env['ir.config_parameter'].sudo().get_param('google_api.refresh_token')
  119. missing_credentials = []
  120. if not client_id:
  121. missing_credentials.append('Client ID')
  122. if not client_secret:
  123. missing_credentials.append('Client Secret')
  124. if not refresh_token:
  125. missing_credentials.append('Refresh Token')
  126. if missing_credentials:
  127. raise UserError(_('Missing Google API credentials: %s') % ', '.join(missing_credentials))
  128. return True
  129. except Exception as e:
  130. _logger.error(f"Error validating credentials: {str(e)}")
  131. raise
  132. def get_auth_headers(self, user=None):
  133. """Get authentication headers for API requests"""
  134. try:
  135. access_token = self.get_access_token(user)
  136. if not access_token:
  137. raise UserError(_('Could not obtain valid access token for user %s') % (user.name if user else self.env.user.name))
  138. return {
  139. 'Authorization': f'Bearer {access_token}',
  140. 'Content-Type': 'application/json'
  141. }
  142. except Exception as e:
  143. _logger.error(f"Error getting auth headers: {str(e)}")
  144. raise