Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions calendar_import_ics/README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=====================
Calendar - Import ics
=====================
Expand All @@ -17,7 +13,7 @@ Calendar - Import ics
.. |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/license-AGPL--3-blue.png
.. |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%2Fcalendar-lightgray.png?logo=github
Expand Down Expand Up @@ -48,7 +44,9 @@ odoo calendar, importing events and the following attributes:
Usage
=====

To use this module, follow these steps:
To use this module, your user should be part of the 'Calendar Import
Ics' group. You need to be in debug mode to add this group to your user.
Then, follow these steps:

1. Navigate to the Calendar App.
2. Go to Configuration.
Expand Down
5 changes: 4 additions & 1 deletion calendar_import_ics/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
To use this module, follow these steps:

To use this module, your user should be part of the 'Calendar Import Ics' group.
You need to be in debug mode to add this group to your user.
Then, follow these steps:

1. Navigate to the Calendar App.
2. Go to Configuration.
Expand Down
4 changes: 4 additions & 0 deletions calendar_import_ics/security/calendar_import_security.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@
<record id="group_calendar_import" model="res.groups">
<field name="name">Calendar Import Ics</field>
<field name="category_id" ref="base.module_category_hidden" />
<field
name="users"
eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"
/>
</record>
</odoo>
30 changes: 13 additions & 17 deletions calendar_import_ics/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>README.rst</title>
<title>Calendar - Import ics</title>
<style type="text/css">

