mirror of
https://github.com/OCA/knowledge.git
synced 2025-07-22 20:12:04 -06:00
[ADD]document_url_google_drive: attach document from Google Drive
This commit is contained in:
parent
82b8383a8d
commit
ea29d68258
141
document_url_google_drive/README.rst
Normal file
141
document_url_google_drive/README.rst
Normal file
@ -0,0 +1,141 @@
|
||||
===========================
|
||||
Google Drive URL Attachment
|
||||
===========================
|
||||
|
||||
..
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! This file is generated by oca-gen-addon-readme !!
|
||||
!! changes will be overwritten. !!
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
!! source digest: sha256:e7df1efead13f8fba62e6369e05f7f52b812a1d44741ab2832e9597f6ac748d9
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
.. |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
|
||||
|
||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
||||
|
||||
This module extends the functionality of the document_url module and
|
||||
allows you to attach a link to a file from your Google Drive
|
||||
|
||||
**Table of contents**
|
||||
|
||||
.. contents::
|
||||
:local:
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
To configure this module, you need to:
|
||||
|
||||
- Go to Settings -> General Settings and scroll down to the
|
||||
Integrations section.
|
||||
|
||||
- Enable "Google API", save. Setup instructions
|
||||
https://developers.google.com/drive/picker/guides/overview
|
||||
|
||||
- "Google Client ID" - enter the client ID from the Google API
|
||||
console:
|
||||
https://developers.google.com/identity/oauth2/web/guides/get-google-api-clientid
|
||||
- "Google API key" - enter the API key from the Google API console.
|
||||
- "Google App ID" - enter the ID of the Google application. The
|
||||
default value is ``odoo``.
|
||||
|
||||
You will be asked to authenticate when you add a link for the first
|
||||
time.
|
||||
|
||||
|Configuration|
|
||||
|
||||
**To modify your personal login credentials later**
|
||||
|
||||
- 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 can always log off from the current Google Account by clicking
|
||||
the "logout" icon right to the "Add GDrive link".
|
||||
|
||||
.. |Configuration| image:: https://raw.githubusercontent.com/OCA/knowledge/16.0/document_url_google_drive/static/img/google_api_settings.png
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
To use this module, you need to:
|
||||
|
||||
1. Open the form view of an object (Example: Customer Invoice
|
||||
INV/2019/0007).
|
||||
2. Go to the chatter and click on the attached icon.
|
||||
3. Click **Add GDrive link**.
|
||||
4. Fill the wizard fields and click on Add button.
|
||||
5. In the open window, select the files you need and press the select
|
||||
button.
|
||||
6. You will see a new **URL attachment** in the set of attachments
|
||||
related to the object.
|
||||
7. In order to log in under another google user, click on the logout
|
||||
icon located after **Add GDrive link**
|
||||
|
||||
|Google Drive Link|
|
||||
|
||||
.. |Google Drive Link| image:: https://raw.githubusercontent.com/OCA/knowledge/16.0/document_url_google_drive/static/img/gdrive_link.png
|
||||
|
||||
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
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
Cetmix <cetmix.com> Ivan Sokolov Mykola Demchuk
|
||||
|
||||
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.
|
||||
|
||||
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.
|
4
document_url_google_drive/__init__.py
Normal file
4
document_url_google_drive/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
# Copyright (C) 2023 Cetmix OÜ
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import models, wizard
|
28
document_url_google_drive/__manifest__.py
Normal file
28
document_url_google_drive/__manifest__.py
Normal file
@ -0,0 +1,28 @@
|
||||
# Copyright (C) 2023 Cetmix OÜ
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
{
|
||||
"name": "Google Drive URL Attachment",
|
||||
"summary": "Attach Google Drive link to Odoo document using Google Drive Picker",
|
||||
"version": "16.0.1.0.0",
|
||||
"category": "Tools",
|
||||
"website": "https://github.com/OCA/knowledge",
|
||||
"author": "Cetmix, Odoo Community Association (OCA)",
|
||||
"license": "AGPL-3",
|
||||
"installable": True,
|
||||
"images": ["static/description/banner.png"],
|
||||
"depends": [
|
||||
"document_url",
|
||||
"google_account",
|
||||
],
|
||||
"data": [
|
||||
"views/res_users_view.xml",
|
||||
"views/res_config_settings_view.xml",
|
||||
],
|
||||
"assets": {
|
||||
"web.assets_backend": [
|
||||
"document_url_google_drive/static/src/js/attachment_google_picker.esm.js",
|
||||
"document_url_google_drive/static/src/xml/google_picker_url.xml",
|
||||
"document_url_google_drive/static/src/xml/attachment_google_picker.xml",
|
||||
],
|
||||
},
|
||||
}
|
4
document_url_google_drive/models/__init__.py
Normal file
4
document_url_google_drive/models/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
# Copyright (C) 2023 Cetmix OÜ
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import res_users, res_config_settings
|
26
document_url_google_drive/models/res_config_settings.py
Normal file
26
document_url_google_drive/models/res_config_settings.py
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2023 Cetmix OÜ
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = "res.config.settings"
|
||||
|
||||
is_active_google_api = fields.Boolean(
|
||||
string="Google APIs",
|
||||
config_parameter="is_active_google_api",
|
||||
)
|
||||
google_picker_client_id = fields.Char(
|
||||
string="Google Client ID",
|
||||
config_parameter="google_picker_client_id",
|
||||
)
|
||||
google_picker_api_key = fields.Char(
|
||||
string="Google API Key",
|
||||
config_parameter="google_picker_api_key",
|
||||
)
|
||||
google_picker_app_id = fields.Char(
|
||||
string="Google App ID",
|
||||
config_parameter="google_picker_app_id",
|
||||
default="odoo",
|
||||
)
|
58
document_url_google_drive/models/res_users.py
Normal file
58
document_url_google_drive/models/res_users.py
Normal file
@ -0,0 +1,58 @@
|
||||
# Copyright (C) 2023 Cetmix OÜ
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResUsers(models.Model):
|
||||
_inherit = "res.users"
|
||||
|
||||
google_picker_scope = fields.Char(
|
||||
string="Google Scope",
|
||||
default="https://www.googleapis.com/auth/drive.readonly",
|
||||
)
|
||||
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_active = fields.Boolean(
|
||||
compute="_compute_google_picker_active",
|
||||
)
|
||||
|
||||
def get_google_picker_params(self):
|
||||
"""
|
||||
Get Google Picker params
|
||||
:return: dict
|
||||
"""
|
||||
self.ensure_one()
|
||||
config = self.env["ir.config_parameter"].sudo()
|
||||
google_service = self.env["google.service"]
|
||||
|
||||
if not self.google_picker_active:
|
||||
return {}
|
||||
return {
|
||||
"client_id": google_service._get_client_id("picker"),
|
||||
"api_key": config.get_param("google_picker_api_key"),
|
||||
"app_id": config.get_param("google_picker_app_id"),
|
||||
"scope": self.google_picker_scope,
|
||||
"access_token": self.google_picker_access_token,
|
||||
"expires_date": self.google_picker_expires_date,
|
||||
"mime_types": self.google_picker_mime_types,
|
||||
}
|
||||
|
||||
def save_google_picker_access_token(self, access_token, expires_date):
|
||||
"""
|
||||
Save Google Picker access token
|
||||
:param access_token: str
|
||||
:return: None
|
||||
"""
|
||||
self.ensure_one()
|
||||
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")
|
31
document_url_google_drive/readme/CONFIGURE.md
Normal file
31
document_url_google_drive/readme/CONFIGURE.md
Normal file
@ -0,0 +1,31 @@
|
||||
To configure this module, you need to:
|
||||
|
||||
- Go to Settings -> General Settings and scroll down to the Integrations section.
|
||||
|
||||
- Enable "Google API", save. Setup instructions https://developers.google.com/drive/picker/guides/overview
|
||||
|
||||
- "Google Client ID" - enter the client ID from the Google API console: https://developers.google.com/identity/oauth2/web/guides/get-google-api-clientid
|
||||
- "Google API key" - enter the API key from the Google API console.
|
||||
- "Google App ID" - enter the ID of the Google application. The default value is
|
||||
`odoo`.
|
||||
|
||||
You will be asked to authenticate when you add a link for the first time.
|
||||
|
||||

