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

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

View File

@ -18,6 +18,7 @@
# 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)
@ -323,7 +329,7 @@ class calendar_attendee(osv.osv):
('needs-action', 'Needs Action'),
('accepted', 'Accepted'),
('declined', 'Declined'),
('delegated', 'Delegated')], 'State', readonly=True,
('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"),
@ -333,19 +339,32 @@ class calendar_attendee(osv.osv):
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."),
'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"),
'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'),
'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"),
}
@ -356,11 +375,15 @@ request was delegated to"),
response_re = re.compile("Are you coming\?.*\n*.*(YES|NO|MAYBE).*", re.UNICODE)
def msg_new(self, cr, uid, msg):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks, """
return False
def msg_act_get(self, msg):
"""
Get Message.
@param self: The object pointer
@return: dictionary of actions which contain state field value.
"""
@ -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 ''
@ -441,6 +465,7 @@ request was delegated to"),
@param user_id: User id
@return: dictionary of value. which put value in email and availability fields.
"""
if not user_id:
return {'value': {'email': ''}}
usr_obj = self.pool.get('res.users')
@ -448,6 +473,13 @@ request was delegated to"),
return {'value': {'email': user.address_id.email, 'availability':user.availability}}
def do_tentative(self, cr, uid, ids, context=None, *args):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendar attendees IDs
@param *args: Get Tupple value
@param context: A standard dictionary for contextual values """
self.write(cr, uid, ids, {'state': 'tentative'}, context)
def do_accept(self, cr, uid, ids, context=None, *args):
@ -458,6 +490,7 @@ request was delegated to"),
@param ids: List of calendar attendees IDs.
@return: True
"""
if not context:
context = {}
@ -475,9 +508,21 @@ request was delegated to"),
return True
def do_decline(self, cr, uid, ids, context=None, *args):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendar attendees IDs
@param *args: Get Tupple value
@param context: A standard dictionary for contextual values """
self.write(cr, uid, ids, {'state': 'declined'}, context)
def create(self, cr, uid, vals, context=None):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get Values
@param context: A standard dictionary for contextual values """
if not context:
context = {}
@ -506,7 +551,8 @@ class res_alarm(osv.osv):
'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."),
'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."),
}
@ -528,6 +574,7 @@ 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]
@ -574,6 +621,7 @@ are both optional, but if one occurs, so MUST the other"""),
@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]
@ -597,17 +645,22 @@ class calendar_alarm(osv.osv):
_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"""),
'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'),
'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."""),
'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'),
@ -636,6 +689,7 @@ or contains the text to be used for display"""),
@param context: A standard dictionary for contextual values
@return: new record id for calendar_alarm.
"""
event_date = vals.get('event_date', False)
if event_date:
dtstart = datetime.strptime(vals['event_date'], "%Y-%m-%d %H:%M:%S")
@ -652,6 +706,15 @@ or contains the text to be used for display"""),
def do_run_scheduler(self, cr, uid, automatic=False, use_new_cursor=False, \
context=None):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendar alarms IDs.
@param use_new_cursor: False or the dbname
@param context: A standard dictionary for contextual values
"""
if not context:
context = {}
@ -722,6 +785,17 @@ class calendar_event(osv.osv):
def onchange_dates(self, cr, uid, ids, start_date, duration=False, end_date=False, context={}):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendar events IDs.
@param start_date: Get starting date
@param duration: Get Duration between start date and end date or False
@param end_date: Get Ending Date or False
@param context: A standard dictionary for contextual values
"""
if not start_date:
return {}
value = {}
@ -782,10 +856,11 @@ class calendar_event(osv.osv):
'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'),
@ -793,7 +868,8 @@ rule or repeating pattern for anexception to a recurrence set"),
'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),
'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'), \
@ -835,6 +911,16 @@ rule or repeating pattern for anexception to a recurrence set"),
}
def modify_this(self, cr, uid, event_id, defaults, real_date, context=None, *args):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param event_id: Get Event_id
@param real_date: Get Real Date
@param context: A standard dictionary for contextual values
@param *args: Get Tuppel Value
"""
event_id = base_calendar_id2real_id(event_id)
datas = self.read(cr, uid, event_id, context=context)
@ -878,6 +964,14 @@ rule or repeating pattern for anexception to a recurrence set"),
return True
def get_recurrent_ids(self, cr, uid, select, base_start_date, base_until_date, limit=100):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param base_start_date: Get Start Date
@param base_until_date: Get End Date
@param limit: The Number of Results to Return """
if not limit:
limit = 100
if isinstance(select, (str, int, long)):
@ -1009,6 +1103,8 @@ rule or repeating pattern for anexception to a recurrence set"),
@param cr: the current row, from the database cursor,
@param user: the current users ID for security checks,
@param args: list of tuples of form [(name_of_the_field, operator, value), ...].
@param offset: The Number of Results to Pass
@param limit: The Number of Results to Return
@return: List of id
"""
args_without_date = []
@ -1182,17 +1278,38 @@ rule or repeating pattern for anexception to a recurrence set"),
calendar_event()
class calendar_todo(osv.osv):
""" Calendar Task """
_name = "calendar.todo"
_inherit = "calendar.event"
_description = "Calendar Task"
def _get_date(self, cr, uid, ids, name, arg, context):
""" Get Date
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendar todo's IDs.
@param args: list of tuples of form [(name_of_the_field, operator, value), ...].
@param context: A standard dictionary for contextual values
"""
res = {}
for event in self.browse(cr, uid, ids, context=context):
res[event.id] = event.date_start
return res
def _set_date(self, cr, uid, id, name, value, arg, context):
""" Set Date
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param id: calendar's ID.
@param value: Get Value
@param args: list of tuples of form [(name_of_the_field, operator, value), ...].
@param context: A standard dictionary for contextual values
"""
event = self.browse(cr, uid, id, context=context)
cr.execute("UPDATE %s set date_start='%s' where id=%s" \
% (self._table, value, id))
@ -1214,6 +1331,13 @@ class ir_attachment(osv.osv):
_inherit = 'ir.attachment'
def search_count(self, cr, user, args, context=None):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param user: the current users ID for security checks,
@param args: list of tuples of form [(name_of_the_field, operator, value), ...].
@param context: A standard dictionary for contextual values
"""
args1 = []
for arg in args:
args1.append(map(lambda x:str(x).split('-')[0], arg))
@ -1221,6 +1345,16 @@ class ir_attachment(osv.osv):
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param args: list of tuples of form [(name_of_the_field, operator, value), ...].
@param offset: The Number of Results to pass,
@param limit: The Number of Results to Return,
@param context: A standard dictionary for contextual values
"""
new_args = args
for i, arg in enumerate(new_args):
if arg[0] == 'res_id':
@ -1235,6 +1369,13 @@ class ir_values(osv.osv):
def set(self, cr, uid, key, key2, name, models, value, replace=True, \
isobject=False, meta=False, preserve_user=False, company=False):
""" set IR Values
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param model: Get The Model """
new_model = []
for data in models:
if type(data) in (list, tuple):
@ -1246,6 +1387,13 @@ class ir_values(osv.osv):
def get(self, cr, uid, key, key2, models, meta=False, context={}, \
res_id_req=False, without_user=True, key2_req=True):
""" Get IR Values
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param model: Get The Model """
new_model = []
for data in models:
if type(data) in (list, tuple):
@ -1263,6 +1411,15 @@ class ir_model(osv.osv):
def read(self, cr, uid, ids, fields=None, context={},
load='_classic_read'):
""" Read IR Model
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of IR Models IDs.
@param context: A standard dictionary for contextual values """
data = super(ir_model, self).read(cr, uid, ids, fields=fields, \
context=context, load=load)
if data:
@ -1275,13 +1432,21 @@ ir_model()
class virtual_report_spool(web_services.report_spool):
def exp_report(self, db, uid, object, ids, datas=None, context=None):
""" Export Report
@param self: The object pointer
@param db: get the current database,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values """
if object == 'printscreen.list':
return super(virtual_report_spool, self).exp_report(db, uid, \
object, ids, datas, context)
new_ids = []
for id in ids:
new_ids.append(base_calendar_id2real_id(id))
if datas.get('id',False):
if datas.get('id', False):
datas['id'] = base_calendar_id2real_id(datas['id'])
return super(virtual_report_spool, self).exp_report(db, uid, object, new_ids, datas, context)
@ -1291,6 +1456,14 @@ class res_users(osv.osv):
_inherit = 'res.users'
def _get_user_avail(self, cr, uid, ids, context=None):
""" Get USer Availability
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of res users IDs.
@param context: A standard dictionary for contextual values """
current_datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
res = {}
attendee_obj = self.pool.get('calendar.attendee')
@ -1313,6 +1486,14 @@ class res_users(osv.osv):
return res
def _get_user_avail_fun(self, cr, uid, ids, name, args, context=None):
""" Get USer Availability Function
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of res users IDs.
@param context: A standard dictionary for contextual values """
return self._get_user_avail(cr, uid, ids, context=context)
_columns = {

View File

@ -41,7 +41,8 @@ class base_calendar_invite_attendee(osv.osv_memory):
'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')
'send_mail': fields.boolean('Send mail?', help='Check this if you want to \
send an Email to Invited Person')
}
_defaults = {
@ -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 {}
@ -155,6 +156,7 @@ class base_calendar_invite_attendee(osv.osv_memory):
@param partner_id: id of Partner
@return: dictionary of value.
"""
if not partner_id:
return {'value': {'contact_ids': []}}
cr.execute('select id from res_partner_address \

View File

@ -3,7 +3,8 @@
<data>
<!-- Attendee invite wizard-->
<record id="view_calendar_invite_attendee_wizard" model="ir.ui.view">
<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>
@ -11,7 +12,7 @@
<form string="Invite People">
<field name="type" />
<field name="send_mail" />
<newline/>
<newline />
<group col="1" colspan="4"
attrs="{'invisible': [('type', '!=', 'external')]}">
<field name="email" colspan="4"
@ -36,7 +37,7 @@
nolabel="1" domain="[('partner_id', '=', partner_id)]"
attrs="{'readonly': [('type', '!=', 'partner')]}" />
</group>
<newline/>
<newline />
<separator string="" colspan="6" />
<label string="" colspan="2" />
<button icon='gtk-cancel' special="cancel"

View File

@ -25,7 +25,11 @@ from osv import fields
class calendar_event_edit_all(osv.osv_memory):
def _default_values(self, cr, uid, context={}):
"""
""" Get Default value for Start Date
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values
@Return: Get Default value for Start Date
"""
context_id = context and context.get('active_id', False) or False
@ -39,9 +43,14 @@ class calendar_event_edit_all(osv.osv_memory):
return event['date']
def _default_deadline(self, cr, uid, context={}):
"""
""" Get Default value for End Date
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values
@return: Get Default value for End Date
"""
context_id = context and context.get('active_id', False) or False
if context_id:
if context.get('date_deadline'):

View File

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

View File

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

View File

@ -14,7 +14,7 @@ import urlparse
from utils import create_treelist, is_prefix
from errors import *
def deltree(dc,uri,exclude={}):
def deltree(dc, uri, exclude={}):
""" delete a tree of resources
dc -- dataclass to use
@ -30,22 +30,22 @@ 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
@ -53,7 +53,7 @@ def deltree(dc,uri,exclude={}):
# 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
@ -62,11 +62,11 @@ def deltree(dc,uri,exclude={}):
try:
delone(dc,element)
except DAV_Error, (ec,dd):
result[element]=ec
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,7 +79,7 @@ def delone(dc,uri):
# helper function
def copy(dc,src,dst):
def copy(dc, src, dst):
""" only copy the element
This is just a helper method factored out from copy and
@ -101,13 +101,13 @@ 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
@ -117,7 +117,7 @@ def copyone(dc,src,dst,overwrite=None):
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
@ -133,32 +133,32 @@ 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
@ -167,14 +167,14 @@ def copytree(dc,src,dst,overwrite=None):
# 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
result[element] = ec
return result
@ -185,7 +185,7 @@ def copytree(dc,src,dst,overwrite=None):
###
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
@ -198,7 +198,7 @@ def moveone(dc,src,dst,overwrite=None):
# then delete it
dc.rm(src)
def movetree(dc,src,dst,overwrite=None):
def movetree(dc, src, dst, overwrite=None):
""" move a collection
This is done by first copying it and then deleting
@ -209,10 +209,11 @@ def movetree(dc,src,dst,overwrite=None):
"""
# first copy it
res=copytree(dc,src,dst,overwrite)
res = copytree(dc,src,dst,overwrite)
# then delete it
res=deltree(dc,src,exclude=res)
res = deltree(dc,src,exclude=res)
return res
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

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

View File

@ -47,11 +47,11 @@ class MOVE:
"""
def __init__(self,dataclass,src_uri,dst_uri,overwrite):
self.__dataclass=dataclass
self.__src=src_uri
self.__dst=dst_uri
self.__overwrite=overwrite
def __init__(self, dataclass, src_uri, dst_uri, overwrite):
self.__dataclass = dataclass
self.__src = src_uri
self.__dst = dst_uri
self.__overwrite = overwrite
def single_action(self):
@ -62,16 +62,16 @@ class MOVE:
"""
dc=self.__dataclass
base=self.__src
dc = self.__dataclass
base = self.__src
### some basic tests
# test if dest exists and overwrite is false
if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
# test if src and dst are the same
# (we assume that both uris are on the same server!)
ps=urlparse.urlparse(self.__src)[2]
pd=urlparse.urlparse(self.__dst)[2]
ps = urlparse.urlparse(self.__src)[2]
pd = urlparse.urlparse(self.__dst)[2]
if ps==pd: raise DAV_Error, 403
return dc.moveone(self.__src,self.__dst,self.__overwrite)
@ -82,21 +82,22 @@ class MOVE:
Here we return a multistatus xml element.
"""
dc=self.__dataclass
base=self.__src
dc = self.__dataclass
base = self.__src
### some basic tests
# test if dest exists and overwrite is false
if dc.exists(self.__dst) and not self.__overwrite: raise DAV_Error, 412
# test if src and dst are the same
# (we assume that both uris are on the same server!)
ps=urlparse.urlparse(self.__src)[2]
pd=urlparse.urlparse(self.__dst)[2]
ps = urlparse.urlparse(self.__src)[2]
pd = urlparse.urlparse(self.__dst)[2]
if ps==pd: raise DAV_Error, 403
result=dc.movetree(self.__src,self.__dst,self.__overwrite)
result = dc.movetree(self.__src,self.__dst,self.__overwrite)
if not result: return None
# create the multistatus XML element
return make_xmlresponse(result)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

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

View File

@ -12,11 +12,11 @@ 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
@ -32,9 +32,9 @@ 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]
@ -47,10 +47,11 @@ class DAV_NotFound(DAV_Error):
class DAV_Forbidden(DAV_Error):
""" a method on a resource is not allowed """
def __init__(self,*args):
def __init__(self, *args):
if len(args):
DAV_Error.__init__(self,403,args[0])
else:
DAV_Error.__init__(self,403)
pass
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -36,10 +36,10 @@ 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):
def get_propnames(self, uri):
""" return the property names allowed for the given URI
In this method we simply return the above defined properties
@ -50,14 +50,14 @@ class dav_interface:
"""
return self.PROPS
def get_prop2(self,uri,ns,pname):
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,7 +86,7 @@ class dav_interface:
### DATA methods (for GET and PUT)
###
def get_data(self,uri):
def get_data(self, uri):
""" return the content of an object
return data or raise an exception
@ -94,7 +94,7 @@ class dav_interface:
"""
raise DAV_NotFound
def put(self,uri,data):
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,11 +127,11 @@ 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()
@ -142,7 +142,7 @@ class dav_interface:
### methods for deleting a resource
def rmcol(self,uri):
def rmcol(self, uri):
""" delete a collection
This should not delete any children! This is automatically done
@ -153,7 +153,7 @@ class dav_interface:
"""
raise DAV_NotFound
def rm(self,uri):
def rm(self, uri):
""" delete a single resource
return a success code or raise an exception
@ -210,27 +210,27 @@ 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):
def copy(self, src, dst):
""" copy a resource with depth==0
You don't need to bother about overwrite or not.
@ -241,7 +241,7 @@ class dav_interface:
return 201
def copycol(self,src,dst):
def copycol(self, src, dst):
""" copy a resource with depth==infinity
You don't need to bother about overwrite or not.
@ -253,11 +253,12 @@ class dav_interface:
### some utility functions you need to implement
def exists(self,uri):
def exists(self, uri):
""" return 1 or None depending on if a resource exists """
return None # no
def is_collection(self,uri):
def is_collection(self, uri):
""" return 1 or None depending on if a resource is a collection """
return None # no
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

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

View File

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

View File

@ -36,7 +36,8 @@ 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
@ -44,6 +45,12 @@ except ImportError:
# 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:
@ -67,10 +74,21 @@ def uid2openobjectid(cr, uidval, oomodel, rdate):
return (False, None)
def openobjectid2uid(cr, uidval, oomodel):
""" Open Object Id To UId
@param cr: the current row, from the database cursor,
@param uidval: Get USerId vale
@oomodel: Open Object ModelName """
value = 'OpenObject-%s_%s@%s' % (oomodel, uidval, cr.dbname)
return value
def get_attribute_mapping(cr, uid, calname, context={}):
""" Attribute Mapping with Basic calendar fields and lines
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param calname: Get Calendar name
@param context: A standard dictionary for contextual values """
if not context:
context = {}
pool = pooler.get_pool(cr.dbname)
@ -100,6 +118,10 @@ def get_attribute_mapping(cr, uid, calname, context={}):
return res
def map_data(cr, uid, obj):
""" Map Data
@param self: The object pointer
@param cr: the current row, from the database cursor,"""
vals = {}
for map_dict in obj.__attribute__:
map_val = obj.ical_get(map_dict, 'value')
@ -149,11 +171,23 @@ class CalDAV(object):
def ical_set(self, name, value, type):
""" set calendar Attribute
@param self: The object pointer,
@param name: Get Attribute Name
@param value: Get Attribute Value
@param type: Get Attribute Type
"""
if name in self.__attribute__ and self.__attribute__[name]:
self.__attribute__[name][type] = value
return True
def ical_get(self, name, type):
""" Get calendar Attribute
@param self: The object pointer,
@param name: Get Attribute Name
@param type: Get Attribute Type
"""
if self.__attribute__.get(name):
val = self.__attribute__.get(name).get(type, None)
valtype = self.__attribute__.get(name).get('type', None)
@ -168,12 +202,23 @@ class CalDAV(object):
return self.__attribute__.get(name, None)
def ical_reset(self, type):
""" Reset Calendar Attribute
@param self: The object pointer,
@param type: Get Attribute Type
"""
for name in self.__attribute__:
if self.__attribute__[name]:
self.__attribute__[name][type] = None
return True
def parse_ics(self, cr, uid, child, cal_children=None, context=None):
""" parse calendaring and scheduling information
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values """
att_data = []
for cal_data in child.getChildren():
if cal_data.name.lower() == 'attendee':
@ -205,6 +250,12 @@ class CalDAV(object):
return vals
def create_ics(self, cr, uid, datas, name, ical, context=None):
""" create calendaring and scheduling information
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values """
if not datas:
return
timezones = []
@ -280,6 +331,14 @@ class CalDAV(object):
return vevent
def check_import(self, cr, uid, vals, context={}):
"""
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get Values
@param context: A standard dictionary for contextual values
"""
ids = []
model_obj = self.pool.get(context.get('model'))
recur_pool = {}
@ -311,6 +370,14 @@ class CalDAV(object):
return ids
def export_cal(self, cr, uid, datas, vobj=None, context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param datas: Get Data's for caldav
@param context: A standard dictionary for contextual values
"""
try:
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context)
ical = vobject.iCalendar()
@ -320,6 +387,14 @@ class CalDAV(object):
raise osv.except_osv(('Error !'), (str(e)))
def import_cal(self, cr, uid, content, data_id=None, context=None):
""" Import Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param data_id: Get Datas ID or False
@param context: A standard dictionary for contextual values
"""
ical_data = base64.decodestring(content)
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, context)
parsedCal = vobject.readOne(ical_data)
@ -335,6 +410,7 @@ class CalDAV(object):
self.ical_reset('value')
return res
class Calendar(CalDAV, osv.osv):
_name = 'basic.calendar'
_description = 'Calendar'
@ -366,6 +442,14 @@ class Calendar(CalDAV, osv.osv):
}
def export_cal(self, cr, uid, ids, vobj='vevent', context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ids: List of calendars IDs
@param context: A standard dictionary for contextual values
"""
cal = self.browse(cr, uid, ids[0])
ical = vobject.iCalendar()
for line in cal.line_ids:
@ -382,6 +466,14 @@ class Calendar(CalDAV, osv.osv):
return ical.serialize()
def import_cal(self, cr, uid, content, data_id=None, context=None):
""" Import Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param data_id: Get Datas ID or False
@param context: A standard dictionary for contextual values
"""
if not context:
context = {}
vals = []
@ -410,9 +502,13 @@ class Calendar(CalDAV, osv.osv):
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'), \
@ -430,6 +526,14 @@ class basic_calendar_line(osv.osv):
}
def create(self, cr, uid, vals, context={}):
""" create calendar's line
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get the Values
@param context: A standard dictionary for contextual values
"""
cr.execute("Select count(id) from basic_calendar_lines \
where name='%s' and calendar_id=%s" % (vals.get('name'), vals.get('calendar_id')))
res = cr.fetchone()
@ -441,6 +545,7 @@ line "%s" more than once' % (vals.get('name'))))
basic_calendar_line()
class basic_calendar_attribute(osv.osv):
_name = 'basic.calendar.attributes'
_description = 'Calendar attributes'
@ -454,7 +559,10 @@ class basic_calendar_attribute(osv.osv):
basic_calendar_attribute()
class basic_calendar_fields(osv.osv):
""" Calendar fields """
_name = 'basic.calendar.fields'
_description = 'Calendar fields'
@ -476,6 +584,13 @@ class basic_calendar_fields(osv.osv):
}
def check_line(self, cr, uid, vals, name, context=None):
""" check calendar's line
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get Values
@param context: A standard dictionary for contextual values
"""
f_obj = self.pool.get('ir.model.fields')
field = f_obj.browse(cr, uid, vals['field_id'], context=context)
relation = field.relation
@ -489,6 +604,14 @@ class basic_calendar_fields(osv.osv):
return True
def create(self, cr, uid, vals, context={}):
""" Create Calendar's fields
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get Values
@param context: A standard dictionary for contextual values
"""
cr.execute('select name from basic_calendar_attributes \
where id=%s' % (vals.get('name')))
name = cr.fetchone()
@ -504,6 +627,14 @@ class basic_calendar_fields(osv.osv):
return super(basic_calendar_fields, self).create(cr, uid, vals, context=context)
def write(self, cr, uid, ids, vals, context=None):
""" write Calendar's fields
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param vals: Get Values
@param context: A standard dictionary for contextual values
"""
if not vals:
return
for id in ids:
@ -522,6 +653,7 @@ class basic_calendar_fields(osv.osv):
basic_calendar_fields()
class Event(CalDAV, osv.osv_memory):
_name = 'basic.calendar.event'
_calname = 'vevent'
@ -560,11 +692,21 @@ class Event(CalDAV, osv.osv_memory):
'duration': None, # Use: O-1, Type: DURATION, Specifies a positive duration of time.
'dtend': None, # Use: O-1, Type: DATE-TIME, Specifies the date and time that a calendar component ends.
}
def export_cal(self, cr, uid, datas, vobj='vevent', context={}):
""" Export calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param datas: Get datas
@param context: A standard dictionary for contextual values
"""
return super(Event, self).export_cal(cr, uid, datas, 'vevent', context=context)
Event()
class ToDo(CalDAV, osv.osv_memory):
_name = 'basic.calendar.todo'
_calname = 'vtodo'
@ -605,14 +747,24 @@ class ToDo(CalDAV, osv.osv_memory):
}
def export_cal(self, cr, uid, datas, vobj='vevent', context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param datas: Get datas
@param context: A standard dictionary for contextual values
"""
return super(ToDo, self).export_cal(cr, uid, datas, 'vtodo', context=context)
ToDo()
class Journal(CalDAV):
__attribute__ = {
}
class FreeBusy(CalDAV):
__attribute__ = {
'contact': None, # Use: O-1, Type: Text, Represent contact information or alternately a reference to contact information associated with the calendar component.
@ -645,6 +797,13 @@ class Timezone(CalDAV, osv.osv_memory):
}
def get_name_offset(self, cr, uid, tzid, context={}):
""" Get Name Offset value
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param context: A standard dictionary for contextual values
"""
mytz = pytz.timezone(tzid.title())
mydt = datetime.now(tz=mytz)
offset = mydt.utcoffset()
@ -655,6 +814,14 @@ class Timezone(CalDAV, osv.osv_memory):
return (mydt.tzname(), realoffset)
def export_cal(self, cr, uid, model, tzid, ical, context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param model: Get Model's name
@param context: A standard dictionary for contextual values
"""
ctx = context.copy()
ctx.update({'model': model})
cal_tz = ical.add('vtimezone')
@ -668,6 +835,14 @@ class Timezone(CalDAV, osv.osv_memory):
return ical
def import_cal(self, cr, uid, ical_data, context=None):
""" Import Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ical_data: Get calendar's data
@param context: A standard dictionary for contextual values
"""
for child in ical_data.getChildren():
if child.name.lower() == 'tzid':
tzname = child.value
@ -695,6 +870,15 @@ class Alarm(CalDAV, osv.osv_memory):
}
def export_cal(self, cr, uid, model, alarm_id, vevent, context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param model: Get Model's name
@param alarm_id: Get Alarm's Id
@param context: A standard dictionary for contextual values
"""
valarm = vevent.add('valarm')
alarm_object = self.pool.get(model)
alarm_data = alarm_object.read(cr, uid, alarm_id, [])
@ -721,6 +905,14 @@ class Alarm(CalDAV, osv.osv_memory):
return vevent
def import_cal(self, cr, uid, ical_data, context=None):
""" Import Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ical_data: Get calendar's Data
@param context: A standard dictionary for contextual values
"""
ctx = context.copy()
ctx.update({'model': context.get('model', None)})
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, ctx)
@ -755,6 +947,7 @@ class Alarm(CalDAV, osv.osv_memory):
Alarm()
class Attendee(CalDAV, osv.osv_memory):
_name = 'basic.calendar.attendee'
_calname = 'attendee'
@ -774,6 +967,14 @@ class Attendee(CalDAV, osv.osv_memory):
}
def import_cal(self, cr, uid, ical_data, context=None):
""" Import Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param ical_data: Get calendar's Data
@param context: A standard dictionary for contextual values
"""
ctx = context.copy()
ctx.update({'model': context.get('model', None)})
self.__attribute__ = get_attribute_mapping(cr, uid, self._calname, ctx)
@ -789,6 +990,15 @@ class Attendee(CalDAV, osv.osv_memory):
return vals
def export_cal(self, cr, uid, model, attendee_ids, vevent, context={}):
""" Export Calendar
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current users ID for security checks,
@param model: Get model's name
@param attendee_ids: Get Attendee's Id
@param context: A standard dictionary for contextual values
"""
attendee_object = self.pool.get(model)
ctx = context.copy()
ctx.update({'model': model})
@ -814,5 +1024,4 @@ class Attendee(CalDAV, osv.osv_memory):
Attendee()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

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

