[IMP]: base_calendar caldav crm_caldav: Apply Doc String + quality check

bzr revid: ksa@tinyerp.co.in-20100325120700-qin0rom78ex3vima
This commit is contained in:
ksa (Open ERP) 2010-03-25 17:37:00 +05:30
parent 58fddb6132
commit 0eb05a2c5d
27 changed files with 1362 additions and 899 deletions

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@ -15,9 +15,10 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from datetime import datetime, timedelta
from dateutil import parser
from dateutil import rrule
@ -38,6 +39,7 @@ def get_recurrent_dates(rrulestring, exdate, startdate=None):
"""
Get recurrent dates
"""
def todate(date):
val = parser.parse(''.join((re.compile('\d')).findall(date)))
return val
@ -56,6 +58,7 @@ def base_calendar_id2real_id(base_calendar_id=None, with_date=False):
Convert base calendar id into real id.
@return: base calendar id
"""
if base_calendar_id and isinstance(base_calendar_id, (str, unicode)):
res = base_calendar_id.split('-')
if len(res) >= 2:
@ -74,6 +77,7 @@ def real_id2base_calendar_id(real_id, recurrent_date):
Convert real id into base_calendar_id.
@return: real id with recurrent date.
"""
if real_id and recurrent_date:
recurrent_date = time.strftime("%Y%m%d%H%M%S", \
time.strptime(recurrent_date, "%Y-%m-%d %H:%M:%S"))
@ -89,6 +93,7 @@ def _links_get(self, cr, uid, context={}):
@param context: A standard dictionary for contextual values
@return: list of dictionary which contain object and name and id.
"""
obj = self.pool.get('res.request.link')
ids = obj.search(cr, uid, [])
res = obj.read(cr, uid, ids, ['object', 'name'], context=context)
@ -288,6 +293,7 @@ class calendar_attendee(osv.osv):
@param context: A standard dictionary for contextual values
@return: list of dictionary which contain object and name and id.
"""
obj = self.pool.get('res.request.link')
ids = obj.search(cr, uid, [])
res = obj.read(cr, uid, ids, ['object', 'name'], context=context)
@ -311,59 +317,76 @@ class calendar_attendee(osv.osv):
'cutype': fields.selection([('individual', 'Individual'), \
('group', 'Group'), ('resource', 'Resource'), \
('room', 'Room'), ('unknown', '') ], \
'Invite Type', help="Specify the type of Invitation"),
'member': fields.char('Member', size=124,
help="Indicate the groups that the attendee belongs to"),
'Invite Type', help="Specify the type of Invitation"),
'member': fields.char('Member', size=124,
help="Indicate the groups that the attendee belongs to"),
'role': fields.selection([('req-participant', 'Participation required'), \
('chair', 'Chair Person'), \
('opt-participant', 'Optional Participation'), \
('non-participant', 'For information Purpose')], 'Role', \
help='Participation role for the calendar user'),
'state': fields.selection([('tentative', 'Tentative'),
('needs-action', 'Needs Action'),
('accepted', 'Accepted'),
('declined', 'Declined'),
('delegated', 'Delegated')], 'State', readonly=True,
help="Status of the attendee's participation"),
'rsvp': fields.boolean('Required Reply?',
help="Indicats whether the favor of a reply is requested"),
help='Participation role for the calendar user'),
'state': fields.selection([('tentative', 'Tentative'),
('needs-action', 'Needs Action'),
('accepted', 'Accepted'),
('declined', 'Declined'),
('delegated', 'Delegated')], 'State', readonly=True,\
help="Status of the attendee's participation"),
'rsvp': fields.boolean('Required Reply?',
help="Indicats whether the favor of a reply is requested"),
'delegated_to': fields.function(_compute_data, method=True, \
string='Delegated To', type="char", size=124, store=True, \
multi='delegated_to', help="The users that the original \
request was delegated to"),
request was delegated to"),
'delegated_from': fields.function(_compute_data, method=True, string=\
'Delegated From', type="char", store=True, size=124, multi='delegated_from'),
'parent_ids': fields.many2many('calendar.attendee', 'calendar_attendee_parent_rel', 'attendee_id', 'parent_id', 'Delegrated From'),
'child_ids': fields.many2many('calendar.attendee', 'calendar_attendee_child_rel', 'attendee_id', 'child_id', 'Delegrated To'),
'sent_by': fields.function(_compute_data, method=True, string='Sent By', type="char", multi='sent_by', store=True, size=124, help="Specify the user that is acting on behalf of the calendar user"),
'sent_by_uid': fields.function(_compute_data, method=True, string='Sent By User', type="many2one", relation="res.users", multi='sent_by_uid'),
'cn': fields.function(_compute_data, method=True, string='Common name', type="char", size=124, multi='cn', store=True),
'dir': fields.char('URI Reference', size=124, help="Reference to the URI that points to the directory information corresponding to the attendee."),
'language': fields.function(_compute_data, method=True, string='Language', type="selection", selection=_lang_get, multi='language', store=True, help="To specify the language for text values in a property or property parameter."),
'user_id': fields.many2one('res.users', 'User'),
'partner_address_id': fields.many2one('res.partner.address', 'Contact'),
'partner_id': fields.related('partner_address_id', 'partner_id', type='many2one', relation='res.partner', string='Partner', help="Partner related to contact"),
'email': fields.char('Email', size=124, help="Email of Invited Person"),
'event_date': fields.function(_compute_data, method=True, string='Event Date', type="datetime", multi='event_date'),
'event_end_date': fields.function(_compute_data, method=True, string='Event End Date', type="datetime", multi='event_end_date'),
'ref': fields.reference('Event Ref', selection=_links_get, size=128),
'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"),
'Delegated From', type="char", store=True, size=124, multi='delegated_from'),
'parent_ids': fields.many2many('calendar.attendee', 'calendar_attendee_parent_rel',\
'attendee_id', 'parent_id', 'Delegrated From'),
'child_ids': fields.many2many('calendar.attendee', 'calendar_attendee_child_rel',\
'attendee_id', 'child_id', 'Delegrated To'),
'sent_by': fields.function(_compute_data, method=True, string='Sent By',\
type="char", multi='sent_by', store=True, size=124,\
help="Specify the user that is acting on behalf of the calendar user"),
'sent_by_uid': fields.function(_compute_data, method=True, string='Sent By User',\
type="many2one", relation="res.users", multi='sent_by_uid'),
'cn': fields.function(_compute_data, method=True, string='Common name',\
type="char", size=124, multi='cn', store=True),
'dir': fields.char('URI Reference', size=124, help="Reference to the URI\
that points to the directory information corresponding to the attendee."),
'language': fields.function(_compute_data, method=True, string='Language',\
type="selection", selection=_lang_get, multi='language',\
store=True, help="To specify the language for text values in a\
property or property parameter."),
'user_id': fields.many2one('res.users', 'User'),
'partner_address_id': fields.many2one('res.partner.address', 'Contact'),
'partner_id': fields.related('partner_address_id', 'partner_id', type='many2one',\
relation='res.partner', string='Partner', help="Partner related to contact"),
'email': fields.char('Email', size=124, help="Email of Invited Person"),
'event_date': fields.function(_compute_data, method=True, string='Event Date',\
type="datetime", multi='event_date'),
'event_end_date': fields.function(_compute_data, method=True, string='Event End Date',\
type="datetime", multi='event_end_date'),
'ref': fields.reference('Event Ref', selection=_links_get, size=128),
'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"),
}
_defaults = {
'state': lambda *x: 'needs-action',
'state': lambda *x: 'needs-action',
}
response_re = re.compile("Are you coming\?.*\n*.*(YES|NO|MAYBE).*", re.UNICODE)
def msg_new(self, cr, uid, msg):
def msg_new(self, cr, uid, msg):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks, """
return False
def msg_act_get(self, msg):
"""
Get Message.
@param self: The object pointer
@return: dictionary of actions which contain state field value.
"""
mailgate_obj = self.pool.get('mail.gateway')
body = mailgate_obj.msg_body_get(msg)
actions = {}
@ -399,6 +422,7 @@ request was delegated to"),
@param context: A standard dictionary for contextual values
@return: True
"""
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.name
for att in self.browse(cr, uid, ids, context=context):
sign = att.sent_by_uid and att.sent_by_uid.signature or ''
@ -411,26 +435,26 @@ request was delegated to"),
att_infos.append(((att2.user_id and att2.user_id.name) or \
(att2.partner_id and att2.partner_id.name) or \
att2.email) + ' - Status: ' + att2.state.title())
body_vals = {'name': res_obj.name,
'start_date': res_obj.date,
'end_date': res_obj.date_deadline or False,
'description': res_obj.description or '-',
'location': res_obj.location or '-',
'attendees': '<br>'.join(att_infos),
'user': res_obj.user_id and res_obj.user_id.name or 'OpenERP User',
'sign': sign,
body_vals = {'name': res_obj.name,
'start_date': res_obj.date,
'end_date': res_obj.date_deadline or False,
'description': res_obj.description or '-',
'location': res_obj.location or '-',
'attendees': '<br>'.join(att_infos),
'user': res_obj.user_id and res_obj.user_id.name or 'OpenERP User',
'sign': sign,
'company': company
}
body = html_invitation % body_vals
if mail_to and email_from:
tools.email_send(
email_from,
mail_to,
sub,
body,
subtype='html',
email_from,
mail_to,
sub,
body,
subtype='html',
reply_to=email_from
)
)
return True
def onchange_user_id(self, cr, uid, ids, user_id, *args, **argv):
"""
@ -441,6 +465,7 @@ request was delegated to"),
@param user_id: User id
@return: dictionary of value. which put value in email and availability fields.
"""
if not user_id:
return {'value': {'email': ''}}
usr_obj = self.pool.get('res.users')
@ -448,6 +473,13 @@ request was delegated to"),
return {'value': {'email': user.address_id.email, 'availability':user.availability}}
def do_tentative(self, cr, uid, ids, context=None, *args):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendar attendees IDs
@param *args: Get Tupple value
@param context: A standard dictionary for contextual values """
self.write(cr, uid, ids, {'state': 'tentative'}, context)
def do_accept(self, cr, uid, ids, context=None, *args):
@ -458,6 +490,7 @@ request was delegated to"),
@param ids: List of calendar attendees IDs.
@return: True
"""
if not context:
context = {}
@ -475,9 +508,21 @@ request was delegated to"),
return True
def do_decline(self, cr, uid, ids, context=None, *args):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendar attendees IDs
@param *args: Get Tupple value
@param context: A standard dictionary for contextual values """
self.write(cr, uid, ids, {'state': 'declined'}, context)
def create(self, cr, uid, vals, context=None):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get Values
@param context: A standard dictionary for contextual values """
if not context:
context = {}
@ -488,34 +533,35 @@ request was delegated to"),
vals['cn'] = vals.get("cn")
res = super(calendar_attendee, self).create(cr, uid, vals, context)
return res
calendar_attendee()
class res_alarm(osv.osv):
_name = 'res.alarm'
_description = 'Basic Alarm Information'
_columns = {
'name':fields.char('Name', size=256, required=True),
'name':fields.char('Name', size=256, required=True),
'trigger_occurs': fields.selection([('before', 'Before'), ('after', 'After')], \
'Triggers', required=True),
'Triggers', required=True),
'trigger_interval': fields.selection([('minutes', 'Minutes'), ('hours', 'Hours'), \
('days', 'Days')], 'Interval', required=True),
'trigger_duration': fields.integer('Duration', required=True),
('days', 'Days')], 'Interval', required=True),
'trigger_duration': fields.integer('Duration', required=True),
'trigger_related': fields.selection([('start', 'The event starts'), ('end', \
'The event ends')], 'Related to', required=True),
'The event ends')], 'Related to', required=True),
'duration': fields.integer('Duration', help="""Duration' and 'Repeat' \
are both optional, but if one occurs, so MUST the other"""),
'repeat': fields.integer('Repeat'),
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the event alarm information without removing it."),
are both optional, but if one occurs, so MUST the other"""),
'repeat': fields.integer('Repeat'),
'active': fields.boolean('Active', help="If the active field is set to \
true, it will allow you to hide the event alarm information without removing it."),
}
_defaults = {
'trigger_interval': lambda *x: 'minutes',
'trigger_duration': lambda *x: 5,
'trigger_occurs': lambda *x: 'before',
'trigger_related': lambda *x: 'start',
'active': lambda *x: 1,
'trigger_interval': lambda *x: 'minutes',
'trigger_duration': lambda *x: 5,
'trigger_occurs': lambda *x: 'before',
'trigger_related': lambda *x: 'start',
'active': lambda *x: 1,
}
def do_alarm_create(self, cr, uid, ids, model, date, context={}):
@ -528,13 +574,14 @@ are both optional, but if one occurs, so MUST the other"""),
@param context: A standard dictionary for contextual values
@return: True
"""
alarm_obj = self.pool.get('calendar.alarm')
ir_obj = self.pool.get('ir.model')
model_id = ir_obj.search(cr, uid, [('model', '=', model)])[0]
model_obj = self.pool.get(model)
for data in model_obj.browse(cr, uid, ids):
basic_alarm = data.alarm_id
if not context.get('alarm_id'):
self.do_alarm_unlink(cr, uid, [data.id], model)
@ -542,20 +589,20 @@ are both optional, but if one occurs, so MUST the other"""),
self.do_alarm_unlink(cr, uid, [data.id], model)
if basic_alarm:
vals = {
'action': 'display',
'description': data.description,
'name': data.name,
'attendee_ids': [(6, 0, map(lambda x:x.id, data.attendee_ids))],
'trigger_related': basic_alarm.trigger_related,
'trigger_duration': basic_alarm.trigger_duration,
'trigger_occurs': basic_alarm.trigger_occurs,
'trigger_interval': basic_alarm.trigger_interval,
'duration': basic_alarm.duration,
'repeat': basic_alarm.repeat,
'state': 'run',
'event_date': data[date],
'res_id': data.id,
'model_id': model_id,
'action': 'display',
'description': data.description,
'name': data.name,
'attendee_ids': [(6, 0, map(lambda x:x.id, data.attendee_ids))],
'trigger_related': basic_alarm.trigger_related,
'trigger_duration': basic_alarm.trigger_duration,
'trigger_occurs': basic_alarm.trigger_occurs,
'trigger_interval': basic_alarm.trigger_interval,
'duration': basic_alarm.duration,
'repeat': basic_alarm.repeat,
'state': 'run',
'event_date': data[date],
'res_id': data.id,
'model_id': model_id,
'user_id': uid
}
alarm_id = alarm_obj.create(cr, uid, vals)
@ -567,13 +614,14 @@ are both optional, but if one occurs, so MUST the other"""),
def do_alarm_unlink(self, cr, uid, ids, model, context={}):
"""
Delete alarm specified in ids
Delete alarm specified in ids
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of res alarms IDs.
@param model: Model name.
@return: True
"""
alarm_obj = self.pool.get('calendar.alarm')
ir_obj = self.pool.get('ir.model')
model_id = ir_obj.search(cr, uid, [('model', '=', model)])[0]
@ -596,35 +644,40 @@ class calendar_alarm(osv.osv):
__attribute__ = {}
_columns = {
'alarm_id': fields.many2one('res.alarm', 'Basic Alarm', ondelete='cascade'),
'name': fields.char('Summary', size=124, help="""Contains the text to be used as the message subject for email
or contains the text to be used for display"""),
'alarm_id': fields.many2one('res.alarm', 'Basic Alarm', ondelete='cascade'),
'name': fields.char('Summary', size=124, help="""Contains the text to be \
used as the message subject for email \
or contains the text to be used for display"""),
'action': fields.selection([('audio', 'Audio'), ('display', 'Display'), \
('procedure', 'Procedure'), ('email', 'Email') ], 'Action', \
required=True, help="Defines the action to be invoked when an alarm is triggered"),
'description': fields.text('Description', help='Provides a more complete description of the calendar component, than that provided by the "SUMMARY" property'),
required=True, help="Defines the action to be invoked when an alarm is triggered"),
'description': fields.text('Description', help='Provides a more complete \
description of the calendar component, than that \
provided by the "SUMMARY" property'),
'attendee_ids': fields.many2many('calendar.attendee', 'alarm_attendee_rel', \
'alarm_id', 'attendee_id', 'Attendees', readonly=True),
'attach': fields.binary('Attachment', help="""* Points to a sound resource, which is rendered when the alarm is triggered for audio,
* File which is intended to be sent as message attachments for email,
* Points to a procedure resource, which is invoked when the alarm is triggered for procedure."""),
'res_id': fields.integer('Resource ID'),
'model_id': fields.many2one('ir.model', 'Model'),
'user_id': fields.many2one('res.users', 'Owner'),
'event_date': fields.datetime('Event Date'),
'event_end_date': fields.datetime('Event End Date'),
'trigger_date': fields.datetime('Trigger Date', readonly="True"),
'alarm_id', 'attendee_id', 'Attendees', readonly=True),
'attach': fields.binary('Attachment', help="""* Points to a sound resource,\
which is rendered when the alarm is triggered for audio,
* File which is intended to be sent as message attachments for email,
* Points to a procedure resource, which is invoked when\
the alarm is triggered for procedure."""),
'res_id': fields.integer('Resource ID'),
'model_id': fields.many2one('ir.model', 'Model'),
'user_id': fields.many2one('res.users', 'Owner'),
'event_date': fields.datetime('Event Date'),
'event_end_date': fields.datetime('Event End Date'),
'trigger_date': fields.datetime('Trigger Date', readonly="True"),
'state':fields.selection([
('draft', 'Draft'),
('run', 'Run'),
('stop', 'Stop'),
('done', 'Done'),
], 'State', select=True, readonly=True),
('draft', 'Draft'),
('run', 'Run'),
('stop', 'Stop'),
('done', 'Done'),
], 'State', select=True, readonly=True),
}
_defaults = {
'action': lambda *x: 'email',
'state': lambda *x: 'run',
'action': lambda *x: 'email',
'state': lambda *x: 'run',
}
def create(self, cr, uid, vals, context={}):
@ -636,6 +689,7 @@ or contains the text to be used for display"""),
@param context: A standard dictionary for contextual values
@return: new record id for calendar_alarm.
"""
event_date = vals.get('event_date', False)
if event_date:
dtstart = datetime.strptime(vals['event_date'], "%Y-%m-%d %H:%M:%S")
@ -652,6 +706,15 @@ or contains the text to be used for display"""),
def do_run_scheduler(self, cr, uid, automatic=False, use_new_cursor=False, \
context=None):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendar alarms IDs.
@param use_new_cursor: False or the dbname
@param context: A standard dictionary for contextual values
"""
if not context:
context = {}
@ -667,11 +730,11 @@ or contains the text to be used for display"""),
for alarm in self.browse(cr, uid, alarm_ids):
if alarm.action == 'display':
value = {
'name': alarm.name,
'act_from': alarm.user_id.id,
'act_to': alarm.user_id.id,
'body': alarm.description,
'trigger_date': alarm.trigger_date,
'name': alarm.name,
'act_from': alarm.user_id.id,
'act_to': alarm.user_id.id,
'body': alarm.description,
'trigger_date': alarm.trigger_date,
'ref_doc1': '%s,%s' % (alarm.model_id.model, alarm.res_id)
}
request_id = request_obj.create(cr, uid, value)
@ -701,9 +764,9 @@ or contains the text to be used for display"""),
mail_to.append(att.user_id.address_id.email)
if mail_to:
tools.email_send(
tools.config.get('email_from', False),
mail_to,
sub,
tools.config.get('email_from', False),
mail_to,
sub,
body
)
self.write(cr, uid, [alarm.id], {'state':'done'})
@ -716,12 +779,23 @@ class calendar_event(osv.osv):
_name = "calendar.event"
_description = "Calendar Event"
__attribute__ = {}
def _tz_get(self, cr, uid, context={}):
return [(x.lower(), x) for x in pytz.all_timezones]
def onchange_dates(self, cr, uid, ids, start_date, duration=False, end_date=False, context={}):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendar events IDs.
@param start_date: Get starting date
@param duration: Get Duration between start date and end date or False
@param end_date: Get Ending Date or False
@param context: A standard dictionary for contextual values
"""
if not start_date:
return {}
value = {}
@ -744,13 +818,13 @@ class calendar_event(osv.osv):
Get rule string.
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param id: List of calendar event's ids.
@param id: List of calendar event's ids.
@param context: A standard dictionary for contextual values
@return: dictionary of rrule value.
"""
result = {}
for event in ids:
datas = self.read(cr, uid, event)
if datas.get('rrule_type'):
if datas.get('rrule_type') == 'none':
@ -762,39 +836,41 @@ class calendar_event(osv.osv):
result[event] = self.compute_rule_string(cr, uid, {'freq':\
datas.get('rrule_type').upper(), \
'interval': 1}, context=context)
return result
_columns = {
'id': fields.integer('ID'),
'sequence': fields.integer('Sequence'),
'name': fields.char('Description', size=64, required=True),
'date': fields.datetime('Date'),
'date_deadline': fields.datetime('Deadline'),
'create_date': fields.datetime('Created', readonly=True),
'duration': fields.float('Duration'),
'description': fields.text('Your action'),
'id': fields.integer('ID'),
'sequence': fields.integer('Sequence'),
'name': fields.char('Description', size=64, required=True),
'date': fields.datetime('Date'),
'date_deadline': fields.datetime('Deadline'),
'create_date': fields.datetime('Created', readonly=True),
'duration': fields.float('Duration'),
'description': fields.text('Your action'),
'class': fields.selection([('public', 'Public'), ('private', 'Private'), \
('confidential', 'Confidential')], 'Mark as'),
'location': fields.char('Location', size=264, help="Location of Event"),
('confidential', 'Confidential')], 'Mark as'),
'location': fields.char('Location', size=264, help="Location of Event"),
'show_as': fields.selection([('free', 'Free'), \
('busy', 'Busy')],
'Show as'),
'base_calendar_url': fields.char('Caldav URL', size=264),
('busy', 'Busy')],
'Show as'),
'base_calendar_url': fields.char('Caldav URL', size=264),
'exdate': fields.text('Exception Date/Times', help="This property \
defines the list of date/time exceptions for arecurring calendar component."),
defines the list of date/time exceptions for arecurring calendar component."),
'exrule': fields.char('Exception Rule', size=352, help="defines a \
rule or repeating pattern for anexception to a recurrence set"),
'rrule': fields.function(_get_rulestring, type='char', size=124, method=True, string='Recurrent Rule', store=True),
rule or repeating pattern for anexception to a recurrence set"),
'rrule': fields.function(_get_rulestring, type='char', size=124, method=True,\
string='Recurrent Rule', store=True),
'rrule_type': fields.selection([('none', ''), ('daily', 'Daily'), \
('weekly', 'Weekly'), ('monthly', 'Monthly'), \
('yearly', 'Yearly'), ('custom', 'Custom')], 'Recurrency'),
'alarm_id': fields.many2one('res.alarm', 'Alarm'),
'base_calendar_alarm_id': fields.many2one('calendar.alarm', 'Alarm'),
'recurrent_uid': fields.integer('Recurrent ID'),
'recurrent_id': fields.datetime('Recurrent ID date'),
'vtimezone': fields.related('user_id', 'context_tz', type='char', size=24, string='Timezone', store=True),
'user_id': fields.many2one('res.users', 'Responsible'),
('yearly', 'Yearly'), ('custom', 'Custom')], 'Recurrency'),
'alarm_id': fields.many2one('res.alarm', 'Alarm'),
'base_calendar_alarm_id': fields.many2one('calendar.alarm', 'Alarm'),
'recurrent_uid': fields.integer('Recurrent ID'),
'recurrent_id': fields.datetime('Recurrent ID date'),
'vtimezone': fields.related('user_id', 'context_tz', type='char', size=24,\
string='Timezone', store=True),
'user_id': fields.many2one('res.users', 'Responsible'),
'freq': fields.selection([('None', 'No Repeat'), \
('secondly', 'Secondly'), \
('minutely', 'Minutely'), \
@ -802,46 +878,56 @@ rule or repeating pattern for anexception to a recurrence set"),
('daily', 'Daily'), \
('weekly', 'Weekly'), \
('monthly', 'Monthly'), \
('yearly', 'Yearly')], 'Frequency'),
'interval': fields.integer('Interval'),
'count': fields.integer('Count'),
'mo': fields.boolean('Mon'),
'tu': fields.boolean('Tue'),
'we': fields.boolean('Wed'),
'th': fields.boolean('Thu'),
'fr': fields.boolean('Fri'),
'sa': fields.boolean('Sat'),
'su': fields.boolean('Sun'),
('yearly', 'Yearly')], 'Frequency'),
'interval': fields.integer('Interval'),
'count': fields.integer('Count'),
'mo': fields.boolean('Mon'),
'tu': fields.boolean('Tue'),
'we': fields.boolean('Wed'),
'th': fields.boolean('Thu'),
'fr': fields.boolean('Fri'),
'sa': fields.boolean('Sat'),
'su': fields.boolean('Sun'),
'select1': fields.selection([('date', 'Date of month'), \
('day', 'Day of month')], 'Option'),
'day': fields.integer('Date of month'),
('day', 'Day of month')], 'Option'),
'day': fields.integer('Date of month'),
'week_list': fields.selection([('MO', 'Monday'), ('TU', 'Tuesday'), \
('WE', 'Wednesday'), ('TH', 'Thursday'), \
('FR', 'Friday'), ('SA', 'Saturday'), \
('SU', 'Sunday')], 'Weekday'),
('SU', 'Sunday')], 'Weekday'),
'byday': fields.selection([('1', 'First'), ('2', 'Second'), \
('3', 'Third'), ('4', 'Fourth'), \
('5', 'Fifth'), ('-1', 'Last')], 'By day'),
'month_list': fields.selection(months.items(), 'Month'),
('5', 'Fifth'), ('-1', 'Last')], 'By day'),
'month_list': fields.selection(months.items(), 'Month'),
'end_date': fields.date('Repeat Until')
}
_defaults = {
'class': lambda *a: 'public',
'show_as': lambda *a: 'busy',
'freq': lambda *x: 'None',
'select1': lambda *x: 'date',
'interval': lambda *x: 1,
'class': lambda *a: 'public',
'show_as': lambda *a: 'busy',
'freq': lambda *x: 'None',
'select1': lambda *x: 'date',
'interval': lambda *x: 1,
}
def modify_this(self, cr, uid, event_id, defaults, real_date, context=None, *args):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param event_id: Get Event_id
@param real_date: Get Real Date
@param context: A standard dictionary for contextual values
@param *args: Get Tuppel Value
"""
event_id = base_calendar_id2real_id(event_id)
datas = self.read(cr, uid, event_id, context=context)
defaults.update({
'recurrent_uid': base_calendar_id2real_id(datas['id']),
'recurrent_id': defaults.get('date') or real_date,
'rrule_type': 'none',
'recurrent_uid': base_calendar_id2real_id(datas['id']),
'recurrent_id': defaults.get('date') or real_date,
'rrule_type': 'none',
'rrule': ''
})
exdate = datas['exdate'] and datas['exdate'].split(',') or []
@ -862,10 +948,10 @@ rule or repeating pattern for anexception to a recurrence set"),
#start Loop
for event_id in event_ids:
event_id = base_calendar_id2real_id(event_id)
defaults.pop('id')
defaults.update({'table': self._table})
qry = "UPDATE %(table)s set name = '%(name)s', \
date = '%(date)s', date_deadline = '%(date_deadline)s'"
if defaults.get('alarm_id'):
@ -878,6 +964,14 @@ rule or repeating pattern for anexception to a recurrence set"),
return True
def get_recurrent_ids(self, cr, uid, select, base_start_date, base_until_date, limit=100):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param base_start_date: Get Start Date
@param base_until_date: Get End Date
@param limit: The Number of Results to Return """
if not limit:
limit = 100
if isinstance(select, (str, int, long)):
@ -909,7 +1003,7 @@ rule or repeating pattern for anexception to a recurrence set"),
result.append(idval)
count += 1
else:
exdate = data['exdate'] and data['exdate'].split(',') or []
exdate = data['exdate'] and data['exdate'].split(',') or []
rrule_str = data['rrule']
new_rrule_str = []
rrule_until_date = False
@ -956,9 +1050,9 @@ rule or repeating pattern for anexception to a recurrence set"),
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param datas: dictionary of freq and interval value.
@return: string value which compute FREQILY;INTERVAL
@return: string value which compute FREQILY;INTERVAL
"""
weekdays = ['mo', 'tu', 'we', 'th', 'fr', 'sa', 'su']
weekstring = ''
monthstring = ''
@ -1002,14 +1096,16 @@ rule or repeating pattern for anexception to a recurrence set"),
# End logic
return rrule_string
def search(self, cr, uid, args, offset=0, limit=100, order=None,
def search(self, cr, uid, args, offset=0, limit=100, order=None,
context=None, count=False):
"""
Overrides orm search method.
@param cr: the current row, from the database cursor,
@param user: the current users ID for security checks,
@param args: list of tuples of form [(name_of_the_field, operator, value), ...].
@return: List of id
@param offset: The Number of Results to Pass
@param limit: The Number of Results to Return
@return: List of id
"""
args_without_date = []
start_date = False
@ -1064,7 +1160,7 @@ rule or repeating pattern for anexception to a recurrence set"),
context.update({'alarm_id': vals.get('alarm_id')})
alarm_obj.do_alarm_create(cr, uid, new_ids, self._name, 'date', \
context=context)
return res
def browse(self, cr, uid, ids, context=None, list_class=None, fields_process={}):
@ -1085,7 +1181,7 @@ rule or repeating pattern for anexception to a recurrence set"),
list_class, fields_process)
if isinstance(ids, (str, int, long)):
return res and res[0] or False
return res
def read(self, cr, uid, ids, fields=None, context={}, load='_classic_read'):
@ -1130,7 +1226,7 @@ rule or repeating pattern for anexception to a recurrence set"),
res = super(calendar_event, self).copy(cr, uid, base_calendar_id2real_id(id), default, context)
alarm_obj = self.pool.get('res.alarm')
alarm_obj.do_alarm_create(cr, uid, [res], self._name, 'date')
return res
def unlink(self, cr, uid, ids, context=None):
@ -1182,17 +1278,38 @@ rule or repeating pattern for anexception to a recurrence set"),
calendar_event()
class calendar_todo(osv.osv):
""" Calendar Task """
_name = "calendar.todo"
_inherit = "calendar.event"
_description = "Calendar Task"
def _get_date(self, cr, uid, ids, name, arg, context):
""" Get Date
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendar todo's IDs.
@param args: list of tuples of form [(name_of_the_field, operator, value), ...].
@param context: A standard dictionary for contextual values
"""
res = {}
for event in self.browse(cr, uid, ids, context=context):
res[event.id] = event.date_start
return res
def _set_date(self, cr, uid, id, name, value, arg, context):
""" Set Date
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param id: calendar's ID.
@param value: Get Value
@param args: list of tuples of form [(name_of_the_field, operator, value), ...].
@param context: A standard dictionary for contextual values
"""
event = self.browse(cr, uid, id, context=context)
cr.execute("UPDATE %s set date_start='%s' where id=%s" \
% (self._table, value, id))
@ -1200,33 +1317,50 @@ class calendar_todo(osv.osv):
_columns = {
'date': fields.function(_get_date, method=True, fnct_inv=_set_date, \
string='Duration', store=True, type='datetime'),
'duration': fields.integer('Duration'),
string='Duration', store=True, type='datetime'),
'duration': fields.integer('Duration'),
}
__attribute__ = {}
calendar_todo()
class ir_attachment(osv.osv):
_name = 'ir.attachment'
_inherit = 'ir.attachment'
def search_count(self, cr, user, args, context=None):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param user: the current users ID for security checks,
@param args: list of tuples of form [(name_of_the_field, operator, value), ...].
@param context: A standard dictionary for contextual values
"""
args1 = []
for arg in args:
args1.append(map(lambda x:str(x).split('-')[0], arg))
return super(ir_attachment, self).search_count(cr, user, args1, context)
def search(self, cr, uid, args, offset=0, limit=None, order=None,
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param args: list of tuples of form [(name_of_the_field, operator, value), ...].
@param offset: The Number of Results to pass,
@param limit: The Number of Results to Return,
@param context: A standard dictionary for contextual values
"""
new_args = args
for i, arg in enumerate(new_args):
if arg[0] == 'res_id':
new_args[i] = (arg[0], arg[1], base_calendar_id2real_id(arg[2]))
return super(ir_attachment, self).search(cr, uid, new_args, offset=offset,
limit=limit, order=order,
return super(ir_attachment, self).search(cr, uid, new_args, offset=offset,
limit=limit, order=order,
context=context, count=False)
ir_attachment()
@ -1235,6 +1369,13 @@ class ir_values(osv.osv):
def set(self, cr, uid, key, key2, name, models, value, replace=True, \
isobject=False, meta=False, preserve_user=False, company=False):
""" set IR Values
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param model: Get The Model """
new_model = []
for data in models:
if type(data) in (list, tuple):
@ -1246,6 +1387,13 @@ class ir_values(osv.osv):
def get(self, cr, uid, key, key2, models, meta=False, context={}, \
res_id_req=False, without_user=True, key2_req=True):
""" Get IR Values
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param model: Get The Model """
new_model = []
for data in models:
if type(data) in (list, tuple):
@ -1261,8 +1409,17 @@ class ir_model(osv.osv):
_inherit = 'ir.model'
def read(self, cr, uid, ids, fields=None, context={},
def read(self, cr, uid, ids, fields=None, context={},
load='_classic_read'):
""" Read IR Model
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of IR Models IDs.
@param context: A standard dictionary for contextual values """
data = super(ir_model, self).read(cr, uid, ids, fields=fields, \
context=context, load=load)
if data:
@ -1275,13 +1432,21 @@ ir_model()
class virtual_report_spool(web_services.report_spool):
def exp_report(self, db, uid, object, ids, datas=None, context=None):
""" Export Report
@param self: The object pointer
@param db: get the current database,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values """
if object == 'printscreen.list':
return super(virtual_report_spool, self).exp_report(db, uid, \
object, ids, datas, context)
new_ids = []
for id in ids:
new_ids.append(base_calendar_id2real_id(id))
if datas.get('id',False):
if datas.get('id', False):
datas['id'] = base_calendar_id2real_id(datas['id'])
return super(virtual_report_spool, self).exp_report(db, uid, object, new_ids, datas, context)
@ -1291,11 +1456,19 @@ class res_users(osv.osv):
_inherit = 'res.users'
def _get_user_avail(self, cr, uid, ids, context=None):
""" Get USer Availability
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of res users IDs.
@param context: A standard dictionary for contextual values """
current_datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
res = {}
attendee_obj = self.pool.get('calendar.attendee')
attendee_ids = attendee_obj.search(cr, uid, [
('event_date', '<=', current_datetime), ('event_end_date', '<=', current_datetime),
('event_date', '<=', current_datetime), ('event_end_date', '<=', current_datetime),
('state', '=', 'accepted'), ('user_id', 'in', ids)
])
@ -1305,7 +1478,7 @@ class res_users(osv.osv):
status = 'busy'
res.update({user_id:status})
#TOCHECK: Delegated Event
#TOCHECK: Delegated Event
for user_id in ids:
if user_id not in res:
res[user_id] = 'free'
@ -1313,12 +1486,20 @@ class res_users(osv.osv):
return res
def _get_user_avail_fun(self, cr, uid, ids, name, args, context=None):
""" Get USer Availability Function
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of res users IDs.
@param context: A standard dictionary for contextual values """
return self._get_user_avail(cr, uid, ids, context=context)
_columns = {
'availability': fields.function(_get_user_avail_fun, type='selection', \
selection=[('free', 'Free'), ('busy', 'Busy')], \
string='Free/Busy', method=True),
string='Free/Busy', method=True),
}
res_users()

View File

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="base_calendar_attendee_form_view" model="ir.ui.view">
<field name="name">calendar.attendee.form</field>
<field name="model">calendar.attendee</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Invitation details">
<field name="email" string="Invitation To"/>
<field name="email" string="Invitation To"/>
<field name="sent_by_uid" string="Invitation From" />
<notebook colspan="4">
<page string="Invitation">
@ -22,7 +22,7 @@
string="Partner" readonly="1" />
<field name="role" string="Role" />
<field name="cutype" string="Invitation type" />
<field name="rsvp" />
<field name="rsvp" />
</group>
<separator string="Event Detail" colspan="4" />
<group colspan="4" col="4">
@ -70,7 +70,7 @@
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Invitation details">
<field name="email" string="Invitation To"/>
<field name="email" string="Invitation To"/>
<field name="partner_id" string="Partner" />
<field name="partner_address_id" string="Contact" />
<field name="role" />
@ -125,7 +125,7 @@
<field name="name">res.alarm.tree</field>
<field name="model">res.alarm</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<field name="arch" type="xml">
<tree string="Reminder details">
<field name="name" select="1"/>
<field name="trigger_interval" select="1"/>
@ -136,13 +136,13 @@
</field>
</record>
<record id="action_res_alarm_view" model="ir.actions.act_window">
<field name="name">Available Alarms</field>
<field name="name">Available Alarms</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.alarm</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<!--Available alarms-->
<menuitem id="base.menu_calendar_configuration" name="Calendar"
parent="base.menu_base_config" sequence="10" />

View File

@ -27,21 +27,22 @@ class base_calendar_invite_attendee(osv.osv_memory):
"""
Invite attendee.
"""
_name = "base_calendar.invite.attendee"
_description = "Invite Attendees"
_columns = {
'type': fields.selection([('internal', 'Internal User'), \
('external', 'External Email'), \
('partner', 'Partner Contacts')], 'Type', required=True),
'user_ids': fields.many2many('res.users', 'invite_user_rel',
'invite_id', 'user_id', 'Users'),
'partner_id': fields.many2one('res.partner', 'Partner'),
'email': fields.char('Email', size=124),
'contact_ids': fields.many2many('res.partner.address', 'invite_contact_rel',
'invite_id', 'contact_id', 'Contacts'),
'send_mail': fields.boolean('Send mail?', help='Check this if you want to send an Email to Invited Person')
('partner', 'Partner Contacts')], 'Type', required=True),
'user_ids': fields.many2many('res.users', 'invite_user_rel',
'invite_id', 'user_id', 'Users'),
'partner_id': fields.many2one('res.partner', 'Partner'),
'email': fields.char('Email', size=124),
'contact_ids': fields.many2many('res.partner.address', 'invite_contact_rel',
'invite_id', 'contact_id', 'Contacts'),
'send_mail': fields.boolean('Send mail?', help='Check this if you want to \
send an Email to Invited Person')
}
_defaults = {
@ -57,20 +58,20 @@ class base_calendar_invite_attendee(osv.osv_memory):
@param context: A standard dictionary for contextual values
@return: Dictionary of {}.
"""
if not context:
context = {}
model = False
model_field = False
context_id = context and context.get('active_id', False) or False
if not context or not context.get('model'):
return {}
else:
model = context.get('model')
model_field = context.get('attendee_field', False)
for datas in self.read(cr, uid, ids, context=context):
obj = self.pool.get(model)
@ -85,7 +86,7 @@ class base_calendar_invite_attendee(osv.osv_memory):
if not model == 'calendar.attendee':
if context_id:
ref = {'ref': '%s,%s' % (model, base_calendar.base_calendar_id2real_id(context_id))}
else:
else:
return {}
if type == 'internal':
user_obj = self.pool.get('res.users')
@ -94,7 +95,7 @@ class base_calendar_invite_attendee(osv.osv_memory):
for user_id in datas.get('user_ids'):
user = user_obj.browse(cr, uid, user_id)
res = {
'user_id': user_id,
'user_id': user_id,
'email': user.address_id.email
}
res.update(ref)
@ -112,7 +113,7 @@ class base_calendar_invite_attendee(osv.osv_memory):
add_obj = self.pool.get('res.partner.address')
for contact in add_obj.browse(cr, uid, datas['contact_ids']):
res = {
'partner_address_id': contact.id,
'partner_address_id': contact.id,
'email': contact.email
}
res.update(ref)
@ -121,12 +122,12 @@ class base_calendar_invite_attendee(osv.osv_memory):
mail_to.append(contact.email)
att = att_obj.browse(cr, uid, context_id)
for att_val in vals:
if model == 'calendar.attendee':
if ref:
att_val.update({
'parent_ids': [(4, att.id)],
'parent_ids': [(4, att.id)],
'ref': att.ref._name + ',' +str(att.ref.id)
})
attendees.append(att_obj.create(cr, uid, att_val))
@ -141,7 +142,7 @@ class base_calendar_invite_attendee(osv.osv_memory):
raise osv.except_osv(_('Error!'), ("%s must have an email \
Address to send mail") % (name[0]))
att_obj._send_mail(cr, uid, attendees, mail_to, \
email_from=tools.config.get('email_from', False))
email_from= tools.config.get('email_from', False))
return {}
@ -152,9 +153,10 @@ class base_calendar_invite_attendee(osv.osv_memory):
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of base calendar invite attendees IDs.
@param partner_id: id of Partner
@param partner_id: id of Partner
@return: dictionary of value.
"""
if not partner_id:
return {'value': {'contact_ids': []}}
cr.execute('select id from res_partner_address \

View File

@ -1,63 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Attendee invite wizard-->
<data>
<!-- Attendee invite wizard-->
<record id="view_calendar_invite_attendee_wizard" model="ir.ui.view">
<field name="name">Invite Attendees</field>
<field name="model">base_calendar.invite.attendee</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Invite People">
<field name="type" />
<field name="send_mail" />
<newline/>
<group col="1" colspan="4"
attrs="{'invisible': [('type', '!=', 'external')]}">
<field name="email" colspan="4"
attrs="{'required': [('type', '=', 'external')]}" />
</group>
<group col="1" colspan="4"
attrs="{'invisible': [('type', '!=', 'internal')]}">
<separator string="Users" colspan="4" />
<field name="user_ids" select="1" colspan="4"
nolabel="1" />
<newline />
</group>
<group col="2" colspan="4"
attrs="{'invisible': [('type', '!=', 'partner')]}">
<field name="partner_id" colspan="2"
on_change="onchange_partner_id(partner_id)"
attrs="{'required': [('type', '=', 'partner')]}" />
<newline />
<separator string="Partner Contacts"
colspan="4" />
<field name="contact_ids" select="1" colspan="4"
nolabel="1" domain="[('partner_id', '=', partner_id)]"
attrs="{'readonly': [('type', '!=', 'partner')]}" />
</group>
<newline/>
<separator string="" colspan="6" />
<label string="" colspan="2" />
<button icon='gtk-cancel' special="cancel"
string="Cancel" />
<button name="do_invite" string="Invite"
type="object" icon="gtk-ok" />
</form>
</field>
</record>
<!-- Attendee invite action-->
<record id="action_view_calendar_invite_attendee_wizard" model="ir.actions.act_window">
<field name="name">Invite Attendees</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">base_calendar.invite.attendee</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<record id="view_calendar_invite_attendee_wizard"
model="ir.ui.view">
<field name="name">Invite Attendees</field>
<field name="model">base_calendar.invite.attendee</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Invite People">
<field name="type" />
<field name="send_mail" />
<newline />
<group col="1" colspan="4"
attrs="{'invisible': [('type', '!=', 'external')]}">
<field name="email" colspan="4"
attrs="{'required': [('type', '=', 'external')]}" />
</group>
<group col="1" colspan="4"
attrs="{'invisible': [('type', '!=', 'internal')]}">
<separator string="Users" colspan="4" />
<field name="user_ids" select="1" colspan="4"
nolabel="1" />
<newline />
</group>
<group col="2" colspan="4"
attrs="{'invisible': [('type', '!=', 'partner')]}">
<field name="partner_id" colspan="2"
on_change="onchange_partner_id(partner_id)"
attrs="{'required': [('type', '=', 'partner')]}" />
<newline />
<separator string="Partner Contacts"
colspan="4" />
<field name="contact_ids" select="1" colspan="4"
nolabel="1" domain="[('partner_id', '=', partner_id)]"
attrs="{'readonly': [('type', '!=', 'partner')]}" />
</group>
<newline />
<separator string="" colspan="6" />
<label string="" colspan="2" />
<button icon='gtk-cancel' special="cancel"
string="Cancel" />
<button name="do_invite" string="Invite"
type="object" icon="gtk-ok" />
</form>
</field>
</record>
</data>
<!-- Attendee invite action-->
<record id="action_view_calendar_invite_attendee_wizard" model="ir.actions.act_window">
<field name="name">Invite Attendees</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">base_calendar.invite.attendee</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -23,9 +23,13 @@ from osv import osv
from osv import fields
class calendar_event_edit_all(osv.osv_memory):
def _default_values(self, cr, uid, context={}):
"""
""" Get Default value for Start Date
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values
@Return: Get Default value for Start Date
"""
context_id = context and context.get('active_id', False) or False
@ -36,12 +40,17 @@ class calendar_event_edit_all(osv.osv_memory):
model = context.get('model', False)
model_obj = self.pool.get(model)
event = model_obj.read(cr, uid, context_id, ['name', 'location', 'alarm_id'])
return event['date']
return event['date']
def _default_deadline(self, cr, uid, context={}):
"""
""" Get Default value for End Date
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values
@return: Get Default value for End Date
"""
context_id = context and context.get('active_id', False) or False
if context_id:
if context.get('date_deadline'):
@ -62,7 +71,7 @@ class calendar_event_edit_all(osv.osv_memory):
"""
if not context:
context = {}
context_id = context and context.get('active_id', False) or False
if context_id:
for datas in self.read(cr, uid, ids):
@ -74,16 +83,16 @@ class calendar_event_edit_all(osv.osv_memory):
_name = "calendar.event.edit.all"
_description = "Calendar Edit all event"
_columns = {
'name': fields.char('Title', size=64, required=True),
'date': fields.datetime('Start Date', required=True),
'date_deadline': fields.datetime('End Date', required=True),
'location': fields.char('Location', size=124),
'alarm_id': fields.many2one('res.alarm', 'Reminder'),
'name': fields.char('Title', size=64, required=True),
'date': fields.datetime('Start Date', required=True),
'date_deadline': fields.datetime('End Date', required=True),
'location': fields.char('Location', size=124),
'alarm_id': fields.many2one('res.alarm', 'Reminder'),
}
_defaults = {
'date': _default_values,
'date': _default_values,
'date_deadline': _default_deadline
}
}
calendar_event_edit_all()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="view_calendar_event_edit_all" model="ir.ui.view">
<record id="view_calendar_event_edit_all" model="ir.ui.view">
<field name="name">calendar.event.edit.all.form</field>
<field name="model">calendar.event.edit.all</field>
<field name="type">form</field>
@ -17,25 +17,25 @@
<field name='date' />
<field name='date_deadline' />
<newline />
<field name='alarm_id'/>
<field name='alarm_id'/>
</group>
<separator string="" colspan="4" />
<separator string="" colspan="4" />
<group colspan="4" col="6">
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
<button icon="gtk-save" string="_Save" name="modify_this" type="object"/>
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
<button icon="gtk-save" string="_Save" name="modify_this" type="object"/>
</group>
</form>
</field>
</record>
</record>
<record id="action_calendar_event_edit_all" model="ir.actions.act_window">
<field name="name">Edit all events</field>
<field name="res_model">calendar.event.edit.all</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
<field name="view_id" ref="view_calendar_event_edit_all"/>
<field name="view_id" ref="view_calendar_event_edit_all"/>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -27,6 +27,7 @@ __author__ = AUTHOR
from BaseHTTPServer import BaseHTTPRequestHandler
import os
class BufferedHTTPRequestHandler(BaseHTTPRequestHandler):
"""
Buffering HTTP Request Handler
@ -47,12 +48,12 @@ class BufferedHTTPRequestHandler(BaseHTTPRequestHandler):
If you override the handle() method remember to call
this (see below)
"""
self.__buffer=""
self.__outfp=os.tmpfile()
self.__buffer = ""
self.__outfp = os.tmpfile()
def _append(self,s):
""" append a string to the buffer """
self.__buffer=self.__buffer+s
self.__buffer = self.__buffer+s
def _flush(self):
""" flush the buffer to wfile """
@ -60,7 +61,7 @@ class BufferedHTTPRequestHandler(BaseHTTPRequestHandler):
self.__outfp.write(self.__buffer)
self.__outfp.flush()
self.wfile.flush()
self.__buffer=""
self.__buffer = ""
def handle(self):
""" Handle a HTTP request """
@ -97,3 +98,4 @@ class BufferedHTTPRequestHandler(BaseHTTPRequestHandler):
protocol_version="HTTP/1.1"
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,3 +1,5 @@
#!/usr/bin/env python
"""
Python WebDAV Server.
Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de)
@ -23,12 +25,20 @@ Subclass this class and specify an IFACE_CLASS. See example.
"""
DEBUG=None
DEBUG = None
from utils import VERSION, AUTHOR
__version__ = VERSION
__author__ = AUTHOR
from propfind import PROPFIND
from delete import DELETE
from davcopy import COPY
from davmove import MOVE
from string import atoi, split
from status import STATUS_CODES
from errors import *
import os
import sys
@ -39,16 +49,6 @@ import posixpath
import base64
import urlparse
import urllib
from propfind import PROPFIND
from delete import DELETE
from davcopy import COPY
from davmove import MOVE
from string import atoi,split
from status import STATUS_CODES
from errors import *
import BaseHTTPServer
class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
@ -74,21 +74,21 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def _log(self, message):
pass
def _append(self,s):
def _append(self, s):
""" write the string to wfile """
self.wfile.write(s)
def send_body(self,DATA,code,msg,desc,ctype='application/octet-stream',headers=None):
def send_body(self, DATA, code, msg, desc, ctype='application/octet-stream', headers=None):
""" send a body in one part """
if not headers:
headers = {}
self.send_response(code,message=msg)
self.send_response(code, message=msg)
self.send_header("Connection", "keep-alive")
self.send_header("Accept-Ranges", "bytes")
for a,v in headers.items():
self.send_header(a,v)
for a, v in headers.items():
self.send_header(a, v)
if DATA:
self.send_header("Content-Length", str(len(DATA)))
@ -100,11 +100,11 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
if DATA:
self._append(DATA)
def send_body_chunks(self,DATA,code,msg,desc,ctype='text/xml; encoding="utf-8"'):
def send_body_chunks(self, DATA, code, msg, desc, ctype='text/xml; encoding="utf-8"'):
""" send a body in chunks """
self.responses[207]=(msg,desc)
self.send_response(code,message=msg)
self.responses[207]=(msg, desc)
self.send_response(code, message=msg)
self.send_header("Content-type", ctype)
self.send_header("Connection", "keep-alive")
self.send_header("Transfer-Encoding", "chunked")
@ -128,12 +128,12 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_PROPFIND(self):
dc=self.IFACE_CLASS
dc = self.IFACE_CLASS
# read the body
body=None
body = None
if self.headers.has_key("Content-Length"):
l=self.headers['Content-Length']
body=self.rfile.read(atoi(l))
l = self.headers['Content-Length']
body = self.rfile.read(atoi(l))
alt_body = """<?xml version="1.0" encoding="utf-8"?>
<propfind xmlns="DAV:"><prop>
<getcontentlength xmlns="DAV:"/>
@ -149,26 +149,26 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
# which Depth?
if self.headers.has_key('Depth'):
d=self.headers['Depth']
d = self.headers['Depth']
else:
d="infinity"
d = "infinity"
uri=self.geturi()
pf=PROPFIND(uri,dc,d)
uri = self.geturi()
pf = PROPFIND(uri, dc, d)
if body:
pf.read_propfind(body)
try:
DATA=pf.createResponse()
DATA=DATA+"\n"
DATA = pf.createResponse()
DATA = DATA+"\n"
# print "Data:", DATA
except DAV_NotFound,(ec,dd):
except DAV_NotFound, (ec, dd):
return self.send_notFound(dd, uri)
except DAV_Error, (ec,dd):
return self.send_error(ec,dd)
except DAV_Error, (ec, dd):
return self.send_error(ec, dd)
self.send_body_chunks(DATA,207,"Multi-Status","Multiple responses")
self.send_body_chunks(DATA, 207, "Multi-Status", "Multiple responses")
def geturi(self):
buri = self.IFACE_CLASS.baseuri
@ -179,110 +179,110 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
"""Serve a GET request."""
dc=self.IFACE_CLASS
uri=self.geturi()
dc = self.IFACE_CLASS
uri = self.geturi()
# get the last modified date
try:
lm=dc.get_prop(uri,"DAV:","getlastmodified")
lm = dc.get_prop(uri, "DAV:", "getlastmodified")
except:
lm="Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
headers={"Last-Modified":lm , "Connection": "keep-alive"}
lm = "Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
headers = {"Last-Modified":lm , "Connection": "keep-alive"}
# get the content type
try:
ct=dc.get_prop(uri,"DAV:","getcontenttype")
ct = dc.get_prop(uri, "DAV:", "getcontenttype")
except:
ct="application/octet-stream"
ct = "application/octet-stream"
# get the data
try:
data=dc.get_data(uri)
except DAV_Error, (ec,dd):
data = dc.get_data(uri)
except DAV_Error, (ec, dd):
self.send_status(ec)
return
# send the data
self.send_body(data,200,"OK","OK",ct,headers)
self.send_body(data, 200, "OK", "OK", ct, headers)
def do_HEAD(self):
""" Send a HEAD response """
dc=self.IFACE_CLASS
uri=self.geturi()
dc = self.IFACE_CLASS
uri = self.geturi()
# get the last modified date
try:
lm=dc.get_prop(uri,"DAV:","getlastmodified")
lm = dc.get_prop(uri, "DAV:", "getlastmodified")
except:
lm="Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
lm = "Sun, 01 Dec 2014 00:00:00 GMT" # dummy!
headers={"Last-Modified":lm, "Connection": "keep-alive"}
headers = {"Last-Modified":lm, "Connection": "keep-alive"}
# get the content type
try:
ct=dc.get_prop(uri,"DAV:","getcontenttype")
ct = dc.get_prop(uri, "DAV:", "getcontenttype")
except:
ct="application/octet-stream"
ct = "application/octet-stream"
try:
data=dc.get_data(uri)
headers["Content-Length"]=str(len(data))
data = dc.get_data(uri)
headers["Content-Length"] = str(len(data))
except DAV_NotFound:
self.send_body(None,404,"Not Found","")
self.send_body(None, 404, "Not Found", "")
return
self.send_body(None,200,"OK","OK",ct,headers)
self.send_body(None, 200, "OK", "OK", ct, headers)
def do_POST(self):
self.send_error(404,"File not found")
self.send_error(404, "File not found")
def do_MKCOL(self):
""" create a new collection """
dc=self.IFACE_CLASS
uri=self.geturi()
dc = self.IFACE_CLASS
uri = self.geturi()
try:
res = dc.mkcol(uri)
if res:
self.send_body(None,201,"Created",'')
self.send_body(None, 201, "Created", '')
else:
self.send_body(None,415,"Cannot create",'')
self.send_body(None, 415, "Cannot create", '')
#self.send_header("Connection", "keep-alive")
# Todo: some content, too
except DAV_Error, (ec,dd):
self.send_body(None,int(ec),dd,dd)
except DAV_Error, (ec, dd):
self.send_body(None, int(ec), dd, dd)
def do_DELETE(self):
""" delete an resource """
dc=self.IFACE_CLASS
uri=self.geturi()
dl=DELETE(uri,dc)
dc = self.IFACE_CLASS
uri = self.geturi()
dl = DELETE(uri, dc)
if dc.is_collection(uri):
res=dl.delcol()
res = dl.delcol()
else:
res=dl.delone()
res = dl.delone()
if res:
self.send_status(207,body=res)
self.send_status(207, body=res)
else:
self.send_status(204)
def do_PUT(self):
dc=self.IFACE_CLASS
dc = self.IFACE_CLASS
# read the body
body=None
body = None
if self.headers.has_key("Content-Length"):
l=self.headers['Content-Length']
body=self.rfile.read(atoi(l))
uri=self.geturi()
l = self.headers['Content-Length']
body = self.rfile.read(atoi(l))
uri = self.geturi()
ct=None
ct = None
if self.headers.has_key("Content-Type"):
ct=self.headers['Content-Type']
ct = self.headers['Content-Type']
try:
dc.put(uri,body,ct)
except DAV_Error, (ec,dd):
dc.put(uri, body, ct)
except DAV_Error, (ec, dd):
self.send_status(ec)
return
self.send_status(201)
@ -291,84 +291,84 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
""" copy one resource to another """
try:
self.copymove(COPY)
except DAV_Error, (ec,dd):
except DAV_Error, (ec, dd):
self.send_status(ec)
def do_MOVE(self):
""" move one resource to another """
try:
self.copymove(MOVE)
except DAV_Error, (ec,dd):
except DAV_Error, (ec, dd):
self.send_status(ec)
def copymove(self,CLASS):
def copymove(self, CLASS):
""" common method for copying or moving objects """
dc=self.IFACE_CLASS
dc = self.IFACE_CLASS
# get the source URI
source_uri=self.geturi()
source_uri = self.geturi()
# get the destination URI
dest_uri=self.headers['Destination']
dest_uri=urllib.unquote(dest_uri)
dest_uri = self.headers['Destination']
dest_uri = urllib.unquote(dest_uri)
# Overwrite?
overwrite=1
result_code=204
overwrite = 1
result_code = 204
if self.headers.has_key("Overwrite"):
if self.headers['Overwrite']=="F":
overwrite=None
result_code=201
# instanciate ACTION class
cp=CLASS(dc,source_uri,dest_uri,overwrite)
cp = CLASS(dc, source_uri, dest_uri, overwrite)
# Depth?
d="infinity"
d = "infinity"
if self.headers.has_key("Depth"):
d=self.headers['Depth']
d = self.headers['Depth']
if d!="0" and d!="infinity":
self.send_status(400)
return
if d=="0":
res=cp.single_action()
res = cp.single_action()
self.send_status(res)
return
# now it only can be "infinity" but we nevertheless check for a collection
if dc.is_collection(source_uri):
try:
res=cp.tree_action()
except DAV_Error, (ec,dd):
res = cp.tree_action()
except DAV_Error, (ec, dd):
self.send_status(ec)
return
else:
try:
res=cp.single_action()
except DAV_Error, (ec,dd):
res = cp.single_action()
except DAV_Error, (ec, dd):
self.send_status(ec)
return
if res:
self.send_body_chunks(res,207,STATUS_CODES[207],STATUS_CODES[207],
self.send_body_chunks(res, 207, STATUS_CODES[207], STATUS_CODES[207],
ctype='text/xml; charset="utf-8"')
else:
self.send_status(result_code)
def get_userinfo(self,user,pw):
def get_userinfo(self, user, pw):
""" Dummy method which lets all users in """
return 1
def send_status(self,code=200,mediatype='text/xml; charset="utf-8"', \
msg=None,body=None):
def send_status(self, code=200, mediatype='text/xml; charset="utf-8"', \
msg=None, body=None):
if not msg: msg=STATUS_CODES[code]
self.send_body(body,code,STATUS_CODES[code],msg,mediatype)
if not msg: msg = STATUS_CODES[code]
self.send_body(body, code, STATUS_CODES[code], msg, mediatype)
def send_notFound(self,descr,uri):
def send_notFound(self, descr, uri):
body = """<?xml version="1.0" encoding="utf-8" ?>
<D:response xmlns:D="DAV:">
<D:href>%s</D:href>
@ -376,4 +376,6 @@ class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
<D:responsedescription>%s</D:responsedescription>
</D:response>
"""
return self.send_status(404,descr, body=body % (uri,descr))
return self.send_status(404, descr, body=body % (uri, descr))
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -14,8 +14,8 @@ import urlparse
from utils import create_treelist, is_prefix
from errors import *
def deltree(dc,uri,exclude={}):
""" delete a tree of resources
def deltree(dc, uri, exclude={}):
""" delete a tree of resources
dc -- dataclass to use
uri -- root uri to delete
@ -30,43 +30,43 @@ def deltree(dc,uri,exclude={}):
"""
tlist=create_treelist(dc,uri)
result={}
tlist = create_treelist(dc,uri)
result = {}
for i in range(len(tlist),0,-1):
problem_uris=result.keys()
element=tlist[i-1]
problem_uris = result.keys()
element = tlist[i-1]
# test here, if an element is a prefix of an uri which
# generated an error before.
# note that we walk here from childs to parents, thus
# we cannot delete a parent if a child made a problem.
# (see example in 8.6.2.1)
ok=1
ok = 1
for p in problem_uris:
if is_prefix(element,p):
ok=None
ok = None
break
if not ok: continue
if not ok: continue
# here we test for the exclude list which is the other way round!
for p in exclude.keys():
if is_prefix(p,element):
ok=None
ok = None
break
if not ok: continue
if not ok: continue
# now delete stuff
try:
delone(dc,element)
except DAV_Error, (ec,dd):
result[element]=ec
except DAV_Error, (ec,dd):
result[element] = ec
return result
def delone(dc,uri):
def delone(dc, uri):
""" delete a single object """
if dc.is_collection(uri):
dc.rmcol(uri) # should be empty
@ -79,12 +79,12 @@ def delone(dc,uri):
# helper function
def copy(dc,src,dst):
""" only copy the element
def copy(dc, src, dst):
""" only copy the element
This is just a helper method factored out from copy and
copytree. It will not handle the overwrite or depth header.
"""
# destination should have been deleted before
@ -101,28 +101,28 @@ def copy(dc,src,dst):
# the main functions
def copyone(dc,src,dst,overwrite=None):
def copyone(dc, src, dst, overwrite=None):
""" copy one resource to a new destination """
if overwrite and dc.exists(dst):
delres=deltree(dc,dst)
delres = deltree(dc,dst)
else:
delres={}
delres = {}
# if we cannot delete everything, then do not copy!
if delres: return delres
try:
copy(dc,src,dst) # pass thru exceptions
except DAV_Error, (ec,dd):
return ec
def copytree(dc,src,dst,overwrite=None):
def copytree(dc, src, dst, overwrite=None):
""" copy a tree of resources to another location
dc -- dataclass to use
src -- src uri from where to copy
dst -- dst uri
dst -- dst uri
overwrite -- if 1 then delete dst uri before
returns dict of uri:error_code tuples from which
@ -133,59 +133,59 @@ def copytree(dc,src,dst,overwrite=None):
# first delete the destination resource
if overwrite and dc.exists(dst):
delres=deltree(dc,dst)
delres = deltree(dc,dst)
else:
delres={}
delres = {}
# if we cannot delete everything, then do not copy!
if delres: return delres
# get the tree we have to copy
tlist=create_treelist(dc,src)
result={}
tlist = create_treelist(dc,src)
result = {}
# prepare destination URIs (get the prefix)
dpath=urlparse.urlparse(dst)[2]
dpath = urlparse.urlparse(dst)[2]
for element in tlist:
problem_uris=result.keys()
problem_uris = result.keys()
# now URIs get longer and longer thus we have
# to test if we had a parent URI which we were not
# able to copy in problem_uris which is the prefix
# of the actual element. If it is, then we cannot
# copy this as well but do not generate another error.
ok=1
ok = 1
for p in problem_uris:
if is_prefix(p,element):
ok=None
ok = None
break
if not ok: continue
if not ok: continue
# now create the destination URI which corresponds to
# the actual source URI. -> actual_dst
# ("subtract" the base src from the URI and prepend the
# dst prefix to it.)
esrc=replace(element,src,"")
actual_dst=dpath+esrc
esrc = replace(element,src,"")
actual_dst = dpath+esrc
# now copy stuff
try:
copy(dc,element,actual_dst)
except DAV_Error, (ec,dd):
result[element]=ec
except DAV_Error, (ec,dd):
result[element] = ec
return result
###
### MOVE
###
def moveone(dc,src,dst,overwrite=None):
def moveone(dc, src, dst, overwrite=None):
""" move a single resource
This is done by first copying it and then deleting
@ -197,8 +197,8 @@ def moveone(dc,src,dst,overwrite=None):
# then delete it
dc.rm(src)
def movetree(dc,src,dst,overwrite=None):
def movetree(dc, src, dst, overwrite=None):
""" move a collection
This is done by first copying it and then deleting
@ -209,10 +209,11 @@ def movetree(dc,src,dst,overwrite=None):
"""
# first copy it
res=copytree(dc,src,dst,overwrite)
res = copytree(dc,src,dst,overwrite)
# then delete it
res=deltree(dc,src,exclude=res)
res = deltree(dc,src,exclude=res)
return res
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -47,11 +47,11 @@ class COPY:
"""
def __init__(self,dataclass,src_uri,dst_uri,overwrite):
self.__dataclass=dataclass
self.__src=src_uri
self.__dst=dst_uri
self.__overwrite=overwrite
def __init__(self, dataclass, src_uri, dst_uri, overwrite):
self.__dataclass = dataclass
self.__src = src_uri
self.__dst = dst_uri
self.__overwrite = overwrite
def single_action(self):
@ -62,16 +62,16 @@ class COPY:
"""
dc=self.__dataclass
base=self.__src
dc = self.__dataclass
base = self.__src
### some basic tests
# test if dest exists and overwrite is false
if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
# test if src and dst are the same
# (we assume that both uris are on the same server!)
ps=urlparse.urlparse(self.__src)[2]
pd=urlparse.urlparse(self.__dst)[2]
ps = urlparse.urlparse(self.__src)[2]
pd = urlparse.urlparse(self.__dst)[2]
if ps==pd: raise DAV_Error, 403
return dc.copyone(self.__src,self.__dst,self.__overwrite)
@ -84,20 +84,20 @@ class COPY:
Here we return a multistatus xml element.
"""
dc=self.__dataclass
base=self.__src
dc = self.__dataclass
base = self.__src
### some basic tests
# test if dest exists and overwrite is false
if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
# test if src and dst are the same
# (we assume that both uris are on the same server!)
ps=urlparse.urlparse(self.__src)[2]
pd=urlparse.urlparse(self.__dst)[2]
ps = urlparse.urlparse(self.__src)[2]
pd = urlparse.urlparse(self.__dst)[2]
if ps==pd: raise DAV_Error, 403
result=dc.copytree(self.__src,self.__dst,self.__overwrite)
result = dc.copytree(self.__src,self.__dst,self.__overwrite)
#result=copytree(dc,self.__src,self.__dst,self.__overwrite)
if not result: return None
@ -109,25 +109,26 @@ class COPY:
###
doc = Document(None)
ms=doc.createElement("D:multistatus")
ms = doc.createElement("D:multistatus")
ms.setAttribute("xmlns:D","DAV:")
doc.appendChild(ms)
for el,ec in result.items():
re=doc.createElement("D:response")
hr=doc.createElement("D:href")
st=doc.createElement("D:status")
huri=doc.createTextNode(quote_uri(el))
t=doc.createTextNode(gen_estring(ec))
re = doc.createElement("D:response")
hr = doc.createElement("D:href")
st = doc.createElement("D:status")
huri = doc.createTextNode(quote_uri(el))
t = doc.createTextNode(gen_estring(ec))
st.appendChild(t)
hr.appendChild(huri)
re.appendChild(hr)
re.appendChild(st)
ms.appendChild(re)
sfile=StringIO()
ext.PrettyPrint(doc,stream=sfile)
s=sfile.getvalue()
sfile = StringIO()
ext.PrettyPrint(doc,stream = sfile)
s = sfile.getvalue()
sfile.close()
return s
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -39,19 +39,19 @@ class MOVE:
""" move resources and eventually create multistatus responses
This module implements the MOVE class which is responsible for
moving resources.
moving resources.
MOVE is implemented by a COPY followed by a DELETE of the old
resource.
resource.
"""
def __init__(self,dataclass,src_uri,dst_uri,overwrite):
self.__dataclass=dataclass
self.__src=src_uri
self.__dst=dst_uri
self.__overwrite=overwrite
def __init__(self, dataclass, src_uri, dst_uri, overwrite):
self.__dataclass = dataclass
self.__src = src_uri
self.__dst = dst_uri
self.__overwrite = overwrite
def single_action(self):
@ -62,16 +62,16 @@ class MOVE:
"""
dc=self.__dataclass
base=self.__src
dc = self.__dataclass
base = self.__src
### some basic tests
# test if dest exists and overwrite is false
if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
# test if src and dst are the same
# (we assume that both uris are on the same server!)
ps=urlparse.urlparse(self.__src)[2]
pd=urlparse.urlparse(self.__dst)[2]
ps = urlparse.urlparse(self.__src)[2]
pd = urlparse.urlparse(self.__dst)[2]
if ps==pd: raise DAV_Error, 403
return dc.moveone(self.__src,self.__dst,self.__overwrite)
@ -82,21 +82,22 @@ class MOVE:
Here we return a multistatus xml element.
"""
dc=self.__dataclass
base=self.__src
dc = self.__dataclass
base = self.__src
### some basic tests
# test if dest exists and overwrite is false
if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
# test if src and dst are the same
# (we assume that both uris are on the same server!)
ps=urlparse.urlparse(self.__src)[2]
pd=urlparse.urlparse(self.__dst)[2]
ps = urlparse.urlparse(self.__src)[2]
pd = urlparse.urlparse(self.__dst)[2]
if ps==pd: raise DAV_Error, 403
result=dc.movetree(self.__src,self.__dst,self.__overwrite)
result = dc.movetree(self.__src,self.__dst,self.__overwrite)
if not result: return None
# create the multistatus XML element
return make_xmlresponse(result)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -32,15 +32,15 @@ from davcmd import deltree
class DELETE:
def __init__(self,uri,dataclass):
self.__dataclass=dataclass
self.__uri=uri
def __init__(self, uri, dataclass):
self.__dataclass = dataclass
self.__uri = uri
def delcol(self):
""" delete a collection """
dc=self.__dataclass
result=dc.deltree(self.__uri)
dc = self.__dataclass
result = dc.deltree(self.__uri)
if not len(result.items()):
return None # everything ok
@ -51,9 +51,9 @@ class DELETE:
def delone(self):
""" delete a resource """
dc=self.__dataclass
result=dc.delone(self.__uri)
dc = self.__dataclass
result = dc.delone(self.__uri)
if not result: return None
if not len(result.items()):
return None # everything ok
@ -61,3 +61,4 @@ class DELETE:
# create the result element
return make_xmlresponse(result)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -12,15 +12,15 @@ class DAV_Error(Exception):
2. the error result element, e.g. a <multistatus> element
"""
def __init__(self,*args):
def __init__(self, *args):
if len(args)==1:
self.args=(args[0],"")
self.args = (args[0],"")
else:
self.args=args
self.args = args
class DAV_Secret(DAV_Error):
""" the user is not allowed to know anything about it
returning this for a property value means to exclude it
from the response xml element.
"""
@ -31,10 +31,10 @@ class DAV_Secret(DAV_Error):
class DAV_NotFound(DAV_Error):
""" a requested property was not found for a resource """
def __init__(self,*args):
def __init__(self, *args):
if len(args):
if isinstance(args[0],list):
if isinstance(args[0], list):
stre = "Path %s not found!"%('/'.join(args[0]))
else:
stre = args[0]
@ -46,11 +46,12 @@ class DAV_NotFound(DAV_Error):
class DAV_Forbidden(DAV_Error):
""" a method on a resource is not allowed """
def __init__(self,*args):
def __init__(self, *args):
if len(args):
DAV_Error.__init__(self,403,args[0])
else:
DAV_Error.__init__(self,403)
pass
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -18,16 +18,16 @@ class dav_interface:
### defined properties (modify this but let the DAV stuff there!)
### the format is namespace: [list of properties]
PROPS={"DAV:" : ('creationdate',
'displayname',
'getcontentlanguage',
'getcontentlength',
'getcontenttype',
'getetag',
'getlastmodified',
'lockdiscovery',
'resourcetype',
'source',
PROPS={"DAV:" : ('creationdate',
'displayname',
'getcontentlanguage',
'getcontentlength',
'getcontenttype',
'getetag',
'getlastmodified',
'lockdiscovery',
'resourcetype',
'source',
'supportedlock'),
"NS2" : ("p1","p2")
}
@ -36,28 +36,28 @@ class dav_interface:
# the first item is the namespace URI and the second one
# the method prefix
# e.g. for DAV:getcontenttype we call dav_getcontenttype()
M_NS={"DAV:" : "_get_dav",
M_NS = {"DAV:" : "_get_dav",
"NS2" : "ns2" }
def get_propnames(self,uri):
""" return the property names allowed for the given URI
def get_propnames(self, uri):
""" return the property names allowed for the given URI
In this method we simply return the above defined properties
assuming that they are valid for any resource.
assuming that they are valid for any resource.
You can override this in order to return a different set
of property names for each resource.
"""
return self.PROPS
def get_prop2(self,uri,ns,pname):
""" return the value of a property
def get_prop2(self, uri, ns, pname):
""" return the value of a property
"""
if lower(ns)=="dav:": return self.get_dav(uri,pname)
raise DAV_NotFound
def get_prop(self,uri,ns,propname):
def get_prop(self, uri, ns, propname):
""" return the value of a given property
uri -- uri of the object to get the property of
@ -65,17 +65,17 @@ class dav_interface:
pname -- name of the property
"""
if self.M_NS.has_key(ns):
prefix=self.M_NS[ns]
prefix = self.M_NS[ns]
else:
print "No namespace:",ns, "( for prop:", propname,")"
raise DAV_NotFound
mname=prefix+"_"+propname
mname = prefix+"_"+propname
if not hasattr(self,mname):
raise DAV_NotFound
try:
m=getattr(self,mname)
r=m(uri)
m = getattr(self,mname)
r = m(uri)
return r
except AttributeError, e:
print 'Property %s not supported' % propname
@ -86,16 +86,16 @@ class dav_interface:
### DATA methods (for GET and PUT)
###
def get_data(self,uri):
""" return the content of an object
def get_data(self, uri):
""" return the content of an object
return data or raise an exception
"""
raise DAV_NotFound
def put(self,uri,data):
""" write an object to the repository
def put(self, uri, data):
""" write an object to the repository
return a result code or raise an exception
"""
@ -106,17 +106,17 @@ class dav_interface:
### Methods for DAV properties
###
def _get_dav_creationdate(self,uri):
def _get_dav_creationdate(self, uri):
""" return the creationdate of a resource """
d=self.get_creationdate(uri)
d = self.get_creationdate(uri)
# format it
if isinstance(d, int) or isinstance(d, float):
d = time.localtimetime(d)
return time.strftime("%Y-%m-%dT%H:%M:%S%Z",d)
def _get_dav_getlastmodified(self,uri):
def _get_dav_getlastmodified(self, uri):
""" return the last modified date of a resource """
d=self.get_lastmodified(uri)
d = self.get_lastmodified(uri)
if isinstance(d, int) or isinstance(d, float):
d = time.localtime(d)
# format it
@ -127,37 +127,37 @@ class dav_interface:
### OVERRIDE THESE!
###
def get_creationdate(self,uri):
def get_creationdate(self, uri):
""" return the creationdate of the resource """
return time.time()
def get_lastmodified(self,uri):
def get_lastmodified(self, uri):
""" return the last modification date of the resource """
return time.time()
###
### COPY MOVE DELETE
###
### methods for deleting a resource
def rmcol(self,uri):
""" delete a collection
def rmcol(self, uri):
""" delete a collection
This should not delete any children! This is automatically done
before by the DELETE class in DAV/delete.py
return a success code or raise an exception
"""
raise DAV_NotFound
def rm(self,uri):
""" delete a single resource
def rm(self, uri):
""" delete a single resource
return a success code or raise an exception
"""
raise DAV_NotFound
@ -182,7 +182,7 @@ class dav_interface:
1. to handle the action directly (e.g. cp or mv on filesystems)
2. to let it handle via the copy/move methods in davcmd.
ad 1) The first approach can be used when we know that no error can
ad 1) The first approach can be used when we know that no error can
happen inside a tree or when the action can exactly tell which
element made which error. We have to collect these and return
it in a dict of the form {uri: error_code, ...}
@ -210,28 +210,28 @@ class dav_interface:
### MOVE handlers
def moveone(self,src,dst,overwrite):
def moveone(self, src, dst, overwrite):
""" move one resource with Depth=0 """
return moveone(self,src,dst,overwrite)
return moveone(self, src, dst, overwrite)
def movetree(self,src,dst,overwrite):
def movetree(self, src, dst, overwrite):
""" move a collection with Depth=infinity """
return movetree(self,src,dst,overwrite)
return movetree(self, src, dst, overwrite)
### COPY handlers
def copyone(self,src,dst,overwrite):
def copyone(self, src, dst, overwrite):
""" copy one resource with Depth=0 """
return copyone(self,src,dst,overwrite)
return copyone(self, src, dst, overwrite)
def copytree(self,src,dst,overwrite):
def copytree(self, src, dst, overwrite):
""" copy a collection with Depth=infinity """
return copytree(self,src,dst,overwrite)
return copytree(self, src, dst, overwrite)
### low level copy methods (you only need these for method 2)
def copy(self,src,dst):
""" copy a resource with depth==0
def copy(self, src, dst):
""" copy a resource with depth==0
You don't need to bother about overwrite or not.
This has been done already.
@ -241,8 +241,8 @@ class dav_interface:
return 201
def copycol(self,src,dst):
""" copy a resource with depth==infinity
def copycol(self, src, dst):
""" copy a resource with depth==infinity
You don't need to bother about overwrite or not.
This has been done already.
@ -253,11 +253,12 @@ class dav_interface:
### some utility functions you need to implement
def exists(self,uri):
def exists(self, uri):
""" return 1 or None depending on if a resource exists """
return None # no
def is_collection(self,uri):
def is_collection(self, uri):
""" return 1 or None depending on if a resource is a collection """
return None # no
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -18,8 +18,8 @@
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
"""
from xml.dom import ext
from xml.dom.Document import Document
@ -45,9 +45,9 @@ class PROPFIND:
It will set the following instance vars:
request_class : ALLPROP | PROPNAME | PROP
proplist : list of properties
nsmap : map of namespaces
request_class: ALLPROP | PROPNAME | PROP
proplist: list of properties
nsmap: map of namespaces
The list of properties will contain tuples of the form
(element name, ns_prefix, ns_uri)
@ -55,21 +55,20 @@ class PROPFIND:
"""
def __init__(self, uri, dataclass, depth):
self.request_type = None
self.nsmap = {}
self.proplist = {}
self.default_ns = None
self.__dataclass = dataclass
self.__depth = str(depth)
self.__uri = uri
self.use_full_urls = True
self.__has_body = None # did we parse a body?
def __init__(self,uri,dataclass,depth):
self.request_type=None
self.nsmap={}
self.proplist={}
self.default_ns=None
self.__dataclass=dataclass
self.__depth=str(depth)
self.__uri=uri
self.use_full_urls=True
self.__has_body=None # did we parse a body?
def read_propfind(self, xml_doc):
self.request_type,self.proplist,self.namespaces = utils.parse_propfind(xml_doc)
def read_propfind(self,xml_doc):
self.request_type,self.proplist,self.namespaces=utils.parse_propfind(xml_doc)
# a violation of the expected logic: client (korganizer) will ask for DAV:resourcetype
# but we also have to return the http://groupdav.org/:resourcetype property!
if self.proplist.has_key('DAV:') and 'resourcetype' in self.proplist['DAV:']:
@ -91,7 +90,7 @@ class PROPFIND:
If we get an ALLPROP we first get the list of properties and then
we do the same as with a PROP method.
If the uri doesn't exist, return an xml response with a 404 status
"""
@ -114,41 +113,41 @@ class PROPFIND:
def create_propname(self):
""" create a multistatus response for the prop names """
dc=self.__dataclass
dc = self.__dataclass
# create the document generator
doc = Document(None)
ms=doc.createElement("D:multistatus")
ms = doc.createElement("D:multistatus")
ms.setAttribute("xmlns:D","DAV:")
doc.appendChild(ms)
if self.__depth=="0":
pnames=dc.get_propnames(self.__uri)
re=self.mk_propname_response(self.__uri,pnames,doc)
pnames = dc.get_propnames(self.__uri)
re = self.mk_propname_response(self.__uri,pnames,doc)
ms.appendChild(re)
elif self.__depth=="1":
pnames=dc.get_propnames(self.__uri)
re=self.mk_propname_response(self.__uri,pnames,doc)
pnames = dc.get_propnames(self.__uri)
re = self.mk_propname_response(self.__uri,pnames,doc)
ms.appendChild(re)
for newuri in dc.get_childs(self.__uri):
pnames=dc.get_propnames(newuri)
re=self.mk_propname_response(newuri,pnames,doc)
pnames = dc.get_propnames(newuri)
re = self.mk_propname_response(newuri,pnames,doc)
ms.appendChild(re)
# *** depth=="infinity"
sfile=StringIO()
ext.PrettyPrint(doc,stream=sfile)
s=sfile.getvalue()
sfile = StringIO()
ext.PrettyPrint(doc,stream = sfile)
s = sfile.getvalue()
sfile.close()
return s
def create_allprop(self):
""" return a list of all properties """
self.proplist={}
self.namespaces=[]
self.proplist = {}
self.namespaces = []
for ns,plist in self.__dataclass.get_propnames(self.__uri).items():
self.proplist[ns]=plist
self.proplist[ns] = plist
self.namespaces.append(ns)
return self.create_prop()
@ -178,32 +177,32 @@ class PROPFIND:
# create the document generator
doc = Document(None)
ms=doc.createElement("D:multistatus")
ms = doc.createElement("D:multistatus")
ms.setAttribute("xmlns:D","DAV:")
doc.appendChild(ms)
if self.__depth=="0":
gp,bp=self.get_propvalues(self.__uri)
res=self.mk_prop_response(self.__uri,gp,bp,doc)
gp,bp = self.get_propvalues(self.__uri)
res = self.mk_prop_response(self.__uri,gp,bp,doc)
ms.appendChild(res)
elif self.__depth=="1":
gp,bp=self.get_propvalues(self.__uri)
res=self.mk_prop_response(self.__uri,gp,bp,doc)
gp,bp = self.get_propvalues(self.__uri)
res = self.mk_prop_response(self.__uri,gp,bp,doc)
ms.appendChild(res)
try:
for newuri in self.__dataclass.get_childs(self.__uri):
gp,bp=self.get_propvalues(newuri)
res=self.mk_prop_response(newuri,gp,bp,doc)
gp,bp = self.get_propvalues(newuri)
res = self.mk_prop_response(newuri,gp,bp,doc)
ms.appendChild(res)
except DAV_NotFound:
# If no children, never mind.
pass
sfile=StringIO()
ext.PrettyPrint(doc,stream=sfile)
s=sfile.getvalue()
sfile = StringIO()
ext.PrettyPrint(doc,stream = sfile)
s = sfile.getvalue()
sfile.close()
return s
@ -215,32 +214,32 @@ class PROPFIND:
propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...}
"""
re=doc.createElement("D:response")
re = doc.createElement("D:response")
# write href information
href=doc.createElement("D:href")
href = doc.createElement("D:href")
if self.use_full_urls:
huri=doc.createTextNode(uri)
huri = doc.createTextNode(uri)
else:
uparts=urlparse.urlparse(uri)
fileloc=uparts[2]
huri=doc.createTextNode(urllib.quote(fileloc.encode('utf8')))
uparts = urlparse.urlparse(uri)
fileloc = uparts[2]
huri = doc.createTextNode(urllib.quote(fileloc.encode('utf8')))
href.appendChild(huri)
re.appendChild(href)
ps=doc.createElement("D:propstat")
nsnum=0
ps = doc.createElement("D:propstat")
nsnum = 0
for ns,plist in propnames.items():
# write prop element
pr=doc.createElement("D:prop")
nsp="ns"+str(nsnum)
pr = doc.createElement("D:prop")
nsp = "ns"+str(nsnum)
pr.setAttribute("xmlns:"+nsp,ns)
nsnum=nsnum+1
nsnum = nsnum+1
# write propertynames
for p in plist:
pe=doc.createElement(nsp+":"+p)
pe = doc.createElement(nsp+":"+p)
pr.appendChild(pe)
ps.appendChild(pr)
@ -257,33 +256,33 @@ class PROPFIND:
one, that means).
"""
re=doc.createElement("D:response")
re = doc.createElement("D:response")
# append namespaces to response
nsnum=0
nsnum = 0
for nsname in self.namespaces:
re.setAttribute("xmlns:ns"+str(nsnum),nsname)
nsnum=nsnum+1
nsnum = nsnum+1
# write href information
href=doc.createElement("D:href")
href = doc.createElement("D:href")
if self.use_full_urls:
huri=doc.createTextNode(uri)
huri = doc.createTextNode(uri)
else:
uparts=urlparse.urlparse(uri)
fileloc=uparts[2]
huri=doc.createTextNode(urllib.quote(fileloc.encode('utf8')))
uparts = urlparse.urlparse(uri)
fileloc = uparts[2]
huri = doc.createTextNode(urllib.quote(fileloc.encode('utf8')))
href.appendChild(huri)
re.appendChild(href)
# write good properties
if good_props and len(good_props.items()):
ps=doc.createElement("D:propstat")
ps = doc.createElement("D:propstat")
gp=doc.createElement("D:prop")
gp = doc.createElement("D:prop")
for ns in good_props.keys():
ns_prefix="ns"+str(self.namespaces.index(ns))+":"
for p,v in good_props[ns].items():
pe=doc.createElement(ns_prefix+str(p))
pe = doc.createElement(ns_prefix+str(p))
if v == None:
pass
elif ns=='DAV:' and p=="resourcetype":
@ -294,15 +293,15 @@ class PROPFIND:
ve=doc.createElement(ns_prefix+v[0])
pe.appendChild(ve)
else:
ve=doc.createTextNode(utf8str(v))
ve = doc.createTextNode(utf8str(v))
pe.appendChild(ve)
gp.appendChild(pe)
if gp.hasChildNodes():
re.appendChild(ps)
ps.appendChild(gp)
s=doc.createElement("D:status")
t=doc.createTextNode("HTTP/1.1 200 OK")
s = doc.createElement("D:status")
t = doc.createTextNode("HTTP/1.1 200 OK")
s.appendChild(t)
ps.appendChild(s)
re.appendChild(ps)
@ -312,20 +311,20 @@ class PROPFIND:
# write a propstat for each error code
for ecode in bad_props.keys():
ps=doc.createElement("D:propstat")
ps = doc.createElement("D:propstat")
re.appendChild(ps)
bp=doc.createElement("D:prop")
bp = doc.createElement("D:prop")
ps.appendChild(bp)
for ns in bad_props[ecode].keys():
ns_prefix="ns"+str(self.namespaces.index(ns))+":"
ns_prefix = "ns"+str(self.namespaces.index(ns))+":"
for p in bad_props[ecode][ns]:
pe=doc.createElement(ns_prefix+str(p))
pe = doc.createElement(ns_prefix+str(p))
bp.appendChild(pe)
s=doc.createElement("D:status")
t=doc.createTextNode(utils.gen_estring(ecode))
s = doc.createElement("D:status")
t = doc.createTextNode(utils.gen_estring(ecode))
s.appendChild(t)
ps.appendChild(s)
re.appendChild(ps)
@ -342,20 +341,20 @@ class PROPFIND:
found or the user is not allowed to read them.
"""
good_props={}
bad_props={}
good_props = {}
bad_props = {}
for (ns,plist) in self.proplist.items():
good_props[ns]={}
bad_props={}
good_props[ns] = {}
bad_props = {}
ec = 0
for prop in plist:
try:
ec = 0
r=self.__dataclass.get_prop(uri,ns,prop)
good_props[ns][prop]=r
r = self.__dataclass.get_prop(uri,ns,prop)
good_props[ns][prop] = r
except DAV_Error, error_code:
ec=error_code[0]
ec = error_code[0]
# ignore props with error_code if 0 (invisible)
if ec==0: continue
@ -364,9 +363,11 @@ class PROPFIND:
if bad_props[ec].has_key(ns):
bad_props[ec][ns].append(prop)
else:
bad_props[ec][ns]=[prop]
bad_props[ec][ns] = [prop]
else:
bad_props[ec]={ns:[prop]}
bad_props[ec] = {ns:[prop]}
return good_props, bad_props
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -27,7 +27,7 @@ AUTHOR = 'Simon Pamies <s.pamies@banality.de>'
def gen_estring(ecode):
""" generate an error string from the given code """
ec=atoi(str(ecode))
ec = atoi(str(ecode))
if STATUS_CODES.has_key(ec):
return "HTTP/1.1 %s %s" %(ec,STATUS_CODES[ec])
else:
@ -46,20 +46,20 @@ def parse_propfind(xml_doc):
doc = PyExpat.Reader().fromString(xml_doc)
snit = doc.createNodeIterator(doc, NodeFilter.NodeFilter.SHOW_ELEMENT, None, None)
request_type=None
props={}
namespaces=[]
request_type = None
props = {}
namespaces = []
while 1:
curr_elem = snit.nextNode()
if not curr_elem: break
ename=fname=lower(curr_elem.nodeName)
ename=fname = lower(curr_elem.nodeName)
if ":" in fname:
ename=split(fname,":")[1]
if ename=="prop": request_type=RT_PROP; continue
ename = split(fname,":")[1]
if ename=="prop": request_type = RT_PROP; continue
if ename=="propfind": continue
if ename=="allprop": request_type=RT_ALLPROP; continue
if ename=="propname": request_type=RT_PROPNAME; continue
if ename=="allprop": request_type = RT_ALLPROP; continue
if ename=="propname": request_type = RT_PROPNAME; continue
# rest should be names of attributes
@ -67,13 +67,13 @@ def parse_propfind(xml_doc):
if props.has_key(ns):
props[ns].append(ename)
else:
props[ns]=[ename]
props[ns] = [ename]
namespaces.append(ns)
return request_type,props,namespaces
def create_treelist(dataclass,uri):
def create_treelist(dataclass, uri):
""" create a list of resources out of a tree
This function is used for the COPY, MOVE and DELETE methods
@ -83,23 +83,23 @@ def create_treelist(dataclass,uri):
It will return the flattened tree as list
"""
queue=[uri]
list=[uri]
queue = [uri]
list = [uri]
while len(queue):
element=queue[-1]
element = queue[-1]
if dataclass.is_collection(element):
childs=dataclass.get_childs(element)
childs = dataclass.get_childs(element)
else:
childs=[]
childs = []
if len(childs):
list=list+childs
list = list+childs
# update queue
del queue[-1]
if len(childs):
queue=queue+childs
queue = queue+childs
return list
def is_prefix(uri1,uri2):
def is_prefix(uri1, uri2):
""" returns 1 of uri1 is a prefix of uri2 """
if uri2[:len(uri1)]==uri1:
return 1
@ -111,50 +111,51 @@ def quote_uri(uri):
import urlparse
import urllib
up=urlparse.urlparse(uri)
np=urllib.quote(up[2])
return urlparse.urlunparse((up[0],up[1],np,up[3],up[4],up[5]))
up = urlparse.urlparse(uri)
np = urllib.quote(up[2])
return urlparse.urlunparse((up[0], up[1], np, up[3], up[4], up[5]))
def get_uriparentpath(uri):
""" extract the uri path and remove the last element """
up=urlparse.urlparse(uri)
return joinfields(split(up[2],"/")[:-1],"/")
up = urlparse.urlparse(uri)
return joinfields(split(up[2], "/")[:-1], "/")
def get_urifilename(uri):
""" extract the uri path and return the last element """
up=urlparse.urlparse(uri)
return split(up[2],"/")[-1]
up = urlparse.urlparse(uri)
return split(up[2], "/")[-1]
def get_parenturi(uri):
""" return the parent of the given resource"""
up=urlparse.urlparse(uri)
np=joinfields(split(up[2],"/")[:-1],"/")
return urlparse.urlunparse((up[0],up[1],np,up[3],up[4],up[5]))
up = urlparse.urlparse(uri)
np = joinfields(split(up[2], "/")[:-1], "/")
return urlparse.urlunparse((up[0], up[1], np, up[3], up[4], up[5]))
### XML utilities
def make_xmlresponse(result):
""" construct a response from a dict of uri:error_code elements """
doc = Document(None)
ms=doc.createElement("D:multistatus")
ms.setAttribute("xmlns:D","DAV:")
ms = doc.createElement("D:multistatus")
ms.setAttribute("xmlns:D", "DAV:")
doc.appendChild(ms)
for el,ec in result.items():
re=doc.createElement("D:response")
hr=doc.createElement("D:href")
st=doc.createElement("D:status")
huri=doc.createTextNode(quote_uri(el))
t=doc.createTextNode(gen_estring(ec))
for el, ec in result.items():
re = doc.createElement("D:response")
hr = doc.createElement("D:href")
st = doc.createElement("D:status")
huri = doc.createTextNode(quote_uri(el))
t = doc.createTextNode(gen_estring(ec))
st.appendChild(t)
hr.appendChild(huri)
re.appendChild(hr)
re.appendChild(st)
ms.appendChild(re)
sfile=StringIO()
ext.PrettyPrint(doc,stream=sfile)
s=sfile.getvalue()
sfile = StringIO()
ext.PrettyPrint(doc, stream = sfile)
s = sfile.getvalue()
sfile.close()
return s
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@ -36,14 +36,21 @@ import time
try:
import vobject
except ImportError:
raise osv.except_osv('vobject Import Error!','Please install python-vobject from http://vobject.skyhouseconsulting.com/')
raise osv.except_osv('vobject Import Error!','Please install python-vobject \
from http://vobject.skyhouseconsulting.com/')
# O-1 Optional and can come only once
# O-n Optional and can come more than once
# R-1 Required and can come only once
# R-n Required and can come more than once
def uid2openobjectid(cr, uidval, oomodel, rdate):
""" UID To Open Object Id
@param cr: the current row, from the database cursor,
@param uidval: Get USerId vale
@oomodel: Open Object ModelName
@param rdate: Get Recurrent Date
"""
__rege = re.compile(r'OpenObject-([\w|\.]+)_([0-9]+)@(\w+)$')
wematch = __rege.match(uidval.encode('utf8'))
if not wematch:
@ -60,17 +67,28 @@ def uid2openobjectid(cr, uidval, oomodel, rdate):
r_id = cr.fetchone()
if r_id:
return (id, r_id[0])
cr.execute(qry)
cr.execute(qry)
ids = map(lambda x: str(x[0]), cr.fetchall())
if id in ids:
return (id, None)
return (False, None)
def openobjectid2uid(cr, uidval, oomodel):
""" Open Object Id To UId
@param cr: the current row, from the database cursor,
@param uidval: Get USerId vale
@oomodel: Open Object ModelName """
value = 'OpenObject-%s_%s@%s' % (oomodel, uidval, cr.dbname)
return value
def get_attribute_mapping(cr, uid, calname, context={}):
""" Attribute Mapping with Basic calendar fields and lines
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param calname: Get Calendar name
@param context: A standard dictionary for contextual values """
if not context:
context = {}
pool = pooler.get_pool(cr.dbname)
@ -100,6 +118,10 @@ def get_attribute_mapping(cr, uid, calname, context={}):
return res
def map_data(cr, uid, obj):
""" Map Data
@param self: The object pointer
@param cr: the current row, from the database cursor,"""
vals = {}
for map_dict in obj.__attribute__:
map_val = obj.ical_get(map_dict, 'value')
@ -146,14 +168,26 @@ def map_data(cr, uid, obj):
class CalDAV(object):
__attribute__ = {}
def ical_set(self, name, value, type):
""" set calendar Attribute
@param self: The object pointer,
@param name: Get Attribute Name
@param value: Get Attribute Value
@param type: Get Attribute Type
"""
if name in self.__attribute__ and self.__attribute__[name]:
self.__attribute__[name][type] = value
return True
def ical_get(self, name, type):
""" Get calendar Attribute
@param self: The object pointer,
@param name: Get Attribute Name
@param type: Get Attribute Type
"""
if self.__attribute__.get(name):
val = self.__attribute__.get(name).get(type, None)
valtype = self.__attribute__.get(name).get('type', None)
@ -168,12 +202,23 @@ class CalDAV(object):
return self.__attribute__.get(name, None)
def ical_reset(self, type):
""" Reset Calendar Attribute
@param self: The object pointer,
@param type: Get Attribute Type
"""
for name in self.__attribute__:
if self.__attribute__[name]:
self.__attribute__[name][type] = None
return True
def parse_ics(self, cr, uid, child, cal_children=None, context=None):
""" parse calendaring and scheduling information
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values """
att_data = []
for cal_data in child.getChildren():
if cal_data.name.lower() == 'attendee':
@ -197,7 +242,7 @@ class CalDAV(object):
self.ical_set(cal_data.name.lower(), ','.join(exval), 'value')
continue
if cal_data.name.lower() in self.__attribute__:
if cal_data.params.get('X-VOBJ-ORIGINAL-TZID'):
self.ical_set('vtimezone', cal_data.params.get('X-VOBJ-ORIGINAL-TZID'), 'value')
self.ical_set(cal_data.name.lower(), cal_data.value, 'value')
@ -205,6 +250,12 @@ class CalDAV(object):
return vals
def create_ics(self, cr, uid, datas, name, ical, context=None):
""" create calendaring and scheduling information
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values """
if not datas:
return
timezones = []
@ -223,10 +274,10 @@ class CalDAV(object):
model_obj = self.pool.get(model)
r_ids = []
if model_obj._columns.get('recurrent_uid', None):
cr.execute('select id from %s where recurrent_uid=%s'
cr.execute('select id from %s where recurrent_uid=%s'
% (model_obj._table, data[map_field]))
r_ids = map(lambda x: x[0], cr.fetchall())
if r_ids:
if r_ids:
rdata = self.pool.get(model).read(cr, uid, r_ids)
event_obj = self.pool.get('basic.calendar.event')
rcal = event_obj.export_cal(cr, uid, rdata, context=context)
@ -258,7 +309,7 @@ class CalDAV(object):
if field in ('exdate'):
vevent.add(field).value = map(parser.parse, (data[map_field]).split(','))
else:
vevent.add(field).value = tools.ustr(data[map_field])
vevent.add(field).value = tools.ustr(data[map_field])
elif map_type in ('datetime', 'date') and data[map_field]:
dtfield = vevent.add(field)
dtfield.value = parser.parse(data[map_field])
@ -278,8 +329,16 @@ class CalDAV(object):
if val1 == data[map_field]:
vevent.add(field).value = key1
return vevent
def check_import(self, cr, uid, vals, context={}):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get Values
@param context: A standard dictionary for contextual values
"""
ids = []
model_obj = self.pool.get(context.get('model'))
recur_pool = {}
@ -311,6 +370,14 @@ class CalDAV(object):
return ids
def export_cal(self, cr, uid, datas, vobj=None, context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param datas: Get Data's for caldav
@param context: A standard dictionary for contextual values
"""
try:
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context)
ical = vobject.iCalendar()
@ -320,6 +387,14 @@ class CalDAV(object):
raise osv.except_osv(('Error !'), (str(e)))
def import_cal(self, cr, uid, content, data_id=None, context=None):
""" Import Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param data_id: Get Datas ID or False
@param context: A standard dictionary for contextual values
"""
ical_data = base64.decodestring(content)
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context)
parsedCal = vobject.readOne(ical_data)
@ -335,6 +410,7 @@ class CalDAV(object):
self.ical_reset('value')
return res
class Calendar(CalDAV, osv.osv):
_name = 'basic.calendar'
_description = 'Calendar'
@ -354,27 +430,35 @@ class Calendar(CalDAV, osv.osv):
'vtimezone': None, # Use: O-n, Type: Collection of Timezone class
}
_columns = {
'name': fields.char("Name", size=64),
'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'),
'active': fields.boolean('Active'),
'create_date': fields.datetime('Created Date'),
'write_date': fields.datetime('Modifided Date'),
'name': fields.char("Name", size=64),
'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'),
'active': fields.boolean('Active'),
'create_date': fields.datetime('Created Date'),
'write_date': fields.datetime('Modifided Date'),
}
_defaults = {
'active': lambda *a: True,
'active': lambda *a: True,
}
def export_cal(self, cr, uid, ids, vobj='vevent', context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendars IDs
@param context: A standard dictionary for contextual values
"""
cal = self.browse(cr, uid, ids[0])
ical = vobject.iCalendar()
ical = vobject.iCalendar()
for line in cal.line_ids:
if line.name in ('valarm', 'attendee'):
continue
mod_obj = self.pool.get(line.object_id.model)
data_ids = mod_obj.search(cr, uid, eval(line.domain), context=context)
datas = mod_obj.read(cr, uid, data_ids, context=context)
context.update({'model': line.object_id.model,
context.update({'model': line.object_id.model,
'calendar_id': cal.id
})
self.__attribute__ = get_attribute_mapping(cr, uid, line.name, context)
@ -382,6 +466,14 @@ class Calendar(CalDAV, osv.osv):
return ical.serialize()
def import_cal(self, cr, uid, content, data_id=None, context=None):
""" Import Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param data_id: Get Datas ID or False
@param context: A standard dictionary for contextual values
"""
if not context:
context = {}
vals = []
@ -396,7 +488,7 @@ class Calendar(CalDAV, osv.osv):
cal_children[line.name] = line.object_id.model
for child in parsedCal.getChildren():
if child.name.lower() in cal_children:
context.update({'model': cal_children[child.name.lower()],
context.update({'model': cal_children[child.name.lower()],
'calendar_id': cal.id
})
self.__attribute__ = get_attribute_mapping(cr, uid, child.name.lower(), context=context)
@ -409,27 +501,39 @@ class Calendar(CalDAV, osv.osv):
self.check_import(cr, uid, vals, context=context)
return {}
Calendar()
class basic_calendar_line(osv.osv):
""" Calendar Lines """
_name = 'basic.calendar.lines'
_description = 'Calendar Lines'
_columns = {
'name': fields.selection([('vevent', 'Event'), ('vtodo', 'TODO'), \
('valarm', 'Alarm'), \
('attendee', 'Attendee')], \
string="Type", size=64),
'object_id': fields.many2one('ir.model', 'Object'),
string="Type", size=64),
'object_id': fields.many2one('ir.model', 'Object'),
'calendar_id': fields.many2one('basic.calendar', 'Calendar', \
required=True, ondelete='cascade'),
'domain': fields.char('Domain', size=124),
required=True, ondelete='cascade'),
'domain': fields.char('Domain', size=124),
'mapping_ids': fields.one2many('basic.calendar.fields', 'type_id', 'Fields Mapping')
}
}
_defaults = {
'domain': lambda *a: '[]',
'domain': lambda *a: '[]',
}
def create(self, cr, uid, vals, context={}):
""" create calendar's line
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get the Values
@param context: A standard dictionary for contextual values
"""
cr.execute("Select count(id) from basic_calendar_lines \
where name='%s' and calendar_id=%s" % (vals.get('name'), vals.get('calendar_id')))
res = cr.fetchone()
@ -441,41 +545,52 @@ line "%s" more than once' % (vals.get('name'))))
basic_calendar_line()
class basic_calendar_attribute(osv.osv):
_name = 'basic.calendar.attributes'
_description = 'Calendar attributes'
_columns = {
'name': fields.char("Name", size=64, required=True),
_columns = {
'name': fields.char("Name", size=64, required=True),
'type': fields.selection([('vevent', 'Event'), ('vtodo', 'TODO'), \
('alarm', 'Alarm'), \
('attendee', 'Attendee')], \
string="Type", size=64, required=True),
string="Type", size=64, required=True),
}
basic_calendar_attribute()
class basic_calendar_fields(osv.osv):
""" Calendar fields """
_name = 'basic.calendar.fields'
_description = 'Calendar fields'
_columns = {
'field_id': fields.many2one('ir.model.fields', 'OpenObject Field'),
'name': fields.many2one('basic.calendar.attributes', 'Name', required=True),
'field_id': fields.many2one('ir.model.fields', 'OpenObject Field'),
'name': fields.many2one('basic.calendar.attributes', 'Name', required=True),
'type_id': fields.many2one('basic.calendar.lines', 'Type', \
required=True, ondelete='cascade'),
'expr': fields.char("Expression", size=64),
'fn': fields.selection([('field', 'Use the field'),
('const', 'Expression as constant'),
('hours', 'Interval in hours'),
], 'Function'),
'mapping': fields.text('Mapping'),
required=True, ondelete='cascade'),
'expr': fields.char("Expression", size=64),
'fn': fields.selection([('field', 'Use the field'),
('const', 'Expression as constant'),
('hours', 'Interval in hours'),
], 'Function'),
'mapping': fields.text('Mapping'),
}
_defaults = {
'fn': lambda *a: 'field',
'fn': lambda *a: 'field',
}
def check_line(self, cr, uid, vals, name, context=None):
""" check calendar's line
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get Values
@param context: A standard dictionary for contextual values
"""
f_obj = self.pool.get('ir.model.fields')
field = f_obj.browse(cr, uid, vals['field_id'], context=context)
relation = field.relation
@ -487,8 +602,16 @@ class basic_calendar_fields(osv.osv):
if (relation != 'NULL') and (not relation == line_rel):
raise osv.except_osv(_('Warning !'), _('Please provide proper configuration of "%s" in Calendar Lines' % (name)))
return True
def create(self, cr, uid, vals, context={}):
""" Create Calendar's fields
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get Values
@param context: A standard dictionary for contextual values
"""
cr.execute('select name from basic_calendar_attributes \
where id=%s' % (vals.get('name')))
name = cr.fetchone()
@ -502,8 +625,16 @@ class basic_calendar_fields(osv.osv):
if res[0] > 0:
raise osv.except_osv(_('Warning !'), _('Can not map the field more than once'))
return super(basic_calendar_fields, self).create(cr, uid, vals, context=context)
def write(self, cr, uid, ids, vals, context=None):
""" write Calendar's fields
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get Values
@param context: A standard dictionary for contextual values
"""
if not vals:
return
for id in ids:
@ -522,6 +653,7 @@ class basic_calendar_fields(osv.osv):
basic_calendar_fields()
class Event(CalDAV, osv.osv_memory):
_name = 'basic.calendar.event'
_calname = 'vevent'
@ -542,7 +674,7 @@ class Event(CalDAV, osv.osv_memory):
'transp': None, # Use: O-1, Type: TEXT, Defines whether an event is transparent or not to busy time searches.
'uid': None, # Use: O-1, Type: TEXT, Defines the persistent, globally unique identifier for the calendar component.
'url': None, # Use: O-1, Type: URL, Defines a Uniform Resource Locator (URL) associated with the iCalendar object.
'recurid': None,
'recurid': None,
'attach': None, # Use: O-n, Type: BINARY, Provides the capability to associate a document object with a calendar component.
'attendee': None, # Use: O-n, Type: CAL-ADDRESS, Defines an "Attendee" within a calendar component.
'categories': None, # Use: O-n, Type: TEXT, Defines the categories for a calendar component.
@ -550,69 +682,89 @@ class Event(CalDAV, osv.osv_memory):
'contact': None, # Use: O-n, Type: TEXT, Used to represent contact information or alternately a reference to contact information associated with the calendar component.
'exdate': None, # Use: O-n, Type: DATE-TIME, Defines the list of date/time exceptions for a recurring calendar component.
'exrule': None, # Use: O-n, Type: RECUR, Defines a rule or repeating pattern for an exception to a recurrence set.
'rstatus': None,
'rstatus': None,
'related': None, # Use: O-n, Specify the relationship of the alarm trigger with respect to the start or end of the calendar component.
# like A trigger set 5 minutes after the end of the event or to-do.---> TRIGGER;related=END:PT5M
'resources': None, # Use: O-n, Type: TEXT, Defines the equipment or resources anticipated for an activity specified by a calendar entity like RESOURCES:EASEL,PROJECTOR,VCR, LANGUAGE=fr:1 raton-laveur
'rdate': None, # Use: O-n, Type: DATE-TIME, Defines the list of date/times for a recurrence set.
'rrule': None, # Use: O-n, Type: RECUR, Defines a rule or repeating pattern for recurring events, to-dos, or time zone definitions.
'x-prop': None,
'x-prop': None,
'duration': None, # Use: O-1, Type: DURATION, Specifies a positive duration of time.
'dtend': None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that a calendar component ends.
}
def export_cal(self, cr, uid, datas, vobj='vevent', context={}):
""" Export calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param datas: Get datas
@param context: A standard dictionary for contextual values
"""
return super(Event, self).export_cal(cr, uid, datas, 'vevent', context=context)
Event()
class ToDo(CalDAV, osv.osv_memory):
_name = 'basic.calendar.todo'
_calname = 'vtodo'
__attribute__ = {
'class': None,
'completed': None,
'created': None,
'description': None,
'dtstamp': None,
'dtstart': None,
'duration': None,
'due': None,
'geo': None,
'last-mod ': None,
'location': None,
'organizer': None,
'percent': None,
'priority': None,
'recurid': None,
'seq': None,
'status': None,
'summary': None,
'uid': None,
'url': None,
'attach': None,
'attendee': None,
'categories': None,
'comment': None,
'contact': None,
'exdate': None,
'exrule': None,
'rstatus': None,
'related': None,
'resources': None,
'rdate': None,
'rrule': None,
'class': None,
'completed': None,
'created': None,
'description': None,
'dtstamp': None,
'dtstart': None,
'duration': None,
'due': None,
'geo': None,
'last-mod ': None,
'location': None,
'organizer': None,
'percent': None,
'priority': None,
'recurid': None,
'seq': None,
'status': None,
'summary': None,
'uid': None,
'url': None,
'attach': None,
'attendee': None,
'categories': None,
'comment': None,
'contact': None,
'exdate': None,
'exrule': None,
'rstatus': None,
'related': None,
'resources': None,
'rdate': None,
'rrule': None,
}
def export_cal(self, cr, uid, datas, vobj='vevent', context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param datas: Get datas
@param context: A standard dictionary for contextual values
"""
return super(ToDo, self).export_cal(cr, uid, datas, 'vtodo', context=context)
ToDo()
class Journal(CalDAV):
__attribute__ = {
}
class FreeBusy(CalDAV):
__attribute__ = {
'contact': None, # Use: O-1, Type: Text, Represent contact information or alternately a reference to contact information associated with the calendar component.
@ -626,15 +778,15 @@ class FreeBusy(CalDAV):
'attendee': None, # Use: O-n, Type: CAL-ADDRESS, Defines an "Attendee" within a calendar component.
'comment': None, # Use: O-n, Type: TEXT, Specifies non-processing information intended to provide a comment to the calendar user.
'freebusy': None, # Use: O-n, Type: PERIOD, Defines one or more free or busy time intervals.
'rstatus': None,
'X-prop': None,
'rstatus': None,
'X-prop': None,
}
class Timezone(CalDAV, osv.osv_memory):
_name = 'basic.calendar.timezone'
_calname = 'vtimezone'
__attribute__ = {
'tzid': {'field': 'tzid'}, # Use: R-1, Type: Text, Specifies the text value that uniquely identifies the "VTIMEZONE" calendar component.
'last-mod': None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that the information associated with the calendar component was last revised in the calendar store.
@ -643,8 +795,15 @@ class Timezone(CalDAV, osv.osv_memory):
'daylightc': {'tzprop': None}, # Use: R-1,
'x-prop': None, # Use: O-n, Type: Text,
}
def get_name_offset(self, cr, uid, tzid, context={}):
""" Get Name Offset value
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values
"""
mytz = pytz.timezone(tzid.title())
mydt = datetime.now(tz=mytz)
offset = mydt.utcoffset()
@ -655,6 +814,14 @@ class Timezone(CalDAV, osv.osv_memory):
return (mydt.tzname(), realoffset)
def export_cal(self, cr, uid, model, tzid, ical, context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param model: Get Model's name
@param context: A standard dictionary for contextual values
"""
ctx = context.copy()
ctx.update({'model': model})
cal_tz = ical.add('vtimezone')
@ -666,8 +833,16 @@ class Timezone(CalDAV, osv.osv_memory):
tz_std.add("DTSTART").value = datetime.now() # TODO
tz_std.add("TZNAME").value = tzname
return ical
def import_cal(self, cr, uid, ical_data, context=None):
""" Import Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ical_data: Get calendar's data
@param context: A standard dictionary for contextual values
"""
for child in ical_data.getChildren():
if child.name.lower() == 'tzid':
tzname = child.value
@ -675,7 +850,7 @@ class Timezone(CalDAV, osv.osv_memory):
vals = map_data(cr, uid, self)
return vals
Timezone()
Timezone()
class Alarm(CalDAV, osv.osv_memory):
@ -691,10 +866,19 @@ class Alarm(CalDAV, osv.osv_memory):
'duration': None, # Type: DURATION, Duration' and 'repeat' are both optional, and MUST NOT occur more than once each, but if one occurs, so MUST the other. Use:- 0-1 for AUDIO, EMAIL and PROCEDURE, Use:- 0-n for DISPLAY
'repeat': None, # Type: INTEGER, Duration' and 'repeat' are both optional, and MUST NOT occur more than once each, but if one occurs, so MUST the other. Use:- 0-1 for AUDIO, EMAIL and PROCEDURE, Use:- 0-n for DISPLAY
'attach': None, # Use:- O-n: which MUST point to a sound resource, which is rendered when the alarm is triggered for AUDIO, Use:- O-n: which are intended to be sent as message attachments for EMAIL, Use:- R-1:which MUST point to a procedure resource, which is invoked when the alarm is triggered for PROCEDURE.
'x-prop': None,
'x-prop': None,
}
def export_cal(self, cr, uid, model, alarm_id, vevent, context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param model: Get Model's name
@param alarm_id: Get Alarm's Id
@param context: A standard dictionary for contextual values
"""
valarm = vevent.add('valarm')
alarm_object = self.pool.get(model)
alarm_data = alarm_object.read(cr, uid, alarm_id, [])
@ -721,6 +905,14 @@ class Alarm(CalDAV, osv.osv_memory):
return vevent
def import_cal(self, cr, uid, ical_data, context=None):
""" Import Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ical_data: Get calendar's Data
@param context: A standard dictionary for contextual values
"""
ctx = context.copy()
ctx.update({'model': context.get('model', None)})
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, ctx)
@ -755,6 +947,7 @@ class Alarm(CalDAV, osv.osv_memory):
Alarm()
class Attendee(CalDAV, osv.osv_memory):
_name = 'basic.calendar.attendee'
_calname = 'attendee'
@ -774,6 +967,14 @@ class Attendee(CalDAV, osv.osv_memory):
}
def import_cal(self, cr, uid, ical_data, context=None):
""" Import Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ical_data: Get calendar's Data
@param context: A standard dictionary for contextual values
"""
ctx = context.copy()
ctx.update({'model': context.get('model', None)})
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, ctx)
@ -789,6 +990,15 @@ class Attendee(CalDAV, osv.osv_memory):
return vals
def export_cal(self, cr, uid, model, attendee_ids, vevent, context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param model: Get model's name
@param attendee_ids: Get Attendee's Id
@param context: A standard dictionary for contextual values
"""
attendee_object = self.pool.get(model)
ctx = context.copy()
ctx.update({'model': model})
@ -814,5 +1024,4 @@ class Attendee(CalDAV, osv.osv_memory):
Attendee()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,3 +1,24 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import time
import heapq
@ -10,8 +31,8 @@ def memoize(maxsize):
def wrapper(*args):
key = repr(args)
# performance crap
_cache=cache
_heap=heap
_cache = cache
_heap = heap
_heappop = heapq.heappop
_heappush = heapq.heappush
_time = time.time
@ -20,13 +41,13 @@ def memoize(maxsize):
if not _cache.has_key(key):
if _cursize == _maxsize:
# pop oldest element
(_,oldkey) = _heappop(_heap)
(_, oldkey) = _heappop(_heap)
_cache.pop(oldkey)
else:
_cursize += 1
# insert this element
_cache[key] = f(*args)
_heappush(_heap,(_time(),key))
_heappush(_heap, (_time(), key))
wrapper.misses += 1
else:
wrapper.hits += 1
@ -34,6 +55,8 @@ def memoize(maxsize):
wrapper.__doc__ = f.__doc__
wrapper.__name__ = f.__name__
wrapper.hits = wrapper.misses = 0
return wrapper
return wrapper
return decorating_function
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@ -50,10 +50,10 @@ class tinydav_handler(dav_interface):
"""
PROPS={'DAV:': dav_interface.PROPS['DAV:'], }
M_NS={ "DAV:" : dav_interface.M_NS['DAV:'], }
M_NS={ "DAV:": dav_interface.M_NS['DAV:'], }
def __init__(self, parent, verbose=False):
self.db_name = False
self.db_name = False
self.parent = parent
self.baseuri = parent.baseuri
@ -65,7 +65,7 @@ class tinydav_handler(dav_interface):
if not dbname:
cr.close()
return props
node = self.uri2object(cr,uid,pool, uri2)
node = self.uri2object(cr, uid, pool, uri2)
if node:
props.update(node.get_dav_props(cr))
cr.close()
@ -79,18 +79,18 @@ class tinydav_handler(dav_interface):
pname -- name of the property
"""
if self.M_NS.has_key(ns):
return dav_interface.get_prop(self,uri,ns,propname)
return dav_interface.get_prop(self, uri, ns, propname)
if uri[-1]=='/':uri=uri[:-1]
if uri[-1]=='/':uri = uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
cr.close()
raise DAV_NotFound
node = self.uri2object(cr,uid,pool, uri2)
node = self.uri2object(cr, uid, pool, uri2)
if not node:
cr.close()
raise DAV_NotFound
res = node.get_dav_eprop(cr,ns,propname)
res = node.get_dav_eprop(cr, ns, propname)
cr.close()
return res
@ -98,21 +98,21 @@ class tinydav_handler(dav_interface):
""" Return the base URI of this request, or even join it with the
ajoin path elements
"""
return self.baseuri+ '/'.join(ajoin)
return self.baseuri+ '/'.join(ajoin)
def uri2local(self, uri):
uparts=urlparse.urlparse(uri)
reluri=uparts[2]
uparts = urlparse.urlparse(uri)
reluri = uparts[2]
if reluri and reluri[-1]=="/":
reluri=reluri[:-1]
reluri = reluri[:-1]
return reluri
#
# pos: -1 to get the parent of the uri
#
def get_cr(self, uri):
def get_cr(self, uri):
pdb = self.parent.auth_proxy.last_auth
reluri = self.uri2local(uri)
reluri = self.uri2local(uri)
try:
dbname = reluri.split('/')[2]
except:
@ -122,7 +122,7 @@ class tinydav_handler(dav_interface):
if not pdb and dbname:
# if dbname was in our uri, we should have authenticated
# against that.
raise Exception("Programming error")
raise Exception("Programming error")
assert pdb == dbname, " %s != %s" %(pdb, dbname)
user, passwd, dbn2, uid = self.parent.auth_proxy.auth_creds[pdb]
db,pool = pooler.get_db_and_pool(dbname)
@ -135,29 +135,29 @@ class tinydav_handler(dav_interface):
return None
return pool.get('basic.calendar').get_calendar_object(cr, uid, uri)
def get_data(self,uri):
def get_data(self, uri):
self.parent.log_message('GET: %s' % uri)
if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
try:
if not dbname:
raise DAV_Error, 409
node = self.uri2object(cr,uid,pool, uri2)
node = self.uri2object(cr, uid, pool, uri2)
if not node:
raise DAV_NotFound(uri2)
try:
try:
datas = node.get_data(cr, uid)
except TypeError,e:
except TypeError, e:
import traceback
self.parent.log_error("GET typeError: %s", str(e))
self.parent.log_message("Exc: %s",traceback.format_exc())
self.parent.log_message("Exc: %s", traceback.format_exc())
raise DAV_Forbidden
except IndexError,e :
except IndexError, e :
self.parent.log_error("GET IndexError: %s", str(e))
raise DAV_NotFound(uri2)
except Exception,e:
except Exception, e:
import traceback
self.parent.log_error("GET exception: %s",str(e))
self.parent.log_error("GET exception: %s", str(e))
self.parent.log_message("Exc: %s", traceback.format_exc())
raise DAV_Error, 409
return datas
@ -165,7 +165,7 @@ class tinydav_handler(dav_interface):
cr.close()
@memoize(CACHE_SIZE)
def _get_dav_resourcetype(self,uri):
def _get_dav_resourcetype(self, uri):
""" return type of object """
self.parent.log_message('get RT: %s' % uri)
if uri[-1]=='/':uri=uri[:-1]
@ -173,21 +173,21 @@ class tinydav_handler(dav_interface):
try:
if not dbname:
return COLLECTION
node = self.uri2object(cr,uid,pool, uri2)
node = self.uri2object(cr, uid, pool, uri2)
if not node:
raise DAV_NotFound(uri2)
raise DAV_NotFound(uri2)
return OBJECT
finally:
cr.close()
def _get_dav_displayname(self,uri):
def _get_dav_displayname(self, uri):
self.parent.log_message('get DN: %s' % uri)
if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
cr.close()
return COLLECTION
node = self.uri2object(cr,uid,pool, uri2)
node = self.uri2object(cr, uid, pool, uri2)
if not node:
cr.close()
raise DAV_NotFound(uri2)
@ -195,7 +195,7 @@ class tinydav_handler(dav_interface):
return node.displayname
@memoize(CACHE_SIZE)
def _get_dav_getcontentlength(self,uri):
def _get_dav_getcontentlength(self, uri):
""" return the content length of an object """
self.parent.log_message('get length: %s' % uri)
if uri[-1]=='/':uri=uri[:-1]
@ -213,7 +213,7 @@ class tinydav_handler(dav_interface):
return str(result)
@memoize(CACHE_SIZE)
def _get_dav_getetag(self,uri):
def _get_dav_getetag(self, uri):
""" return the ETag of an object """
self.parent.log_message('get etag: %s' % uri)
if uri[-1]=='/':uri=uri[:-1]
@ -231,7 +231,7 @@ class tinydav_handler(dav_interface):
return str(result)
@memoize(CACHE_SIZE)
def get_lastmodified(self,uri):
def get_lastmodified(self, uri):
""" return the last modified date of the object """
if uri[-1]=='/':uri=uri[:-1]
today = time.time()
@ -239,18 +239,18 @@ class tinydav_handler(dav_interface):
try:
if not dbname:
return today
node = self.uri2object(cr,uid,pool, uri2)
node = self.uri2object(cr, uid, pool, uri2)
if not node:
raise DAV_NotFound(uri2)
if node.write_date:
return time.mktime(time.strptime(node.write_date,'%Y-%m-%d %H:%M:%S'))
return time.mktime(time.strptime(node.write_date, '%Y-%m-%d %H:%M:%S'))
else:
return today
finally:
cr.close()
@memoize(CACHE_SIZE)
def get_creationdate(self,uri):
def get_creationdate(self, uri):
""" return the last modified date of the object """
if uri[-1]=='/':uri=uri[:-1]
@ -258,11 +258,11 @@ class tinydav_handler(dav_interface):
try:
if not dbname:
raise DAV_Error, 409
node = self.uri2object(cr,uid,pool, uri2)
node = self.uri2object(cr, uid, pool, uri2)
if not node:
raise DAV_NotFound(uri2)
if node.create_date:
result = time.strptime(node.create_date,'%Y-%m-%d %H:%M:%S')
result = time.strptime(node.create_date, '%Y-%m-%d %H:%M:%S')
else:
result = time.gmtime()
return result
@ -270,14 +270,14 @@ class tinydav_handler(dav_interface):
cr.close()
@memoize(CACHE_SIZE)
def _get_dav_getcontenttype(self,uri):
def _get_dav_getcontenttype(self, uri):
self.parent.log_message('get contenttype: %s' % uri)
if uri[-1]=='/':uri=uri[:-1]
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
try:
if not dbname:
return 'httpd/unix-directory'
node = self.uri2object(cr,uid,pool, uri2)
node = self.uri2object(cr, uid, pool, uri2)
if not node:
raise DAV_NotFound(uri2)
result = node.mimetype
@ -286,50 +286,50 @@ class tinydav_handler(dav_interface):
finally:
cr.close()
def put(self, uri, data, content_type=None):
""" put the object into the filesystem """
self.parent.log_message('Putting %s (%d), %s'%( misc.ustr(uri), len(data), content_type))
self.parent.log_message('Putting %s (%d), %s'%(misc.ustr(uri), len(data), content_type))
parent='/'.join(uri.split('/')[:-1])
cr, uid, pool,dbname, uri2 = self.get_cr(uri)
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
raise DAV_Forbidden
try:
node = self.uri2object(cr,uid,pool, uri2[:])
node = self.uri2object(cr, uid, pool, uri2[:])
except:
node = False
node = False
if not node:
raise DAV_Forbidden
else:
try:
node.set_data(cr, uid, data)
except Exception,e:
import traceback
node.set_data(cr, uid, data)
except Exception, e:
import traceback
self.parent.log_error("Cannot save :%s", str(e))
self.parent.log_message("Exc: %s",traceback.format_exc())
self.parent.log_message("Exc: %s", traceback.format_exc())
raise DAV_Forbidden
cr.commit()
cr.close()
return 201
def exists(self,uri):
def exists(self, uri):
""" test if a resource exists """
result = False
cr, uid, pool,dbname, uri2 = self.get_cr(uri)
cr, uid, pool, dbname, uri2 = self.get_cr(uri)
if not dbname:
cr.close()
return True
try:
node = self.uri2object(cr,uid,pool, uri2)
node = self.uri2object(cr, uid, pool, uri2)
if node:
result = True
except:
pass
cr.close()
return result
return result
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
#
@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@ -26,45 +26,47 @@ import tools
import time
import base64
class node_calendar(object):
class node_calendar(object):
def __init__(self, path, context, calendar):
self.path = path
self.context = context
self.calendar_id = calendar.id
self.mimetype = 'ics'
self.calendar_id = calendar.id
self.mimetype = 'ics'
self.create_date = calendar.create_date
self.write_date = calendar.write_date or calendar.create_date
self.content_length = 0
self.displayname = calendar.name
def get_data(self, cr, uid):
def get_data(self, cr, uid):
calendar_obj = pooler.get_pool(cr.dbname).get('basic.calendar')
return calendar_obj.export_cal(cr, uid, [self.calendar_id])
def get_data_len(self, cr):
return calendar_obj.export_cal(cr, uid, [self.calendar_id])
def get_data_len(self, cr):
return self.content_length
def set_data(self, cr, uid, data):
calendar_obj = pooler.get_pool(cr.dbname).get('basic.calendar')
def set_data(self, cr, uid, data):
calendar_obj = pooler.get_pool(cr.dbname).get('basic.calendar')
return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id)
def get_etag(self,cr):
def get_etag(self, cr):
""" Get a tag, unique per object + modification.
see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """
return self._get_ttag(cr) + ':' + self._get_wtag(cr)
def _get_wtag(self,cr):
def _get_wtag(self, cr):
""" Return the modification time as a unique, compact string """
if self.write_date:
wtime = time.mktime(time.strptime(self.write_date,'%Y-%m-%d %H:%M:%S'))
wtime = time.mktime(time.strptime(self.write_date, '%Y-%m-%d %H:%M:%S'))
else: wtime = time.time()
return str(wtime)
def _get_ttag(self,cr):
def _get_ttag(self, cr):
return 'calendar-%d' % self.calendar_id
class Calendar(osv.osv):
_inherit = 'basic.calendar'
@ -79,5 +81,7 @@ class Calendar(osv.osv):
return None
calendar_id, calendar_name = res[0]
calendar = self.browse(cr, uid, calendar_id)
return node_calendar(uri, context, calendar)
return node_calendar(uri, context, calendar)
Calendar()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4

View File

@ -31,7 +31,7 @@
<separator string="Value Mapping" colspan="4" />
<field name="mapping" select="1" colspan="4" nolabel="1" />
</form>
</field>
</field>
</form>
<tree string="Attributes Mapping" editable="bottom">
<field name="name" select="1" />

View File

@ -1,9 +1,7 @@
# -*- encoding: utf-8 -*-
#
# Copyright P. Christeas <p_christ@hol.gr> 2008,2009
#
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
@ -33,15 +31,16 @@ from tools.config import config
from DAV.WebDAVServer import DAVRequestHandler
from service.websrv_lib import HTTPDir,FixSendError
class DAVHandler(FixSendError,DAVRequestHandler):
class DAVHandler(FixSendError, DAVRequestHandler):
verbose = False
def get_userinfo(self,user,pw):
def get_userinfo(self, user, pw):
return False
def _log(self, message):
netsvc.Logger().notifyChannel("webdav",netsvc.LOG_DEBUG,message)
netsvc.Logger().notifyChannel("webdav", netsvc.LOG_DEBUG, message)
def handle(self):
pass
@ -50,30 +49,30 @@ class DAVHandler(FixSendError,DAVRequestHandler):
def setup(self):
davpath = '/calendar/'
self.baseuri = "http://%s:%d%s"% (self.server.server_name,self.server.server_port,davpath)
self.baseuri = "http://%s:%d%s"% (self.server.server_name, self.server.server_port, davpath)
self.IFACE_CLASS = tinydav_handler(self)
pass
def log_message(self, format, *args):
netsvc.Logger().notifyChannel('webdav',netsvc.LOG_DEBUG_RPC,format % args)
netsvc.Logger().notifyChannel('webdav', netsvc.LOG_DEBUG_RPC, format % args)
def log_error(self, format, *args):
netsvc.Logger().notifyChannel('webdav',netsvc.LOG_WARNING,format % args)
netsvc.Logger().notifyChannel('webdav', netsvc.LOG_WARNING, format % args)
try:
from service.http_server import reg_http_service,OpenERPAuthProvider
from service.http_server import reg_http_service, OpenERPAuthProvider
davpath = '/calendar/'
handler = DAVHandler
handler.verbose = config.get_misc('webdav','verbose',True)
handler.debug = config.get_misc('webdav','debug',True)
reg_http_service(HTTPDir(davpath,DAVHandler,OpenERPAuthProvider()))
netsvc.Logger().notifyChannel('webdav',netsvc.LOG_INFO,"WebDAV service registered at path: %s/ "% davpath)
handler.verbose = config.get_misc('webdav', 'verbose', True)
handler.debug = config.get_misc('webdav', 'debug', True)
reg_http_service(HTTPDir(davpath, DAVHandler, OpenERPAuthProvider()))
netsvc.Logger().notifyChannel('webdav', netsvc.LOG_INFO, "WebDAV service registered at path: %s/ "% davpath)
except Exception, e:
logger = netsvc.Logger()
logger.notifyChannel('webdav', netsvc.LOG_ERROR, 'Cannot launch webdav: %s' % e)
#eof
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@ -41,7 +41,7 @@ class calendar_event_export(osv.osv_memory):
calendar = model_obj.export_cal(cr, uid, context['active_ids'], context)
#TODO: check why returns wrong value
return base64.encodestring(calendar)
def _process_export_ics_name(self, cr, uid, context):
"""
Get Default value for Name field.
@ -50,19 +50,20 @@ class calendar_event_export(osv.osv_memory):
model_obj = self.pool.get(model)
calendar = model_obj.export_cal(cr, uid, context['active_ids'], context)
return 'OpenERP %s.ics' % (model_obj._description)
_name = "calendar.event.export"
_description = "Event Export"
_columns = {
'file_path':fields.binary('Save ICS file', filters='*.ics', required=True),
'name':fields.char('File name', size=34, required=True, help='Save in .ics format')
}
_defaults={
'name':_process_export_ics_name,
'file_path':_process_export_ics
_defaults = {
'name': _process_export_ics_name,
'file_path': _process_export_ics
}
calendar_event_export()

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@ -42,6 +42,7 @@ class calendar_event_import(osv.osv_memory):
@param ids: List of calendar event imports IDs
@return: dictionary of calendar evet import window with Import successful msg.
"""
for data in self.read(cr, uid, ids):
model = data.get('model', 'basic.calendar')
model_obj = self.pool.get(model)
@ -63,17 +64,19 @@ class calendar_event_import(osv.osv_memory):
'target': 'new'
}
return value
_name = "calendar.event.import"
_description = "Event Import"
_columns = {
'file_path': fields.binary('Select ICS file', filters='*.ics', required=True),
'msg': fields.text('', readonly=True),
}
_defaults={
_defaults = {
'msg':lambda *a:'Import Sucessful'
}
calendar_event_import()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
##############################################################################
#
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
#
@ -15,7 +15,7 @@
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
@ -63,7 +63,7 @@ class calendar_event_subscribe(osv.osv_memory):
id2 = data_obj._get_id(cr, uid, 'caldav', 'view_calendar_event_subscribe_display')
if id2:
id2 = data_obj.browse(cr, uid, id2, context=context).res_id
value = {
'view_type': 'form',
'view_mode': 'form',
@ -73,17 +73,19 @@ class calendar_event_subscribe(osv.osv_memory):
'target': 'new'
}
return value
_name = "calendar.event.subscribe"
_description = "Event subscribe"
_columns = {
'url_path': fields.char('Provide path for remote calendar', size=124, required=True),
'msg': fields.text('', readonly=True),
}
_defaults={
_defaults = {
'msg':lambda *a:'Import Sucessful.'
}
calendar_event_subscribe()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -24,10 +24,18 @@ from crm import crm
from caldav import caldav
from base_calendar import base_calendar
class crm_meeting(osv.osv):
class crm_meeting(osv.osv):
_inherit = 'crm.meeting'
def export_cal(self, cr, uid, ids, context={}):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of CRM Meetings IDs
@param context: A standard dictionary for contextual values
"""
ids = map(lambda x: base_calendar.base_calendar_id2real_id(x), ids)
event_data = self.read(cr, uid, ids)
event_obj = self.pool.get('basic.calendar.event')
@ -35,6 +43,15 @@ class crm_meeting(osv.osv):
return ical.serialize()
def import_cal(self, cr, uid, data, data_id=None, context={}):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param data: Get Data of CRM Meetings
@param data_id: calendar's Id
@param context: A standard dictionary for contextual values
"""
event_obj = self.pool.get('basic.calendar.event')
vals = event_obj.import_cal(cr, uid, data, context=context)
return self.check_import(cr, uid, vals, context=context)