[16.0][ADD]document_url_google_drive: added page Google Api to user profile

This commit is contained in:
Demchuk Mykola 2023-11-06 22:18:03 +02:00
parent 62f73d21d1
commit 5cc621beab
7 changed files with 186 additions and 43 deletions

View File

@ -1,35 +1,127 @@
**This file is going to be generated by oca-gen-addon-readme.** ===========================
Google Drive URL attachment
===========================
*Manual changes will be overwritten.* ..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:c5d9ab55bc4eea23f037ee922df0021f29e6fe04a6aa716a4a28146b4f75502e
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Please provide content in the ``readme`` directory: .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fknowledge-lightgray.png?logo=github
:target: https://github.com/OCA/knowledge/tree/16.0/document_url_google_drive
:alt: OCA/knowledge
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/knowledge-16-0/knowledge-16-0-document_url_google_drive
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/knowledge&target_branch=16.0
:alt: Try me on Runboat
* **DESCRIPTION.rst** (required) |badge1| |badge2| |badge3| |badge4| |badge5|
* INSTALL.rst (optional)
* CONFIGURE.rst (optional)
* **USAGE.rst** (optional, highly recommended)
* DEVELOP.rst (optional)
* ROADMAP.rst (optional)
* HISTORY.rst (optional, recommended)
* **CONTRIBUTORS.rst** (optional, highly recommended)
* CREDITS.rst (optional)
Content of this README will also be drawn from the addon manifest, This module extends the functionality of the document_url module and
from keys such as name, authors, maintainers, development_status, allows you to attach a link to a file from your Google Drive
and license.
A good, one sentence summary in the manifest is also highly recommended. **Table of contents**
.. contents::
:local:
Automatic changelog generation Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ =============
`HISTORY.rst` can be auto generated using `towncrier <https://pypi.org/project/towncrier>`_. To configure this module, you need to:
Just put towncrier compatible changelog fragments into `readme/newsfragments` - Go to Settings -> General Settings and scroll down to the
and the changelog file will be automatically generated and updated when a new fragment is added. Integrations section.
Please refer to `towncrier` documentation to know more. - Enable "Google API", save. Setup instructions
https://developers.google.com/drive/picker/guides/overview
NOTE: the changelog will be automatically generated when using `/ocabot merge $option`. - field "Google Client ID" - enter the client ID from the Google API
If you need to run it manually, refer to `OCA/maintainer-tools README <https://github.com/OCA/maintainer-tools>`_. console.
- field "Google API key" - enter the API key from the Google API
console.
- field "Google App ID" - enter the ID of the Google application.
The default value is ``odoo``.
- Next, open your user profile and set up personal access credentials
on the "Google API" tab.
- field "Google Scope" - enter the scope for the Google API. The
default value is
``https://www.googleapis.com/auth/drive.readonly``.
- field "Google Access Token" - your token will be displayed here.
It is necessary to edit it.
- field "Google Mime Types" - enter the file formats to be filtered
when selecting. Example:
``application/pdf, image/jpeg, image/png``. By default, all files
are selected
- You will be asked to authenticate when you add a link for the first
time.
Usage
=====
To use this module, you need to:
#. Open the form view of an object (Example: Customer Invoice
INV/2019/0007). #. Go to the chatter and click on the attached icon. #.
Click **Add GDrive link**. #. Fill the wizard fields and click on Add
button. #. In the open window, select the files you need and press the
select button. #. You will see a new **URL attachment** in the set of
attachments related to the object. #. In order to log in under another
google user, click on the logout icon located after **Add GDrive link**
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/knowledge/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/knowledge/issues/new?body=module:%20document_url_google_drive%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.
Credits
=======
Authors
-------
* Cetmix
Maintainers
-----------
This module is maintained by the OCA.
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
.. |maintainer-CetmixGitDrone| image:: https://github.com/CetmixGitDrone.png?size=40px
:target: https://github.com/CetmixGitDrone
:alt: CetmixGitDrone
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|maintainer-CetmixGitDrone|
This module is part of the `OCA/knowledge <https://github.com/OCA/knowledge/tree/16.0/document_url_google_drive>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -12,7 +12,11 @@ class ResUsers(models.Model):
default="https://www.googleapis.com/auth/drive.readonly", default="https://www.googleapis.com/auth/drive.readonly",
) )
google_picker_access_token = fields.Char(string="Google Access Token") google_picker_access_token = fields.Char(string="Google Access Token")
google_picker_expires_date = fields.Integer(string="Google Expires Date")
google_picker_mime_types = fields.Char(string="Google Mime Types") google_picker_mime_types = fields.Char(string="Google Mime Types")
google_picker_active = fields.Boolean(
compute="_compute_google_picker_active",
)
def get_google_picker_params(self): def get_google_picker_params(self):
""" """
@ -22,9 +26,8 @@ class ResUsers(models.Model):
self.ensure_one() self.ensure_one()
config = self.env["ir.config_parameter"].sudo() config = self.env["ir.config_parameter"].sudo()
google_service = self.env["google.service"] google_service = self.env["google.service"]
is_active_google_api = config.get_param("is_active_google_api")
if not is_active_google_api: if not self.google_picker_active:
return {} return {}
return { return {
"client_id": google_service._get_client_id("picker"), "client_id": google_service._get_client_id("picker"),
@ -32,10 +35,11 @@ class ResUsers(models.Model):
"app_id": config.get_param("google_picker_app_id"), "app_id": config.get_param("google_picker_app_id"),
"scope": self.google_picker_scope, "scope": self.google_picker_scope,
"access_token": self.google_picker_access_token, "access_token": self.google_picker_access_token,
"expires_date": self.google_picker_expires_date,
"mime_types": self.google_picker_mime_types, "mime_types": self.google_picker_mime_types,
} }
def save_google_picker_access_token(self, access_token): def save_google_picker_access_token(self, access_token, expires_date):
""" """
Save Google Picker access token Save Google Picker access token
:param access_token: str :param access_token: str
@ -43,3 +47,12 @@ class ResUsers(models.Model):
""" """
self.ensure_one() self.ensure_one()
self.google_picker_access_token = access_token self.google_picker_access_token = access_token
self.google_picker_expires_date = expires_date
def _compute_google_picker_active(self):
"""
Compute Google Picker Active
:return: None
"""
conf = self.env["ir.config_parameter"].sudo()
self.google_picker_active = conf.get_param("is_active_google_api")

View File

@ -2,7 +2,7 @@ To configure this module, you need to:
- Go to Settings -> General Settings and scroll down to the Integrations section. - Go to Settings -> General Settings and scroll down to the Integrations section.
- Enable "Google API", save. - Enable "Google API", save. Setup instructions https://developers.google.com/drive/picker/guides/overview
- field "Google Client ID" - enter the client ID from the Google API console. - field "Google Client ID" - enter the client ID from the Google API console.
- field "Google API key" - enter the API key from the Google API console. - field "Google API key" - enter the API key from the Google API console.

View File

@ -25,6 +25,7 @@ export class AttachmentGooglePicker extends Component {
client_id: "", client_id: "",
app_id: "", app_id: "",
accessToken: null, accessToken: null,
expiresDate: 0,
}); });
this.tokenClient = null; this.tokenClient = null;
@ -48,9 +49,15 @@ export class AttachmentGooglePicker extends Component {
// Public // Public
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
_onAddGooglePickerUrl() { async _onAddGooglePickerUrl() {
console.log("Add Google Picker URL"); if (
this.handleAuthClick(); this.state.accessToken &&
this.state.expiresDate > Math.floor(Date.now() / 1000)
) {
await this.createPicker();
} else {
await this.handleAuthClick();
}
} }
checkActive() { checkActive() {
@ -74,11 +81,15 @@ export class AttachmentGooglePicker extends Component {
const res = await this.orm.call("res.users", "get_google_picker_params", [ const res = await this.orm.call("res.users", "get_google_picker_params", [
this.user.userId, this.user.userId,
]); ]);
if (!res) {
return;
}
this.state.client_id = res.client_id; this.state.client_id = res.client_id;
this.state.api_key = res.api_key; this.state.api_key = res.api_key;
this.state.app_id = res.app_id; this.state.app_id = res.app_id;
this.state.scopes = res.scope; this.state.scopes = res.scope;
this.state.accessToken = res.access_token; this.state.accessToken = res.access_token;
this.state.expiresDate = res.expires_date;
this.state.mime_types = res.mime_types; this.state.mime_types = res.mime_types;
} }
@ -86,6 +97,7 @@ export class AttachmentGooglePicker extends Component {
await this.orm.call("res.users", "save_google_picker_access_token", [ await this.orm.call("res.users", "save_google_picker_access_token", [
this.user.userId, this.user.userId,
this.state.accessToken, this.state.accessToken,
this.state.expiresDate,
]); ]);
} }
@ -106,6 +118,8 @@ export class AttachmentGooglePicker extends Component {
throw response; throw response;
} }
this.state.accessToken = response.access_token; this.state.accessToken = response.access_token;
this.state.expiresDate =
Math.floor(Date.now() / 1000) + response.expires_in;
await this.createPicker(); await this.createPicker();
await this.saveUserAuthAccessToken(); await this.saveUserAuthAccessToken();
}; };
@ -113,10 +127,13 @@ export class AttachmentGooglePicker extends Component {
if (this.state.accessToken === null) { if (this.state.accessToken === null) {
// Prompt the user to select a Google Account and ask for consent to share their data // Prompt the user to select a Google Account and ask for consent to share their data
// when establishing a new session. // when establishing a new session.
this.tokenClient.requestAccessToken({prompt: "consent"}); this.tokenClient.requestAccessToken({
prompt: "consent",
access_type: "offline",
});
} else { } else {
// Skip display of account chooser and consent dialog for an existing session. // Skip display of account chooser and consent dialog for an existing session.
this.tokenClient.requestAccessToken({prompt: ""}); this.tokenClient.requestAccessToken({prompt: "", access_type: "offline"});
} }
} }

View File

@ -33,17 +33,15 @@ class TestDocumentUrl(common.TransactionCase):
self.assertEqual(attachment.mimetype, "application/link") self.assertEqual(attachment.mimetype, "application/link")
def test_get_google_picker_params_is_active(self): def test_get_google_picker_params_is_active(self):
self.config_settings.set_param( self.config_settings.set_param("is_active_google_api", True)
"document_url_google_drive.is_active_google_api", True self.config_settings.set_param("google_picker_api_key", "test_api_key")
) self.config_settings.set_param("google_picker_app_id", "test_app_id")
self.config_settings.set_param("google_picker_client_id", "test_client_id")
user = self.users.with_context(no_reset_password=True).create( user = self.users.with_context(no_reset_password=True).create(
{ {
"name": "Test User", "name": "Test User",
"login": "test_user", "login": "test_user",
"google_picker_client_id": "test_client_id",
"google_picker_api_key": "test_api_key",
"google_picker_scope": "test_scope", "google_picker_scope": "test_scope",
"google_picker_app_id": "test_app_id",
"google_picker_access_token": "test_access_token", "google_picker_access_token": "test_access_token",
"google_picker_mime_types": "test_mime_types", "google_picker_mime_types": "test_mime_types",
} }
@ -62,9 +60,7 @@ class TestDocumentUrl(common.TransactionCase):
) )
def test_get_google_picker_params_not_is_active(self): def test_get_google_picker_params_not_is_active(self):
self.config_settings.set_param( self.config_settings.set_param("is_active_google_api", False)
"document_url_google_drive.is_active_google_api", False
)
user = self.users.with_context(no_reset_password=True).create( user = self.users.with_context(no_reset_password=True).create(
{ {
"name": "Test User", "name": "Test User",

View File

@ -9,7 +9,32 @@
<field name="inherit_id" ref="base.view_users_form" /> <field name="inherit_id" ref="base.view_users_form" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//notebook" position="inside"> <xpath expr="//notebook" position="inside">
<page string="Google API"> <field name="google_picker_active" invisible="1" />
<page
string="Google API"
attrs="{'invisible': [('google_picker_active', '=', False)]}"
>
<group>
<field name="google_picker_scope" />
<field name="google_picker_access_token" readonly="1" />
<field name="google_picker_mime_types" />
</group>
</page>
</xpath>
</field>
</record>
<record id="res_users_google_picker_view_form_simple_modif" model="ir.ui.view">
<field name="name">res.users.simple_modif (document_url_google_drive)</field>
<field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form_simple_modif" />
<field name="arch" type="xml">
<xpath expr="//notebook" position="inside">
<field name="google_picker_active" invisible="1" />
<page
string="Google API"
attrs="{'invisible': [('google_picker_active', '=', False)]}"
>
<group> <group>
<field name="google_picker_scope" /> <field name="google_picker_scope" />
<field name="google_picker_access_token" readonly="1" /> <field name="google_picker_access_token" readonly="1" />

BIN
pandoc-3.1.9-1-amd64.deb Normal file

Binary file not shown.