View File

@ -50,7 +50,7 @@ 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
@ -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
@ -101,10 +101,10 @@ class tinydav_handler(dav_interface):
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
#
@ -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:
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)
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
@ -290,13 +290,13 @@ class tinydav_handler(dav_interface):
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
@ -305,31 +305,31 @@ class tinydav_handler(dav_interface):
else:
try:
node.set_data(cr, uid, data)
except Exception,e:
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
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -26,6 +26,7 @@ import tools
import time
import base64
class node_calendar(object):
def __init__(self, path, context, calendar):
self.path = path
@ -49,22 +50,23 @@ class node_calendar(object):
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'
@ -81,3 +83,5 @@ class Calendar(osv.osv):
calendar = self.browse(cr, uid, calendar_id)
return node_calendar(uri, context, calendar)
Calendar()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4

View File

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

View File

@ -53,14 +53,15 @@ class calendar_event_export(osv.osv_memory):
_name = "calendar.event.export"
_description = "Event Export"
_columns = {
'file_path':fields.binary('Save ICS file', filters='*.ics', required=True),
'name':fields.char('File name', size=34, required=True, help='Save in .ics format')
}
_defaults={
'name':_process_export_ics_name,
'file_path':_process_export_ics
_defaults = {
'name': _process_export_ics_name,
'file_path': _process_export_ics
}
calendar_event_export()

View File

@ -42,6 +42,7 @@ class calendar_event_import(osv.osv_memory):
@param ids: List of calendar event imports IDs
@return: dictionary of calendar evet import window with Import successful msg.
"""
for data in self.read(cr, uid, ids):
model = data.get('model', 'basic.calendar')
model_obj = self.pool.get(model)
@ -66,11 +67,13 @@ class calendar_event_import(osv.osv_memory):
_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'
}

View File

@ -76,11 +76,13 @@ class calendar_event_subscribe(osv.osv_memory):
_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.'
}

View File

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