-
-
Notifications
You must be signed in to change notification settings - Fork 352
[18.0][MIG] base_dav: standard migrate #431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: 18.0
Are you sure you want to change the base?
Changes from all commits
e762095
bed6264
0028800
1d280f3
5812846
ea33b07
06a47c4
f32d3f3
a806fd7
4f99229
462f41c
14f10be
ec62a45
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| ========================== | ||
| Caldav and Carddav support | ||
| ========================== | ||
|
|
||
| .. | ||
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
| !! This file is generated by oca-gen-addon-readme !! | ||
| !! changes will be overwritten. !! | ||
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
| !! source digest: sha256:6cc5b91f1cff865b4527a2097534adb50c8bade6eaed9f3b820275b7b8ab19d3 | ||
| !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
|
|
||
| .. |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%2Fserver--backend-lightgray.png?logo=github | ||
| :target: https://github.com/OCA/server-backend/tree/18.0/base_dav | ||
| :alt: OCA/server-backend | ||
| .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png | ||
| :target: https://translation.odoo-community.org/projects/server-backend-18-0/server-backend-18-0-base_dav | ||
| :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/server-backend&target_branch=18.0 | ||
| :alt: Try me on Runboat | ||
|
|
||
| |badge1| |badge2| |badge3| |badge4| |badge5| | ||
|
|
||
| This module adds WebDAV support to Odoo, specifically CalDAV and | ||
| CardDAV. | ||
|
|
||
| You can configure arbitrary objects as a calendar or an address book, | ||
| thus make arbitrary information accessible in external systems or your | ||
| mobile. | ||
|
|
||
| **Table of contents** | ||
|
|
||
| .. contents:: | ||
| :local: | ||
|
|
||
| Configuration | ||
| ============= | ||
|
|
||
| To configure this module, you need to: | ||
|
|
||
| 1. Go to Settings / WebDAV Collections and create or edit your | ||
| collections. There, you'll also see the URL to point your clients to. | ||
|
|
||
| Note that you need to configure a dbfilter if you use multiple | ||
| databases. | ||
|
|
||
| Known issues / Roadmap | ||
| ====================== | ||
|
|
||
| - Much better UX for configuring collections (probably provide a group | ||
| that sees the current fully flexible field mappings, and by default | ||
| show some dumbed down version where you can select some preselected | ||
| vobject fields); | ||
| - Support todo lists and journals; | ||
| - Support configuring default field mappings per model; | ||
| - Support plain WebDAV collections to make some model's records | ||
| accessible as folders, and the records' attachments as files (r/w); | ||
| - Support configuring lists of calendars so that you can have a calendar | ||
| for every project and appointments are tasks, or a calendar for every | ||
| sales team and appointments are sale orders. Lots of possibilities. | ||
|
|
||
| Bug Tracker | ||
| =========== | ||
|
|
||
| Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-backend/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/server-backend/issues/new?body=module:%20base_dav%0Aversion:%2018.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 | ||
| ------- | ||
|
|
||
| * initOS GmbH | ||
| * Therp BV | ||
|
|
||
| Contributors | ||
| ------------ | ||
|
|
||
| - Holger Brunn <hbrunn@therp.nl> | ||
| - Florian Kantelberg <florian.kantelberg@initos.com> | ||
| - `Cetmix <https://cetmix.com/>`__ | ||
|
|
||
| - Ivan Sokolov | ||
| - George Smirnov | ||
| - Dmitry Meita | ||
|
|
||
| Other credits | ||
| ------------- | ||
|
|
||
| - Odoo Community Association | ||
| - All the actual work is done by `Radicale <https://radicale.org>`__ | ||
|
|
||
| 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-hbrunn| image:: https://github.com/hbrunn.png?size=40px | ||
| :target: https://github.com/hbrunn | ||
| :alt: hbrunn | ||
|
|
||
| Current `maintainer <https://odoo-community.org/page/maintainer-role>`__: | ||
|
|
||
| |maintainer-hbrunn| | ||
|
|
||
| This module is part of the `OCA/server-backend <https://github.com/OCA/server-backend/tree/18.0/base_dav>`_ project on GitHub. | ||
|
|
||
| You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| # Copyright 2018 Therp BV <https://therp.nl> | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
| import logging | ||
|
|
||
| from . import models | ||
| from . import controllers | ||
| from . import radicale | ||
|
|
||
|
|
||
| def _restore_odoo_runbot_level_name(): | ||
| """Restore odoo RUNBOT level display name after Radicale imports.""" | ||
| runbot_level = getattr(logging, "RUNBOT", 25) | ||
| if logging.getLevelName(runbot_level) != "INFO": | ||
| logging.addLevelName(runbot_level, "INFO") | ||
|
|
||
|
|
||
| _restore_odoo_runbot_level_name() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # Copyright 2018 Therp BV <https://therp.nl> | ||
| # Copyright 2019-2020 initOS GmbH <https://initos.com> | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
| { | ||
| "name": "Caldav and Carddav support", | ||
| "version": "18.0.1.0.0", | ||
| "author": "initOS GmbH,Therp BV,Odoo Community Association (OCA)", | ||
| "license": "AGPL-3", | ||
| "category": "Extra Tools", | ||
| "summary": "Access Odoo data as calendar or address book", | ||
| "website": "https://github.com/OCA/server-backend", | ||
| "maintainers": ["hbrunn"], | ||
| "depends": [ | ||
| "base", | ||
This comment was marked as resolved.
Sorry, something went wrong.
This comment was marked as resolved.
Sorry, something went wrong. |
||
| ], | ||
| "demo": [ | ||
| "demo/dav_collection.xml", | ||
| ], | ||
| "data": [ | ||
| "views/dav_collection.xml", | ||
| "security/ir.model.access.csv", | ||
| ], | ||
| "external_dependencies": { | ||
| "python": ["radicale>3.3.0"], | ||
| }, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i didn't specify them on purpose because these are the default values - https://arc.net/l/quote/rentkjyl |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # Copyright 2018 Therp BV <https://therp.nl> | ||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
| from . import main |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,102 @@ | ||||||
| # Copyright 2018 Therp BV <https://therp.nl> | ||||||
| # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||||||
|
|
||||||
| import io | ||||||
| import sys | ||||||
| from functools import lru_cache | ||||||
|
|
||||||
| import werkzeug | ||||||
| from radicale import config as radicale_config | ||||||
| from radicale.app import Application | ||||||
| from werkzeug.wrappers.response import Response as WerkzeugResponse | ||||||
|
|
||||||
| from odoo import http | ||||||
| from odoo.http import request | ||||||
|
|
||||||
| PREFIX = "/.dav" | ||||||
|
|
||||||
|
|
||||||
| @lru_cache(maxsize=1) | ||||||
| def _get_radicale_app(): | ||||||
| """Build and cache a Radicale app per worker process.""" | ||||||
| configuration = radicale_config.load() | ||||||
| configuration.update( | ||||||
| { | ||||||
| "auth": {"type": "odoo.addons.base_dav.radicale.auth"}, | ||||||
| "storage": {"type": "odoo.addons.base_dav.radicale.collection"}, | ||||||
| "rights": {"type": "odoo.addons.base_dav.radicale.rights"}, | ||||||
| "web": {"type": "none"}, | ||||||
| }, | ||||||
| "odoo", | ||||||
| ) | ||||||
| return Application(configuration) | ||||||
|
|
||||||
|
|
||||||
| class Main(http.Controller): | ||||||
| @http.route( | ||||||
| ["/.well-known/carddav", "/.well-known/caldav", "/.well-known/webdav"], | ||||||
| type="http", | ||||||
| auth="none", | ||||||
| csrf=False, | ||||||
| ) | ||||||
| def handle_well_known_request(self) -> WerkzeugResponse: | ||||||
| """ | ||||||
| Redirect well-known CalDAV/CardDAV/WebDAV endpoints to the Radicale mount point. | ||||||
|
|
||||||
| :return: HTTP 301 redirect response to ``/.dav``. | ||||||
| :rtype: werkzeug.wrappers.response.Response | ||||||
| """ | ||||||
| return werkzeug.utils.redirect(PREFIX, 301) | ||||||
|
|
||||||
| @http.route( | ||||||
| [PREFIX, f"{PREFIX}/<path:davpath>"], | ||||||
| type="http", | ||||||
| auth="none", | ||||||
| csrf=False, | ||||||
| ) | ||||||
| def handle_dav_request(self, davpath=None, **kwargs): | ||||||
| """Proxy WebDAV/CalDAV/CardDAV requests to the Radicale app. | ||||||
|
|
||||||
| :param davpath: Path relative to the DAV mount point. | ||||||
| :type davpath: str | None | ||||||
| :param kwargs: Extra route keyword arguments, unused. | ||||||
| :type kwargs: dict | ||||||
|
|
||||||
| :return: Response produced by Radicale. | ||||||
| :rtype: odoo.http.Response | ||||||
| """ | ||||||
| del kwargs | ||||||
| app = _get_radicale_app() | ||||||
|
|
||||||
| environ = dict(request.httprequest.environ) | ||||||
| environ.setdefault("wsgi.errors", sys.stderr) | ||||||
|
|
||||||
| raw_body = request.httprequest.get_data(cache=False) or b"" | ||||||
| environ["wsgi.input"] = io.BytesIO(raw_body) | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not
Suggested change
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. request.httprequest.stream is not exposed publicly here rebuilding wsgi.input from get_data() gives radicale a plain readable stream with a matching CONTENT_LENGTH, independent of how odoo wraps the underlying werkzeug request this is also the variant i verified locally while request.httprequest.stream is not exposed here
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as soon as this module fully supports files it will be needed because then we absolutely don't want to copy a potentially large upload here. will not press the point for now |
||||||
|
|
||||||
| environ["SCRIPT_NAME"] = PREFIX | ||||||
| environ["HTTP_X_SCRIPT_NAME"] = PREFIX | ||||||
| environ["PATH_INFO"] = "/" + (davpath or "") | ||||||
|
|
||||||
| status_headers = {"status": "500 Internal Server Error", "headers": []} | ||||||
|
|
||||||
| def start_response(status, headers, exc_info=None): | ||||||
| """WSGI start_response callback used by Radicale. | ||||||
|
|
||||||
| :param status: HTTP status line. | ||||||
| :type status: str | ||||||
| :param headers: Sequence of ``(header_name, header_value)``. | ||||||
| :type headers: Sequence[tuple[str, str]] | ||||||
| :param exc_info: Optional exception info as per WSGI spec (unused). | ||||||
| :type exc_info: Any, optional | ||||||
| """ | ||||||
| status_headers["status"] = status | ||||||
| status_headers["headers"] = headers | ||||||
|
|
||||||
| result_iter = app(environ, start_response) | ||||||
|
|
||||||
| return http.Response( | ||||||
| response=result_iter, | ||||||
| status=status_headers["status"], | ||||||
| headers=status_headers["headers"], | ||||||
| ) | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| <odoo> | ||
| <record id="collection_addressbook" model="dav.collection"> | ||
| <field name="name">Addressbook</field> | ||
| <field name="dav_type">addressbook</field> | ||
| <field name="model_id" ref="base.model_res_partner" /> | ||
| <field name="domain">[]</field> | ||
| <field name="rights">authenticated</field> | ||
| </record> | ||
|
|
||
| <record id="field_mapping_addressbook_n" model="dav.collection.field_mapping"> | ||
| <field name="name">N</field> | ||
| <field name="field_id" ref="base.field_res_partner__name" /> | ||
| <field name="collection_id" ref="collection_addressbook" /> | ||
| </record> | ||
|
|
||
| <record id="field_mapping_addressbook_fn" model="dav.collection.field_mapping"> | ||
| <field name="name">FN</field> | ||
| <field name="field_id" ref="base.field_res_partner__name" /> | ||
| <field name="collection_id" ref="collection_addressbook" /> | ||
| </record> | ||
|
|
||
| <record id="field_mapping_addressbook_photo" model="dav.collection.field_mapping"> | ||
| <field name="name">photo</field> | ||
| <field name="field_id" ref="base.field_res_partner__image_1920" /> | ||
| <field name="collection_id" ref="collection_addressbook" /> | ||
| </record> | ||
|
|
||
| <record id="field_mapping_addressbook_email" model="dav.collection.field_mapping"> | ||
| <field name="name">email</field> | ||
| <field name="field_id" ref="base.field_res_partner__email" /> | ||
| <field name="collection_id" ref="collection_addressbook" /> | ||
| </record> | ||
|
|
||
| <record id="field_mapping_addressbook_tel" model="dav.collection.field_mapping"> | ||
| <field name="name">tel</field> | ||
| <field name="field_id" ref="base.field_res_partner__phone" /> | ||
| <field name="collection_id" ref="collection_addressbook" /> | ||
| </record> | ||
| </odoo> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you want to take longterm responsibility for this module, add yourself too