280 lines
13 KiB
Python
280 lines
13 KiB
Python
|
from openerp import models, fields, api, _
|
||
|
from pytz import timezone
|
||
|
from openerp.exceptions import except_orm, Warning, RedirectWarning
|
||
|
from datetime import datetime, timedelta, time
|
||
|
from time import strptime, mktime, strftime
|
||
|
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||
|
import re
|
||
|
|
||
|
from openerp import http
|
||
|
from openerp.http import request
|
||
|
|
||
|
import logging
|
||
|
_logger = logging.getLogger(__name__)
|
||
|
|
||
|
try:
|
||
|
from icalendar import Calendar, Event, vDatetime, FreeBusy
|
||
|
except ImportError:
|
||
|
raise Warning('icalendar library missing, pip install icalendar')
|
||
|
|
||
|
try:
|
||
|
import urllib2
|
||
|
except ImportError:
|
||
|
raise Warning('urllib2 library missing, pip install urllib2')
|
||
|
|
||
|
class res_partner_icalendar(http.Controller):
|
||
|
# http://partner/<res.partner>/calendar/[private.ics|freebusy.ics|public.ics]
|
||
|
#~ simple_blog_list = request.env['blog.post'].sudo().search([('blog_id', '=', simple_blog.id)], order='message_last_post desc')
|
||
|
|
||
|
#~ @http.route(['/partner/<model("res.partner"):partner>/calendar/private.ics'], type='http', auth="public", website=True)
|
||
|
#~ def icalendar_private(self, partner=False, **post):
|
||
|
#~ if partner:
|
||
|
#~ document = partner.sudo().get_ics_calendar(type='private').to_ical()
|
||
|
#~ return request.make_response(
|
||
|
#~ headers=[('WWW-Authenticate', 'Basic realm="MaxRealm"')]
|
||
|
#~ )
|
||
|
#~ else:
|
||
|
#~ raise Warning("Private failed")
|
||
|
#~ pass # Some error page
|
||
|
|
||
|
@http.route(['/partner/<model("res.partner"):partner>/calendar/freebusy.ics'], type='http', auth="public", website=True)
|
||
|
def icalendar_freebusy(self, partner=False, **post):
|
||
|
if partner:
|
||
|
#~ raise Warning("Public successfull %s" % partner.get_ics_calendar(type='public').to_ical())
|
||
|
#~ return partner.get_ics_calendar(type='public').to_ical()
|
||
|
document = partner.sudo().get_ics_calendar(type='freebusy').to_ical()
|
||
|
return request.make_response(
|
||
|
document,
|
||
|
headers=[
|
||
|
('Content-Disposition', 'attachment; filename="freebusy.ifb"'),
|
||
|
('Content-Type', 'text/calendar'),
|
||
|
('Content-Length', len(document)),
|
||
|
]
|
||
|
)
|
||
|
else:
|
||
|
raise Warning()
|
||
|
pass # Some error page
|
||
|
|
||
|
@http.route(['/partner/<model("res.partner"):partner>/calendar/public.ics'], type='http', auth="public", website=True)
|
||
|
def icalendar_public(self, partner=False, **post):
|
||
|
if partner:
|
||
|
#~ raise Warning("Public successfull %s" % partner.get_ics_calendar(type='public').to_ical())
|
||
|
#~ return partner.sudo().get_ics_calendar(type='public')
|
||
|
document = partner.sudo().get_ics_calendar(type='public')
|
||
|
return request.make_response(
|
||
|
document,
|
||
|
headers=[
|
||
|
('Content-Disposition', 'attachment; filename="public.ics"'),
|
||
|
('Content-Type', 'text/calendar'),
|
||
|
('Content-Length', len(document)),
|
||
|
]
|
||
|
)
|
||
|
else:
|
||
|
raise Warning("Public failed")
|
||
|
pass # Some error page
|
||
|
|
||
|
class res_partner(models.Model):
|
||
|
_inherit = "res.partner"
|
||
|
|
||
|
ics_url = fields.Char(string='Url',required=False)
|
||
|
ics_active = fields.Boolean(string='Active',default=False)
|
||
|
ics_nextdate = fields.Datetime(string="Next")
|
||
|
#~ ics_frequency = fields.Integer(string="Frequency",default=60, help="Frequency in minutes, 60 = every hour, 1440 once per day, 10080 week, 43920 month, 131760 quarterly")
|
||
|
ics_frequency = fields.Selection([('15', 'Every fifteen minutes'), ('60', 'Every hour'), ('360', 'Four times a day'), ('1440', 'Once per day'), ('10080', 'Once every week'), ('43920', 'Once every month'), ('131760', 'Once every third month')], string='Frequency', default='60')
|
||
|
ics_class = fields.Selection([('private', 'Private'), ('public', 'Public'), ('confidential', 'Public for Employees')], string='Privacy', default='private')
|
||
|
ics_show_as = fields.Selection([('free', 'Free'), ('busy', 'Busy')], string='Show Time as')
|
||
|
ics_location = fields.Char(string='Location', help="Location of Event")
|
||
|
ics_allday = fields.Boolean(string='All Day')
|
||
|
ics_url_field = fields.Char(string='URL to the calendar', compute='create_ics_url')
|
||
|
|
||
|
@api.one
|
||
|
def create_ics_url(self):
|
||
|
self.ics_url_field = '%s/partner/%s/calendar/public.ics' % (self.env['ir.config_parameter'].sudo().get_param('web.base.url'), self.id)
|
||
|
|
||
|
@api.v7
|
||
|
def ics_cron_job(self, cr, uid, context=None):
|
||
|
for ics in self.pool.get('res.partner').browse(cr, uid, self.pool.get('res.partner').search(cr, uid, [('ics_active','=',True)])):
|
||
|
if (datetime.fromtimestamp(mktime(strptime(ics.ics_nextdate, DEFAULT_SERVER_DATETIME_FORMAT))) < datetime.today()):
|
||
|
ics.get_ics_events()
|
||
|
ics.ics_nextdate = datetime.fromtimestamp(mktime(strptime(ics.ics_nextdate, DEFAULT_SERVER_DATETIME_FORMAT))) + timedelta(minutes=int(ics.ics_frequency))
|
||
|
_logger.info('Cron job for %s done' % ics.name)
|
||
|
|
||
|
@api.one
|
||
|
def rm_ics_events(self):
|
||
|
self.env['calendar.event'].search(['&',('partner_ids','in',self.id),('ics_subscription','=',True)]).unlink()
|
||
|
|
||
|
@api.one
|
||
|
def get_ics_events(self):
|
||
|
if (self.ics_url):
|
||
|
try:
|
||
|
res = urllib2.urlopen(self.ics_url).read()
|
||
|
except urllib2.HTTPError as e:
|
||
|
_logger.error('ICS a %s %s' % (e.code, e.reason))
|
||
|
return False
|
||
|
except urllib2.URLError as e:
|
||
|
_logger.error('ICS c %s %s' % (e.code, e.reason))
|
||
|
return False
|
||
|
_logger.error('ICS %s' % res)
|
||
|
|
||
|
self.env['calendar.event'].search(['&',('partner_ids','in',self.id),('ics_subscription','=',True)]).unlink()
|
||
|
#~ for event in self.env['calendar.event'].search([('ics_id','=',self.id)]):
|
||
|
#~ event.unlink()
|
||
|
|
||
|
self.env['calendar.event'].set_ics_event(res, self)
|
||
|
|
||
|
@api.multi
|
||
|
def get_attendee_ids(self, event):
|
||
|
#~ raise Warning('get_attendee_ids run')
|
||
|
partner_ids = []
|
||
|
#~ attendee_mails = []
|
||
|
event_attendee_list = event.get('attendee')
|
||
|
if event_attendee_list:
|
||
|
if not (type(event_attendee_list) is list):
|
||
|
event_attendee_list = [event_attendee_list]
|
||
|
|
||
|
for vAttendee in event_attendee_list:
|
||
|
_logger.error('Attendee found %s' % vAttendee)
|
||
|
attendee_mailto = re.search('(:MAILTO:)([a-zA-Z0-9_@.\-]*)', vAttendee)
|
||
|
attendee_cn = re.search('(CN=)([^:]*)', vAttendee)
|
||
|
if attendee_mailto:
|
||
|
attendee_mailto = attendee_mailto.group(2)
|
||
|
if attendee_cn:
|
||
|
attendee_cn = attendee_cn.group(2)
|
||
|
elif not attendee_mailto and not attendee_cn:
|
||
|
attendee_cn = vAttendee
|
||
|
_logger.error('Attendee found %s' % attendee_cn)
|
||
|
|
||
|
#~ raise Warning('%s %s' % (vAttendee, attendee_cn))
|
||
|
if attendee_mailto:
|
||
|
partner_result = self.env['res.partner'].search([('email','=',attendee_mailto)])
|
||
|
|
||
|
if not partner_result:
|
||
|
partner_id = self.env['res.partner'].create({
|
||
|
'email': attendee_mailto,
|
||
|
'name': attendee_cn or attendee_mailto,
|
||
|
})
|
||
|
else:
|
||
|
partner_id = partner_result[0]
|
||
|
elif attendee_cn:
|
||
|
partner_result = self.env['res.partner'].search([('name','=',attendee_cn)])
|
||
|
|
||
|
if not partner_result:
|
||
|
partner_id = self.env['res.partner'].create({
|
||
|
'name': attendee_cn or attendee_mailto,
|
||
|
})
|
||
|
else:
|
||
|
partner_id = partner_result[0]
|
||
|
|
||
|
#~ self.env['calendar.attendee'].create({
|
||
|
#~ 'event_id': event_id.id,
|
||
|
#~ 'partner_id': partner_id.id or None,
|
||
|
#~ 'email': attendee_mailto or '',
|
||
|
#~ })
|
||
|
|
||
|
partner_ids.append(partner_id.id or None)
|
||
|
#~ attendee_mails.append(attendee_mailto or '')
|
||
|
|
||
|
return partner_ids
|
||
|
#~ return [partner_ids, attendee_mails]
|
||
|
|
||
|
def get_ics_calendar(self,type='public'):
|
||
|
calendar = Calendar()
|
||
|
if type == 'private':
|
||
|
for event in self.env['calendar.event'].search([('partner_ids','in',self.id)]):
|
||
|
calendar.add_component(event.get_ics_file())
|
||
|
elif type == 'freebusy':
|
||
|
fc = FreeBusy()
|
||
|
|
||
|
organizer_add = self.name and ('CN=' + self.name) or ''
|
||
|
if self.name and self.email:
|
||
|
organizer_add += ':'
|
||
|
organizer_add += self.email and ('MAILTO:' + self.email) or ''
|
||
|
fc['organizer'] = organizer_add
|
||
|
|
||
|
for event in self.env['calendar.event'].search([('partner_ids','in',self.id)]):
|
||
|
fc.add('freebusy', event.get_ics_freebusy(), encode=0)
|
||
|
#~ fb.add_component(fc)
|
||
|
return fc
|
||
|
elif type == 'public':
|
||
|
#~ raise Warning(self.env['calendar.event'].search([('partner_ids','in',self.id)]))
|
||
|
exported_ics = []
|
||
|
for event in reversed(self.env['calendar.event'].search([('partner_ids','in',self.id)])):
|
||
|
temporary_ics = event.get_ics_file(exported_ics, self)
|
||
|
if temporary_ics:
|
||
|
exported_ics.append(temporary_ics[1])
|
||
|
#~ temporary_ics[0].add('url', self.ics_url_field, encode=0)
|
||
|
calendar.add_component(temporary_ics[0])
|
||
|
#~ calendar.add('vevent', temporary_ics[0], encode=0)
|
||
|
|
||
|
#~ for attendees in event.attendee_ids:
|
||
|
#~ calendar.add('attendee', event.get_event_attendees(attendees), encode=0)
|
||
|
|
||
|
tmpCalendar = calendar.to_ical()
|
||
|
tmpSearch = re.findall('RRULE:[^\n]*\\;[^\n]*', tmpCalendar)
|
||
|
|
||
|
for counter in range(len(tmpSearch)):
|
||
|
tmpCalendar = tmpCalendar.replace(tmpSearch[counter], tmpSearch[counter].replace('\\;', ';', tmpSearch[counter].count('\\;')))
|
||
|
|
||
|
#~ raise Warning(tmpCalendar)
|
||
|
|
||
|
return tmpCalendar
|
||
|
|
||
|
@api.multi
|
||
|
def ics_mail(self,context=None):
|
||
|
#raise Warning('%s | %s' % (ids,picking))
|
||
|
compose_form = self.env.ref('mail.email_compose_message_wizard_form', False)
|
||
|
#~ raise Warning("%s compose_form" % compose_form)
|
||
|
mail= self.env['mail.compose.message'].create({
|
||
|
'template_id':self.env.ref('calendar_ics.email_ics_url').id,
|
||
|
'model': 'res.partner',
|
||
|
'res_id': self.id,
|
||
|
})
|
||
|
mail.write(mail.onchange_template_id( # gets defaults from template
|
||
|
self.env.ref('calendar_ics.email_ics_url').id, mail.composition_mode,
|
||
|
mail.model, mail.res_id,context=context
|
||
|
)['value'])
|
||
|
return {
|
||
|
'name': _('Compose Email'),
|
||
|
'type': 'ir.actions.act_window',
|
||
|
'view_type': 'form',
|
||
|
'view_mode': 'form',
|
||
|
'res_model': 'mail.compose.message',
|
||
|
'res_id':mail.id,
|
||
|
'views': [(compose_form.id, 'form')],
|
||
|
'view_id': compose_form.id,
|
||
|
'target': 'new',
|
||
|
}
|
||
|
|
||
|
return {'value': {'partner_id': False}, 'warning': {'title': 'Hello', 'message': 'Hejsan'}}
|
||
|
|
||
|
|
||
|
#~ ics['freebusy'] = '%s/%s' % (ics_datetime(event.start, event.allday), ics_datetime(event.stop, event.allday))
|
||
|
|
||
|
# vtodo, vjournal, vfreebusy
|
||
|
|
||
|
|
||
|
#~ eventprop = *(
|
||
|
|
||
|
#~ ; the following are optional,
|
||
|
#~ ; but MUST NOT occur more than once
|
||
|
|
||
|
#~ class / created / description / dtstart / geo /
|
||
|
#~ last-mod / location / organizer / priority /
|
||
|
#~ dtstamp / seq / status / summary / transp /
|
||
|
#~ uid / url / recurid /
|
||
|
|
||
|
#~ ; either 'dtend' or 'duration' may appear in
|
||
|
#~ ; a 'eventprop', but 'dtend' and 'duration'
|
||
|
#~ ; MUST NOT occur in the same 'eventprop'
|
||
|
|
||
|
#~ dtend / duration /
|
||
|
|
||
|
#~ ; the following are optional,
|
||
|
#~ ; and MAY occur more than once
|
||
|
|
||
|
#~ attach / attendee / categories / comment /
|
||
|
#~ contact / exdate / exrule / rstatus / related /
|
||
|
#~ resources / rdate / rrule / x-prop
|
||
|
|
||
|
#~ )
|