|
||||
|
||||
**To modify your personal login credentials later**
|
||||
|
||||
- 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 can always log off from the current Google Account by clicking the "logout" icon right to the "Add GDrive link".
|
||||
|
||||
|
3
document_url_google_drive/readme/CONTRIBUTORS.md
Normal file
3
document_url_google_drive/readme/CONTRIBUTORS.md
Normal file
@ -0,0 +1,3 @@
|
||||
Cetmix <cetmix.com>
|
||||
Ivan Sokolov
|
||||
Mykola Demchuk
|
2
document_url_google_drive/readme/DESCRIPTION.md
Normal file
2
document_url_google_drive/readme/DESCRIPTION.md
Normal file
@ -0,0 +1,2 @@
|
||||
This module extends the functionality of the document_url module and allows you to
|
||||
attach a link to a file from your Google Drive
|
11
document_url_google_drive/readme/USAGE.md
Normal file
11
document_url_google_drive/readme/USAGE.md
Normal file
@ -0,0 +1,11 @@
|
||||
To use this module, you need to:
|
||||
|
||||
1. Open the form view of an object (Example: Customer Invoice INV/2019/0007).
|
||||
1. Go to the chatter and click on the attached icon.
|
||||
1. Click **Add GDrive link**.
|
||||
1. Fill the wizard fields and click on Add button.
|
||||
1. In the open window, select the files you need and press the select button.
|
||||
1. You will see a new **URL attachment** in the set of attachments related to the object.
|
||||
1. In order to log in under another google user, click on the logout icon located after **Add GDrive link**
|
||||
|
||||

