[IMP]: base_calendar caldav crm_caldav: Apply Doc String + quality check
bzr revid: ksa@tinyerp.co.in-20100325120700-qin0rom78ex3vima
This commit is contained in:
parent
58fddb6132
commit
0eb05a2c5d
|
@ -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 user’s 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 user’s ID for security checks,
|
||||
@param ids: List of calendar attendee’s 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 attendee’s 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 user’s ID for security checks,
|
||||
@param ids: List of calendar attendee’s 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 user’s 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 user’s ID for security checks,
|
||||
@param ids: List of res alarm’s 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 user’s ID for security checks,
|
||||
@param ids: List of calendar alarm’s 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 user’s ID for security checks,
|
||||
@param ids: List of calendar event’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s ID for security checks,
|
||||
@param ids: List of IR Model’s 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 user’s 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 user’s ID for security checks,
|
||||
@param ids: List of res user’s 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 user’s ID for security checks,
|
||||
@param ids: List of res user’s 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()
|
||||
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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 user’s ID for security checks,
|
||||
@param ids: List of base calendar invite attendee’s 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 \
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 user’s 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 user’s 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:
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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:
|
|
@ -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/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
|
|
|
@ -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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s ID for security checks,
|
||||
@param data_id: Get Data’s 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 user’s ID for security checks,
|
||||
@param ids: List of calendar’s 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 user’s ID for security checks,
|
||||
@param data_id: Get Data’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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 user’s 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:
|
||||
|
|
|
@ -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:
|
|
@ -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:
|
|
@ -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
|
|
@ -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" />
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
@ -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 import’s 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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 user’s ID for security checks,
|
||||
@param ids: List of CRM Meeting’s 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 user’s 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)
|
||||
|
|
Loading…
Reference in New Issue