125 lines
4.6 KiB
Python
125 lines
4.6 KiB
Python
from odoo import models, api, fields
|
|
import caldav
|
|
from caldav.elements import dav, cdav
|
|
import logging
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
class CalendarEvent(models.Model):
|
|
_inherit = 'calendar.event'
|
|
|
|
caldav_uid = fields.Char(string='CalDAV UID', readonly=True)
|
|
|
|
@api.model
|
|
def create(self, vals):
|
|
event = super(CalendarEvent, self).create(vals)
|
|
event.sync_to_caldav()
|
|
return event
|
|
|
|
def write(self, vals):
|
|
res = super(CalendarEvent, self).write(vals)
|
|
self.sync_to_caldav()
|
|
return res
|
|
|
|
def unlink(self):
|
|
for event in self:
|
|
event.remove_from_caldav()
|
|
return super(CalendarEvent, self).unlink()
|
|
|
|
def _is_caldav_enabled(self):
|
|
user = self.env.user
|
|
return all([user.caldav_calendar_url, user.caldav_username, user.caldav_password])
|
|
|
|
def _get_caldav_client(self):
|
|
user = self.env.user
|
|
return caldav.DAVClient(
|
|
url=user.caldav_calendar_url,
|
|
username=user.caldav_username,
|
|
password=user.caldav_password
|
|
)
|
|
|
|
def sync_to_caldav(self):
|
|
if not self._is_caldav_enabled():
|
|
return
|
|
client = self._get_caldav_client()
|
|
calendar = client.calendar(self.env.user.caldav_calendar_url)
|
|
for event in self:
|
|
ical_event = event._get_icalendar()
|
|
if event.caldav_uid:
|
|
caldav_event = calendar.event_by_uid(event.caldav_uid)
|
|
caldav_event.save(ical_event)
|
|
else:
|
|
caldav_event = calendar.add_event(ical_event)
|
|
event.caldav_uid = caldav_event.id
|
|
|
|
def remove_from_caldav(self):
|
|
if not self._is_caldav_enabled():
|
|
return
|
|
client = self._get_caldav_client()
|
|
calendar = client.calendar(self.env.user.caldav_calendar_url)
|
|
for event in self:
|
|
if event.caldav_uid:
|
|
caldav_event = calendar.event_by_uid(event.caldav_uid)
|
|
caldav_event.delete()
|
|
|
|
def _get_icalendar(self):
|
|
from icalendar import Calendar, Event
|
|
calendar = Calendar()
|
|
calendar.add('prodid', '-//Odoo//mxm.dk//')
|
|
calendar.add('version', '2.0')
|
|
|
|
for event in self:
|
|
ical_event = Event()
|
|
ical_event.add('uid', event.caldav_uid or '')
|
|
ical_event.add('dtstamp', event.write_date)
|
|
ical_event.add('dtstart', event.start)
|
|
ical_event.add('dtend', event.stop)
|
|
ical_event.add('summary', event.name)
|
|
ical_event.add('description', event.description)
|
|
ical_event.add('location', event.location)
|
|
calendar.add_component(ical_event)
|
|
|
|
return calendar.to_ical()
|
|
|
|
@api.model
|
|
def poll_caldav_server(self):
|
|
users = self.env['res.users'].search([('caldav_calendar_url', '!=', False)])
|
|
for user in users:
|
|
try:
|
|
self.with_user(user).poll_user_caldav_server()
|
|
except Exception as e:
|
|
_logger.error(f"Failed to poll CalDAV server for user {user.name}: {e}")
|
|
|
|
def poll_user_caldav_server(self):
|
|
if not self._is_caldav_enabled():
|
|
return
|
|
client = self._get_caldav_client()
|
|
calendar = client.calendar(self.env.user.caldav_calendar_url)
|
|
events = calendar.events()
|
|
for caldav_event in events:
|
|
ical_event = caldav_event.icalendar_instance
|
|
self.sync_event_from_ical(ical_event)
|
|
|
|
def sync_event_from_ical(self, ical_event):
|
|
from icalendar import Event
|
|
for component in ical_event.subcomponents:
|
|
if isinstance(component, Event):
|
|
uid = str(component.get('uid'))
|
|
event = self.search([('caldav_uid', '=', uid)], limit=1)
|
|
if not event:
|
|
self.create({
|
|
'name': str(component.get('summary')),
|
|
'start': component.decoded('dtstart'),
|
|
'stop': component.decoded('dtend'),
|
|
'description': str(component.get('description')),
|
|
'location': str(component.get('location')),
|
|
'caldav_uid': uid,
|
|
})
|
|
else:
|
|
event.write({
|
|
'name': str(component.get('summary')),
|
|
'start': component.decoded('dtstart'),
|
|
'stop': component.decoded('dtend'),
|
|
'description': str(component.get('description')),
|
|
'location': str(component.get('location')),
|
|
})
|