|
BIN
document_url_google_drive/static/description/banner.png
Normal file
BIN
document_url_google_drive/static/description/banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
BIN
document_url_google_drive/static/description/icon.png
Normal file
BIN
document_url_google_drive/static/description/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.2 KiB |
79
document_url_google_drive/static/description/icon.svg
Normal file
79
document_url_google_drive/static/description/icon.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 45 KiB |
124
document_url_google_drive/static/description/index.html
Normal file
124
document_url_google_drive/static/description/index.html
Normal file
@ -0,0 +1,124 @@
|
||||
<section class="oe_container">
|
||||
<div class="oe_row oe_spaced">
|
||||
<div class="oe_span12">
|
||||
<h2 class="oe_slogan">Module name</h2>
|
||||
<p>This module was written to extend the functionality of ... to support ... and allow you to ...</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="oe_container oe_dark">
|
||||
<div class="oe_row oe_spaced">
|
||||
<div class="oe_span12">
|
||||
<h2 class="oe_slogan">Installation</h2>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<p class="oe_mt32">To install this module, you need to:
|
||||
<ul>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<div class="oe_demo oe_picture oe_screenshot">
|
||||
<a href="https://www.odoo.com/saas_master/demo?lang=en_US&module=crm">
|
||||
<img src="crm_sc_01.png">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="oe_container">
|
||||
<div class="oe_row oe_spaced">
|
||||
<div class="oe_span12">
|
||||
<h2 class="oe_slogan">Configuration</h2>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<p class="oe_mt32">To configure this module, you need to:
|
||||
<ul>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<div class="oe_demo oe_picture oe_screenshot">
|
||||
<a href="https://www.odoo.com/saas_master/demo?lang=en_US&module=crm">
|
||||
<img src="crm_sc_01.png">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="oe_container oe_dark">
|
||||
<div class="oe_row oe_spaced">
|
||||
<div class="oe_span12">
|
||||
<h2 class="oe_slogan">Usage</h2>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<p class="oe_mt32">To use this module, you need to:
|
||||
<ul>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p class="oe_mt32">For further information, please visit:
|
||||
<ul>
|
||||
<li><a href="https://www.odoo.com/forum/help-1">https://www.odoo.com/forum/help-1</a></li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<div class="oe_demo oe_picture oe_screenshot">
|
||||
<a href="https://www.odoo.com/saas_master/demo?lang=en_US&module=crm">
|
||||
<img src="crm_sc_01.png">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="oe_container">
|
||||
<div class="oe_row oe_spaced">
|
||||
<div class="oe_span12">
|
||||
<h2 class="oe_slogan">Known issues / Roadmap</h2>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<p class="oe_mt32">
|
||||
<ul>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
</p>
|
||||
</div>
|
||||
<div class="oe_span6">
|
||||
<div class="oe_demo oe_picture oe_screenshot">
|
||||
<a href="https://www.odoo.com/saas_master/demo?lang=en_US&module=crm">
|
||||
<img src="crm_sc_01.png">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="oe_container oe_dark">
|
||||
<div class="oe_row">
|
||||
<div class="oe_span12">
|
||||
<h2 class="oe_slogan">Credits</h2>
|
||||
</div>
|
||||
<div class="oe_span12">
|
||||
<h3>Contributors</h3>
|
||||
<ul>
|
||||
<li>Firstname Lastname <<a href="mailto:email.address@example.com">email.address@example.com</a>></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="oe_span12">
|
||||
<h3>Maintainer</h3>
|
||||
<p>
|
||||
This module is maintained by the OCA.<br/>
|
||||
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.<br/>
|
||||
To contribute to this module, please visit <a href="http://odoo-community.org">http://odoo-community.org</a>.<br/>
|
||||
<a href="http://odoo-community.org"><img class="oe_picture oe_centered" src="http://odoo-community.org/logo.png"></a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
BIN
document_url_google_drive/static/img/gdrive_link.png
Normal file
BIN
document_url_google_drive/static/img/gdrive_link.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
BIN
document_url_google_drive/static/img/google_api_settings.png
Normal file
BIN
document_url_google_drive/static/img/google_api_settings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 166 KiB |
BIN
document_url_google_drive/static/src/img/logo-google-drive.png
Normal file
BIN
document_url_google_drive/static/src/img/logo-google-drive.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
@ -0,0 +1,195 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import {loadJS} from "@web/core/assets";
|
||||
import {registerMessagingComponent} from "@mail/utils/messaging_component";
|
||||
import {useComponentToModel} from "@mail/component_hooks/use_component_to_model";
|
||||
import {useService} from "@web/core/utils/hooks";
|
||||
|
||||
const {Component, onWillStart, useState} = owl;
|
||||
|
||||
export class AttachmentGooglePicker extends Component {
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
setup() {
|
||||
super.setup();
|
||||
useComponentToModel({fieldName: "component"});
|
||||
this.orm = useService("orm");
|
||||
this.user = useService("user");
|
||||
this.action = useService("action");
|
||||
this.state = useState({
|
||||
pickerInited: false,
|
||||
gisInited: false,
|
||||
api_key: "",
|
||||
scopes: "",
|
||||
client_id: "",
|
||||
app_id: "",
|
||||
accessToken: null,
|
||||
expiresDate: 0,
|
||||
});
|
||||
this.tokenClient = null;
|
||||
|
||||
onWillStart(async () => {
|
||||
await this.getUserAuthParams();
|
||||
if (!this.checkActive()) {
|
||||
return;
|
||||
}
|
||||
await loadJS("https://apis.google.com/js/api.js", {
|
||||
attrs: {async: true, defer: true},
|
||||
});
|
||||
await this.gapiLoaded();
|
||||
await loadJS("https://accounts.google.com/gsi/client", {
|
||||
attrs: {async: true, defer: true},
|
||||
});
|
||||
await this.gisLoaded();
|
||||
});
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Public
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
async _onAddGooglePickerUrl() {
|
||||
if (
|
||||
this.state.accessToken &&
|
||||
this.state.expiresDate > Math.floor(Date.now() / 1000)
|
||||
) {
|
||||
await this.createPicker();
|
||||
} else {
|
||||
await this.handleAuthClick();
|
||||
}
|
||||
}
|
||||
|
||||
checkActive() {
|
||||
return (
|
||||
Boolean(this.state.api_key) &&
|
||||
Boolean(this.state.scopes) &&
|
||||
Boolean(this.state.client_id) &&
|
||||
Boolean(this.state.app_id)
|
||||
);
|
||||
}
|
||||
|
||||
async _onSignOut() {
|
||||
this.state.accessToken = null;
|
||||
await this.saveUserAuthAccessToken();
|
||||
}
|
||||
// --------------------------------------------------------------------------
|
||||
// Private
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
async getUserAuthParams() {
|
||||
const res = await this.orm.call("res.users", "get_google_picker_params", [
|
||||
this.user.userId,
|
||||
]);
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
this.state.client_id = res.client_id;
|
||||
this.state.api_key = res.api_key;
|
||||
this.state.app_id = res.app_id;
|
||||
this.state.scopes = res.scope;
|
||||
this.state.accessToken = res.access_token;
|
||||
this.state.expiresDate = res.expires_date;
|
||||
this.state.mime_types = res.mime_types;
|
||||
}
|
||||
|
||||
async saveUserAuthAccessToken() {
|
||||
await this.orm.call("res.users", "save_google_picker_access_token", [
|
||||
this.user.userId,
|
||||
this.state.accessToken,
|
||||
this.state.expiresDate,
|
||||
]);
|
||||
}
|
||||
|
||||
async gapiLoaded() {
|
||||
window.gapi.load("client:picker", this.initializePicker.bind(this));
|
||||
}
|
||||
|
||||
async initializePicker() {
|
||||
await window.gapi.client.load(
|
||||
"https://www.googleapis.com/discovery/v1/apis/drive/v3/rest"
|
||||
);
|
||||
this.state.pickerInited = true;
|
||||
}
|
||||
|
||||
handleAuthClick() {
|
||||
this.tokenClient.callback = async (response) => {
|
||||
if (response.error !== undefined) {
|
||||
throw response;
|
||||
}
|
||||
this.state.accessToken = response.access_token;
|
||||
this.state.expiresDate =
|
||||
Math.floor(Date.now() / 1000) + response.expires_in;
|
||||
await this.createPicker();
|
||||
await this.saveUserAuthAccessToken();
|
||||
};
|
||||
|
||||
if (this.state.accessToken === null) {
|
||||
// Prompt the user to select a Google Account and ask for consent to share their data
|
||||
// when establishing a new session.
|
||||
this.tokenClient.requestAccessToken({
|
||||
prompt: "consent",
|
||||
access_type: "offline",
|
||||
});
|
||||
} else {
|
||||
// Skip display of account chooser and consent dialog for an existing session.
|
||||
this.tokenClient.requestAccessToken({prompt: "", access_type: "offline"});
|
||||
}
|
||||
}
|
||||
|
||||
async gisLoaded() {
|
||||
this.tokenClient = window.google.accounts.oauth2.initTokenClient({
|
||||
client_id: this.state.client_id,
|
||||
scope: this.state.scopes,
|
||||
callback: "",
|
||||
});
|
||||
this.state.gisInited = true;
|
||||
}
|
||||
|
||||
createPicker() {
|
||||
const view = new window.google.picker.View(window.google.picker.ViewId.DOCS);
|
||||
if (this.state.mime_types) {
|
||||
view.setMimeTypes(this.state.mime_types);
|
||||
}
|
||||
const picker = new window.google.picker.PickerBuilder()
|
||||
.enableFeature(window.google.picker.Feature.NAV_HIDDEN)
|
||||
.enableFeature(window.google.picker.Feature.MULTISELECT_ENABLED)
|
||||
.setDeveloperKey(this.state.api_key)
|
||||
.setAppId(this.state.app_id)
|
||||
.setOAuthToken(this.state.accessToken)
|
||||
.addView(view)
|
||||
.addView(new window.google.picker.DocsUploadView())
|
||||
.setCallback(this.pickerCallback.bind(this))
|
||||
.build();
|
||||
picker.setVisible(true);
|
||||
}
|
||||
|
||||
async pickerCallback(data) {
|
||||
if (data.action === window.google.picker.Action.PICKED) {
|
||||
for (const document of data.docs) {
|
||||
await this.createAttachment(document);
|
||||
}
|
||||
await this._onAddedUrl();
|
||||
}
|
||||
}
|
||||
|
||||
async createAttachment(document) {
|
||||
await this.orm.call("ir.attachment.add_url", "add_attachment_google_drive", [
|
||||
document.url,
|
||||
document.name,
|
||||
this.props.record.chatter.thread.model,
|
||||
[this.props.record.chatter.thread.id],
|
||||
]);
|
||||
}
|
||||
|
||||
async _onAddedUrl() {
|
||||
this.props.record.chatter.refresh();
|
||||
}
|
||||
}
|
||||
|
||||
Object.assign(AttachmentGooglePicker, {
|
||||
props: {record: Object},
|
||||
template: "document_url_google_drive.GooglePickerUrl",
|
||||
});
|
||||
|
||||
registerMessagingComponent(AttachmentGooglePicker);
|
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!-- Copyright (C) 2023 Cetmix OÜ
|
||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="document_url_google_drive.GooglePickerUrl" owl="1">
|
||||
<button
|
||||
t-att-style="'display: ' + (checkActive() ? 'inline-block' : 'none') + ';'"
|
||||
type="button"
|
||||
class="o_add_url_button btn btn-link"
|
||||
t-on-click="_onAddGooglePickerUrl"
|
||||
>
|
||||
<i class="fa fa-plus-square" />
|
||||
Add GDrive link
|
||||
|
||||
</button>
|
||||
<i
|
||||
t-if="state.accessToken"
|
||||
class="fa fa-sign-out"
|
||||
aria-hidden="true"
|
||||
t-on-click="_onSignOut"
|
||||
/>
|
||||
</t>
|
||||
|
||||
</templates>
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!-- Copyright (C) 2023 Cetmix OÜ
|
||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
|
||||
<templates>
|
||||
<t t-inherit="mail.AttachmentBox" t-inherit-mode="extension" owl="1">
|
||||
<xpath expr="//div[hasclass('o_AttachmentBox_content')]/div" position="inside">
|
||||
<AttachmentGooglePicker record="attachmentBoxView" />
|
||||
</xpath>
|
||||
</t>
|
||||
</templates>
|
4
document_url_google_drive/tests/__init__.py
Normal file
4
document_url_google_drive/tests/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
# Copyright (C) 2023 Cetmix OÜ
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from . import test_document_url
|
76
document_url_google_drive/tests/test_document_url.py
Normal file
76
document_url_google_drive/tests/test_document_url.py
Normal file
@ -0,0 +1,76 @@
|
||||
# Copyright (C) 2023 Cetmix OÜ
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
||||
|
||||
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
class TestDocumentUrl(common.TransactionCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super().setUpClass()
|
||||
cls.wizard_add_url = cls.env["ir.attachment.add_url"]
|
||||
cls.config_settings = cls.env["ir.config_parameter"].sudo()
|
||||
cls.users = cls.env["res.users"]
|
||||
|
||||
def test_add_google_drive_url_attachment(self):
|
||||
self.wizard_add_url.add_attachment_google_drive(
|
||||
"http://www.odoodemouser.com",
|
||||
"Demo User (Website)",
|
||||
"res.users",
|
||||
[self.env.ref("base.user_demo").id],
|
||||
)
|
||||
domain = [
|
||||
("type", "=", "url"),
|
||||
("name", "=", "Demo User (Website)"),
|
||||
("url", "=", "http://www.odoodemouser.com"),
|
||||
("res_model", "=", "res.users"),
|
||||
("res_id", "=", self.env.ref("base.user_demo").id),
|
||||
]
|
||||
attachment_added_count = self.env["ir.attachment"].search_count(domain)
|
||||
self.assertEqual(attachment_added_count, 1)
|
||||
attachment = self.env["ir.attachment"].search(domain)
|
||||
self.assertEqual(attachment.mimetype, "application/link")
|
||||
|
||||
def test_get_google_picker_params_is_active(self):
|
||||
self.config_settings.set_param("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(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "test_user",
|
||||
"google_picker_scope": "test_scope",
|
||||
"google_picker_access_token": "test_access_token",
|
||||
"google_picker_mime_types": "test_mime_types",
|
||||
"google_picker_expires_date": 0,
|
||||
}
|
||||
)
|
||||
params = user.get_google_picker_params()
|
||||
self.assertEqual(
|
||||
params,
|
||||
{
|
||||
"client_id": "test_client_id",
|
||||
"api_key": "test_api_key",
|
||||
"scope": "test_scope",
|
||||
"app_id": "test_app_id",
|
||||
"access_token": "test_access_token",
|
||||
"expires_date": 0,
|
||||
"mime_types": "test_mime_types",
|
||||
},
|
||||
)
|
||||
|
||||
def test_get_google_picker_params_not_is_active(self):
|
||||
self.config_settings.set_param("is_active_google_api", False)
|
||||
user = self.users.with_context(no_reset_password=True).create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "test_user",
|
||||
}
|
||||
)
|
||||
params = user.get_google_picker_params()
|
||||
self.assertEqual(
|
||||
params,
|
||||
{},
|
||||
)
|
56
document_url_google_drive/views/res_config_settings_view.xml
Normal file
56
document_url_google_drive/views/res_config_settings_view.xml
Normal file
@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- Copyright (C) 2023 Cetmix OÜ
|
||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
<record id="res_config_settings_view_form" model="ir.ui.view">
|
||||
<field
|
||||
name="name"
|
||||
>res.config.settings.view.form.inherit.document.url.google.drive</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base_setup.res_config_settings_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@id='recaptcha']" position="after">
|
||||
<div class="col-12 col-lg-6 o_setting_box" id="google_api">
|
||||
<div class="o_setting_left_pane">
|
||||
<field name="is_active_google_api" />
|
||||
</div>
|
||||
<div class="o_setting_right_pane" id="website_recaptcha_settings">
|
||||
<label for="is_active_google_api" />
|
||||
<div class="text-muted">
|
||||
Use google integration.
|
||||
</div>
|
||||
<div
|
||||
class="content-group"
|
||||
attrs="{'invisible': [('is_active_google_api','=',False)]}"
|
||||
>
|
||||
<div class="mt16 row">
|
||||
<label
|
||||
for="google_picker_client_id"
|
||||
string="Google Client ID"
|
||||
class="col-3 col-lg-3 o_light_label"
|
||||
/>
|
||||
<field name="google_picker_client_id" nolabel="1" />
|
||||
</div>
|
||||
<div class="mt16 row">
|
||||
<label
|
||||
for="google_picker_api_key"
|
||||
string="Google Api Key"
|
||||
class="col-3 col-lg-3 o_light_label"
|
||||
/>
|
||||
<field name="google_picker_api_key" nolabel="1" />
|
||||
</div>
|
||||
<div class="mt16 row">
|
||||
<label
|
||||
for="google_picker_app_id"
|
||||
string="Google App Id"
|
||||
class="col-3 col-lg-3 o_light_label"
|
||||
/>
|
||||
<field name="google_picker_app_id" nolabel="1" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
48
document_url_google_drive/views/res_users_view.xml
Normal file
48
document_url_google_drive/views/res_users_view.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!-- Copyright (C) 2023 Cetmix OÜ
|
||||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
|
||||
<odoo>
|
||||
|
||||
<record id="res_users_google_picker_view_form" model="ir.ui.view">
|
||||
<field name="name">res.users (document_url_google_drive)</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form" />
|
||||
<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>
|
||||
<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>
|
||||
<field name="google_picker_scope" />
|
||||
<field name="google_picker_access_token" readonly="1" />
|
||||
<field name="google_picker_mime_types" />
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
4
document_url_google_drive/wizard/__init__.py
Normal file
4
document_url_google_drive/wizard/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
# Copyright (C) 2023 Cetmix OÜ
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
from . import document_url
|
26
document_url_google_drive/wizard/document_url.py
Normal file
26
document_url_google_drive/wizard/document_url.py
Normal file
@ -0,0 +1,26 @@
|
||||
# Copyright (C) 2023 Cetmix OÜ
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
|
||||
|
||||
from urllib import parse
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class AddUrlWizard(models.TransientModel):
|
||||
_inherit = "ir.attachment.add_url"
|
||||
|
||||
@api.model
|
||||
def add_attachment_google_drive(self, url, name, active_model, active_ids):
|
||||
attachment_obj = self.env["ir.attachment"]
|
||||
url_parse = parse.urlparse(url)
|
||||
if not url_parse.scheme:
|
||||
url_parse = parse.urlparse("{}{}".format("http://", url))
|
||||
for active_id in active_ids:
|
||||
attachment = {
|
||||
"name": name,
|
||||
"type": "url",
|
||||
"url": url_parse.geturl(),
|
||||
"res_id": active_id,
|
||||
"res_model": active_model,
|
||||
}
|
||||
attachment_obj.create(attachment)
|
@ -0,0 +1 @@
|
||||
../../../../document_url_google_drive
|
6
setup/document_url_google_drive/setup.py
Normal file
6
setup/document_url_google_drive/setup.py
Normal file
@ -0,0 +1,6 @@
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['setuptools-odoo'],
|
||||
odoo_addon=True,
|
||||
)
|
Loading…
Reference in New Issue
Block a user