/*
Expand Down Expand Up @@ -360,21 +360,16 @@
</style>
</head>
<body>
<div class="document">
<div class="document" id="calendar-import-ics">
<h1 class="title">Calendar - Import ics</h1>


<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
</a>
<div class="section" id="calendar-import-ics">
<h1>Calendar - Import ics</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:0b76e943a6186b958123d04eef313d6d66e7b9361daf4122b045fbca02b88b23
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/calendar/tree/18.0/calendar_import_ics"><img alt="OCA/calendar" src="https://img.shields.io/badge/github-OCA%2Fcalendar-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/calendar-18-0/calendar-18-0-calendar_import_ics"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/calendar&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/calendar/tree/18.0/calendar_import_ics"><img alt="OCA/calendar" src="https://img.shields.io/badge/github-OCA%2Fcalendar-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/calendar-18-0/calendar-18-0-calendar_import_ics"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/calendar&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module adds a new wizard that allows you to import .ics files into
odoo calendar, importing events and the following attributes:</p>
<ul class="simple">
Expand All @@ -397,8 +392,10 @@ <h1>Calendar - Import ics</h1>
</ul>
</div>
<div class="section" id="usage">
<h2><a class="toc-backref" href="#toc-entry-1">Usage</a></h2>
<p>To use this module, follow these steps:</p>
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
<p>To use this module, your user should be part of the ‘Calendar Import
Ics’ group. You need to be in debug mode to add this group to your user.
Then, follow these steps:</p>
<ol class="arabic simple">
<li>Navigate to the Calendar App.</li>
<li>Go to Configuration.</li>
Expand All @@ -412,31 +409,31 @@ <h2><a class="toc-backref" href="#toc-entry-1">Usage</a></h2>
</ul>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h2>
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/calendar/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/calendar/issues/new?body=module:%20calendar_import_ics%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-3">Credits</a></h2>
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-4">Authors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>ForgeFlow S.L.</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-5">Contributors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Arnau Cruz &lt;<a class="reference external" href="mailto:arnau.cruz&#64;forgeflow.com">arnau.cruz&#64;forgeflow.com</a>&gt;</li>
</ul>
<p>Do not contact contributors directly about support or help with
technical issues.</p>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h3>
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
Expand All @@ -449,6 +446,5 @@ <h3><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h3>
</div>
</div>
</div>
</div>
</body>
</html>
6 changes: 4 additions & 2 deletions calendar_import_ics/tests/sample_files/test_calendar.ics
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ X-APPLE-CALENDAR-COLOR:#3A429C
X-WR-CALNAME:_CE
X-WR-TIMEZONE:US/Pacific
BEGIN:VEVENT
DTEND:20061010T210000Z
DTEND:20061010T210000
DTSTAMP:20240221T094129Z
DTSTART:20061010T200000Z
DTSTART:20061010T200000
SEQUENCE:0
SUMMARY:Event 1 Test
TRANSP:OPAQUE
Expand All @@ -19,6 +19,8 @@ BEGIN:VEVENT
DTEND;TZID=America/Denver:20061011T190000
DTSTAMP:20240221T094129Z
DTSTART;TZID=America/Denver:20061011T160000
ATTENDEE:MAILTO:len@lambdao.dev
ATTENDEE:MAILTO:fanny@lambdao.dev
SEQUENCE:0
SUMMARY:Unavailable
TRANSP:OPAQUE
Expand Down
17 changes: 17 additions & 0 deletions calendar_import_ics/tests/test_calendar_import_ics.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ def _get_test_file(cls, file_name):
def test_import_ics(self):
events_before_imp = self.event_model.search([])
filename = "test_calendar.ics"
vals_len = {"name": "len", "email": "len@lambdao.dev"}
partner_len = self.env["res.partner"].create(vals_len)
vals_fanny = {"name": "fanny", "email": "fanny@lambdao.dev"}
partner_fanny = self.env["res.partner"].create(vals_fanny)
wiz = self.import_wiz.create(
{
"import_ics_file": self._get_test_file(filename),
"import_ics_filename": filename,
"additional_partner_emails": [(6, 0, [partner_fanny.id])],
}
)
wiz.button_import()
Expand All @@ -42,6 +47,15 @@ def test_import_ics(self):
self.assertEqual(event_1.start, start_date)
self.assertEqual(event_1.stop, end_date)
self.assertEqual(event_1.name, name)

uid_2 = "4b1a0cb2081f6b3243bfdf191c985fe86237344c"
event_2 = self.event_model.search([("event_identifier", "=", uid_2)])
event_partners = event_2.attendee_ids.partner_id
# we added fanny as partners to look for in the attendees
self.assertIn(partner_fanny, event_partners)
# we didn't add len, so its partner hasn't been added as attendee
self.assertNotIn(partner_len, event_partners)

filename = "test_calendar_2.ics"
wiz = self.import_wiz.create(
{
Expand All @@ -68,8 +82,11 @@ def test_import_ics(self):
}
)
wiz.button_import()
# event_1 has not been imported, and has been deleted as it had no other partner
event_1 = self.event_model.search([("event_identifier", "=", uid)])
self.assertFalse(event_1)
# event_2 has not been deleted, since we imported fanny as other attendee on it
self.assertTrue(event_2)
wiz = self.import_wiz.create(
{
"import_ics_file": self._get_test_file(filename),
Expand Down
38 changes: 33 additions & 5 deletions calendar_import_ics/wizards/wizard_import_ics.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ class CalendarImportIcs(models.TransientModel):
"that are not in this import will be deleted",
default=True,
)
additional_partner_emails = fields.Many2many(
"res.partner",
help="Partners to be searched for as attendee emails",
)
no_mail_to_attendees = fields.Boolean(
string="No mail to attendees?",
help="If checked, the attendees will not receive a mail",
default=False,
)

def button_import(self):
imported_events = []
Expand All @@ -44,13 +53,24 @@ def button_import(self):
file_str = file_decoded.decode("utf-8")
lines = file_str.split("\n")
ics_event = {}
emails_to_partner = {p.email: p.id for p in self.additional_partner_emails}
# raise if there are multiple partners with the same email?
processor = self
if self.no_mail_to_attendees:
processor = self.with_context(no_mail_to_attendees=True)
for line in lines:
if line.startswith(("DTSTART", "DTEND")) and "TZID=" in line:
line = self.convert_date_to_z(line)
if line.startswith("BEGIN:VEVENT"):
ics_event = {}
elif line.startswith("END:VEVENT"):
self._process_event(ics_event, imported_events)
processor._process_event(ics_event, imported_events)
elif line.startswith("ATTENDEE:MAILTO:"):
email = line.split(":MAILTO:")[1].strip()
if "partner_ids" not in ics_event:
ics_event["partner_ids"] = []
if email in emails_to_partner:
ics_event["partner_ids"].append(emails_to_partner[email])
else:
if ":" in line:
key, value = line.strip().split(":", 1)
Expand Down Expand Up @@ -78,18 +98,24 @@ def _process_event(self, ics_event, imported_events):
self._create_event(ics_event, event_start_date, event_end_date)

def _parse_date(self, date_str):
if not date_str.endswith("Z"):
date_str += "Z"
return datetime.strptime(date_str, "%Y%m%dT%H%M%SZ")

def _get_partner_vals(self, ics_event):
partner_ids = ics_event.get("partner_ids", [])
if self.partner_id.id not in partner_ids:
partner_ids.append(self.partner_id.id)
return [(4, pid) for pid in partner_ids]

def _update_event(self, event, ics_event, event_start_date, event_end_date):
vals = {}
vals = {"partner_ids": self._get_partner_vals(ics_event)}
if event.start != event_start_date:
vals["start"] = event_start_date
if event.stop != event_end_date:
vals["stop"] = event_end_date
if event.name != ics_event["SUMMARY"]:
vals["name"] = ics_event["SUMMARY"]
if self.partner_id not in event.partner_ids:
vals["partner_ids"] = [(4, self.partner_id.id, 0)]
event.write(vals)

def _create_event(self, ics_event, event_start_date, event_end_date):
Expand All @@ -99,7 +125,7 @@ def _create_event(self, ics_event, event_start_date, event_end_date):
"stop": event_end_date,
"name": ics_event["SUMMARY"],
"event_identifier": ics_event["UID"],
"partner_ids": [(4, self.partner_id.id)],
"partner_ids": self._get_partner_vals(ics_event),
}
)

Expand All @@ -119,6 +145,8 @@ def _delete_non_imported_events(self, imported_events):
non_imported_events = self.env["calendar.event"].search(domain)
for non_imported_event in non_imported_events:
non_imported_event.write({"partner_ids": [(3, self.partner_id.id)]})
# TODO: this should be an option?
# If we imported another partner on it, we shouldn't skip the unlink
if not non_imported_events.partner_ids:
non_imported_events.unlink()

Expand Down
2 changes: 2 additions & 0 deletions calendar_import_ics/wizards/wizard_import_ics.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
<field name="do_remove_old_event" />
<field name="import_ics_file" filename="import_ics_filename" />
<field name="import_ics_filename" invisible="1" />
<field name="additional_partner_emails" widget="many2many_tags" />
<field name="no_mail_to_attendees" widget="boolean_toggle" />
</group>
<footer>
<button
Expand Down
Loading