From 0d836ea56e5a5530ad558ac634da4b4240de0aeb Mon Sep 17 00:00:00 2001 From: "Jay (Open ERP)" Date: Tue, 16 Feb 2010 13:21:43 +0530 Subject: [PATCH 001/761] [FIX] Fixed error notification on parent_store=true with a column without ondelete=cascade lp bug: https://launchpad.net/bugs/522227 fixed bzr revid: jvo@tinyerp.com-20100216075143-f0e3axlg1m2eskmq --- bin/osv/orm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 3e8f869e4ea..fd67b593405 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -1745,7 +1745,7 @@ class orm(orm_template): if 'parent_right' not in self._columns: logger.notifyChannel('orm', netsvc.LOG_ERROR, 'create a column parent_right on object %s: fields.integer(\'Right Parent\', select=1)' % (self._table, )) if self._columns[self._parent_name].ondelete<>'cascade': - logger.notifyChannel('orm', netsvc.LOG_ERROR, "the columns %s on object must be set as ondelete='cascasde'" % (self._name, self._parent_name)) + logger.notifyChannel('orm', netsvc.LOG_ERROR, "The column %s on object %s must be set as ondelete='cascade'" % (self._parent_name, self._name)) cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_left" INTEGER' % (self._table,)) cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_right" INTEGER' % (self._table,)) cr.commit() From c7e1318927f514711d614176eec2813034162477 Mon Sep 17 00:00:00 2001 From: "Jay (Open ERP)" Date: Tue, 16 Feb 2010 14:24:53 +0530 Subject: [PATCH 002/761] [IMP] Account/base_iban : bank and iban displayed on list view of O2M to partner lp bug: https://launchpad.net/bugs/519225 fixed bzr revid: jvo@tinyerp.com-20100216085453-xgt3s52brv1ei04y --- addons/account/partner_view.xml | 1 + addons/base_iban/base_iban_view.xml | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/addons/account/partner_view.xml b/addons/account/partner_view.xml index d93349d9f62..9402f0ff2e5 100644 --- a/addons/account/partner_view.xml +++ b/addons/account/partner_view.xml @@ -113,6 +113,7 @@ + diff --git a/addons/base_iban/base_iban_view.xml b/addons/base_iban/base_iban_view.xml index d93e9ffb086..00203665c50 100644 --- a/addons/base_iban/base_iban_view.xml +++ b/addons/base_iban/base_iban_view.xml @@ -42,6 +42,17 @@ + + res.partner.form.iban.inherit.list + res.partner + + form + + + + + + From d07c7bc4d6f85d593071e1d5a4900771d32545d1 Mon Sep 17 00:00:00 2001 From: "ksa (Open ERP)" Date: Tue, 23 Mar 2010 18:21:25 +0530 Subject: [PATCH 003/761] [IMP]: crm: Apply Doc String bzr revid: ksa@tinyerp.co.in-20100323125125-2ehrrtyh7tvi9vc4 --- addons/crm/crm.py | 234 +++++++++++++--------------------- addons/crm/crm_action_rule.py | 2 + addons/crm/crm_fundraising.py | 2 + 3 files changed, 95 insertions(+), 143 deletions(-) diff --git a/addons/crm/crm.py b/addons/crm/crm.py index a3eb8437546..ab02e943828 100644 --- a/addons/crm/crm.py +++ b/addons/crm/crm.py @@ -19,14 +19,14 @@ # ############################################################################## +import time from datetime import datetime from datetime import timedelta + +import tools from osv import fields from osv import osv from tools.translate import _ -import time -import tools - MAX_LEVEL = 15 AVAILABLE_STATES = [ @@ -82,6 +82,7 @@ class crm_case_section(osv.osv): ] def _check_recursion(self, cr, uid, ids): + """ Checks for recursion level for sections @param self: The object pointer @@ -105,7 +106,8 @@ class crm_case_section(osv.osv): ] def name_get(self, cr, uid, ids, context={}): - """Overrides orm name_get method + + """ Overrides orm name_get method @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -123,6 +125,7 @@ class crm_case_section(osv.osv): name = record['parent_id'][1] + ' / ' + name res.append((record['id'], name)) return res + crm_case_section() @@ -137,10 +140,10 @@ class crm_case_categ(osv.osv): 'section_id': fields.many2one('crm.case.section', 'Sales Team'), 'object_id': fields.many2one('ir.model', 'Object Name'), } - + def _find_object_id(self, cr, uid, context=None): - """ + """ Find Object's Id for Category @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -150,11 +153,13 @@ class crm_case_categ(osv.osv): object_id = context and context.get('object_id', False) or False ids = self.pool.get('ir.model').search(cr, uid, [('model', '=', object_id)]) return ids and ids[0] - - _defaults = { + + _defaults = { 'object_id' : _find_object_id + } -# + + crm_case_categ() @@ -170,16 +175,16 @@ class crm_case_resource_type(osv.osv): 'section_id': fields.many2one('crm.case.section', 'Sales Team'), 'object_id': fields.many2one('ir.model', 'Object Name'), } - + def _find_object_id(self, cr, uid, context=None): - """ + + """ Find object's Id for resource Type @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param context: A standard dictionary for contextual values """ - object_id = context and context.get('object_id', False) or False ids = self.pool.get('ir.model').search(cr, uid, [('model', '=', object_id)]) return ids and ids[0] @@ -210,10 +215,10 @@ class crm_case_stage(osv.osv): help="Change Probability on next and previous stages."), 'requirements': fields.text('Requirements') } - + def _find_object_id(self, cr, uid, context=None): - """ + """ Find Object's Id of case stage @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -233,20 +238,19 @@ class crm_case_stage(osv.osv): crm_case_stage() def _links_get(self, cr, uid, context={}): - """ + + """ Get Link for Object and name @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param context: A standard dictionary for contextual values """ - obj = self.pool.get('res.request.link') ids = obj.search(cr, uid, []) res = obj.read(cr, uid, ids, ['object', 'name'], context) return [(r['object'], r['name']) for r in res] - class crm_case(osv.osv): """ CRM Case """ @@ -289,12 +293,13 @@ class crm_case(osv.osv): def _get_log_ids(self, cr, uid, ids, field_names, arg, context={}): - """ + """ Get Log's Id for crm case @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of case log’s IDs @param context: A standard dictionary for contextual values + @return:Dictionary of History Ids """ result = {} @@ -360,10 +365,10 @@ class crm_case(osv.osv): \nIf the case needs to be reviewed then the state is set to \'Pending\'.'), 'company_id': fields.many2one('res.company', 'Company'), } - + def _get_default_partner_address(self, cr, uid, context): - """ + """ Get Partner Address for current user @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -376,7 +381,7 @@ class crm_case(osv.osv): def _get_default_partner(self, cr, uid, context): - """ + """ Get Partner for current user @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -392,7 +397,7 @@ class crm_case(osv.osv): def _get_default_email(self, cr, uid, context): - """ + """ Get User Email Address @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -407,7 +412,8 @@ class crm_case(osv.osv): return user.address_id.email def _get_default_user(self, cr, uid, context): - """ + + """ Get Default User @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -419,7 +425,8 @@ class crm_case(osv.osv): return uid def _get_section(self, cr, uid, context): - """ + + """ Get User's Section @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -445,7 +452,7 @@ class crm_case(osv.osv): def unlink(self, cr, uid, ids, context={}): - """ + """ Unlink the crm case data @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -459,7 +466,8 @@ class crm_case(osv.osv): return super(crm_case, self).unlink(cr, uid, ids, context) def stage_next(self, cr, uid, ids, context={}): - """ + + """ Get Next Stage's ID @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -476,7 +484,8 @@ class crm_case(osv.osv): return True def get_stage_dict(self, cr, uid, ids, context={}): - """ + + """ Gets stage id and maps it to section according to stage sequence @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -495,12 +504,13 @@ class crm_case(osv.osv): return s def stage_previous(self, cr, uid, ids, context={}): - """ + + """ Get Previous stage's Id @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of stage previous’s IDs - @param context: A standard dictionary for contextual values""" + @param context: A standard dictionary for contextual values """ s = self.get_stage_dict(cr, uid, ids, context=context) for case in self.browse(cr, uid, ids, context): @@ -514,13 +524,15 @@ class crm_case(osv.osv): return True def onchange_case_id(self, cr, uid, ids, case_id, name, partner_id, context={}): - """ + + """ Get Partner Address and email Address depend on the Partner Id @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of case’s IDs @partner_id: Get Partner Id @param context: A standard dictionary for contextual values + """ if not case_id: @@ -540,12 +552,16 @@ class crm_case(osv.osv): return {'value': value} def history(self, cr, uid, ids, keyword, history=False, email=False, details=None, context={}): - """ + + """ Get History For Email @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of History’s IDs - @param context: A standard dictionary for contextual values""" + @param context: A standard dictionary for contextual values + @history: Get the History If pass Value else False + @email: Get email if pass Value else False + @details: Get Detail if pass Value else False """ cases = self.browse(cr, uid, ids, context=context) return self.__history(cr, uid, cases, keyword=keyword, \ @@ -553,16 +569,18 @@ class crm_case(osv.osv): context=context) def __history(self, cr, uid, cases, keyword, history=False, email=False, details=None, context={}): - """ + + """ Get History For Email @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of History’s IDs - @param context: A standard dictionary for contextual values""" - + @param context: A standard dictionary for contextual values + @history: Get the History If pass Value else False + @email: Get email if pass Value else False + @details: Get Detail if pass Value else False""" model_obj = self.pool.get('ir.model') - for case in cases: model_ids = model_obj.search(cr, uid, [('model', '=', case._name)]) data = { @@ -603,7 +621,7 @@ class crm_case(osv.osv): def add_reply(self, cursor, user, ids, context=None): - """ + """ Reply For Particular Email Address @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -620,12 +638,13 @@ class crm_case(osv.osv): def case_log(self, cr, uid, ids, context={}, email=False, *args): - """ + """ Display case Log For Particular Email Address @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param context: A standard dictionary for contextual values @param *args: Give Tuple Value + @email: Get Email if pass Value else False """ cases = self.browse(cr, uid, ids) @@ -635,7 +654,7 @@ class crm_case(osv.osv): def case_log_reply(self, cr, uid, ids, context={}, email=False, *args): - """ + """ Give Reply on particular Email Address @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -660,9 +679,9 @@ class crm_case(osv.osv): self.__history(cr, uid, cases, _('Send'), history=True, email=False) for case in cases: self.write(cr, uid, [case.id], { - 'description': False, - 'som': False, - 'canal_id': False, + 'description': False, + 'som': False, + 'canal_id': False, }) emails = [case.email_from] + (case.email_cc or '').split(',') emails = filter(None, emails) @@ -676,21 +695,22 @@ class crm_case(osv.osv): _("No E-Mail ID Found for your Company address!")) tools.email_send( - emailfrom, - emails, - '[' + str(case.id) + '] ' + case.name, - self.format_body(body), - reply_to = case.section_id.reply_to, + emailfrom, + emails, + '[' + str(case.id) + '] ' + case.name, + self.format_body(body), + reply_to = case.section_id.reply_to, openobject_id = str(case.id) ) return True def onchange_partner_id(self, cr, uid, ids, part, email=False): - """ + """ Get Partner Contact on partner ID @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, + @email: Get email if pass Value else False """ if not part: @@ -704,10 +724,11 @@ class crm_case(osv.osv): def onchange_partner_address_id(self, cr, uid, ids, add, email=False): - """ + """ Get Email Address @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, + @email: Get email if pass Value else False """ data = {} @@ -719,7 +740,7 @@ class crm_case(osv.osv): def case_close(self, cr, uid, ids, *args): - """ + """ case close when state apply done @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -739,7 +760,7 @@ class crm_case(osv.osv): def case_escalate(self, cr, uid, ids, *args): - """ + """ Escalates case to upper level @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -766,7 +787,7 @@ class crm_case(osv.osv): def case_open(self, cr, uid, ids, *args): - """ + """ case open when state apply open @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -787,7 +808,7 @@ class crm_case(osv.osv): def case_cancel(self, cr, uid, ids, *args): - """ + """ case cancel when state apply cancel @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -804,7 +825,7 @@ class crm_case(osv.osv): def case_pending(self, cr, uid, ids, *args): - """ + """ case pending when state apply pending @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -821,7 +842,7 @@ class crm_case(osv.osv): def case_reset(self, cr, uid, ids, *args): - """ + """ case reset to draft when state apply draft @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @@ -846,14 +867,14 @@ class crm_case_log(osv.osv): _order = "id desc" _columns = { - 'name': fields.char('Status', size=64), - 'som': fields.many2one('res.partner.som', 'State of Mind'), - 'date': fields.datetime('Date'), - 'canal_id': fields.many2one('res.partner.canal', 'Channel'), - 'section_id': fields.many2one('crm.case.section', 'Section'), - 'user_id': fields.many2one('res.users', 'User Responsible', readonly=True), - 'model_id': fields.many2one('ir.model', "Model"), - 'res_id': fields.integer('Resource ID'), + 'name': fields.char('Status', size=64), + 'som': fields.many2one('res.partner.som', 'State of Mind'), + 'date': fields.datetime('Date'), + 'canal_id': fields.many2one('res.partner.canal', 'Channel'), + 'section_id': fields.many2one('crm.case.section', 'Section'), + 'user_id': fields.many2one('res.users', 'User Responsible', readonly=True), + 'model_id': fields.many2one('ir.model', "Model"), + 'res_id': fields.integer('Resource ID'), } _defaults = { @@ -872,11 +893,13 @@ class crm_case_history(osv.osv): def _note_get(self, cursor, user, ids, name, arg, context=None): - """ @param self: The object pointer + """ + @param self: The object pointer @param cr: the current row, from the database cursor, @param uid: the current user’s ID for security checks, @param ids: List of case History’s IDs @param context: A standard dictionary for contextual values + @return: email address ,date and description """ res = {} @@ -886,89 +909,15 @@ class crm_case_history(osv.osv): return res _columns = { - 'description': fields.text('Description'), - 'note': fields.function(_note_get, method=True, string="Description", type="text"), - 'email': fields.char('Email', size=84), + 'description': fields.text('Description'), + 'note': fields.function(_note_get, method=True, string="Description", type="text"), + 'email': fields.char('Email', size=84), 'email_from' : fields.char('From Email', size=84), - 'log_id': fields.many2one('crm.case.log', 'Log', ondelete='cascade'), + 'log_id': fields.many2one('crm.case.log', 'Log', ondelete='cascade'), } crm_case_history() -class crm_email_add_cc_wizard(osv.osv_memory): - """ Email Add CC""" - - _name = "crm.email.add.cc" - _description = "Email Add CC" - - _columns = { - 'name': fields.selection([('user', 'User'), ('partner', 'Partner'),\ - ('email', 'Email Address')], 'Send to', required=True), - 'user_id': fields.many2one('res.users', "User"), - 'partner_id': fields.many2one('res.partner', "Partner"), - 'email': fields.char('Email', size=32), - 'subject': fields.char('Subject', size=32), - } - - def change_email(self, cr, uid, ids, user, partner): - - """ @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param ids: List of Mail’s IDs - """ - - if (not partner and not user): - return {'value': {'email': False}} - email = False - if partner: - addr = self.pool.get('res.partner').address_get(cr, uid, [partner], ['contact']) - if addr: - email = self.pool.get('res.partner.address').read(cr, uid, addr['contact'] , ['email'])['email'] - elif user: - addr = self.pool.get('res.users').read(cr, uid, user, ['address_id'])['address_id'] - if addr: - email = self.pool.get('res.partner.address').read(cr, uid, addr[0] , ['email'])['email'] - return {'value': {'email': email}} - - - def add_cc(self, cr, uid, ids, context={}): - - """ @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param ids: List of create menu’s IDs - @param context: A standard dictionary for contextual values - """ - - data = self.read(cr, uid, ids[0]) - email = data['email'] - subject = data['subject'] - - if not context: - return {} - history_line = self.pool.get('crm.case.history').browse(cr, uid, context['active_id']) - model = history_line.log_id.model_id.model - model_pool = self.pool.get(model) - case = model_pool.browse(cr, uid, history_line.log_id.res_id) - body = history_line.description.replace('\n', '\n> ') - flag = tools.email_send( - case.user_id.address_id.email, - [case.email_from], - subject or '[' + str(case.id) + '] ' + case.name, - model_pool.format_body(body), - email_cc = [email], - openobject_id = str(case.id), - subtype = "html" - ) - - if flag: - model_pool.write(cr, uid, case.id, {'email_cc' : case.email_cc and case.email_cc + ',' + email or email}) - else: - raise osv.except_osv(_('Email Fail!'), ("Lastest Email is not sent successfully")) - return {} - -crm_email_add_cc_wizard() class users(osv.osv): _inherit = 'res.users' @@ -984,7 +933,6 @@ class res_partner(osv.osv): _columns = { 'section_id': fields.many2one('crm.case.section', 'Sales Team'), } - res_partner() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/crm/crm_action_rule.py b/addons/crm/crm_action_rule.py index f2d5a19997d..2de58710f0a 100644 --- a/addons/crm/crm_action_rule.py +++ b/addons/crm/crm_action_rule.py @@ -249,3 +249,5 @@ class base_action_rule_line(osv.osv): } base_action_rule_line() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/crm/crm_fundraising.py b/addons/crm/crm_fundraising.py index 927a3d05915..afd7f7fbf4d 100644 --- a/addons/crm/crm_fundraising.py +++ b/addons/crm/crm_fundraising.py @@ -73,3 +73,5 @@ class crm_fundraising(osv.osv): } crm_fundraising() + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From aa70854c09a1e287342e830318c873131bf9744f Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Tue, 6 Apr 2010 16:41:32 +0530 Subject: [PATCH 004/761] [IMP] document_webdav: removed DAV and refactore code bzr revid: hmo@tinyerp.com-20100406111132-9bscvnb6aojdvioo --- addons/document/nodes.py | 6 +- .../DAV/BufferingHTTPServer.py | 99 ----- addons/document_webdav/DAV/WebDAVServer.py | 379 ------------------ addons/document_webdav/DAV/__init__.py | 20 - addons/document_webdav/DAV/constants.py | 18 - addons/document_webdav/DAV/davcmd.py | 218 ---------- addons/document_webdav/DAV/davcopy.py | 133 ------ addons/document_webdav/DAV/davmove.py | 102 ----- addons/document_webdav/DAV/delete.py | 63 --- addons/document_webdav/DAV/errors.py | 56 --- addons/document_webdav/DAV/iface.py | 263 ------------ addons/document_webdav/DAV/propfind.py | 372 ----------------- addons/document_webdav/DAV/status.py | 31 -- addons/document_webdav/DAV/utils.py | 160 -------- addons/document_webdav/dav_fs.py | 173 ++++---- addons/document_webdav/webdav_server.py | 140 ++++++- 16 files changed, 214 insertions(+), 2019 deletions(-) delete mode 100644 addons/document_webdav/DAV/BufferingHTTPServer.py delete mode 100644 addons/document_webdav/DAV/WebDAVServer.py delete mode 100644 addons/document_webdav/DAV/__init__.py delete mode 100644 addons/document_webdav/DAV/constants.py delete mode 100644 addons/document_webdav/DAV/davcmd.py delete mode 100755 addons/document_webdav/DAV/davcopy.py delete mode 100755 addons/document_webdav/DAV/davmove.py delete mode 100755 addons/document_webdav/DAV/delete.py delete mode 100755 addons/document_webdav/DAV/errors.py delete mode 100644 addons/document_webdav/DAV/iface.py delete mode 100755 addons/document_webdav/DAV/propfind.py delete mode 100644 addons/document_webdav/DAV/status.py delete mode 100755 addons/document_webdav/DAV/utils.py diff --git a/addons/document/nodes.py b/addons/document/nodes.py index c7eb80c0a45..a8553426d3f 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -193,7 +193,11 @@ class node_dir(node_class): pass def children(self,cr): - return self._child_get(cr) + self._file_get(cr) + res = self._child_get(cr) + self._file_get(cr) + return res + + def get_data(self,cr): + return '' def child(self,cr, name): res = self._child_get(cr,name) diff --git a/addons/document_webdav/DAV/BufferingHTTPServer.py b/addons/document_webdav/DAV/BufferingHTTPServer.py deleted file mode 100644 index 37520421432..00000000000 --- a/addons/document_webdav/DAV/BufferingHTTPServer.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python - -""" - Buffering HTTP Server - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -""" - - -from utils import VERSION, AUTHOR -__version__ = VERSION -__author__ = AUTHOR - -from BaseHTTPServer import BaseHTTPRequestHandler -import os -class BufferedHTTPRequestHandler(BaseHTTPRequestHandler): - """ - Buffering HTTP Request Handler - - This class is an extension to the BaseHTTPRequestHandler - class which buffers the whole output and sends it at once - after the processing if the request is finished. - - This makes it possible to work together with some clients - which otherwise would break (e.g. cadaver) - - """ - - - def _init_buffer(self): - """initialize the buffer. - - If you override the handle() method remember to call - this (see below) - """ - self.__buffer="" - self.__outfp=os.tmpfile() - - def _append(self,s): - """ append a string to the buffer """ - self.__buffer=self.__buffer+s - - def _flush(self): - """ flush the buffer to wfile """ - self.wfile.write(self.__buffer) - self.__outfp.write(self.__buffer) - self.__outfp.flush() - self.wfile.flush() - self.__buffer="" - - def handle(self): - """ Handle a HTTP request """ - self._init_buffer() - BaseHTTPRequestHandler.handle(self) - self._flush() - - def send_header(self, keyword, value): - """Send a MIME header.""" - if self.request_version != 'HTTP/0.9': - self._append("%s: %s\r\n" % (keyword, value)) - - def end_headers(self): - """Send the blank line ending the MIME headers.""" - if self.request_version != 'HTTP/0.9': - self._append("\r\n") - - def send_response(self, code, message=None): - self.log_request(code) - - if message is None: - if self.responses.has_key(code): - message = self.responses[code][0] - else: - message = '' - - if self.request_version != 'HTTP/0.9': - self._append("%s %s %s\r\n" % - (self.protocol_version, str(code), message)) - - self.send_header('Server', self.version_string()) - self.send_header('Connection', 'close') - self.send_header('Date', self.date_time_string()) - - protocol_version="HTTP/1.1" - diff --git a/addons/document_webdav/DAV/WebDAVServer.py b/addons/document_webdav/DAV/WebDAVServer.py deleted file mode 100644 index 5f409773c18..00000000000 --- a/addons/document_webdav/DAV/WebDAVServer.py +++ /dev/null @@ -1,379 +0,0 @@ -""" - Python WebDAV Server. - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -This module builds on AuthServer by implementing the standard DAV -methods. - -Subclass this class and specify an IFACE_CLASS. See example. - -""" - -DEBUG=None - -from utils import VERSION, AUTHOR -__version__ = VERSION -__author__ = AUTHOR - - -import os -import sys -import time -import socket -import string -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): - """Simple DAV request handler with - - - GET - - HEAD - - PUT - - OPTIONS - - PROPFIND - - PROPPATCH - - MKCOL - - It uses the resource/collection classes for serving and - storing content. - - """ - - server_version = "DAV/" + __version__ - protocol_version = 'HTTP/1.1' - - ### utility functions - def _log(self, message): - pass - - 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): - """ send a body in one part """ - - if not headers: - headers = {} - 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) - - if DATA: - self.send_header("Content-Length", str(len(DATA))) - self.send_header("Content-Type", ctype) - else: - self.send_header("Content-Length", "0") - - self.end_headers() - if DATA: - self._append(DATA) - - 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.send_header("Content-type", ctype) - self.send_header("Connection", "keep-alive") - self.send_header("Transfer-Encoding", "chunked") - self.end_headers() - self._append(hex(len(DATA))[2:]+"\r\n") - self._append(DATA) - self._append("\r\n") - self._append("0\r\n") - self._append("\r\n") - - ### HTTP METHODS - - def do_OPTIONS(self): - """return the list of capabilities """ - self.send_response(200) - self.send_header("Allow", "GET, HEAD, COPY, MOVE, POST, PUT, PROPFIND, PROPPATCH, OPTIONS, MKCOL, DELETE, TRACE") - self.send_header("Content-Type", "text/plain") - self.send_header("Connection", "keep-alive") - self.send_header("DAV", "1") - self.end_headers() - - def do_PROPFIND(self): - - dc=self.IFACE_CLASS - # read the body - body=None - if self.headers.has_key("Content-Length"): - l=self.headers['Content-Length'] - body=self.rfile.read(atoi(l)) - alt_body = """ - - - - - - - - - - """ - #self.wfile.write(body) - - # which Depth? - if self.headers.has_key('Depth'): - d=self.headers['Depth'] - else: - d="infinity" - - uri=self.geturi() - pf=PROPFIND(uri,dc,d) - - if body: - pf.read_propfind(body) - - try: - DATA=pf.createResponse() - DATA=DATA+"\n" - # print "Data:", DATA - except DAV_NotFound,(ec,dd): - return self.send_notFound(dd, uri) - except DAV_Error, (ec,dd): - return self.send_error(ec,dd) - - self.send_body_chunks(DATA,207,"Multi-Status","Multiple responses") - - def geturi(self): - buri = self.IFACE_CLASS.baseuri - if buri[-1] == '/': - return urllib.unquote(buri[:-1]+self.path) - else: - return urllib.unquote(buri+self.path) - - def do_GET(self): - """Serve a GET request.""" - dc=self.IFACE_CLASS - uri=self.geturi() - - # get the last modified date - try: - 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"} - - # get the content type - try: - ct=dc.get_prop(uri,"DAV:","getcontenttype") - except: - ct="application/octet-stream" - - # get the data - try: - 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) - - def do_HEAD(self): - """ Send a HEAD response """ - dc=self.IFACE_CLASS - uri=self.geturi() - - # get the last modified date - try: - 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"} - - # get the content type - try: - ct=dc.get_prop(uri,"DAV:","getcontenttype") - except: - ct="application/octet-stream" - - try: - data=dc.get_data(uri) - headers["Content-Length"]=str(len(data)) - except DAV_NotFound: - self.send_body(None,404,"Not Found","") - return - - self.send_body(None,200,"OK","OK",ct,headers) - - def do_POST(self): - self.send_error(404,"File not found") - - def do_MKCOL(self): - """ create a new collection """ - - dc=self.IFACE_CLASS - uri=self.geturi() - try: - res = dc.mkcol(uri) - if res: - self.send_body(None,201,"Created",'') - else: - 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) - - def do_DELETE(self): - """ delete an resource """ - dc=self.IFACE_CLASS - uri=self.geturi() - dl=DELETE(uri,dc) - if dc.is_collection(uri): - res=dl.delcol() - else: - res=dl.delone() - - if res: - self.send_status(207,body=res) - else: - self.send_status(204) - - def do_PUT(self): - dc=self.IFACE_CLASS - - # read the body - body=None - if self.headers.has_key("Content-Length"): - l=self.headers['Content-Length'] - body=self.rfile.read(atoi(l)) - uri=self.geturi() - - ct=None - if self.headers.has_key("Content-Type"): - ct=self.headers['Content-Type'] - try: - dc.put(uri,body,ct) - except DAV_Error, (ec,dd): - self.send_status(ec) - return - self.send_status(201) - - def do_COPY(self): - """ copy one resource to another """ - try: - self.copymove(COPY) - 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): - self.send_status(ec) - - def copymove(self,CLASS): - """ common method for copying or moving objects """ - dc=self.IFACE_CLASS - - # get the source URI - source_uri=self.geturi() - - # get the destination URI - dest_uri=self.headers['Destination'] - dest_uri=urllib.unquote(dest_uri) - - # Overwrite? - 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) - - # Depth? - d="infinity" - if self.headers.has_key("Depth"): - d=self.headers['Depth'] - - if d!="0" and d!="infinity": - self.send_status(400) - return - - if d=="0": - 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): - self.send_status(ec) - return - else: - try: - 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], - ctype='text/xml; charset="utf-8"') - else: - self.send_status(result_code) - - 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): - - if not msg: msg=STATUS_CODES[code] - self.send_body(body,code,STATUS_CODES[code],msg,mediatype) - - def send_notFound(self,descr,uri): - body = """ - - %s - - %s - - """ - return self.send_status(404,descr, body=body % (uri,descr)) diff --git a/addons/document_webdav/DAV/__init__.py b/addons/document_webdav/DAV/__init__.py deleted file mode 100644 index 10abdb40014..00000000000 --- a/addons/document_webdav/DAV/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -""" - - diff --git a/addons/document_webdav/DAV/constants.py b/addons/document_webdav/DAV/constants.py deleted file mode 100644 index e858ac519c2..00000000000 --- a/addons/document_webdav/DAV/constants.py +++ /dev/null @@ -1,18 +0,0 @@ -""" - -constants definition - - -""" - -# definition for resourcetype -COLLECTION=1 -OBJECT=None -DAV_PROPS=['creationdate', 'displayname', 'getcontentlanguage', 'getcontentlength', 'getcontenttype', 'getetag', 'getlastmodified', 'lockdiscovery', 'resourcetype', 'source', 'supportedlock'] - - -# Request classes in propfind - -RT_ALLPROP=1 -RT_PROPNAME=2 -RT_PROP=3 diff --git a/addons/document_webdav/DAV/davcmd.py b/addons/document_webdav/DAV/davcmd.py deleted file mode 100644 index 5c6be3ff9f7..00000000000 --- a/addons/document_webdav/DAV/davcmd.py +++ /dev/null @@ -1,218 +0,0 @@ -""" - -davcmd.py ---------- - -containts commands like copy, move, delete for normal -resources and collections - -""" - -from string import split,replace,joinfields -import urlparse - -from utils import create_treelist, is_prefix -from errors import * - -def deltree(dc,uri,exclude={}): - """ delete a tree of resources - - dc -- dataclass to use - uri -- root uri to delete - exclude -- an optional list of uri:error_code pairs which should not - be deleted. - - returns dict of uri:error_code tuples from which - another method can create a multistatus xml element. - - Also note that we only know Depth=infinity thus we don't have - to test for it. - - """ - - tlist=create_treelist(dc,uri) - result={} - - for i in range(len(tlist),0,-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 - for p in problem_uris: - if is_prefix(element,p): - ok=None - break - - if not ok: continue - - # here we test for the exclude list which is the other way round! - for p in exclude.keys(): - if is_prefix(p,element): - ok=None - break - - if not ok: continue - - # now delete stuff - try: - delone(dc,element) - except DAV_Error, (ec,dd): - result[element]=ec - - return result - -def delone(dc,uri): - """ delete a single object """ - if dc.is_collection(uri): - dc.rmcol(uri) # should be empty - else: - dc.rm(uri) - -### -### COPY -### - -# helper function - -def copy(dc,src,dst): - """ only copy the element - - This is just a helper method factored out from copy and - copytree. It will not handle the overwrite or depth header. - - """ - - # destination should have been deleted before - if dc.exists(dst): raise DAV_Error, 412 - - # source should exist also - if not dc.exists(src): raise DAV_NotFound - - if dc.is_collection(src): - dc.copycol(src,dst) # an exception will be passed thru - else: - dc.copy(src,dst) # an exception will be passed thru - - -# the main functions - -def copyone(dc,src,dst,overwrite=None): - """ copy one resource to a new destination """ - - if overwrite and dc.exists(dst): - delres=deltree(dc,dst) - else: - delres={} - - # if we cannot delete everything, then do not copy! - if delres: return delres - - try: - copy(dc,src,dst) # pass thru exceptions - except DAV_Error, (ec,dd): - return ec - -def copytree(dc,src,dst,overwrite=None): - """ copy a tree of resources to another location - - dc -- dataclass to use - src -- src uri from where to copy - dst -- dst uri - overwrite -- if 1 then delete dst uri before - - returns dict of uri:error_code tuples from which - another method can create a multistatus xml element. - - """ - - - # first delete the destination resource - if overwrite and dc.exists(dst): - delres=deltree(dc,dst) - else: - 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={} - - # prepare destination URIs (get the prefix) - dpath=urlparse.urlparse(dst)[2] - - for element in tlist: - 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 - for p in problem_uris: - if is_prefix(p,element): - ok=None - break - - if not ok: continue - - # now create the destination URI which corresponds to - # the actual source URI. -> actual_dst - # ("subtract" the base src from the URI and prepend the - # dst prefix to it.) - esrc=replace(element,src,"") - actual_dst=dpath+esrc - - # now copy stuff - try: - copy(dc,element,actual_dst) - except DAV_Error, (ec,dd): - result[element]=ec - - return result - - - -### -### MOVE -### - - -def moveone(dc,src,dst,overwrite=None): - """ move a single resource - - This is done by first copying it and then deleting - the original. - """ - - # first copy it - copyone(dc,src,dst,overwrite) - - # then delete it - dc.rm(src) - -def movetree(dc,src,dst,overwrite=None): - """ move a collection - - This is done by first copying it and then deleting - the original. - - PROBLEM: if something did not copy then we have a problem - when deleting as the original might get deleted! - """ - - # first copy it - res=copytree(dc,src,dst,overwrite) - - # then delete it - res=deltree(dc,src,exclude=res) - - return res - diff --git a/addons/document_webdav/DAV/davcopy.py b/addons/document_webdav/DAV/davcopy.py deleted file mode 100755 index ec44931b107..00000000000 --- a/addons/document_webdav/DAV/davcopy.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python - -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - 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 - -import sys -import string -import urlparse -import urllib -from StringIO import StringIO - -import utils -from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP -from errors import * -from utils import create_treelist, quote_uri, gen_estring - -class COPY: - """ copy resources and eventually create multistatus responses - - This module implements the COPY class which is responsible for - copying resources. Usually the normal copy work is done in the - interface class. This class only creates error messages if error - occur. - - """ - - - 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): - """ copy a normal resources. - - We try to copy it and return the result code. - This is for Depth==0 - - """ - - 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] - if ps==pd: raise DAV_Error, 403 - - return dc.copyone(self.__src,self.__dst,self.__overwrite) - - #return copyone(dc,self.__src,self.__dst,self.__overwrite) - - def tree_action(self): - """ copy a tree of resources (a collection) - - Here we return a multistatus xml element. - - """ - 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] - if ps==pd: raise DAV_Error, 403 - - - result=dc.copytree(self.__src,self.__dst,self.__overwrite) - #result=copytree(dc,self.__src,self.__dst,self.__overwrite) - - if not result: return None - - ### - ### create the multistatus XML element - ### (this is also the same as in delete.py. - ### we might make a common method out of it) - ### - - doc = Document(None) - 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)) - 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.close() - return s - diff --git a/addons/document_webdav/DAV/davmove.py b/addons/document_webdav/DAV/davmove.py deleted file mode 100755 index 78c1e649389..00000000000 --- a/addons/document_webdav/DAV/davmove.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python - -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -""" - - -import sys -import string -import urlparse -import urllib -from StringIO import StringIO - -import utils -from constants import COLLECTION, OBJECT, DAV_PROPS -from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP -from errors import * -from utils import create_treelist, quote_uri, gen_estring, make_xmlresponse -from davcmd import moveone, movetree - -class MOVE: - """ move resources and eventually create multistatus responses - - This module implements the MOVE class which is responsible for - moving resources. - - MOVE is implemented by a COPY followed by a DELETE of the old - resource. - - """ - - - def __init__(self,dataclass,src_uri,dst_uri,overwrite): - self.__dataclass=dataclass - self.__src=src_uri - self.__dst=dst_uri - self.__overwrite=overwrite - - - def single_action(self): - """ move a normal resources. - - We try to move it and return the result code. - This is for Depth==0 - - """ - - 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] - if ps==pd: raise DAV_Error, 403 - - return dc.moveone(self.__src,self.__dst,self.__overwrite) - - def tree_action(self): - """ move a tree of resources (a collection) - - Here we return a multistatus xml element. - - """ - 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] - if ps==pd: raise DAV_Error, 403 - - result=dc.movetree(self.__src,self.__dst,self.__overwrite) - if not result: return None - - # create the multistatus XML element - return make_xmlresponse(result) - diff --git a/addons/document_webdav/DAV/delete.py b/addons/document_webdav/DAV/delete.py deleted file mode 100755 index ed017e53b6d..00000000000 --- a/addons/document_webdav/DAV/delete.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python - -""" - - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -""" -import os -import string -import urllib -from StringIO import StringIO - -from status import STATUS_CODES -from utils import gen_estring, quote_uri, make_xmlresponse -from davcmd import deltree - -class DELETE: - - 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) - - if not len(result.items()): - return None # everything ok - - # create the result element - return make_xmlresponse(result) - - def delone(self): - """ delete a resource """ - - dc=self.__dataclass - result=dc.delone(self.__uri) - - if not result: return None - if not len(result.items()): - return None # everything ok - - # create the result element - return make_xmlresponse(result) - diff --git a/addons/document_webdav/DAV/errors.py b/addons/document_webdav/DAV/errors.py deleted file mode 100755 index 9c0e7667913..00000000000 --- a/addons/document_webdav/DAV/errors.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -""" - - Exceptions for the DAVserver implementation - -""" - -class DAV_Error(Exception): - """ in general we can have the following arguments: - - 1. the error code - 2. the error result element, e.g. a element - """ - - def __init__(self,*args): - if len(args)==1: - self.args=(args[0],"") - else: - self.args=args - -class DAV_Secret(DAV_Error): - """ the user is not allowed to know anything about it - - returning this for a property value means to exclude it - from the response xml element. - """ - - def __init__(self): - DAV_Error.__init__(self,0) - pass - -class DAV_NotFound(DAV_Error): - """ a requested property was not found for a resource """ - - def __init__(self,*args): - if len(args): - if isinstance(args[0],list): - stre = "Path %s not found!"%('/'.join(args[0])) - else: - stre = args[0] - DAV_Error.__init__(self,404,stre) - else: - DAV_Error.__init__(self,404) - - pass - -class DAV_Forbidden(DAV_Error): - """ a method on a resource is not allowed """ - - def __init__(self,*args): - if len(args): - DAV_Error.__init__(self,403,args[0]) - else: - DAV_Error.__init__(self,403) - pass - diff --git a/addons/document_webdav/DAV/iface.py b/addons/document_webdav/DAV/iface.py deleted file mode 100644 index c8f5fe2594d..00000000000 --- a/addons/document_webdav/DAV/iface.py +++ /dev/null @@ -1,263 +0,0 @@ -""" - -basic interface class - -use this for subclassing when writing your own interface -class. - -""" - -from errors import * - -import time -from string import lower - -class dav_interface: - """ interface class for implementing DAV servers """ - - ### defined properties (modify this but let the DAV stuff there!) - ### the format is namespace: [list of properties] - - PROPS={"DAV:" : ('creationdate', - 'displayname', - 'getcontentlanguage', - 'getcontentlength', - 'getcontenttype', - 'getetag', - 'getlastmodified', - 'lockdiscovery', - 'resourcetype', - 'source', - 'supportedlock'), - "NS2" : ("p1","p2") - } - - # here we define which methods handle which namespace - # 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", - "NS2" : "ns2" } - - def get_propnames(self,uri): - """ return the property names allowed for the given URI - - In this method we simply return the above defined properties - assuming that they are valid for any resource. - You can override this in order to return a different set - of property names for each resource. - - """ - return self.PROPS - - def get_prop2(self,uri,ns,pname): - """ return the value of a property - """ - if lower(ns)=="dav:": return self.get_dav(uri,pname) - - raise DAV_NotFound - - def get_prop(self,uri,ns,propname): - """ return the value of a given property - - uri -- uri of the object to get the property of - ns -- namespace of the property - pname -- name of the property - """ - if self.M_NS.has_key(ns): - prefix=self.M_NS[ns] - else: - print "No namespace:",ns, "( for prop:", propname,")" - raise DAV_NotFound - mname=prefix+"_"+propname - if not hasattr(self,mname): - raise DAV_NotFound - - try: - m=getattr(self,mname) - r=m(uri) - return r - except AttributeError, e: - print 'Property %s not supported' % propname - print "Exception:", e - raise DAV_NotFound - - ### - ### DATA methods (for GET and PUT) - ### - - def get_data(self,uri): - """ return the content of an object - - return data or raise an exception - - """ - raise DAV_NotFound - - def put(self,uri,data): - """ write an object to the repository - - return a result code or raise an exception - """ - - raise DAV_Forbidden - - ### - ### Methods for DAV properties - ### - - def _get_dav_creationdate(self,uri): - """ return the creationdate of a resource """ - 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): - """ return the last modified date of a resource """ - d=self.get_lastmodified(uri) - if isinstance(d, int) or isinstance(d, float): - d = time.localtime(d) - # format it - return time.asctime(d) - - - ### - ### OVERRIDE THESE! - ### - - def get_creationdate(self,uri): - """ return the creationdate of the resource """ - return time.time() - - def get_lastmodified(self,uri): - """ return the last modification date of the resource """ - return time.time() - - - ### - ### COPY MOVE DELETE - ### - - ### methods for deleting a resource - - def rmcol(self,uri): - """ delete a collection - - This should not delete any children! This is automatically done - before by the DELETE class in DAV/delete.py - - return a success code or raise an exception - - """ - raise DAV_NotFound - - def rm(self,uri): - """ delete a single resource - - return a success code or raise an exception - - """ - raise DAV_NotFound - - """ - - COPY/MOVE HANDLER - - These handler are called when a COPY or MOVE method is invoked by - a client. In the default implementation it works as follows: - - - the davserver receives a COPY/MOVE method - - the davcopy or davmove module will be loaded and the corresponding - class will be initialized - - this class parses the query and decides which method of the interface class - to call: - - copyone for a single resource to copy - copytree for a tree to copy (collection) - (the same goes for move of course). - - - the interface class has now two options: - 1. to handle the action directly (e.g. cp or mv on filesystems) - 2. to let it handle via the copy/move methods in davcmd. - - ad 1) The first approach can be used when we know that no error can - happen inside a tree or when the action can exactly tell which - element made which error. We have to collect these and return - it in a dict of the form {uri: error_code, ...} - - ad 2) The copytree/movetree/... methods of davcmd.py will do the recursion - themselves and call for each resource the copy/move method of the - interface class. Thus method will then only act on a single resource. - (Thus a copycol on a normal unix filesystem actually only needs to do - an mkdir as the content will be copied by the davcmd.py function. - The davcmd.py method will also automatically collect all errors and - return the dictionary described above. - When you use 2) you also have to implement the copy() and copycol() - methods in your interface class. See the example for details. - - To decide which approach is the best you have to decide if your application - is able to generate errors inside a tree. E.g. a function which completely - fails on a tree if one of the tree's childs fail is not what we need. Then - 2) would be your way of doing it. - Actually usually 2) is the better solution and should only be replaced by - 1) if you really need it. - - The remaining question is if we should do the same for the DELETE method. - - """ - - ### MOVE handlers - - def moveone(self,src,dst,overwrite): - """ move one resource with Depth=0 """ - return moveone(self,src,dst,overwrite) - - def movetree(self,src,dst,overwrite): - """ move a collection with Depth=infinity """ - return movetree(self,src,dst,overwrite) - - ### COPY handlers - - def copyone(self,src,dst,overwrite): - """ copy one resource with Depth=0 """ - return copyone(self,src,dst,overwrite) - - def copytree(self,src,dst,overwrite): - """ copy a collection with Depth=infinity """ - return copytree(self,src,dst,overwrite) - - - ### low level copy methods (you only need these for method 2) - def copy(self,src,dst): - """ copy a resource with depth==0 - - You don't need to bother about overwrite or not. - This has been done already. - - return a success code or raise an exception if something fails - """ - return 201 - - - def copycol(self,src,dst): - """ copy a resource with depth==infinity - - You don't need to bother about overwrite or not. - This has been done already. - - return a success code or raise an exception if something fails - """ - return 201 - - ### some utility functions you need to implement - - def exists(self,uri): - """ return 1 or None depending on if a resource exists """ - return None # no - - def is_collection(self,uri): - """ return 1 or None depending on if a resource is a collection """ - return None # no - diff --git a/addons/document_webdav/DAV/propfind.py b/addons/document_webdav/DAV/propfind.py deleted file mode 100755 index 0fb9c229c03..00000000000 --- a/addons/document_webdav/DAV/propfind.py +++ /dev/null @@ -1,372 +0,0 @@ -#!/usr/bin/env python - -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - 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 - -import sys -import string -import urlparse -import urllib -from StringIO import StringIO - -import utils -from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP -from errors import * - -def utf8str(st): - if isinstance(st,unicode): - return st.encode('utf8') - else: - return str(st) - -class PROPFIND: - """ parse a propfind xml element and extract props - - It will set the following instance vars: - - 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) - - - """ - - - 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) - - # a violation of the expected logic: client (korganizer) will ask for DAV:resourcetype - # but we also have to return the http://groupdav.org/:resourcetype property! - if self.proplist.has_key('DAV:') and 'resourcetype' in self.proplist['DAV:']: - if not self.proplist.has_key('http://groupdav.org/'): - self.proplist['http://groupdav.org/'] = [] - self.proplist['http://groupdav.org/'].append('resourcetype') - if 'DAV:' in self.namespaces: #TMP - self.namespaces.append('http://groupdav.org/') - - def createResponse(self): - """ create the multistatus response - - This will be delegated to the specific method - depending on which request (allprop, propname, prop) - was found. - - If we get a PROPNAME then we simply return the list with empty - values which we get from the interface class - - If we get an ALLPROP we first get the list of properties and then - we do the same as with a PROP method. - - If the uri doesn't exist, return an xml response with a 404 status - - """ - - if not self.__dataclass.exists(self.__uri): - raise DAV_NotFound("Path %s doesn't exist" % self.__uri) - - if self.request_type==RT_ALLPROP: - return self.create_allprop() - - if self.request_type==RT_PROPNAME: - return self.create_propname() - - if self.request_type==RT_PROP: - return self.create_prop() - - # no body means ALLPROP! - return self.create_allprop() - - def create_propname(self): - """ create a multistatus response for the prop names """ - - dc=self.__dataclass - # create the document generator - doc = Document(None) - 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) - ms.appendChild(re) - - elif self.__depth=="1": - 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) - ms.appendChild(re) - # *** depth=="infinity" - - 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=[] - for ns,plist in self.__dataclass.get_propnames(self.__uri).items(): - self.proplist[ns]=plist - self.namespaces.append(ns) - - return self.create_prop() - - def create_prop(self): - """ handle a request - - This will - - 1. set up the -Framework - - 2. read the property values for each URI - (which is dependant on the Depth header) - This is done by the get_propvalues() method. - - 3. For each URI call the append_result() method - to append the actual -Tag to the result - document. - - We differ between "good" properties, which have been - assigned a value by the interface class and "bad" - properties, which resulted in an error, either 404 - (Not Found) or 403 (Forbidden). - - """ - - - # create the document generator - doc = Document(None) - 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) - ms.appendChild(res) - - elif self.__depth=="1": - 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) - ms.appendChild(res) - except DAV_NotFound: - # If no children, never mind. - pass - - sfile=StringIO() - ext.PrettyPrint(doc,stream=sfile) - s=sfile.getvalue() - sfile.close() - return s - - - def mk_propname_response(self,uri,propnames,doc): - """ make a new result element for a PROPNAME request - - This will simply format the propnames list. - propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...} - - """ - re=doc.createElement("D:response") - - # write href information - href=doc.createElement("D:href") - if self.use_full_urls: - huri=doc.createTextNode(uri) - else: - 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 - - for ns,plist in propnames.items(): - # write prop element - pr=doc.createElement("D:prop") - nsp="ns"+str(nsnum) - pr.setAttribute("xmlns:"+nsp,ns) - nsnum=nsnum+1 - - # write propertynames - for p in plist: - pe=doc.createElement(nsp+":"+p) - pr.appendChild(pe) - - ps.appendChild(pr) - - re.appendChild(ps) - - return re - - def mk_prop_response(self,uri,good_props,bad_props,doc): - """ make a new result element - - We differ between the good props and the bad ones for - each generating an extra -Node (for each error - one, that means). - - """ - re=doc.createElement("D:response") - # append namespaces to response - nsnum=0 - for nsname in self.namespaces: - re.setAttribute("xmlns:ns"+str(nsnum),nsname) - nsnum=nsnum+1 - - # write href information - href=doc.createElement("D:href") - if self.use_full_urls: - huri=doc.createTextNode(uri) - else: - 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") - - 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)) - if v == None: - pass - elif ns=='DAV:' and p=="resourcetype": - if v == 1: - ve=doc.createElement("D:collection") - pe.appendChild(ve) - elif isinstance(v,tuple) and v[1] == ns: - ve=doc.createElement(ns_prefix+v[0]) - pe.appendChild(ve) - else: - 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.appendChild(t) - ps.appendChild(s) - re.appendChild(ps) - - # now write the errors! - if len(bad_props.items()): - - # write a propstat for each error code - for ecode in bad_props.keys(): - ps=doc.createElement("D:propstat") - re.appendChild(ps) - bp=doc.createElement("D:prop") - ps.appendChild(bp) - - for ns in bad_props[ecode].keys(): - ns_prefix="ns"+str(self.namespaces.index(ns))+":" - - for p in bad_props[ecode][ns]: - pe=doc.createElement(ns_prefix+str(p)) - bp.appendChild(pe) - - s=doc.createElement("D:status") - t=doc.createTextNode(utils.gen_estring(ecode)) - s.appendChild(t) - ps.appendChild(s) - re.appendChild(ps) - - # return the new response element - return re - - def get_propvalues(self,uri): - """ create lists of property values for an URI - - We create two lists for an URI: the properties for - which we found a value and the ones for which we - only got an error, either because they haven't been - found or the user is not allowed to read them. - - """ - good_props={} - bad_props={} - - for (ns,plist) in self.proplist.items(): - 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 - except DAV_Error, error_code: - ec=error_code[0] - - # ignore props with error_code if 0 (invisible) - if ec==0: continue - - if bad_props.has_key(ec): - if bad_props[ec].has_key(ns): - bad_props[ec][ns].append(prop) - else: - bad_props[ec][ns]=[prop] - else: - bad_props[ec]={ns:[prop]} - - return good_props, bad_props - diff --git a/addons/document_webdav/DAV/status.py b/addons/document_webdav/DAV/status.py deleted file mode 100644 index 62cb323c4fb..00000000000 --- a/addons/document_webdav/DAV/status.py +++ /dev/null @@ -1,31 +0,0 @@ -""" - -status codes for DAV services - - -""" - - -STATUS_CODES={ - 102: "Processing", - 200: "Ok", - 201: "Created", - 204: "No Content", - 207: "Multi-Status", - 201: "Created", - 400: "Bad Request", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 409: "Conflict", - 412: "Precondition failed", - 423: "Locked", - 415: "Unsupported Media Type", - 507: "Insufficient Storage", - 422: "Unprocessable Entity", - 423: "Locked", - 424: "Failed Dependency", - 502: "Bad Gateway", - 507: "Insufficient Storage", - 999: "Some error in Create Method please check the data of create method" -} diff --git a/addons/document_webdav/DAV/utils.py b/addons/document_webdav/DAV/utils.py deleted file mode 100755 index c4bb4d1a4c0..00000000000 --- a/addons/document_webdav/DAV/utils.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python - -""" - -UTILITIES - -- parse a propfind request body into a list of props - -""" - -from xml.dom import ext -from xml.dom.Document import Document -from xml.dom.ext.reader import PyExpat -from xml.dom import Node -from xml.dom import NodeIterator, NodeFilter - -from string import lower, split, atoi, joinfields -import urlparse -from StringIO import StringIO - -from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP -from status import STATUS_CODES - -VERSION = '0.6' -AUTHOR = 'Simon Pamies ' - - -def gen_estring(ecode): - """ generate an error string from the given code """ - ec=atoi(str(ecode)) - if STATUS_CODES.has_key(ec): - return "HTTP/1.1 %s %s" %(ec,STATUS_CODES[ec]) - else: - return "HTTP/1.1 %s" %(ec) - -def parse_propfind(xml_doc): - """ parse an propfind xml file and return a list of props - - returns: - - request_type -- ALLPROP, PROPNAME, PROP - proplist -- list of properties found - namespaces -- list of namespaces found - - """ - doc = PyExpat.Reader().fromString(xml_doc) - snit = doc.createNodeIterator(doc, NodeFilter.NodeFilter.SHOW_ELEMENT, None, None) - - request_type=None - props={} - namespaces=[] - - while 1: - curr_elem = snit.nextNode() - if not curr_elem: break - ename=fname=lower(curr_elem.nodeName) - if ":" in fname: - 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 - - # rest should be names of attributes - - ns = curr_elem.namespaceURI - if props.has_key(ns): - props[ns].append(ename) - else: - props[ns]=[ename] - namespaces.append(ns) - - return request_type,props,namespaces - - -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 - - uri - the root of the subtree to flatten - - It will return the flattened tree as list - - """ - queue=[uri] - list=[uri] - while len(queue): - element=queue[-1] - if dataclass.is_collection(element): - childs=dataclass.get_childs(element) - else: - childs=[] - if len(childs): - list=list+childs - # update queue - del queue[-1] - if len(childs): - queue=queue+childs - return list - -def is_prefix(uri1,uri2): - """ returns 1 of uri1 is a prefix of uri2 """ - if uri2[:len(uri1)]==uri1: - return 1 - else: - return None - -def quote_uri(uri): - """ quote an URL but not the protocol part """ - 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])) - -def get_uriparentpath(uri): - """ extract the uri path and remove the last element """ - 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] - -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])) - -### 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:") - 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)) - 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.close() - return s - diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 1acbfd7d5ec..9ef91e0f9a6 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -59,67 +59,47 @@ class tinydav_handler(dav_interface): """ This class models a Tiny ERP interface for the DAV server """ - PROPS={'DAV:': dav_interface.PROPS['DAV:'], } + 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): + def __init__(self, parent, verbose=False): self.db_name = False self.directory_id=False self.db_name_list=[] self.parent = parent self.baseuri = parent.baseuri + self.verbose = verbose - def get_propnames(self,uri): - props = self.PROPS - self.parent.log_message('get propnames: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - cr.close() - return props - node = self.uri2object(cr,uid,pool, uri2) - if node: - props.update(node.get_dav_props(cr)) - cr.close() - return props + def get_propnames(self,uri): + props = self.PROPS + return props - def get_prop(self,uri,ns,propname): - """ return the value of a given property + def _get_dav_lockdiscovery(self, uri): + raise DAV_NotFound - uri -- uri of the object to get the property of - ns -- namespace of the property - pname -- name of the property - """ - if self.M_NS.has_key(ns): - return dav_interface.get_prop(self,uri,ns,propname) + def _get_dav_supportedlock(self, uri): + raise DAV_NotFound + def get_prop(self,uri,ns,propname): + """ return the value of a given property - 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) - if not node: - cr.close() - raise DAV_NotFound - res = node.get_dav_eprop(cr,ns,propname) - cr.close() - return res + uri -- uri of the object to get the property of + ns -- namespace of the property + pname -- name of the property + """ + if self.M_NS.has_key(ns): + return dav_interface.get_prop(self,uri,ns,propname) + raise DAV_NotFound -# -# def get_db(self,uri): -# names=self.uri2local(uri).split('/') -# self.db_name=False -# if len(names) > 1: -# self.db_name=self.uri2local(uri).split('/')[1] -# if self.db_name=='': -# raise Exception,'Plese specify Database name in folder' -# return self.db_name -# - - def later_get_db_from_path(self,path): - return "aaa" + def get_db(self,uri): + names=self.uri2local(uri).split('/') + self.db_name=False + if len(names) > 1: + self.db_name=self.uri2local(uri).split('/')[1] + if self.db_name=='': + raise Exception,'Plese specify Database name in folder' + return self.db_name + def urijoin(self,*ajoin): """ Return the base URI of this request, or even join it with the @@ -130,7 +110,7 @@ class tinydav_handler(dav_interface): @memoize(4) def db_list(self): s = netsvc.ExportService.getService('db') - result = s.list() + result = s.exp_list() self.db_name_list=[] for db_name in result: db = pooler.get_db_only(db_name) @@ -146,16 +126,17 @@ class tinydav_handler(dav_interface): """ return the child objects as self.baseuris for the given URI """ self.parent.log_message('get childs: %s' % uri) if uri[-1]=='/':uri=uri[:-1] - cr, uid, pool, dbname, uri2 = self.get_cr(uri) + cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - s = netsvc.ExportService.getService('db') - cr.close() - return map(lambda x: self.urijoin(x), self.db_list()) + if not dbname: + if cr: cr.close() + res = map(lambda x: self.urijoin(x), self.db_list()) + return res result = [] node = self.uri2object(cr,uid,pool, uri2[:]) + if not node: - cr.close() + if cr: cr.close() raise DAV_NotFound(uri2) else: fp = node.full_path() @@ -165,12 +146,13 @@ class tinydav_handler(dav_interface): else: fp = None for d in node.children(cr): - self.parent.log_message('child: %s' % d.path) + self.parent.log_message('child: %s' % d.path) if fp: result.append( self.urijoin(dbname,fp,d.path) ) else: result.append( self.urijoin(dbname,d.path) ) - cr.close() + if cr: cr.close() + return result def uri2local(self, uri): @@ -183,24 +165,28 @@ class tinydav_handler(dav_interface): # # pos: -1 to get the parent of the uri # - def get_cr(self, uri): + def get_cr(self, uri): pdb = self.parent.auth_proxy.last_auth reluri = self.uri2local(uri) try: - dbname = reluri.split('/')[2] + dbname = reluri.split('/')[1] except: - dbname = False + dbname = False if not dbname: return None, None, None, False, None if not pdb and dbname: # if dbname was in our uri, we should have authenticated # against that. raise Exception("Programming error") - assert pdb == dbname, " %s != %s" %(pdb, dbname) - user, passwd, dbn2, uid = self.parent.auth_proxy.auth_creds[pdb] + #assert pdb == dbname, " %s != %s" %(pdb, dbname) + res = self.parent.auth_proxy.auth_creds.get(dbname, False) + if not res: + self.parent.auth_proxy.checkRequest(self.parent, uri, dbname) + res = self.parent.auth_proxy.auth_creds[dbname] + user, passwd, dbn2, uid = res db,pool = pooler.get_db_and_pool(dbname) cr = db.cursor() - uri2 = reluri.split('/')[3:] + uri2 = reluri.split('/')[2:] return cr, uid, pool, dbname, uri2 def uri2object(self, cr,uid, pool,uri): @@ -208,20 +194,20 @@ class tinydav_handler(dav_interface): return None return pool.get('document.directory').get_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) except TypeError,e: - import traceback + import traceback self.parent.log_error("GET typeError: %s", str(e)) self.parent.log_message("Exc: %s",traceback.format_exc()) raise DAV_Forbidden @@ -235,11 +221,11 @@ class tinydav_handler(dav_interface): raise DAV_Error, 409 return datas finally: - cr.close() + if cr: cr.close() @memoize(CACHE_SIZE) def _get_dav_resourcetype(self,uri): - """ return type of object """ + """ return type of object """ self.parent.log_message('get RT: %s' % uri) if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) @@ -253,7 +239,7 @@ class tinydav_handler(dav_interface): return COLLECTION return OBJECT finally: - cr.close() + if cr: cr.close() def _get_dav_displayname(self,uri): self.parent.log_message('get DN: %s' % uri) @@ -271,14 +257,14 @@ class tinydav_handler(dav_interface): @memoize(CACHE_SIZE) def _get_dav_getcontentlength(self,uri): - """ return the content length of an object """ + """ return the content length of an object """ self.parent.log_message('get length: %s' % uri) if uri[-1]=='/':uri=uri[:-1] result = 0 - cr, uid, pool, dbname, uri2 = self.get_cr(uri) + cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: - cr.close() - return '0' + if cr: cr.close() + return str(result) node = self.uri2object(cr, uid, pool, uri2) if not node: cr.close() @@ -311,9 +297,9 @@ class tinydav_handler(dav_interface): if uri[-1]=='/':uri=uri[:-1] today = time.time() cr, uid, pool, dbname, uri2 = self.get_cr(uri) - try: - if not dbname: - return today + if not dbname: + return today + try: node = self.uri2object(cr,uid,pool, uri2) if not node: raise DAV_NotFound(uri2) @@ -322,36 +308,35 @@ class tinydav_handler(dav_interface): else: return today finally: - cr.close() + if cr: cr.close() @memoize(CACHE_SIZE) def get_creationdate(self,uri): - """ return the last modified date of the object """ - + """ return the last modified date of the object """ if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) - try: - if not dbname: - raise DAV_Error, 409 + if not dbname: + raise DAV_Error, 409 + try: node = self.uri2object(cr,uid,pool, uri2) if not node: - raise DAV_NotFound(uri2) + raise DAV_NotFound(uri2) if node.create_date: - result = time.strptime(node.create_date,'%Y-%m-%d %H:%M:%S') + result = time.mktime(time.strptime(node.create_date,'%Y-%m-%d %H:%M:%S')) else: - result = time.gmtime() + result = time.time() return result finally: - cr.close() + if cr: cr.close() @memoize(CACHE_SIZE) 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' + if not dbname: + return 'httpd/unix-directory' + try: node = self.uri2object(cr,uid,pool, uri2) if not node: raise DAV_NotFound(uri2) @@ -359,8 +344,8 @@ class tinydav_handler(dav_interface): return result #raise DAV_NotFound, 'Could not find %s' % path finally: - cr.close() - + if cr: cr.close() + def mkcol(self,uri): """ create a new collection """ self.parent.log_message('MKCOL: %s' % uri) @@ -401,7 +386,7 @@ 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), data and len(data) or 0, content_type)) parent='/'.join(uri.split('/')[:-1]) cr, uid, pool,dbname, uri2 = self.get_cr(uri) if not dbname: @@ -633,7 +618,7 @@ class tinydav_handler(dav_interface): result = False cr, uid, pool,dbname, uri2 = self.get_cr(uri) if not dbname: - cr.close() + if cr: cr.close() return True try: node = self.uri2object(cr,uid,pool, uri2) diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index 15e8e030824..f2c129dd608 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -28,10 +28,113 @@ import netsvc +import tools from dav_fs import tinydav_handler from tools.config import config from DAV.WebDAVServer import DAVRequestHandler from service.websrv_lib import HTTPDir,FixSendError +from DAV.propfind import PROPFIND + +import xml.dom.minidom +domimpl = xml.dom.minidom.getDOMImplementation() +import urlparse +import urllib +from DAV import utils + +super_mk_prop_response = PROPFIND.mk_prop_response +def mk_prop_response(self,uri,good_props,bad_props,doc): + """ make a new result element + + We differ between the good props and the bad ones for + each generating an extra -Node (for each error + one, that means). + + """ + re=doc.createElement("D:response") + # append namespaces to response + nsnum=0 + for nsname in self.namespaces: + re.setAttribute("xmlns:ns"+str(nsnum),nsname) + nsnum=nsnum+1 + + # write href information + uparts=urlparse.urlparse(uri) + fileloc=uparts[2] + href=doc.createElement("D:href") + huri=doc.createTextNode(uparts[0]+'://'+'/'.join(uparts[1:2]) + urllib.quote(fileloc)) + href.appendChild(huri) + re.appendChild(href) + + # write good properties + ps=doc.createElement("D:propstat") + if good_props: + re.appendChild(ps) + + 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(): + if not v: + pass + pe=doc.createElement(ns_prefix+str(p)) + if hasattr(v, '__class__') and v.__class__.__name__ == 'Element': + pe.appendChild(v) + else: + if p=="resourcetype": + if v==1: + ve=doc.createElement("D:collection") + pe.appendChild(ve) + else: + ve=doc.createTextNode(tools.ustr(v)) + pe.appendChild(ve) + + gp.appendChild(pe) + + ps.appendChild(gp) + s=doc.createElement("D:status") + t=doc.createTextNode("HTTP/1.1 200 OK") + s.appendChild(t) + ps.appendChild(s) + re.appendChild(ps) + + # now write the errors! + if len(bad_props.items()): + + # write a propstat for each error code + for ecode in bad_props.keys(): + ps=doc.createElement("D:propstat") + re.appendChild(ps) + bp=doc.createElement("D:prop") + ps.appendChild(bp) + + for ns in bad_props[ecode].keys(): + ns_prefix="ns"+str(self.namespaces.index(ns))+":" + + for p in bad_props[ecode][ns]: + pe=doc.createElement(ns_prefix+str(p)) + bp.appendChild(pe) + + s=doc.createElement("D:status") + t=doc.createTextNode(utils.gen_estring(ecode)) + s.appendChild(t) + ps.appendChild(s) + re.appendChild(ps) + + # return the new response element + return re + + +PROPFIND.mk_prop_response = mk_prop_response + +def OpenDAVConfig(**kw): + class OpenDAV: + def __init__(self, **kw): + self.__dict__.update(**kw) + + class Config: + DAV = OpenDAV(**kw) + + return Config() class DAVHandler(FixSendError,DAVRequestHandler): verbose = False @@ -43,16 +146,24 @@ class DAVHandler(FixSendError,DAVRequestHandler): netsvc.Logger().notifyChannel("webdav",netsvc.LOG_DEBUG,message) def handle(self): - pass + self._init_buffer() def finish(self): pass + def get_db_from_path(self, uri): + if uri or uri == '/': + dbs = self.IFACE_CLASS.db_list() + res = len(dbs) and dbs[0] or False + else: + res = self.IFACE_CLASS.get_db(uri) + return res + def setup(self): - davpath = '/'+config.get_misc('webdav','vdir','webdav')+'/' - self.baseuri = "http://%s:%d%s"% (self.server.server_name,self.server.server_port,davpath) - self.IFACE_CLASS = tinydav_handler(self) - pass + davpath = '/'+config.get_misc('webdav','vdir','webdav') + self.baseuri = "http://%s:%d/"% (self.server.server_name,self.server.server_port) + self.IFACE_CLASS = tinydav_handler(self, self.verbose) + def log_message(self, format, *args): netsvc.Logger().notifyChannel('webdav',netsvc.LOG_DEBUG_RPC,format % args) @@ -62,14 +173,23 @@ class DAVHandler(FixSendError,DAVRequestHandler): try: - from service.http_server import reg_http_service,OpenERPAuthProvider + from service.http_server import reg_http_service,OpenERPAuthProvider + if (config.get_misc('webdav','enable',True)): - davpath = '/'+config.get_misc('webdav','vdir','webdav')+'/' + directory = '/'+config.get_misc('webdav','vdir','webdav') handler = DAVHandler - handler.verbose = config.get_misc('webdav','verbose',True) + 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) + _dc = { 'verbose' : verbose, + 'directory' : directory, + 'lockemulation' : False, + + } + + conf = OpenDAVConfig(**_dc) + handler._config = conf + reg_http_service(HTTPDir(directory,DAVHandler,OpenERPAuthProvider())) + netsvc.Logger().notifyChannel('webdav',netsvc.LOG_INFO,"WebDAV service registered at path: %s/ "% directory) except Exception, e: logger = netsvc.Logger() logger.notifyChannel('webdav', netsvc.LOG_ERROR, 'Cannot launch webdav: %s' % e) From 565d1a18c737021cde9e0faa7b5718ae04992972 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Mon, 12 Apr 2010 16:22:00 +0530 Subject: [PATCH 005/761] [REF+IMP] caldav bzr revid: hmo@tinyerp.com-20100412105200-c3kvao81ypbh8l0g --- addons/caldav/DAV/BufferingHTTPServer.py | 101 ----- addons/caldav/DAV/WebDAVServer.py | 381 ------------------ addons/caldav/DAV/__init__.py | 20 - addons/caldav/DAV/constants.py | 18 - addons/caldav/DAV/davcmd.py | 219 ---------- addons/caldav/DAV/davcopy.py | 134 ------ addons/caldav/DAV/davmove.py | 103 ----- addons/caldav/DAV/delete.py | 64 --- addons/caldav/DAV/errors.py | 57 --- addons/caldav/DAV/iface.py | 264 ------------ addons/caldav/DAV/propfind.py | 373 ----------------- addons/caldav/DAV/status.py | 31 -- addons/caldav/DAV/utils.py | 161 -------- addons/caldav/__init__.py | 5 +- addons/caldav/__terp__.py | 3 +- addons/caldav/caldav_cache.py | 62 --- .../{caldav.py => caldav_collection.py} | 13 +- addons/caldav/caldav_fs.py | 311 +------------- addons/caldav/caldav_view.xml | 81 ++-- addons/caldav/security/ir.model.access.csv | 1 - addons/caldav/webdav_server.py | 78 ---- addons/caldav/wizard/calendar_event_export.py | 4 +- .../wizard/calendar_event_export_view.xml | 6 +- addons/caldav/wizard/calendar_event_import.py | 2 +- .../wizard/calendar_event_import_view.xml | 6 +- .../caldav/wizard/calendar_event_subscribe.py | 4 +- .../wizard/calendar_event_subscribe_view.xml | 8 +- addons/crm_caldav/crm_caldav.py | 2 - addons/crm_caldav/crm_caldav_data.xml | 2 +- addons/document_webdav/__init__.py | 34 +- addons/document_webdav/dav_fs.py | 39 +- addons/document_webdav/webdav.py | 114 ++++++ addons/document_webdav/webdav_server.py | 96 +---- addons/project_caldav/project_caldav_data.xml | 2 +- 34 files changed, 227 insertions(+), 2572 deletions(-) delete mode 100644 addons/caldav/DAV/BufferingHTTPServer.py delete mode 100644 addons/caldav/DAV/WebDAVServer.py delete mode 100644 addons/caldav/DAV/__init__.py delete mode 100644 addons/caldav/DAV/constants.py delete mode 100644 addons/caldav/DAV/davcmd.py delete mode 100755 addons/caldav/DAV/davcopy.py delete mode 100755 addons/caldav/DAV/davmove.py delete mode 100755 addons/caldav/DAV/delete.py delete mode 100755 addons/caldav/DAV/errors.py delete mode 100644 addons/caldav/DAV/iface.py delete mode 100755 addons/caldav/DAV/propfind.py delete mode 100644 addons/caldav/DAV/status.py delete mode 100755 addons/caldav/DAV/utils.py delete mode 100644 addons/caldav/caldav_cache.py rename addons/caldav/{caldav.py => caldav_collection.py} (99%) delete mode 100644 addons/caldav/webdav_server.py create mode 100644 addons/document_webdav/webdav.py diff --git a/addons/caldav/DAV/BufferingHTTPServer.py b/addons/caldav/DAV/BufferingHTTPServer.py deleted file mode 100644 index bf2e9e59800..00000000000 --- a/addons/caldav/DAV/BufferingHTTPServer.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python - -""" - Buffering HTTP Server - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -""" - - -from utils import VERSION, AUTHOR -__version__ = VERSION -__author__ = AUTHOR - -from BaseHTTPServer import BaseHTTPRequestHandler -import os - -class BufferedHTTPRequestHandler(BaseHTTPRequestHandler): - """ - Buffering HTTP Request Handler - - This class is an extension to the BaseHTTPRequestHandler - class which buffers the whole output and sends it at once - after the processing if the request is finished. - - This makes it possible to work together with some clients - which otherwise would break (e.g. cadaver) - - """ - - - def _init_buffer(self): - """initialize the buffer. - - If you override the handle() method remember to call - this (see below) - """ - self.__buffer = "" - self.__outfp = os.tmpfile() - - def _append(self,s): - """ append a string to the buffer """ - self.__buffer = self.__buffer+s - - def _flush(self): - """ flush the buffer to wfile """ - self.wfile.write(self.__buffer) - self.__outfp.write(self.__buffer) - self.__outfp.flush() - self.wfile.flush() - self.__buffer = "" - - def handle(self): - """ Handle a HTTP request """ - self._init_buffer() - BaseHTTPRequestHandler.handle(self) - self._flush() - - def send_header(self, keyword, value): - """Send a MIME header.""" - if self.request_version != 'HTTP/0.9': - self._append("%s: %s\r\n" % (keyword, value)) - - def end_headers(self): - """Send the blank line ending the MIME headers.""" - if self.request_version != 'HTTP/0.9': - self._append("\r\n") - - def send_response(self, code, message=None): - self.log_request(code) - - if message is None: - if self.responses.has_key(code): - message = self.responses[code][0] - else: - message = '' - - if self.request_version != 'HTTP/0.9': - self._append("%s %s %s\r\n" % - (self.protocol_version, str(code), message)) - - self.send_header('Server', self.version_string()) - self.send_header('Connection', 'close') - self.send_header('Date', self.date_time_string()) - - protocol_version="HTTP/1.1" - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/caldav/DAV/WebDAVServer.py b/addons/caldav/DAV/WebDAVServer.py deleted file mode 100644 index fa30aa6b82b..00000000000 --- a/addons/caldav/DAV/WebDAVServer.py +++ /dev/null @@ -1,381 +0,0 @@ -#!/usr/bin/env python - -""" - Python WebDAV Server. - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -This module builds on AuthServer by implementing the standard DAV -methods. - -Subclass this class and specify an IFACE_CLASS. See example. - -""" - -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 -import time -import socket -import string -import posixpath -import base64 -import urlparse -import urllib -import BaseHTTPServer - -class DAVRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): - """Simple DAV request handler with - - - GET - - HEAD - - PUT - - OPTIONS - - PROPFIND - - PROPPATCH - - MKCOL - - It uses the resource/collection classes for serving and - storing content. - - """ - - server_version = "DAV/" + __version__ - protocol_version = 'HTTP/1.1' - - ### utility functions - def _log(self, message): - pass - - 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): - """ send a body in one part """ - - if not headers: - headers = {} - 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) - - if DATA: - self.send_header("Content-Length", str(len(DATA))) - self.send_header("Content-Type", ctype) - else: - self.send_header("Content-Length", "0") - - self.end_headers() - if DATA: - self._append(DATA) - - 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.send_header("Content-type", ctype) - self.send_header("Connection", "keep-alive") - self.send_header("Transfer-Encoding", "chunked") - self.end_headers() - self._append(hex(len(DATA))[2:]+"\r\n") - self._append(DATA) - self._append("\r\n") - self._append("0\r\n") - self._append("\r\n") - - ### HTTP METHODS - - def do_OPTIONS(self): - """return the list of capabilities """ - self.send_response(200) - self.send_header("Allow", "GET, HEAD, COPY, MOVE, POST, PUT, PROPFIND, PROPPATCH, OPTIONS, MKCOL, DELETE, TRACE") - self.send_header("Content-Type", "text/plain") - self.send_header("Connection", "keep-alive") - self.send_header("DAV", "1") - self.end_headers() - - def do_PROPFIND(self): - - dc = self.IFACE_CLASS - # read the body - body = None - if self.headers.has_key("Content-Length"): - l = self.headers['Content-Length'] - body = self.rfile.read(atoi(l)) - alt_body = """ - - - - - - - - - - """ - #self.wfile.write(body) - - # which Depth? - if self.headers.has_key('Depth'): - d = self.headers['Depth'] - else: - d = "infinity" - - uri = self.geturi() - pf = PROPFIND(uri, dc, d) - - if body: - pf.read_propfind(body) - - try: - DATA = pf.createResponse() - DATA = DATA+"\n" - # print "Data:", DATA - except DAV_NotFound, (ec, dd): - return self.send_notFound(dd, uri) - except DAV_Error, (ec, dd): - return self.send_error(ec, dd) - - self.send_body_chunks(DATA, 207, "Multi-Status", "Multiple responses") - - def geturi(self): - buri = self.IFACE_CLASS.baseuri - if buri[-1] == '/': - return urllib.unquote(buri[:-1]+self.path) - else: - return urllib.unquote(buri+self.path) - - def do_GET(self): - """Serve a GET request.""" - dc = self.IFACE_CLASS - uri = self.geturi() - - # get the last modified date - try: - 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"} - - # get the content type - try: - ct = dc.get_prop(uri, "DAV:", "getcontenttype") - except: - ct = "application/octet-stream" - - # get the data - try: - 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) - - def do_HEAD(self): - """ Send a HEAD response """ - dc = self.IFACE_CLASS - uri = self.geturi() - - # get the last modified date - try: - 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"} - - # get the content type - try: - ct = dc.get_prop(uri, "DAV:", "getcontenttype") - except: - ct = "application/octet-stream" - - try: - data = dc.get_data(uri) - headers["Content-Length"] = str(len(data)) - except DAV_NotFound: - self.send_body(None, 404, "Not Found", "") - return - - self.send_body(None, 200, "OK", "OK", ct, headers) - - def do_POST(self): - self.send_error(404, "File not found") - - def do_MKCOL(self): - """ create a new collection """ - - dc = self.IFACE_CLASS - uri = self.geturi() - try: - res = dc.mkcol(uri) - if res: - self.send_body(None, 201, "Created", '') - else: - 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) - - def do_DELETE(self): - """ delete an resource """ - dc = self.IFACE_CLASS - uri = self.geturi() - dl = DELETE(uri, dc) - if dc.is_collection(uri): - res = dl.delcol() - else: - res = dl.delone() - - if res: - self.send_status(207, body=res) - else: - self.send_status(204) - - def do_PUT(self): - dc = self.IFACE_CLASS - - # read the body - body = None - if self.headers.has_key("Content-Length"): - l = self.headers['Content-Length'] - body = self.rfile.read(atoi(l)) - uri = self.geturi() - - ct = None - if self.headers.has_key("Content-Type"): - ct = self.headers['Content-Type'] - try: - dc.put(uri, body, ct) - except DAV_Error, (ec, dd): - self.send_status(ec) - return - self.send_status(201) - - def do_COPY(self): - """ copy one resource to another """ - try: - self.copymove(COPY) - 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): - self.send_status(ec) - - def copymove(self, CLASS): - """ common method for copying or moving objects """ - dc = self.IFACE_CLASS - - # get the source URI - source_uri = self.geturi() - - # get the destination URI - dest_uri = self.headers['Destination'] - dest_uri = urllib.unquote(dest_uri) - - # Overwrite? - 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) - - # Depth? - d = "infinity" - if self.headers.has_key("Depth"): - d = self.headers['Depth'] - - if d!="0" and d!="infinity": - self.send_status(400) - return - - if d=="0": - 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): - self.send_status(ec) - return - else: - try: - 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], - ctype='text/xml; charset="utf-8"') - else: - self.send_status(result_code) - - 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): - - if not msg: msg = STATUS_CODES[code] - self.send_body(body, code, STATUS_CODES[code], msg, mediatype) - - def send_notFound(self, descr, uri): - body = """ - - %s - - %s - - """ - return self.send_status(404, descr, body=body % (uri, descr)) - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/caldav/DAV/__init__.py b/addons/caldav/DAV/__init__.py deleted file mode 100644 index 10abdb40014..00000000000 --- a/addons/caldav/DAV/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -""" - - diff --git a/addons/caldav/DAV/constants.py b/addons/caldav/DAV/constants.py deleted file mode 100644 index e858ac519c2..00000000000 --- a/addons/caldav/DAV/constants.py +++ /dev/null @@ -1,18 +0,0 @@ -""" - -constants definition - - -""" - -# definition for resourcetype -COLLECTION=1 -OBJECT=None -DAV_PROPS=['creationdate', 'displayname', 'getcontentlanguage', 'getcontentlength', 'getcontenttype', 'getetag', 'getlastmodified', 'lockdiscovery', 'resourcetype', 'source', 'supportedlock'] - - -# Request classes in propfind - -RT_ALLPROP=1 -RT_PROPNAME=2 -RT_PROP=3 diff --git a/addons/caldav/DAV/davcmd.py b/addons/caldav/DAV/davcmd.py deleted file mode 100644 index 34c061d77ab..00000000000 --- a/addons/caldav/DAV/davcmd.py +++ /dev/null @@ -1,219 +0,0 @@ -""" - -davcmd.py ---------- - -containts commands like copy, move, delete for normal -resources and collections - -""" - -from string import split,replace,joinfields -import urlparse - -from utils import create_treelist, is_prefix -from errors import * - -def deltree(dc, uri, exclude={}): - """ delete a tree of resources - - dc -- dataclass to use - uri -- root uri to delete - exclude -- an optional list of uri:error_code pairs which should not - be deleted. - - returns dict of uri:error_code tuples from which - another method can create a multistatus xml element. - - Also note that we only know Depth=infinity thus we don't have - to test for it. - - """ - - tlist = create_treelist(dc,uri) - result = {} - - for i in range(len(tlist),0,-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 - for p in problem_uris: - if is_prefix(element,p): - ok = None - break - - if not ok: continue - - # here we test for the exclude list which is the other way round! - for p in exclude.keys(): - if is_prefix(p,element): - ok = None - break - - if not ok: continue - - # now delete stuff - try: - delone(dc,element) - except DAV_Error, (ec,dd): - result[element] = ec - - return result - -def delone(dc, uri): - """ delete a single object """ - if dc.is_collection(uri): - dc.rmcol(uri) # should be empty - else: - dc.rm(uri) - -### -### COPY -### - -# helper function - -def copy(dc, src, dst): - """ only copy the element - - This is just a helper method factored out from copy and - copytree. It will not handle the overwrite or depth header. - - """ - - # destination should have been deleted before - if dc.exists(dst): raise DAV_Error, 412 - - # source should exist also - if not dc.exists(src): raise DAV_NotFound - - if dc.is_collection(src): - dc.copycol(src,dst) # an exception will be passed thru - else: - dc.copy(src,dst) # an exception will be passed thru - - -# the main functions - -def copyone(dc, src, dst, overwrite=None): - """ copy one resource to a new destination """ - - if overwrite and dc.exists(dst): - delres = deltree(dc,dst) - else: - delres = {} - - # if we cannot delete everything, then do not copy! - if delres: return delres - - try: - copy(dc,src,dst) # pass thru exceptions - except DAV_Error, (ec,dd): - return ec - -def copytree(dc, src, dst, overwrite=None): - """ copy a tree of resources to another location - - dc -- dataclass to use - src -- src uri from where to copy - dst -- dst uri - overwrite -- if 1 then delete dst uri before - - returns dict of uri:error_code tuples from which - another method can create a multistatus xml element. - - """ - - - # first delete the destination resource - if overwrite and dc.exists(dst): - delres = deltree(dc,dst) - else: - 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 = {} - - # prepare destination URIs (get the prefix) - dpath = urlparse.urlparse(dst)[2] - - for element in tlist: - 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 - for p in problem_uris: - if is_prefix(p,element): - ok = None - break - - if not ok: continue - - # now create the destination URI which corresponds to - # the actual source URI. -> actual_dst - # ("subtract" the base src from the URI and prepend the - # dst prefix to it.) - esrc = replace(element,src,"") - actual_dst = dpath+esrc - - # now copy stuff - try: - copy(dc,element,actual_dst) - except DAV_Error, (ec,dd): - result[element] = ec - - return result - - - -### -### MOVE -### - - -def moveone(dc, src, dst, overwrite=None): - """ move a single resource - - This is done by first copying it and then deleting - the original. - """ - - # first copy it - copyone(dc,src,dst,overwrite) - - # then delete it - dc.rm(src) - -def movetree(dc, src, dst, overwrite=None): - """ move a collection - - This is done by first copying it and then deleting - the original. - - PROBLEM: if something did not copy then we have a problem - when deleting as the original might get deleted! - """ - - # first copy it - res = copytree(dc,src,dst,overwrite) - - # then delete it - res = deltree(dc,src,exclude=res) - - return res - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/caldav/DAV/davcopy.py b/addons/caldav/DAV/davcopy.py deleted file mode 100755 index 6333aececf6..00000000000 --- a/addons/caldav/DAV/davcopy.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env python - -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - 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 - -import sys -import string -import urlparse -import urllib -from StringIO import StringIO - -import utils -from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP -from errors import * -from utils import create_treelist, quote_uri, gen_estring - -class COPY: - """ copy resources and eventually create multistatus responses - - This module implements the COPY class which is responsible for - copying resources. Usually the normal copy work is done in the - interface class. This class only creates error messages if error - occur. - - """ - - - 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): - """ copy a normal resources. - - We try to copy it and return the result code. - This is for Depth==0 - - """ - - 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] - if ps==pd: raise DAV_Error, 403 - - return dc.copyone(self.__src,self.__dst,self.__overwrite) - - #return copyone(dc,self.__src,self.__dst,self.__overwrite) - - def tree_action(self): - """ copy a tree of resources (a collection) - - Here we return a multistatus xml element. - - """ - 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] - if ps==pd: raise DAV_Error, 403 - - - result = dc.copytree(self.__src,self.__dst,self.__overwrite) - #result=copytree(dc,self.__src,self.__dst,self.__overwrite) - - if not result: return None - - ### - ### create the multistatus XML element - ### (this is also the same as in delete.py. - ### we might make a common method out of it) - ### - - doc = Document(None) - 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)) - 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.close() - return s - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/caldav/DAV/davmove.py b/addons/caldav/DAV/davmove.py deleted file mode 100755 index 3404f947469..00000000000 --- a/addons/caldav/DAV/davmove.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python - -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -""" - - -import sys -import string -import urlparse -import urllib -from StringIO import StringIO - -import utils -from constants import COLLECTION, OBJECT, DAV_PROPS -from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP -from errors import * -from utils import create_treelist, quote_uri, gen_estring, make_xmlresponse -from davcmd import moveone, movetree - -class MOVE: - """ move resources and eventually create multistatus responses - - This module implements the MOVE class which is responsible for - moving resources. - - MOVE is implemented by a COPY followed by a DELETE of the old - resource. - - """ - - - def __init__(self, dataclass, src_uri, dst_uri, overwrite): - self.__dataclass = dataclass - self.__src = src_uri - self.__dst = dst_uri - self.__overwrite = overwrite - - - def single_action(self): - """ move a normal resources. - - We try to move it and return the result code. - This is for Depth==0 - - """ - - 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] - if ps==pd: raise DAV_Error, 403 - - return dc.moveone(self.__src,self.__dst,self.__overwrite) - - def tree_action(self): - """ move a tree of resources (a collection) - - Here we return a multistatus xml element. - - """ - 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] - if ps==pd: raise DAV_Error, 403 - - 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: \ No newline at end of file diff --git a/addons/caldav/DAV/delete.py b/addons/caldav/DAV/delete.py deleted file mode 100755 index 3e75066f30e..00000000000 --- a/addons/caldav/DAV/delete.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python - -""" - - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - -""" -import os -import string -import urllib -from StringIO import StringIO - -from status import STATUS_CODES -from utils import gen_estring, quote_uri, make_xmlresponse -from davcmd import deltree - -class DELETE: - - 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) - - if not len(result.items()): - return None # everything ok - - # create the result element - return make_xmlresponse(result) - - def delone(self): - """ delete a resource """ - - dc = self.__dataclass - result = dc.delone(self.__uri) - - if not result: return None - if not len(result.items()): - return None # everything ok - - # create the result element - return make_xmlresponse(result) - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/caldav/DAV/errors.py b/addons/caldav/DAV/errors.py deleted file mode 100755 index 58d1d3be1d2..00000000000 --- a/addons/caldav/DAV/errors.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python -""" - - Exceptions for the DAVserver implementation - -""" - -class DAV_Error(Exception): - """ in general we can have the following arguments: - - 1. the error code - 2. the error result element, e.g. a element - """ - - def __init__(self, *args): - if len(args)==1: - self.args = (args[0],"") - else: - self.args = args - -class DAV_Secret(DAV_Error): - """ the user is not allowed to know anything about it - - returning this for a property value means to exclude it - from the response xml element. - """ - - def __init__(self): - DAV_Error.__init__(self,0) - pass - -class DAV_NotFound(DAV_Error): - """ a requested property was not found for a resource """ - - def __init__(self, *args): - if len(args): - if isinstance(args[0], list): - stre = "Path %s not found!"%('/'.join(args[0])) - else: - stre = args[0] - DAV_Error.__init__(self,404,stre) - else: - DAV_Error.__init__(self,404) - - pass - -class DAV_Forbidden(DAV_Error): - """ a method on a resource is not allowed """ - - 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: \ No newline at end of file diff --git a/addons/caldav/DAV/iface.py b/addons/caldav/DAV/iface.py deleted file mode 100644 index a723fb9f696..00000000000 --- a/addons/caldav/DAV/iface.py +++ /dev/null @@ -1,264 +0,0 @@ -""" - -basic interface class - -use this for subclassing when writing your own interface -class. - -""" - -from errors import * - -import time -from string import lower - -class dav_interface: - """ interface class for implementing DAV servers """ - - ### defined properties (modify this but let the DAV stuff there!) - ### the format is namespace: [list of properties] - - PROPS={"DAV:" : ('creationdate', - 'displayname', - 'getcontentlanguage', - 'getcontentlength', - 'getcontenttype', - 'getetag', - 'getlastmodified', - 'lockdiscovery', - 'resourcetype', - 'source', - 'supportedlock'), - "NS2" : ("p1","p2") - } - - # here we define which methods handle which namespace - # 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", - "NS2" : "ns2" } - - def get_propnames(self, uri): - """ return the property names allowed for the given URI - - In this method we simply return the above defined properties - assuming that they are valid for any resource. - You can override this in order to return a different set - of property names for each resource. - - """ - return self.PROPS - - def get_prop2(self, uri, ns, pname): - """ return the value of a property - """ - if lower(ns)=="dav:": return self.get_dav(uri,pname) - - raise DAV_NotFound - - def get_prop(self, uri, ns, propname): - """ return the value of a given property - - uri -- uri of the object to get the property of - ns -- namespace of the property - pname -- name of the property - """ - if self.M_NS.has_key(ns): - prefix = self.M_NS[ns] - else: - print "No namespace:",ns, "( for prop:", propname,")" - raise DAV_NotFound - mname = prefix+"_"+propname - if not hasattr(self,mname): - raise DAV_NotFound - - try: - m = getattr(self,mname) - r = m(uri) - return r - except AttributeError, e: - print 'Property %s not supported' % propname - print "Exception:", e - raise DAV_NotFound - - ### - ### DATA methods (for GET and PUT) - ### - - def get_data(self, uri): - """ return the content of an object - - return data or raise an exception - - """ - raise DAV_NotFound - - def put(self, uri, data): - """ write an object to the repository - - return a result code or raise an exception - """ - - raise DAV_Forbidden - - ### - ### Methods for DAV properties - ### - - def _get_dav_creationdate(self, uri): - """ return the creationdate of a resource """ - 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): - """ return the last modified date of a resource """ - d = self.get_lastmodified(uri) - if isinstance(d, int) or isinstance(d, float): - d = time.localtime(d) - # format it - return time.asctime(d) - - - ### - ### OVERRIDE THESE! - ### - - def get_creationdate(self, uri): - """ return the creationdate of the resource """ - return time.time() - - def get_lastmodified(self, uri): - """ return the last modification date of the resource """ - return time.time() - - - ### - ### COPY MOVE DELETE - ### - - ### methods for deleting a resource - - def rmcol(self, uri): - """ delete a collection - - This should not delete any children! This is automatically done - before by the DELETE class in DAV/delete.py - - return a success code or raise an exception - - """ - raise DAV_NotFound - - def rm(self, uri): - """ delete a single resource - - return a success code or raise an exception - - """ - raise DAV_NotFound - - """ - - COPY/MOVE HANDLER - - These handler are called when a COPY or MOVE method is invoked by - a client. In the default implementation it works as follows: - - - the davserver receives a COPY/MOVE method - - the davcopy or davmove module will be loaded and the corresponding - class will be initialized - - this class parses the query and decides which method of the interface class - to call: - - copyone for a single resource to copy - copytree for a tree to copy (collection) - (the same goes for move of course). - - - the interface class has now two options: - 1. to handle the action directly (e.g. cp or mv on filesystems) - 2. to let it handle via the copy/move methods in davcmd. - - ad 1) The first approach can be used when we know that no error can - happen inside a tree or when the action can exactly tell which - element made which error. We have to collect these and return - it in a dict of the form {uri: error_code, ...} - - ad 2) The copytree/movetree/... methods of davcmd.py will do the recursion - themselves and call for each resource the copy/move method of the - interface class. Thus method will then only act on a single resource. - (Thus a copycol on a normal unix filesystem actually only needs to do - an mkdir as the content will be copied by the davcmd.py function. - The davcmd.py method will also automatically collect all errors and - return the dictionary described above. - When you use 2) you also have to implement the copy() and copycol() - methods in your interface class. See the example for details. - - To decide which approach is the best you have to decide if your application - is able to generate errors inside a tree. E.g. a function which completely - fails on a tree if one of the tree's childs fail is not what we need. Then - 2) would be your way of doing it. - Actually usually 2) is the better solution and should only be replaced by - 1) if you really need it. - - The remaining question is if we should do the same for the DELETE method. - - """ - - ### MOVE handlers - - def moveone(self, src, dst, overwrite): - """ move one resource with Depth=0 """ - return moveone(self, src, dst, overwrite) - - def movetree(self, src, dst, overwrite): - """ move a collection with Depth=infinity """ - return movetree(self, src, dst, overwrite) - - ### COPY handlers - - def copyone(self, src, dst, overwrite): - """ copy one resource with Depth=0 """ - return copyone(self, src, dst, overwrite) - - def copytree(self, src, dst, overwrite): - """ copy a collection with Depth=infinity """ - return copytree(self, src, dst, overwrite) - - - ### low level copy methods (you only need these for method 2) - def copy(self, src, dst): - """ copy a resource with depth==0 - - You don't need to bother about overwrite or not. - This has been done already. - - return a success code or raise an exception if something fails - """ - return 201 - - - def copycol(self, src, dst): - """ copy a resource with depth==infinity - - You don't need to bother about overwrite or not. - This has been done already. - - return a success code or raise an exception if something fails - """ - return 201 - - ### some utility functions you need to implement - - def exists(self, uri): - """ return 1 or None depending on if a resource exists """ - return None # no - - 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: \ No newline at end of file diff --git a/addons/caldav/DAV/propfind.py b/addons/caldav/DAV/propfind.py deleted file mode 100755 index 4d009e7912e..00000000000 --- a/addons/caldav/DAV/propfind.py +++ /dev/null @@ -1,373 +0,0 @@ -#!/usr/bin/env python - -""" - python davserver - Copyright (C) 1999 Christian Scholz (ruebe@aachen.heimat.de) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - 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 - -import sys -import string -import urlparse -import urllib -from StringIO import StringIO - -import utils -from constants import COLLECTION, OBJECT, DAV_PROPS, RT_ALLPROP, RT_PROPNAME, RT_PROP -from errors import * - -def utf8str(st): - if isinstance(st,unicode): - return st.encode('utf8') - else: - return str(st) - -class PROPFIND: - """ parse a propfind xml element and extract props - - It will set the following instance vars: - - 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) - - - """ - - 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) - - # a violation of the expected logic: client (korganizer) will ask for DAV:resourcetype - # but we also have to return the http://groupdav.org/:resourcetype property! - if self.proplist.has_key('DAV:') and 'resourcetype' in self.proplist['DAV:']: - if not self.proplist.has_key('http://groupdav.org/'): - self.proplist['http://groupdav.org/'] = [] - self.proplist['http://groupdav.org/'].append('resourcetype') - if 'DAV:' in self.namespaces: #TMP - self.namespaces.append('http://groupdav.org/') - - def createResponse(self): - """ create the multistatus response - - This will be delegated to the specific method - depending on which request (allprop, propname, prop) - was found. - - If we get a PROPNAME then we simply return the list with empty - values which we get from the interface class - - If we get an ALLPROP we first get the list of properties and then - we do the same as with a PROP method. - - If the uri doesn't exist, return an xml response with a 404 status - - """ - - if not self.__dataclass.exists(self.__uri): - raise DAV_NotFound("Path %s doesn't exist" % self.__uri) - - if self.request_type==RT_ALLPROP: - return self.create_allprop() - - if self.request_type==RT_PROPNAME: - return self.create_propname() - - if self.request_type==RT_PROP: - return self.create_prop() - - # no body means ALLPROP! - return self.create_allprop() - - def create_propname(self): - """ create a multistatus response for the prop names """ - - dc = self.__dataclass - # create the document generator - doc = Document(None) - 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) - ms.appendChild(re) - - elif self.__depth=="1": - 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) - ms.appendChild(re) - # *** depth=="infinity" - - 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 = [] - for ns,plist in self.__dataclass.get_propnames(self.__uri).items(): - self.proplist[ns] = plist - self.namespaces.append(ns) - - return self.create_prop() - - def create_prop(self): - """ handle a request - - This will - - 1. set up the -Framework - - 2. read the property values for each URI - (which is dependant on the Depth header) - This is done by the get_propvalues() method. - - 3. For each URI call the append_result() method - to append the actual -Tag to the result - document. - - We differ between "good" properties, which have been - assigned a value by the interface class and "bad" - properties, which resulted in an error, either 404 - (Not Found) or 403 (Forbidden). - - """ - - - # create the document generator - doc = Document(None) - 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) - ms.appendChild(res) - - elif self.__depth=="1": - 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) - ms.appendChild(res) - except DAV_NotFound: - # If no children, never mind. - pass - - sfile = StringIO() - ext.PrettyPrint(doc,stream = sfile) - s = sfile.getvalue() - sfile.close() - return s - - - def mk_propname_response(self,uri,propnames,doc): - """ make a new result element for a PROPNAME request - - This will simply format the propnames list. - propnames should have the format {NS1 : [prop1, prop2, ...], NS2: ...} - - """ - re = doc.createElement("D:response") - - # write href information - href = doc.createElement("D:href") - if self.use_full_urls: - huri = doc.createTextNode(uri) - else: - 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 - - for ns,plist in propnames.items(): - # write prop element - pr = doc.createElement("D:prop") - nsp = "ns"+str(nsnum) - pr.setAttribute("xmlns:"+nsp,ns) - nsnum = nsnum+1 - - # write propertynames - for p in plist: - pe = doc.createElement(nsp+":"+p) - pr.appendChild(pe) - - ps.appendChild(pr) - - re.appendChild(ps) - - return re - - def mk_prop_response(self,uri,good_props,bad_props,doc): - """ make a new result element - - We differ between the good props and the bad ones for - each generating an extra -Node (for each error - one, that means). - - """ - re = doc.createElement("D:response") - # append namespaces to response - nsnum = 0 - for nsname in self.namespaces: - re.setAttribute("xmlns:ns"+str(nsnum),nsname) - nsnum = nsnum+1 - - # write href information - href = doc.createElement("D:href") - if self.use_full_urls: - huri = doc.createTextNode(uri) - else: - 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") - - 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)) - if v == None: - pass - elif ns=='DAV:' and p=="resourcetype": - if v == 1: - ve=doc.createElement("D:collection") - pe.appendChild(ve) - elif isinstance(v,tuple) and v[1] == ns: - ve=doc.createElement(ns_prefix+v[0]) - pe.appendChild(ve) - else: - 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.appendChild(t) - ps.appendChild(s) - re.appendChild(ps) - - # now write the errors! - if len(bad_props.items()): - - # write a propstat for each error code - for ecode in bad_props.keys(): - ps = doc.createElement("D:propstat") - re.appendChild(ps) - bp = doc.createElement("D:prop") - ps.appendChild(bp) - - for ns in bad_props[ecode].keys(): - ns_prefix = "ns"+str(self.namespaces.index(ns))+":" - - for p in bad_props[ecode][ns]: - pe = doc.createElement(ns_prefix+str(p)) - bp.appendChild(pe) - - s = doc.createElement("D:status") - t = doc.createTextNode(utils.gen_estring(ecode)) - s.appendChild(t) - ps.appendChild(s) - re.appendChild(ps) - - # return the new response element - return re - - def get_propvalues(self,uri): - """ create lists of property values for an URI - - We create two lists for an URI: the properties for - which we found a value and the ones for which we - only got an error, either because they haven't been - found or the user is not allowed to read them. - - """ - good_props = {} - bad_props = {} - - for (ns,plist) in self.proplist.items(): - 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 - except DAV_Error, error_code: - ec = error_code[0] - - # ignore props with error_code if 0 (invisible) - if ec==0: continue - - if bad_props.has_key(ec): - if bad_props[ec].has_key(ns): - bad_props[ec][ns].append(prop) - else: - bad_props[ec][ns] = [prop] - else: - bad_props[ec] = {ns:[prop]} - - return good_props, bad_props - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/caldav/DAV/status.py b/addons/caldav/DAV/status.py deleted file mode 100644 index 62cb323c4fb..00000000000 --- a/addons/caldav/DAV/status.py +++ /dev/null @@ -1,31 +0,0 @@ -""" - -status codes for DAV services - - -""" - - -STATUS_CODES={ - 102: "Processing", - 200: "Ok", - 201: "Created", - 204: "No Content", - 207: "Multi-Status", - 201: "Created", - 400: "Bad Request", - 403: "Forbidden", - 404: "Not Found", - 405: "Method Not Allowed", - 409: "Conflict", - 412: "Precondition failed", - 423: "Locked", - 415: "Unsupported Media Type", - 507: "Insufficient Storage", - 422: "Unprocessable Entity", - 423: "Locked", - 424: "Failed Dependency", - 502: "Bad Gateway", - 507: "Insufficient Storage", - 999: "Some error in Create Method please check the data of create method" -} diff --git a/addons/caldav/DAV/utils.py b/addons/caldav/DAV/utils.py deleted file mode 100755 index a4010f27a77..00000000000 --- a/addons/caldav/DAV/utils.py +++ /dev/null @@ -1,161 +0,0 @@ -#!/usr/bin/env python - -""" - -UTILITIES - -- parse a propfind request body into a list of props - -""" - -from xml.dom import ext -from xml.dom.Document import Document -from xml.dom.ext.reader import PyExpat -from xml.dom import Node -from xml.dom import NodeIterator, NodeFilter - -from string import lower, split, atoi, joinfields -import urlparse -from StringIO import StringIO - -from constants import RT_ALLPROP, RT_PROPNAME, RT_PROP -from status import STATUS_CODES - -VERSION = '0.6' -AUTHOR = 'Simon Pamies ' - - -def gen_estring(ecode): - """ generate an error string from the given code """ - ec = atoi(str(ecode)) - if STATUS_CODES.has_key(ec): - return "HTTP/1.1 %s %s" %(ec,STATUS_CODES[ec]) - else: - return "HTTP/1.1 %s" %(ec) - -def parse_propfind(xml_doc): - """ parse an propfind xml file and return a list of props - - returns: - - request_type -- ALLPROP, PROPNAME, PROP - proplist -- list of properties found - namespaces -- list of namespaces found - - """ - doc = PyExpat.Reader().fromString(xml_doc) - snit = doc.createNodeIterator(doc, NodeFilter.NodeFilter.SHOW_ELEMENT, None, None) - - request_type = None - props = {} - namespaces = [] - - while 1: - curr_elem = snit.nextNode() - if not curr_elem: break - ename=fname = lower(curr_elem.nodeName) - if ":" in fname: - 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 - - # rest should be names of attributes - - ns = curr_elem.namespaceURI - if props.has_key(ns): - props[ns].append(ename) - else: - props[ns] = [ename] - namespaces.append(ns) - - return request_type,props,namespaces - - -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 - - uri - the root of the subtree to flatten - - It will return the flattened tree as list - - """ - queue = [uri] - list = [uri] - while len(queue): - element = queue[-1] - if dataclass.is_collection(element): - childs = dataclass.get_childs(element) - else: - childs = [] - if len(childs): - list = list+childs - # update queue - del queue[-1] - if len(childs): - queue = queue+childs - return list - -def is_prefix(uri1, uri2): - """ returns 1 of uri1 is a prefix of uri2 """ - if uri2[:len(uri1)]==uri1: - return 1 - else: - return None - -def quote_uri(uri): - """ quote an URL but not the protocol part """ - 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])) - -def get_uriparentpath(uri): - """ extract the uri path and remove the last element """ - 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] - -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])) - -### 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:") - 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)) - 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.close() - return s - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/caldav/__init__.py b/addons/caldav/__init__.py index 9e222cf99a8..85e6b10a270 100644 --- a/addons/caldav/__init__.py +++ b/addons/caldav/__init__.py @@ -19,11 +19,8 @@ # ############################################################################## -import caldav -import caldav_cache +import caldav_collection import caldav_fs -import caldav_node -import webdav_server import wizard # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/caldav/__terp__.py b/addons/caldav/__terp__.py index 1d25ad8cb77..3717ad32d83 100644 --- a/addons/caldav/__terp__.py +++ b/addons/caldav/__terp__.py @@ -25,6 +25,7 @@ "version" : "1.0", "depends" : [ "base", + "document_webdav", ], 'description': """ This module Contains basic functionality for caldav system like: @@ -34,7 +35,7 @@ - Provides iCal Import/Export functionality To access OpenERP Calendar using caldav to remote site use the URL like: - http://HOSTNAME:PORT/calendar/DATABASE_NAME/CALENDAR_NAME.ics + http://HOSTNAME:PORT/webdav/DATABASE_NAME/Calendars/CALENDAR_NAME.ics Where, HOSTNAME: Host on which OpenERP server(With webdav) is running diff --git a/addons/caldav/caldav_cache.py b/addons/caldav/caldav_cache.py deleted file mode 100644 index 4e5768c3445..00000000000 --- a/addons/caldav/caldav_cache.py +++ /dev/null @@ -1,62 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). -# -# 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 . -# -############################################################################## - -import time -import heapq - -def memoize(maxsize): - """decorator to 'memoize' a function - caching its results""" - def decorating_function(f): - cache = {} # map from key to value - heap = [] # list of keys, in LRU heap - cursize = 0 # because len() is slow - def wrapper(*args): - key = repr(args) - # performance crap - _cache = cache - _heap = heap - _heappop = heapq.heappop - _heappush = heapq.heappush - _time = time.time - _cursize = cursize - _maxsize = maxsize - if not _cache.has_key(key): - if _cursize == _maxsize: - # pop oldest element - (_, oldkey) = _heappop(_heap) - _cache.pop(oldkey) - else: - _cursize += 1 - # insert this element - _cache[key] = f(*args) - _heappush(_heap, (_time(), key)) - wrapper.misses += 1 - else: - wrapper.hits += 1 - return cache[key] - wrapper.__doc__ = f.__doc__ - wrapper.__name__ = f.__name__ - wrapper.hits = wrapper.misses = 0 - return wrapper - return decorating_function - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file diff --git a/addons/caldav/caldav.py b/addons/caldav/caldav_collection.py similarity index 99% rename from addons/caldav/caldav.py rename to addons/caldav/caldav_collection.py index c5534afa649..a58b6249cec 100644 --- a/addons/caldav/caldav.py +++ b/addons/caldav/caldav_collection.py @@ -412,8 +412,7 @@ class CalDAV(object): class Calendar(CalDAV, osv.osv): - _name = 'basic.calendar' - _description = 'Calendar' + _inherit = 'document.directory' _calname = 'calendar' __attribute__ = { @@ -431,15 +430,11 @@ class Calendar(CalDAV, osv.osv): } _columns = { 'name': fields.char("Name", size=64), - 'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'), - 'active': fields.boolean('Active'), + 'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'), 'create_date': fields.datetime('Created Date'), 'write_date': fields.datetime('Modifided Date'), } - - _defaults = { - 'active': lambda *a: True, - } + def export_cal(self, cr, uid, ids, vobj='vevent', context={}): """ Export Calendar @@ -515,7 +510,7 @@ class basic_calendar_line(osv.osv): ('attendee', 'Attendee')], \ string="Type", size=64), 'object_id': fields.many2one('ir.model', 'Object'), - 'calendar_id': fields.many2one('basic.calendar', 'Calendar', \ + 'calendar_id': fields.many2one('document.directory', 'Calendar', \ required=True, ondelete='cascade'), 'domain': fields.char('Domain', size=124), 'mapping_ids': fields.one2many('basic.calendar.fields', 'type_id', 'Fields Mapping') diff --git a/addons/caldav/caldav_fs.py b/addons/caldav/caldav_fs.py index 9ab7a2156d6..1b3d1f4879b 100644 --- a/addons/caldav/caldav_fs.py +++ b/addons/caldav/caldav_fs.py @@ -19,316 +19,7 @@ # ############################################################################## -import pooler - -import base64 -import sys -import os -import time -from string import joinfields, split, lower - -from service import security - -import netsvc -import urlparse - -from DAV.constants import COLLECTION, OBJECT -from DAV.errors import * -from DAV.iface import * -import urllib - -from DAV.davcmd import copyone, copytree, moveone, movetree, delone, deltree -from caldav_cache import memoize -from tools import misc -CACHE_SIZE=20000 - - -class tinydav_handler(dav_interface): - """ - This class models a Tiny ERP interface for the DAV server - """ - PROPS={'DAV:': dav_interface.PROPS['DAV:'], } - - M_NS={ "DAV:": dav_interface.M_NS['DAV:'], } - - def __init__(self, parent, verbose=False): - self.db_name = False - self.parent = parent - self.baseuri = parent.baseuri - - def get_propnames(self, uri): - props = self.PROPS - self.parent.log_message('get propnames: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - cr.close() - return props - node = self.uri2object(cr, uid, pool, uri2) - if node: - props.update(node.get_dav_props(cr)) - cr.close() - return props - - def get_prop(self,uri,ns,propname): - """ return the value of a given property - - uri -- uri of the object to get the property of - ns -- namespace of the property - pname -- name of the property - """ - if self.M_NS.has_key(ns): - return dav_interface.get_prop(self, uri, ns, propname) - - 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) - if not node: - cr.close() - raise DAV_NotFound - res = node.get_dav_eprop(cr, ns, propname) - cr.close() - return res - - def urijoin(self,*ajoin): - """ Return the base URI of this request, or even join it with the - ajoin path elements - """ - return self.baseuri+ '/'.join(ajoin) - - def uri2local(self, uri): - uparts = urlparse.urlparse(uri) - reluri = uparts[2] - if reluri and reluri[-1]=="/": - reluri = reluri[:-1] - return reluri - - # - # pos: -1 to get the parent of the uri - # - def get_cr(self, uri): - pdb = self.parent.auth_proxy.last_auth - reluri = self.uri2local(uri) - try: - dbname = reluri.split('/')[2] - except: - dbname = False - if not dbname: - return None, None, None, False, None - if not pdb and dbname: - # if dbname was in our uri, we should have authenticated - # against that. - raise Exception("Programming error") - assert pdb == dbname, " %s != %s" %(pdb, dbname) - user, passwd, dbn2, uid = self.parent.auth_proxy.auth_creds[pdb] - db,pool = pooler.get_db_and_pool(dbname) - cr = db.cursor() - uri2 = reluri.split('/')[3:] - return cr, uid, pool, dbname, uri2 - - def uri2object(self, cr, uid, pool, uri): - if not uid: - return None - return pool.get('basic.calendar').get_calendar_object(cr, uid, 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) - if not node: - raise DAV_NotFound(uri2) - try: - datas = node.get_data(cr, uid) - except TypeError, e: - import traceback - self.parent.log_error("GET typeError: %s", str(e)) - self.parent.log_message("Exc: %s", traceback.format_exc()) - raise DAV_Forbidden - except IndexError, e : - self.parent.log_error("GET IndexError: %s", str(e)) - raise DAV_NotFound(uri2) - except Exception, e: - import traceback - self.parent.log_error("GET exception: %s", str(e)) - self.parent.log_message("Exc: %s", traceback.format_exc()) - raise DAV_Error, 409 - return datas - finally: - cr.close() - - @memoize(CACHE_SIZE) - def _get_dav_resourcetype(self, uri): - """ return type of object """ - self.parent.log_message('get RT: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - try: - if not dbname: - return COLLECTION - 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): - 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) - if not node: - cr.close() - raise DAV_NotFound(uri2) - cr.close() - return node.displayname - - @memoize(CACHE_SIZE) - 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] - result = 0 - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - cr.close() - return '0' - node = self.uri2object(cr, uid, pool, uri2) - if not node: - cr.close() - raise DAV_NotFound(uri2) - result = node.content_length or 0 - cr.close() - return str(result) - - @memoize(CACHE_SIZE) - 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] - result = 0 - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - cr.close() - return '0' - node = self.uri2object(cr, uid, pool, uri2) - if not node: - cr.close() - raise DAV_NotFound(uri2) - result = node.get_etag(cr) - cr.close() - return str(result) - - @memoize(CACHE_SIZE) - def get_lastmodified(self, uri): - """ return the last modified date of the object """ - if uri[-1]=='/':uri=uri[:-1] - today = time.time() - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - try: - if not dbname: - return today - 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')) - else: - return today - finally: - cr.close() - - @memoize(CACHE_SIZE) - def get_creationdate(self, uri): - """ return the last modified date of the object """ - - 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) - if not node: - raise DAV_NotFound(uri2) - if node.create_date: - result = time.strptime(node.create_date, '%Y-%m-%d %H:%M:%S') - else: - result = time.gmtime() - return result - finally: - cr.close() - - @memoize(CACHE_SIZE) - 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) - if not node: - raise DAV_NotFound(uri2) - result = node.mimetype - return result - #raise DAV_NotFound, 'Could not find %s' % path - finally: - cr.close() - def put(self, uri, data, content_type=None): - """ put the object into the filesystem """ - self.parent.log_message('Putting %s (%d), %s'%(misc.ustr(uri), len(data), content_type)) - parent='/'.join(uri.split('/')[:-1]) - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - raise DAV_Forbidden - try: - node = self.uri2object(cr, uid, pool, uri2[:]) - except: - node = False - - if not node: - raise DAV_Forbidden - else: - try: - node.set_data(cr, uid, data) - except Exception, e: - import traceback - self.parent.log_error("Cannot save :%s", str(e)) - self.parent.log_message("Exc: %s", traceback.format_exc()) - raise DAV_Forbidden - - cr.commit() - cr.close() - return 201 - - def exists(self, uri): - """ test if a resource exists """ - result = False - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - cr.close() - return True - try: - 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: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/caldav/caldav_view.xml b/addons/caldav/caldav_view.xml index f43328ecc3e..696b1833513 100644 --- a/addons/caldav/caldav_view.xml +++ b/addons/caldav/caldav_view.xml @@ -1,15 +1,15 @@ - - - Basic Calendar - basic.calendar - form - -
- - + + CalDAV Collections : Form + document.directory + form + + + + + @@ -33,29 +33,60 @@ - + - - - + + +
- - Calendar - ir.actions.act_window - basic.calendar - form - tree,form - - + + CalDAV Collections : Tree + document.directory + tree + child_ids + + + + + + + + + - + + CalDAV Collections + ir.actions.act_window + document.directory + form + tree,form + [('line_ids','!=', False)] + + + [('line_ids','=', False)] + + + + + tree + + + + + + form + + + + +
diff --git a/addons/caldav/security/ir.model.access.csv b/addons/caldav/security/ir.model.access.csv index 74064f43d75..4dd04fa4c68 100644 --- a/addons/caldav/security/ir.model.access.csv +++ b/addons/caldav/security/ir.model.access.csv @@ -1,5 +1,4 @@ "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" -"access_basic_calendar_all","basic.calendar","model_basic_calendar","base.group_user",1,1,1,1 "access_basic_calendar_event_all","basic.calendar.event","model_basic_calendar_event","base.group_user",1,1,1,0 "access_basic_calendar_attendee_all","basic.calendar.attendee","model_basic_calendar_attendee","base.group_user",1,1,1,0 "access_calendar_todo_all","basic.calendar.todo","model_basic_calendar_todo","base.group_user",1,1,1,0 diff --git a/addons/caldav/webdav_server.py b/addons/caldav/webdav_server.py deleted file mode 100644 index 40519ee19a2..00000000000 --- a/addons/caldav/webdav_server.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- encoding: utf-8 -*- -# -# Copyright P. Christeas 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 -# End users who are looking for a ready-to-use solution with commercial -# garantees and support are strongly adviced to contract a Free Software -# Service Company -# -# This program is Free Software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -############################################################################### - - -import netsvc -from caldav_fs import tinydav_handler -from tools.config import config -from DAV.WebDAVServer import DAVRequestHandler -from service.websrv_lib import HTTPDir,FixSendError - - -class DAVHandler(FixSendError, DAVRequestHandler): - verbose = False - - def get_userinfo(self, user, pw): - return False - - def _log(self, message): - netsvc.Logger().notifyChannel("webdav", netsvc.LOG_DEBUG, message) - - def handle(self): - pass - - def finish(self): - pass - - def setup(self): - davpath = '/calendar/' - 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) - - def log_error(self, format, *args): - netsvc.Logger().notifyChannel('webdav', netsvc.LOG_WARNING, format % args) - - -try: - 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) -except Exception, e: - logger = netsvc.Logger() - logger.notifyChannel('webdav', netsvc.LOG_ERROR, 'Cannot launch webdav: %s' % e) - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4 - - - diff --git a/addons/caldav/wizard/calendar_event_export.py b/addons/caldav/wizard/calendar_event_export.py index 856d9e9bc91..79434d3d24d 100644 --- a/addons/caldav/wizard/calendar_event_export.py +++ b/addons/caldav/wizard/calendar_event_export.py @@ -36,7 +36,7 @@ class calendar_event_export(osv.osv_memory): """ Get Default value for file_path field. """ - model = context.get('model', 'basic.calendar') + model = context.get('model', 'document.directory') model_obj = self.pool.get(model) calendar = model_obj.export_cal(cr, uid, context['active_ids'], context) @@ -47,7 +47,7 @@ class calendar_event_export(osv.osv_memory): """ Get Default value for Name field. """ - model = context.get('model', 'basic.calendar') + model = context.get('model', 'document.directory') model_obj = self.pool.get(model) calendar = model_obj.export_cal(cr, uid, context['active_ids'], context) res = super(calendar_event_export, self).default_get( cr, uid, fields, context=context) diff --git a/addons/caldav/wizard/calendar_event_export_view.xml b/addons/caldav/wizard/calendar_event_export_view.xml index 227822966d0..4d3762d2240 100644 --- a/addons/caldav/wizard/calendar_event_export_view.xml +++ b/addons/caldav/wizard/calendar_event_export_view.xml @@ -30,10 +30,10 @@ - + res_model="calendar.event.export" src_model="document.directory" + view_mode="form" target="new" view_type="form" /> --> diff --git a/addons/caldav/wizard/calendar_event_import.py b/addons/caldav/wizard/calendar_event_import.py index 64a1990f00d..a45647a94d6 100644 --- a/addons/caldav/wizard/calendar_event_import.py +++ b/addons/caldav/wizard/calendar_event_import.py @@ -44,7 +44,7 @@ class calendar_event_import(osv.osv_memory): """ for data in self.read(cr, uid, ids): - model = data.get('model', 'basic.calendar') + model = data.get('model', 'document.directory') model_obj = self.pool.get(model) context.update({'model': model}) data_obj = self.pool.get('ir.model.data') diff --git a/addons/caldav/wizard/calendar_event_import_view.xml b/addons/caldav/wizard/calendar_event_import_view.xml index 6a697de5fee..a0135356e71 100644 --- a/addons/caldav/wizard/calendar_event_import_view.xml +++ b/addons/caldav/wizard/calendar_event_import_view.xml @@ -46,10 +46,10 @@ new - + res_model="calendar.event.import" src_model="document.directory" + view_mode="form" target="new" view_type="form" /> --> diff --git a/addons/caldav/wizard/calendar_event_subscribe.py b/addons/caldav/wizard/calendar_event_subscribe.py index de673b5d7c0..57c618af849 100644 --- a/addons/caldav/wizard/calendar_event_subscribe.py +++ b/addons/caldav/wizard/calendar_event_subscribe.py @@ -51,10 +51,10 @@ class calendar_event_subscribe(osv.osv_memory): f.close() except Exception,e: raise osv.except_osv(_('Error!'), _('Please provide Proper URL !')) - model = data.get('model', 'basic.calendar') + model = data.get('model', 'document.directory') model_obj = self.pool.get(model) context.update({'url': data['url_path'], - 'model': data.get('model', 'basic.calendar')}) + 'model': data.get('model', 'document.directory')}) vals = model_obj.import_cal(cr, uid, base64.encodestring(caldata), \ context['active_id'], context) if vals: diff --git a/addons/caldav/wizard/calendar_event_subscribe_view.xml b/addons/caldav/wizard/calendar_event_subscribe_view.xml index 43224013268..2a10fd400f8 100644 --- a/addons/caldav/wizard/calendar_event_subscribe_view.xml +++ b/addons/caldav/wizard/calendar_event_subscribe_view.xml @@ -46,10 +46,10 @@ new - + res_model="calendar.event.subscribe" src_model="document.directory" + view_mode="form" target="new" view_type="form" /> --> - \ No newline at end of file + diff --git a/addons/crm_caldav/crm_caldav.py b/addons/crm_caldav/crm_caldav.py index a3a1054a1ee..ef1f4b020b9 100644 --- a/addons/crm_caldav/crm_caldav.py +++ b/addons/crm_caldav/crm_caldav.py @@ -21,8 +21,6 @@ from osv import fields, osv from crm import crm -from caldav import caldav -from base_calendar import base_calendar class crm_meeting(osv.osv): _inherit = 'crm.meeting' diff --git a/addons/crm_caldav/crm_caldav_data.xml b/addons/crm_caldav/crm_caldav_data.xml index b5e7d183325..ccaea831cf9 100644 --- a/addons/crm_caldav/crm_caldav_data.xml +++ b/addons/crm_caldav/crm_caldav_data.xml @@ -4,7 +4,7 @@ - + Meetings diff --git a/addons/document_webdav/__init__.py b/addons/document_webdav/__init__.py index 08701e920d2..69312668a74 100644 --- a/addons/document_webdav/__init__.py +++ b/addons/document_webdav/__init__.py @@ -1,29 +1,23 @@ +# -*- coding: utf-8 -*- ############################################################################## # -# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved. -# Fabien Pinckaers +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). # -# 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 -# End users who are looking for a ready-to-use solution with commercial -# garantees and support are strongly adviced to contract a Free Software -# Service Company +# 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 Free Software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# 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. # -# 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . # ############################################################################## +import webdav import webdav_server diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 9ef91e0f9a6..9be77c50daa 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -1,32 +1,23 @@ -# -*- encoding: utf-8 -*- +# -*- coding: utf-8 -*- ############################################################################## # -# Copyright (c) 2004 TINY SPRL. (http://tiny.be) All Rights Reserved. -# Fabien Pinckaers +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). # -# 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 -# End users who are looking for a ready-to-use solution with commercial -# garantees and support are strongly adviced to contract a Free Software -# Service Company +# 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 Free Software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# 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. # -# 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . # ############################################################################## - import pooler import base64 @@ -55,9 +46,9 @@ CACHE_SIZE=20000 urlparse.uses_netloc.append('webdav') urlparse.uses_netloc.append('webdavs') -class tinydav_handler(dav_interface): +class openerp_dav_handler(dav_interface): """ - This class models a Tiny ERP interface for the DAV server + This class models a OpenERP interface for the DAV server """ PROPS={'DAV:': dav_interface.PROPS['DAV:'],} diff --git a/addons/document_webdav/webdav.py b/addons/document_webdav/webdav.py new file mode 100644 index 00000000000..6e816c35e10 --- /dev/null +++ b/addons/document_webdav/webdav.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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 . +# +############################################################################## + +import xml.dom.minidom +domimpl = xml.dom.minidom.getDOMImplementation() +import urlparse +import urllib +from DAV import utils +from DAV.propfind import PROPFIND + + +super_mk_prop_response = PROPFIND.mk_prop_response +def mk_prop_response(self,uri,good_props,bad_props,doc): + """ make a new result element + + We differ between the good props and the bad ones for + each generating an extra -Node (for each error + one, that means). + + """ + re=doc.createElement("D:response") + # append namespaces to response + nsnum=0 + for nsname in self.namespaces: + re.setAttribute("xmlns:ns"+str(nsnum),nsname) + nsnum=nsnum+1 + + # write href information + uparts=urlparse.urlparse(uri) + fileloc=uparts[2] + href=doc.createElement("D:href") + huri=doc.createTextNode(uparts[0]+'://'+'/'.join(uparts[1:2]) + urllib.quote(fileloc)) + href.appendChild(huri) + re.appendChild(href) + + # write good properties + ps=doc.createElement("D:propstat") + if good_props: + re.appendChild(ps) + + 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(): + if not v: + pass + pe=doc.createElement(ns_prefix+str(p)) + if hasattr(v, '__class__') and v.__class__.__name__ == 'Element': + pe.appendChild(v) + else: + if p=="resourcetype": + if v==1: + ve=doc.createElement("D:collection") + pe.appendChild(ve) + else: + ve=doc.createTextNode(tools.ustr(v)) + pe.appendChild(ve) + + gp.appendChild(pe) + + ps.appendChild(gp) + s=doc.createElement("D:status") + t=doc.createTextNode("HTTP/1.1 200 OK") + s.appendChild(t) + ps.appendChild(s) + re.appendChild(ps) + + # now write the errors! + if len(bad_props.items()): + + # write a propstat for each error code + for ecode in bad_props.keys(): + ps=doc.createElement("D:propstat") + re.appendChild(ps) + bp=doc.createElement("D:prop") + ps.appendChild(bp) + + for ns in bad_props[ecode].keys(): + ns_prefix="ns"+str(self.namespaces.index(ns))+":" + + for p in bad_props[ecode][ns]: + pe=doc.createElement(ns_prefix+str(p)) + bp.appendChild(pe) + + s=doc.createElement("D:status") + t=doc.createTextNode(utils.gen_estring(ecode)) + s.appendChild(t) + ps.appendChild(s) + re.appendChild(ps) + + # return the new response element + return re + + +PROPFIND.mk_prop_response = mk_prop_response + diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index f2c129dd608..6cda2d172ef 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -29,102 +29,11 @@ import netsvc import tools -from dav_fs import tinydav_handler +from dav_fs import openerp_dav_handler from tools.config import config from DAV.WebDAVServer import DAVRequestHandler from service.websrv_lib import HTTPDir,FixSendError -from DAV.propfind import PROPFIND -import xml.dom.minidom -domimpl = xml.dom.minidom.getDOMImplementation() -import urlparse -import urllib -from DAV import utils - -super_mk_prop_response = PROPFIND.mk_prop_response -def mk_prop_response(self,uri,good_props,bad_props,doc): - """ make a new result element - - We differ between the good props and the bad ones for - each generating an extra -Node (for each error - one, that means). - - """ - re=doc.createElement("D:response") - # append namespaces to response - nsnum=0 - for nsname in self.namespaces: - re.setAttribute("xmlns:ns"+str(nsnum),nsname) - nsnum=nsnum+1 - - # write href information - uparts=urlparse.urlparse(uri) - fileloc=uparts[2] - href=doc.createElement("D:href") - huri=doc.createTextNode(uparts[0]+'://'+'/'.join(uparts[1:2]) + urllib.quote(fileloc)) - href.appendChild(huri) - re.appendChild(href) - - # write good properties - ps=doc.createElement("D:propstat") - if good_props: - re.appendChild(ps) - - 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(): - if not v: - pass - pe=doc.createElement(ns_prefix+str(p)) - if hasattr(v, '__class__') and v.__class__.__name__ == 'Element': - pe.appendChild(v) - else: - if p=="resourcetype": - if v==1: - ve=doc.createElement("D:collection") - pe.appendChild(ve) - else: - ve=doc.createTextNode(tools.ustr(v)) - pe.appendChild(ve) - - gp.appendChild(pe) - - ps.appendChild(gp) - s=doc.createElement("D:status") - t=doc.createTextNode("HTTP/1.1 200 OK") - s.appendChild(t) - ps.appendChild(s) - re.appendChild(ps) - - # now write the errors! - if len(bad_props.items()): - - # write a propstat for each error code - for ecode in bad_props.keys(): - ps=doc.createElement("D:propstat") - re.appendChild(ps) - bp=doc.createElement("D:prop") - ps.appendChild(bp) - - for ns in bad_props[ecode].keys(): - ns_prefix="ns"+str(self.namespaces.index(ns))+":" - - for p in bad_props[ecode][ns]: - pe=doc.createElement(ns_prefix+str(p)) - bp.appendChild(pe) - - s=doc.createElement("D:status") - t=doc.createTextNode(utils.gen_estring(ecode)) - s.appendChild(t) - ps.appendChild(s) - re.appendChild(ps) - - # return the new response element - return re - - -PROPFIND.mk_prop_response = mk_prop_response def OpenDAVConfig(**kw): class OpenDAV: @@ -136,6 +45,7 @@ def OpenDAVConfig(**kw): return Config() + class DAVHandler(FixSendError,DAVRequestHandler): verbose = False @@ -162,7 +72,7 @@ class DAVHandler(FixSendError,DAVRequestHandler): def setup(self): davpath = '/'+config.get_misc('webdav','vdir','webdav') self.baseuri = "http://%s:%d/"% (self.server.server_name,self.server.server_port) - self.IFACE_CLASS = tinydav_handler(self, self.verbose) + self.IFACE_CLASS = openerp_dav_handler(self, self.verbose) def log_message(self, format, *args): diff --git a/addons/project_caldav/project_caldav_data.xml b/addons/project_caldav/project_caldav_data.xml index 30a200b0315..5970100800d 100644 --- a/addons/project_caldav/project_caldav_data.xml +++ b/addons/project_caldav/project_caldav_data.xml @@ -2,7 +2,7 @@ - + Todo From 37a0b05a170d0fe454f27cfabe8689d0a08ae552 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Mon, 12 Apr 2010 17:15:51 +0530 Subject: [PATCH 006/761] [REF] caldav bzr revid: hmo@tinyerp.com-20100412114551-pkrd135oxul8pw1u --- addons/caldav/__init__.py | 2 +- .../{caldav_collection.py => caldav.py} | 16 ++++-- addons/caldav/caldav_data.xml | 3 ++ addons/caldav/caldav_view.xml | 54 +++++++++---------- addons/crm_caldav/crm_caldav_data.xml | 3 +- addons/document_webdav/webdav.py | 1 + addons/project_caldav/project_caldav_data.xml | 5 +- 7 files changed, 46 insertions(+), 38 deletions(-) rename addons/caldav/{caldav_collection.py => caldav.py} (98%) diff --git a/addons/caldav/__init__.py b/addons/caldav/__init__.py index 85e6b10a270..4a870385a68 100644 --- a/addons/caldav/__init__.py +++ b/addons/caldav/__init__.py @@ -19,7 +19,7 @@ # ############################################################################## -import caldav_collection +import caldav import caldav_fs import wizard diff --git a/addons/caldav/caldav_collection.py b/addons/caldav/caldav.py similarity index 98% rename from addons/caldav/caldav_collection.py rename to addons/caldav/caldav.py index a58b6249cec..fb4eb35ca8d 100644 --- a/addons/caldav/caldav_collection.py +++ b/addons/caldav/caldav.py @@ -410,9 +410,15 @@ class CalDAV(object): self.ical_reset('value') return res +class calendar_collection(osv.osv): + _inherit = 'document.directory' + _columns = { + 'calendar_ids': fields.one2many('basic.calendar', 'collection_id', 'Calendars'), + } +calendar_collection() class Calendar(CalDAV, osv.osv): - _inherit = 'document.directory' + _name = 'basic.calendar' _calname = 'calendar' __attribute__ = { @@ -430,11 +436,13 @@ class Calendar(CalDAV, osv.osv): } _columns = { 'name': fields.char("Name", size=64), + 'collection_id': fields.many2one('document.directory', 'Collection', \ + required=True), + 'user_id': fields.many2one('res.users', 'Owner'), 'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'), 'create_date': fields.datetime('Created Date'), 'write_date': fields.datetime('Modifided Date'), - } - + } def export_cal(self, cr, uid, ids, vobj='vevent', context={}): """ Export Calendar @@ -510,7 +518,7 @@ class basic_calendar_line(osv.osv): ('attendee', 'Attendee')], \ string="Type", size=64), 'object_id': fields.many2one('ir.model', 'Object'), - 'calendar_id': fields.many2one('document.directory', 'Calendar', \ + 'calendar_id': fields.many2one('basic.calendar', 'Calendar', \ required=True, ondelete='cascade'), 'domain': fields.char('Domain', size=124), 'mapping_ids': fields.one2many('basic.calendar.fields', 'type_id', 'Fields Mapping') diff --git a/addons/caldav/caldav_data.xml b/addons/caldav/caldav_data.xml index 7ebab73aca5..cd8b5918a40 100644 --- a/addons/caldav/caldav_data.xml +++ b/addons/caldav/caldav_data.xml @@ -2,6 +2,9 @@ + + Calendars + diff --git a/addons/caldav/caldav_view.xml b/addons/caldav/caldav_view.xml index 696b1833513..794308daa99 100644 --- a/addons/caldav/caldav_view.xml +++ b/addons/caldav/caldav_view.xml @@ -1,15 +1,15 @@ - - CalDAV Collections : Form - document.directory + + Calendar : Form + basic.calendar form -
- + + - + @@ -43,13 +43,12 @@ - - CalDAV Collections : Tree - document.directory - tree - child_ids + + Calendar : Tree + basic.calendar + tree - + @@ -58,35 +57,30 @@ - - CalDAV Collections + + Calendars ir.actions.act_window - document.directory + basic.calendar form - tree,form - [('line_ids','!=', False)] - + tree,form + - - [('line_ids','=', False)] - - - + tree - - + + - + form - - + + diff --git a/addons/crm_caldav/crm_caldav_data.xml b/addons/crm_caldav/crm_caldav_data.xml index ccaea831cf9..ca5f38f65b8 100644 --- a/addons/crm_caldav/crm_caldav_data.xml +++ b/addons/crm_caldav/crm_caldav_data.xml @@ -4,8 +4,9 @@ - + Meetings + diff --git a/addons/document_webdav/webdav.py b/addons/document_webdav/webdav.py index 6e816c35e10..b69c21d62ee 100644 --- a/addons/document_webdav/webdav.py +++ b/addons/document_webdav/webdav.py @@ -25,6 +25,7 @@ import urlparse import urllib from DAV import utils from DAV.propfind import PROPFIND +import tools super_mk_prop_response = PROPFIND.mk_prop_response diff --git a/addons/project_caldav/project_caldav_data.xml b/addons/project_caldav/project_caldav_data.xml index 5970100800d..59c9e5bd9f7 100644 --- a/addons/project_caldav/project_caldav_data.xml +++ b/addons/project_caldav/project_caldav_data.xml @@ -1,9 +1,10 @@ - + - + Todo + From 9f5aa65624110ebd12027b3041f91335a8cdd86a Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Mon, 12 Apr 2010 17:31:15 +0530 Subject: [PATCH 007/761] [REF] caldav bzr revid: hmo@tinyerp.com-20100412120115-spckeb0vi08x6vvt --- addons/caldav/__init__.py | 2 +- addons/caldav/{caldav.py => calendar.py} | 0 addons/project_caldav/project_caldav.py | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename addons/caldav/{caldav.py => calendar.py} (100%) diff --git a/addons/caldav/__init__.py b/addons/caldav/__init__.py index 4a870385a68..0a0787feb89 100644 --- a/addons/caldav/__init__.py +++ b/addons/caldav/__init__.py @@ -19,7 +19,7 @@ # ############################################################################## -import caldav +import calendar import caldav_fs import wizard diff --git a/addons/caldav/caldav.py b/addons/caldav/calendar.py similarity index 100% rename from addons/caldav/caldav.py rename to addons/caldav/calendar.py diff --git a/addons/project_caldav/project_caldav.py b/addons/project_caldav/project_caldav.py index 53bd5545159..9b95ec8e9b8 100644 --- a/addons/project_caldav/project_caldav.py +++ b/addons/project_caldav/project_caldav.py @@ -20,7 +20,7 @@ ############################################################################## from osv import fields, osv -from caldav import caldav +from caldav import calendar class project_task(osv.osv): _name = "project.task" @@ -52,7 +52,7 @@ class project_task(osv.osv): hours = (val['planned_hours'].seconds / float(3600)) + \ (val['planned_hours'].days * 24) val['planned_hours'] = hours - exists, r_id = caldav.uid2openobjectid(cr, val['id'], self._name, val.get('recurrent_id')) + exists, r_id = calendar.uid2openobjectid(cr, val['id'], self._name, val.get('recurrent_id')) val.pop('id') if exists: self.write(cr, uid, [exists], val) From dd61fff76064ce4ad8629efce6f75b46d455295d Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Mon, 12 Apr 2010 17:54:23 +0530 Subject: [PATCH 008/761] [IMP] caldav bzr revid: hmo@tinyerp.com-20100412122423-eyc0bs5h1x3mfu9y --- addons/caldav/caldav_data.xml | 1 + addons/caldav/caldav_view.xml | 66 ++++++++++++++++++++++++++++++++++- addons/caldav/calendar.py | 5 +++ 3 files changed, 71 insertions(+), 1 deletion(-) diff --git a/addons/caldav/caldav_data.xml b/addons/caldav/caldav_data.xml index cd8b5918a40..04f5a6004a7 100644 --- a/addons/caldav/caldav_data.xml +++ b/addons/caldav/caldav_data.xml @@ -4,6 +4,7 @@ Calendars + True diff --git a/addons/caldav/caldav_view.xml b/addons/caldav/caldav_view.xml index 794308daa99..152baf6c876 100644 --- a/addons/caldav/caldav_view.xml +++ b/addons/caldav/caldav_view.xml @@ -1,6 +1,70 @@ + + Calendar Collections : Form + document.directory + form + + + + + + + + + + + Calendar Collections : Tree + document.directory + tree + child_ids + + + + + + + + + + + + Calendar Collections + ir.actions.act_window + document.directory + form + tree,form + [('calendar_collection','=',True)] + + + + [('calendar_collection','=',False)] + + + + + tree + + + + + + form + + + + + + + + Calendar : Form basic.calendar @@ -81,6 +145,6 @@ + parent="menu_calendar"/> diff --git a/addons/caldav/calendar.py b/addons/caldav/calendar.py index fb4eb35ca8d..bcf7eb58d76 100644 --- a/addons/caldav/calendar.py +++ b/addons/caldav/calendar.py @@ -413,8 +413,13 @@ class CalDAV(object): class calendar_collection(osv.osv): _inherit = 'document.directory' _columns = { + 'calendar_collection' : fields.boolean('Calendar Collection'), 'calendar_ids': fields.one2many('basic.calendar', 'collection_id', 'Calendars'), } + _default = { + 'calendar_collection' : False, + } + calendar_collection() class Calendar(CalDAV, osv.osv): From 522724913410a7aa2cf881f1394a36cbd9a8107e Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Mon, 12 Apr 2010 18:01:10 +0530 Subject: [PATCH 009/761] [IMP] caldav bzr revid: hmo@tinyerp.com-20100412123110-6e76f9icz3up62jm --- addons/caldav/wizard/calendar_event_export.py | 4 ++-- addons/caldav/wizard/calendar_event_export_view.xml | 6 +++--- addons/caldav/wizard/calendar_event_import.py | 2 +- addons/caldav/wizard/calendar_event_import_view.xml | 6 +++--- addons/caldav/wizard/calendar_event_subscribe.py | 4 ++-- addons/caldav/wizard/calendar_event_subscribe_view.xml | 6 +++--- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/addons/caldav/wizard/calendar_event_export.py b/addons/caldav/wizard/calendar_event_export.py index 79434d3d24d..856d9e9bc91 100644 --- a/addons/caldav/wizard/calendar_event_export.py +++ b/addons/caldav/wizard/calendar_event_export.py @@ -36,7 +36,7 @@ class calendar_event_export(osv.osv_memory): """ Get Default value for file_path field. """ - model = context.get('model', 'document.directory') + model = context.get('model', 'basic.calendar') model_obj = self.pool.get(model) calendar = model_obj.export_cal(cr, uid, context['active_ids'], context) @@ -47,7 +47,7 @@ class calendar_event_export(osv.osv_memory): """ Get Default value for Name field. """ - model = context.get('model', 'document.directory') + model = context.get('model', 'basic.calendar') model_obj = self.pool.get(model) calendar = model_obj.export_cal(cr, uid, context['active_ids'], context) res = super(calendar_event_export, self).default_get( cr, uid, fields, context=context) diff --git a/addons/caldav/wizard/calendar_event_export_view.xml b/addons/caldav/wizard/calendar_event_export_view.xml index 4d3762d2240..227822966d0 100644 --- a/addons/caldav/wizard/calendar_event_export_view.xml +++ b/addons/caldav/wizard/calendar_event_export_view.xml @@ -30,10 +30,10 @@ - + res_model="calendar.event.export" src_model="basic.calendar" + view_mode="form" target="new" view_type="form" /> diff --git a/addons/caldav/wizard/calendar_event_import.py b/addons/caldav/wizard/calendar_event_import.py index a45647a94d6..64a1990f00d 100644 --- a/addons/caldav/wizard/calendar_event_import.py +++ b/addons/caldav/wizard/calendar_event_import.py @@ -44,7 +44,7 @@ class calendar_event_import(osv.osv_memory): """ for data in self.read(cr, uid, ids): - model = data.get('model', 'document.directory') + model = data.get('model', 'basic.calendar') model_obj = self.pool.get(model) context.update({'model': model}) data_obj = self.pool.get('ir.model.data') diff --git a/addons/caldav/wizard/calendar_event_import_view.xml b/addons/caldav/wizard/calendar_event_import_view.xml index a0135356e71..7e31d08c1e9 100644 --- a/addons/caldav/wizard/calendar_event_import_view.xml +++ b/addons/caldav/wizard/calendar_event_import_view.xml @@ -46,10 +46,10 @@ new - + res_model="calendar.event.import" src_model="basic.calendar" + view_mode="form" target="new" view_type="form" />
diff --git a/addons/caldav/wizard/calendar_event_subscribe.py b/addons/caldav/wizard/calendar_event_subscribe.py index 57c618af849..de673b5d7c0 100644 --- a/addons/caldav/wizard/calendar_event_subscribe.py +++ b/addons/caldav/wizard/calendar_event_subscribe.py @@ -51,10 +51,10 @@ class calendar_event_subscribe(osv.osv_memory): f.close() except Exception,e: raise osv.except_osv(_('Error!'), _('Please provide Proper URL !')) - model = data.get('model', 'document.directory') + model = data.get('model', 'basic.calendar') model_obj = self.pool.get(model) context.update({'url': data['url_path'], - 'model': data.get('model', 'document.directory')}) + 'model': data.get('model', 'basic.calendar')}) vals = model_obj.import_cal(cr, uid, base64.encodestring(caldata), \ context['active_id'], context) if vals: diff --git a/addons/caldav/wizard/calendar_event_subscribe_view.xml b/addons/caldav/wizard/calendar_event_subscribe_view.xml index 2a10fd400f8..39eaae28540 100644 --- a/addons/caldav/wizard/calendar_event_subscribe_view.xml +++ b/addons/caldav/wizard/calendar_event_subscribe_view.xml @@ -46,10 +46,10 @@ new
- + res_model="calendar.event.subscribe" src_model="basic.calendar" + view_mode="form" target="new" view_type="form" />
From 6a94de909b027dc1259b3fc8b4d1cd16d1d2c467 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Tue, 13 Apr 2010 16:33:20 +0530 Subject: [PATCH 010/761] [REF+IMP] document bzr revid: hmo@tinyerp.com-20100413110320-9x1fy7l432sinxvd --- addons/caldav/caldav_node.py | 139 +++++++++---- addons/caldav/caldav_view.xml | 3 +- addons/caldav/calendar.py | 22 +- addons/document/document_directory.py | 48 +---- addons/document/document_view.xml | 3 +- addons/document/nodes.py | 192 +++++++++--------- .../document_ftp/ftpserver/abstracted_fs.py | 35 +--- addons/document_ics/document_demo.xml | 4 +- addons/document_ics/document_ics.py | 34 +--- addons/document_ics/document_view.xml | 28 +-- 10 files changed, 253 insertions(+), 255 deletions(-) diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py index fd17b52f478..6ecfcd30027 100644 --- a/addons/caldav/caldav_node.py +++ b/addons/caldav/caldav_node.py @@ -25,31 +25,60 @@ import pooler import tools import time import base64 +from document import nodes +import StringIO +class node_database(nodes.node_database): + def _child_get(self, cr, name=False, parent_id=False, domain=None): + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + if not domain: + domain = [] + domain2 = domain + [('calendar_collection','=', False)] + res = super(node_database, self)._child_get(cr, name=name, parent_id=parent_id, domain=domain2) + where = [('parent_id','=',parent_id)] + domain2 = domain + [('calendar_collection','=', True)] + if name: + where.append(('name','=',name)) + if domain2: + where += domain2 -class node_calendar(object): - def __init__(self, path, context, calendar): - self.path = path - self.context = context - self.calendar_id = calendar.id - self.mimetype = 'ics' - self.create_date = calendar.create_date - self.write_date = calendar.write_date or calendar.create_date - self.content_length = 0 - self.displayname = calendar.name + where2 = where + [('type', '=', 'directory')] + ids = dirobj.search(cr, uid, where2, context=ctx) + for dirr in dirobj.browse(cr,uid,ids,context=ctx): + res.append(node_calendar_collection(dirr.name,self,self.context,dirr)) + return res +class node_calendar_collection(nodes.node_dir): + def get_dav_props(self, cr): + res = {} + return res - def get_data(self, cr, uid): - calendar_obj = pooler.get_pool(cr.dbname).get('basic.calendar') - return calendar_obj.export_cal(cr, uid, [self.calendar_id]) + def get_dav_eprop(self,cr,ns,prop): + return None - def get_data_len(self, cr): - return self.content_length - - def set_data(self, cr, uid, data): - calendar_obj = pooler.get_pool(cr.dbname).get('basic.calendar') - return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id) + def _child_get(self, cr, name=False, parent_id=False, domain=None): + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + where = [('collection_id','=',self.dir_id)] + if name: + where.append(('name','=',name)) + if not domain: + domain = [] + + fil_obj = dirobj.pool.get('basic.calendar') + ids = fil_obj.search(cr,uid,where,context=ctx) + res = [] + if ids: + for fil in fil_obj.browse(cr,uid,ids,context=ctx): + res.append(node_calendar(fil.name,self,self.context,fil)) + return res + def get_etag(self, cr): """ Get a tag, unique per object + modification. @@ -64,24 +93,64 @@ class node_calendar(object): return str(wtime) def _get_ttag(self, cr): + return 'calendar collection-%d' % self.dir_id + +class node_calendar(nodes.node_class): + our_type = 'file' + def __init__(self,path, parent, context, calendar): + super(node_calendar,self).__init__(path, parent,context) + self.calendar_id = calendar.id + self.mimetype = 'ics' + self.create_date = calendar.create_date + self.write_date = calendar.write_date or calendar.create_date + self.content_length = 0 + self.displayname = calendar.name + + def open(self, cr, mode=False): + uid = self.context.uid + if self.type in ('collection','database'): + return False + fobj = self.context._dirobj.pool.get('basic.calendar').browse(cr, uid, self.calendar_id, context=self.context.context) + s = StringIO.StringIO(self.get_data(cr, fobj)) + s.name = self + return s + + def get_dav_props(self, cr): + res = {} + return res + + def get_dav_eprop(self,cr,ns,prop): + return None + + + def get_data(self, cr, fil_obj = None): + uid = self.context.uid + calendar_obj = self.context._dirobj.pool.get('basic.calendar') + return calendar_obj.export_cal(cr, uid, [self.calendar_id]) + + def get_data_len(self, cr, fil_obj = None): + return self.content_length + + def set_data(self, cr, data, fil_obj = None): + uid = self.context.uid + calendar_obj = self.context._dirobj.pool.get('basic.calendar') + return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id) + + def _get_ttag(self,cr): return 'calendar-%d' % self.calendar_id + -class Calendar(osv.osv): - _inherit = 'basic.calendar' + def get_etag(self, cr): + """ Get a tag, unique per object + modification. - def get_calendar_object(self, cr, uid, uri, context=None): - if not uri: - return None - if len(uri) > 1: - return None - name, file_type = tuple(uri[0].split('.')) - res = self.name_search(cr, uid, name) - if not res: - return None - calendar_id, calendar_name = res[0] - calendar = self.browse(cr, uid, calendar_id) - return node_calendar(uri, context, calendar) -Calendar() + see. http://tools.ietf.org/html/rfc2616#section-13.3.3 """ + return self._get_ttag(cr) + ':' + self._get_wtag(cr) -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4 \ No newline at end of file + 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')) + else: wtime = time.time() + return str(wtime) +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4 diff --git a/addons/caldav/caldav_view.xml b/addons/caldav/caldav_view.xml index 152baf6c876..c982d695fac 100644 --- a/addons/caldav/caldav_view.xml +++ b/addons/caldav/caldav_view.xml @@ -17,8 +17,7 @@ Calendar Collections : Tree document.directory - tree - child_ids + tree diff --git a/addons/caldav/calendar.py b/addons/caldav/calendar.py index bcf7eb58d76..6ccd5989d5c 100644 --- a/addons/caldav/calendar.py +++ b/addons/caldav/calendar.py @@ -31,7 +31,7 @@ import pytz import re import tools import time - +import caldav_node try: import vobject @@ -418,7 +418,12 @@ class calendar_collection(osv.osv): } _default = { 'calendar_collection' : False, - } + } + def _locate_child(self, cr, uid, root_id, uri,nparent, ncontext): + """ try to locate the node in uri, + Return a tuple (node_dir, remaining_path) + """ + return (caldav_node.node_database(context=ncontext), uri) calendar_collection() @@ -449,6 +454,19 @@ class Calendar(CalDAV, osv.osv): 'write_date': fields.datetime('Modifided Date'), } + def get_calendar_object(self, cr, uid, uri, context=None): + if not uri: + return None + if len(uri) > 1: + return None + name, file_type = tuple(uri[0].split('.')) + res = self.name_search(cr, uid, name) + if not res: + return None + calendar_id, calendar_name = res[0] + calendar = self.browse(cr, uid, calendar_id) + return node_calendar(uri, context, calendar) + def export_cal(self, cr, uid, ids, vobj='vevent', context={}): """ Export Calendar @param self: The object pointer diff --git a/addons/document/document_directory.py b/addons/document/document_directory.py index 270f2d9353f..b64ee8df9e2 100644 --- a/addons/document/document_directory.py +++ b/addons/document/document_directory.py @@ -93,8 +93,7 @@ class document_directory(osv.osv): 'user_id': lambda self,cr,uid,ctx: uid, 'domain': lambda self,cr,uid,ctx: '[]', 'type': lambda *args: 'directory', - 'ressource_id': lambda *a: 0, - 'parent_id': _get_root_directory, + 'ressource_id': lambda *a: 0, 'storage_id': _get_def_storage, } _sql_constraints = [ @@ -198,52 +197,11 @@ class document_directory(osv.osv): raise - def _locate_child(self, cr,uid, root_id, uri,nparent, ncontext): + def _locate_child(self, cr, uid, root_id, uri,nparent, ncontext): """ try to locate the node in uri, Return a tuple (node_dir, remaining_path) """ - did = root_id - duri = uri - path = [] - context = ncontext.context - while len(duri): - nid = self.search(cr,uid,[('parent_id','=',did),('name','=',duri[0]),('type','=','directory')], context=context) - if not nid: - break - if len(nid)>1: - print "Duplicate dir? p= %d, n=\"%s\"" %(did,duri[0]) - path.append(duri[0]) - duri = duri[1:] - did = nid[0] - root_node = did and self.browse(cr,uid,did, context) or False - return (nodes.node_dir(path, nparent,ncontext, root_node), duri) - - - nid = self.search(cr,uid,[('parent_id','=',did),('name','=',duri[0]),('type','=','ressource')], context=context) - if nid: - if len(nid)>1: - print "Duplicate dir? p= %d, n=\"%s\"" %(did,duri[0]) - path.append(duri[0]) - duri = duri[1:] - did = nid[0] - return nodes.node_res_dir(path, nparent,ncontext,self.browse(cr,uid,did, context)) - - # Here, we must find the appropriate non-dir child.. - # Chech for files: - fil_obj = self.pool.get('ir.attachment') - nid = fil_obj.search(cr,uid,[('parent_id','=',did),('name','=',duri[0])],context=context) - if nid: - if len(duri)>1: - # cannot treat child as a dir - return None - if len(nid)>1: - print "Duplicate file?",did,duri[0] - path.append(duri[0]) - return nodes.node_file(path,nparent,ncontext,fil_obj.browse(cr,uid,nid[0],context)) - - print "nothing found:",did, duri - #still, nothing found - return None + return (nodes.node_database(context=ncontext), uri) def old_code(): if not uri: diff --git a/addons/document/document_view.xml b/addons/document/document_view.xml index 252b9b36a26..3cc3d139b13 100644 --- a/addons/document/document_view.xml +++ b/addons/document/document_view.xml @@ -118,8 +118,7 @@ document.directory document.directory - tree - child_ids + tree diff --git a/addons/document/nodes.py b/addons/document/nodes.py index a8553426d3f..4957078c442 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -20,7 +20,7 @@ ############################################################################## import base64 - +import StringIO from osv import osv, fields from osv.orm import except_orm import urlparse @@ -69,14 +69,6 @@ class node_context(object): return ndir -class node_database(): - """ A node representing the database directory - Useless? - """ - def __init__(self,ncontext): - self.nctx = ncontext - - class node_class(object): @@ -163,7 +155,76 @@ class node_class(object): def get_dav_eprop(self,cr,ns,prop): return None -class node_dir(node_class): +class node_database(node_class): + """ A node representing the database directory + + """ + our_type = 'database' + def __init__(self, path=[], parent=False, context=None): + super(node_database,self).__init__(path, parent, context) + + def children(self,cr): + res = self._child_get(cr) + self._file_get(cr) + return res + + def child(self, cr, name): + res = self._child_get(cr,name) + if res: + return res[0] + res = self._file_get(cr,name) + if res: + return res[0] + return None + + def _child_get(self, cr, name=False, parent_id=False, domain=None): + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + where = [('parent_id','=',parent_id)] + if name: + where.append(('name','=',name)) + if not domain: + domain = [] + + where2 = where + domain + [('type', '=', 'directory')] + ids = dirobj.search(cr, uid, where2, context=ctx) + res = [] + for dirr in dirobj.browse(cr,uid,ids,context=ctx): + res.append(node_dir(dirr.name,self,self.context,dirr)) + + where2 = where + domain + [('type', '=', 'ressource'), ('ressource_parent_type_id','=',False)] + ids = dirobj.search(cr, uid, where2, context=ctx) + for dirr in dirobj.browse(cr,uid,ids,context=ctx): + res.append(node_res_dir(dirr.name,self,self.context,dirr)) + + fil_obj = dirobj.pool.get('ir.attachment') + ids = fil_obj.search(cr,uid,where,context=ctx) + if ids: + for fil in fil_obj.browse(cr,uid,ids,context=ctx): + res.append(node_file(fil.name,self,self.context,fil)) + return res + + def _file_get(self,cr, nodename=False, directory_id=False): + res = [] + cntobj = self.context._dirobj.pool.get('document.directory.content') + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + where = [('directory_id','=',directory_id) ] + ids = cntobj.search(cr, uid, where, context=ctx) + for content in cntobj.browse(cr, uid, ids, context=ctx): + res3 = cntobj._file_get(cr, self, nodename, content) + if res3: + res.extend(res3) + + return res + + def _get_ttag(self,cr): + return 'db-%s' % cr.dbname + + +class node_dir(node_database): our_type = 'collection' def __init__(self,path, parent, context, dirr, dctx=None): super(node_dir,self).__init__(path, parent,context) @@ -192,93 +253,20 @@ class node_dir(node_class): print e pass - def children(self,cr): - res = self._child_get(cr) + self._file_get(cr) - return res - + def get_data(self,cr): return '' - def child(self,cr, name): - res = self._child_get(cr,name) - if res: - return res[0] - res = self._file_get(cr,name) - if res: - return res[0] - return None + def _file_get(self,cr, nodename=False): - res = [] - cntobj = self.context._dirobj.pool.get('document.directory.content') - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - where = [('directory_id','=',self.dir_id) ] - ids = cntobj.search(cr, uid, where, context=ctx) - for content in cntobj.browse(cr, uid, ids, context=ctx): - res3 = cntobj._file_get(cr, self, nodename, content) - if res3: - res.extend(res3) + return super(node_dir,self)._file_get(cr, nodename, self.dir_id) - return res - - def get_dav_props(self, cr): - res = {} - cntobj = self.context._dirobj.pool.get('document.directory.content') - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - where = [('directory_id','=',self.dir_id) ] - ids = cntobj.search(cr,uid,where,context=ctx) - for content in cntobj.browse(cr,uid,ids,context=ctx): - if content.extension == '.ics': # FIXME: call the content class! - res['http://groupdav.org/'] = ('resourcetype',) - break - return res - - def get_dav_eprop(self,cr,ns,prop): - if ns != 'http://groupdav.org/' or prop != 'resourcetype': - print "Who asked for %s:%s?" % (ns,prop) - return None - res = {} - cntobj = self.context._dirobj.pool.get('document.directory.content') - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - where = [('directory_id','=',self.dir_id) ] - ids = cntobj.search(cr,uid,where,context=ctx) - for content in cntobj.browse(cr,uid,ids,context=ctx): - if content.extension == '.ics': # FIXME: call the content class! - return ('vevent-collection','http://groupdav.org/') - return None - - def _child_get(self,cr,name = None): - dirobj = self.context._dirobj - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - where = [('parent_id','=',self.dir_id) ] - if name: - where.append(('name','=',name)) - - ids = dirobj.search(cr, uid, where + [('ressource_parent_type_id','=',False)],context=ctx) - res = [] - if ids: - for dirr in dirobj.browse(cr,uid,ids,context=ctx): - if dirr.type == 'directory': - res.append(node_dir(dirr.name,self,self.context,dirr)) - elif dirr.type == 'ressource': - res.append(node_res_dir(dirr.name,self,self.context,dirr)) - - fil_obj=dirobj.pool.get('ir.attachment') - #where2 = where # + [('res_model', '=', None)] - ids = fil_obj.search(cr,uid,where,context=ctx) - if ids: - for fil in fil_obj.browse(cr,uid,ids,context=ctx): - res.append(node_file(fil.name,self,self.context,fil)) - return res + + def _child_get(self, cr, name = None): + return super(node_dir,self)._child_get(cr, name, self.dir_id) + def create_child(self,cr,path,data): """ API function to create a child file object and node @@ -601,7 +589,19 @@ class node_file(node_class): if fil.parent_id: self.storage_id = fil.parent_id.storage_id.id else: - self.storage_id = None + self.storage_id = None + + def open(self, cr, mode=False): + uid = self.context.uid + if self.type in ('collection','database'): + return False + fobj = self.context._dirobj.pool.get('ir.attachment').browse(cr, uid, self.file_id, context=self.context.context) + if fobj.store_method and fobj.store_method== 'fs' : + s = StringIO.StringIO(self.get_data(cr, fobj)) + else: + s = StringIO.StringIO(base64.decodestring(fobj.db_datas or '')) + s.name = self + return s def fix_ppath(self, cr, fbro): """Sometimes we may init this w/o path, parent. @@ -687,6 +687,16 @@ class node_content(node_class): if dctx: self.dctx.update(dctx) self.act_id = act_id + + def open(self, cr, mode=False): + uid = self.context.uid + if self.type in ('collection','database'): + return False + pool = self.context._dirobj.pool + res = getattr(pool.get('document.directory.content'), 'process_read')(cr, uid, self) + res = StringIO.StringIO(res) + res.name = self + return res def fill_fields(self,cr,dctx = None): """ Try to read the object and fill missing fields, like mimetype, diff --git a/addons/document_ftp/ftpserver/abstracted_fs.py b/addons/document_ftp/ftpserver/abstracted_fs.py index 0ffa8eb80f2..54b2cb9830f 100644 --- a/addons/document_ftp/ftpserver/abstracted_fs.py +++ b/addons/document_ftp/ftpserver/abstracted_fs.py @@ -309,31 +309,18 @@ class abstracted_fs: def open(self, node, mode): if not node: raise OSError(1, 'Operation not permited.') - # Reading operation - if node.type == 'file': - cr = pooler.get_db(node.context.dbname).cursor() - uid = node.context.uid - if not self.isfile(node): - raise OSError(1, 'Operation not permited.') - fobj = node.context._dirobj.pool.get('ir.attachment').browse(cr, uid, node.file_id, context=node.context.context) - if fobj.store_method and fobj.store_method== 'fs' : - s = StringIO.StringIO(node.get_data(cr, fobj)) - else: - s = StringIO.StringIO(base64.decodestring(fobj.db_datas or '')) - s.name = node - cr.close() - return s - elif node.type == 'content': - uid = node.context.uid - cr = pooler.get_db(node.context.dbname).cursor() - pool = pooler.get_pool(node.context.dbname) - res = getattr(pool.get('document.directory.content'), 'process_read')(cr, uid, node) - res = StringIO.StringIO(res) - res.name = node - cr.close() - return res - else: + # Reading operation + cr = pooler.get_db(node.context.dbname).cursor() + res = False + #try: + if node.type not in ('collection','database'): + res = node.open(cr, mode) + #except: + # pass + cr.close() + if not res: raise OSError(1, 'Operation not permited.') + return res # ok, but need test more diff --git a/addons/document_ics/document_demo.xml b/addons/document_ics/document_demo.xml index a4c892340de..06c72022fe7 100644 --- a/addons/document_ics/document_demo.xml +++ b/addons/document_ics/document_demo.xml @@ -7,14 +7,14 @@ shcal - + Calendars Calendars meetings - + .ics diff --git a/addons/document_ics/document_ics.py b/addons/document_ics/document_ics.py index 9056b3250b4..00f8927eb18 100644 --- a/addons/document_ics/document_ics.py +++ b/addons/document_ics/document_ics.py @@ -332,8 +332,8 @@ class document_directory_content(osv.osv): return s document_directory_content() -class crm_case(osv.osv): - _inherit = 'crm.case' +class crm_meeting(osv.osv): + _inherit = 'crm.meeting' _columns = { 'code': fields.char('Calendar Code', size=64), 'date_deadline': fields.datetime('Deadline', help="Deadline Date is automatically\ @@ -341,7 +341,7 @@ class crm_case(osv.osv): } _defaults = { - 'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'crm.case'), + 'code': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'crm.meeting'), } def copy(self, cr, uid, id, default=None, context=None): @@ -356,32 +356,10 @@ class crm_case(osv.osv): if not default: default = {} if not context: context = {} - default.update({'code': self.pool.get('ir.sequence').get(cr, uid, 'crm.case'), 'id': False}) - return super(crm_case, self).copy(cr, uid, id, default, context) + default.update({'code': self.pool.get('ir.sequence').get(cr, uid, 'crm.meeting'), 'id': False}) + return super(crm_meeting, self).copy(cr, uid, id, default, context) - def on_change_duration(self, cr, uid, id, date, duration): - """ Change Duration - @param self: The object pointer - @param cr: the current row, from the database cursor, - @param uid: the current user’s ID for security checks, - @param id: crm case's ID, - @param date: Pass the Date, - @param duration: Pass the duration, - """ - - if not date: - return {} - start_date = datetime.datetime.fromtimestamp(time.mktime(time.strptime(date, "%Y-%m-%d %H:%M:%S"))) - if duration >= 0 : - end = start_date + datetime.timedelta(hours=duration) - if duration < 0: - raise osv.except_osv(_('Warning !'), - _('You can not set negative Duration.')) - - res = {'value': {'date_deadline' : end.strftime('%Y-%m-%d %H:%M:%S')}} - return res - -crm_case() +crm_meeting() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/document_ics/document_view.xml b/addons/document_ics/document_view.xml index ac99f3723db..0cbfb6f81e2 100644 --- a/addons/document_ics/document_view.xml +++ b/addons/document_ics/document_view.xml @@ -39,36 +39,16 @@ - - crm.case.code.form - crm.case + + crm.meeting.code.form + crm.meeting form - + - - - - - crm.case.inherit.form1 - crm.case - form - - - - - - - - - From a3dab7abb8a0a033827a0fc2bc3e1868544c83a8 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Tue, 13 Apr 2010 19:34:04 +0530 Subject: [PATCH 011/761] [IMP] caldav bzr revid: hmo@tinyerp.com-20100413140404-bku8u3agsv79evyx --- addons/caldav/__init__.py | 1 + addons/caldav/caldav_fs.py | 48 +++++++++++++++++++++++++++++++-- addons/caldav/caldav_node.py | 7 +++++ addons/caldav/caldav_server.py | 49 ++++++++++++++++++++++++++++++++++ addons/document/nodes.py | 13 +++++++++ 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 addons/caldav/caldav_server.py diff --git a/addons/caldav/__init__.py b/addons/caldav/__init__.py index 0a0787feb89..95c230e09f8 100644 --- a/addons/caldav/__init__.py +++ b/addons/caldav/__init__.py @@ -21,6 +21,7 @@ import calendar import caldav_fs +import caldav_server import wizard # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/caldav/caldav_fs.py b/addons/caldav/caldav_fs.py index 1b3d1f4879b..c7505b3846b 100644 --- a/addons/caldav/caldav_fs.py +++ b/addons/caldav/caldav_fs.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2004-2009 Tiny SPRL (). +# Copyright (C) 2004-2010 Tiny SPRL (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -19,7 +19,51 @@ # ############################################################################## +from document_webdav import dav_fs +from document_webdav.cache import memoize +class openerp_dav_handler(dav_fs.openerp_dav_handler): + PROPS = {'DAV:': dav_fs.openerp_dav_handler.PROPS['DAV:'] + + ('owner',), + 'http://calendarserver.org/ns/': ('getctag')} + + M_NS = { "DAV:" : dav_fs.openerp_dav_handler.M_NS['DAV:'], + "http://calendarserver.org/ns/" : '_get_dav'} + + @memoize(dav_fs.CACHE_SIZE) + def _get_dav_getctag(self,uri): + print """ return the CTag of an object """ + self.parent.log_message('get ctag: %s' % uri) + if uri[-1]=='/':uri=uri[:-1] + result = 0 + cr, uid, pool, dbname, uri2 = self.get_cr(uri) + if not dbname: + cr.close() + return '0' + node = self.uri2object(cr, uid, pool, uri2) + if not node: + cr.close() + raise DAV_NotFound(uri2) + result = node.get_ctag(cr) + cr.close() + return str(result) + + @memoize(dav_fs.CACHE_SIZE) + def _get_dav_owner(self,uri): + print """ return the Owner of an object """ + self.parent.log_message('get ctag: %s' % uri) + if uri[-1]=='/':uri=uri[:-1] + result = 0 + cr, uid, pool, dbname, uri2 = self.get_cr(uri) + if not dbname: + cr.close() + return '0' + node = self.uri2object(cr, uid, pool, uri2) + if not node: + cr.close() + raise DAV_NotFound(uri2) + result = node.get_owner(cr) + cr.close() + return str(result) -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py index 6ecfcd30027..311e0fef0c8 100644 --- a/addons/caldav/caldav_node.py +++ b/addons/caldav/caldav_node.py @@ -78,6 +78,9 @@ class node_calendar_collection(nodes.node_dir): res.append(node_calendar(fil.name,self,self.context,fil)) return res + def get_owner(self, cr): + return False + def get_etag(self, cr): """ Get a tag, unique per object + modification. @@ -94,6 +97,10 @@ class node_calendar_collection(nodes.node_dir): def _get_ttag(self, cr): return 'calendar collection-%d' % self.dir_id + + def get_ctag(self, cr): + return self.get_etag(cr) + class node_calendar(nodes.node_class): our_type = 'file' diff --git a/addons/caldav/caldav_server.py b/addons/caldav/caldav_server.py new file mode 100644 index 00000000000..77244e5d764 --- /dev/null +++ b/addons/caldav/caldav_server.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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 . +# +############################################################################## +from service import http_server +from document_webdav import webdav_server +import tools +from caldav_fs import openerp_dav_handler +from tools.config import config + +class DAVHandler(webdav_server.DAVHandler): + def setup(self): + davpath = '/'+config.get_misc('webdav','vdir','webdav') + self.baseuri = "http://%s:%d/"% (self.server.server_name,self.server.server_port) + self.IFACE_CLASS = openerp_dav_handler(self, self.verbose) + + + +handler = webdav_server.handler +if handler: + handler = DAVHandler + handler.debug = config.get_misc('webdav','debug',True) + handler._config = webdav_server.conf + +if http_server.httpd and handler: + for vdir in http_server.httpd.server.vdirs: + print vdir.handler , webdav_server.DAVHandler + if vdir.handler == webdav_server.DAVHandler: + vdir.handler = handler +if http_server.httpsd and handler: + for vdir in http_server.httpsd.server.vdirs: + if vdir.handler == webdav_server.DAVHandler: + vdir.handler = handler diff --git a/addons/document/nodes.py b/addons/document/nodes.py index 4957078c442..527fda3f594 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -289,6 +289,19 @@ class node_dir(node_database): fnode = node_file(path,self,self.context,fil) fnode.set_data(cr,data,fil) return fnode + + 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): + """ 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')) + else: wtime = time.time() + return str(wtime) def _get_ttag(self,cr): return 'dir-%d' % self.dir_id From f2311d256ffe78304388988024ce9b8b3cc4dfef Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Wed, 14 Apr 2010 13:06:16 +0530 Subject: [PATCH 012/761] [REF+IMP] caldav bzr revid: hmo@tinyerp.com-20100414073616-i84h1e197yswuv0v --- addons/caldav/__init__.py | 3 +- addons/caldav/caldav_fs.py | 69 -------------- addons/caldav/caldav_node.py | 129 +++++++++++++++++++++++++-- addons/caldav/caldav_server.py | 49 ---------- addons/caldav/calendar.py | 24 +---- addons/caldav/calendar_collection.py | 80 +++++++++++++++++ addons/document_webdav/dav_fs.py | 30 ++++++- 7 files changed, 230 insertions(+), 154 deletions(-) delete mode 100644 addons/caldav/caldav_fs.py delete mode 100644 addons/caldav/caldav_server.py create mode 100644 addons/caldav/calendar_collection.py diff --git a/addons/caldav/__init__.py b/addons/caldav/__init__.py index 95c230e09f8..cb496d12de0 100644 --- a/addons/caldav/__init__.py +++ b/addons/caldav/__init__.py @@ -20,8 +20,7 @@ ############################################################################## import calendar -import caldav_fs -import caldav_server +import calendar_collection import wizard # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/caldav/caldav_fs.py b/addons/caldav/caldav_fs.py deleted file mode 100644 index c7505b3846b..00000000000 --- a/addons/caldav/caldav_fs.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2010 Tiny SPRL (). -# -# 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 . -# -############################################################################## - -from document_webdav import dav_fs -from document_webdav.cache import memoize -class openerp_dav_handler(dav_fs.openerp_dav_handler): - PROPS = {'DAV:': dav_fs.openerp_dav_handler.PROPS['DAV:'] + - ('owner',), - 'http://calendarserver.org/ns/': ('getctag')} - - M_NS = { "DAV:" : dav_fs.openerp_dav_handler.M_NS['DAV:'], - "http://calendarserver.org/ns/" : '_get_dav'} - - @memoize(dav_fs.CACHE_SIZE) - def _get_dav_getctag(self,uri): - print """ return the CTag of an object """ - self.parent.log_message('get ctag: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] - result = 0 - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - cr.close() - return '0' - node = self.uri2object(cr, uid, pool, uri2) - if not node: - cr.close() - raise DAV_NotFound(uri2) - result = node.get_ctag(cr) - cr.close() - return str(result) - - @memoize(dav_fs.CACHE_SIZE) - def _get_dav_owner(self,uri): - print """ return the Owner of an object """ - self.parent.log_message('get ctag: %s' % uri) - if uri[-1]=='/':uri=uri[:-1] - result = 0 - cr, uid, pool, dbname, uri2 = self.get_cr(uri) - if not dbname: - cr.close() - return '0' - node = self.uri2object(cr, uid, pool, uri2) - if not node: - cr.close() - raise DAV_NotFound(uri2) - result = node.get_owner(cr) - cr.close() - return str(result) - - - diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py index 311e0fef0c8..9c7c73a098d 100644 --- a/addons/caldav/caldav_node.py +++ b/addons/caldav/caldav_node.py @@ -51,12 +51,42 @@ class node_database(nodes.node_database): res.append(node_calendar_collection(dirr.name,self,self.context,dirr)) return res -class node_calendar_collection(nodes.node_dir): - def get_dav_props(self, cr): - res = {} - return res +class node_calendar_collection(nodes.node_dir): + PROPS = { + "http://calendarserver.org/ns/" : ('getctag'), + "urn:ietf:params:xml:ns:caldav" : ( + 'calendar-description', + 'calendar-data', + 'calendar-home-set', + 'calendar-user-address-set', + 'schedule-inbox-URL', + 'schedule-outbox-URL',)} + M_NS = { + "http://calendarserver.org/ns/" : '_get_dav', + "urn:ietf:params:xml:ns:caldav" : '_get_caldav'} + + def get_dav_props(self, cr): + return self.PROPS - def get_dav_eprop(self,cr,ns,prop): + def get_dav_eprop(self,cr, ns, propname): + if self.M_NS.has_key(ns): + prefix = self.M_NS[ns] + else: + print "No namespace:",ns, "( for prop:", propname,")" + return None + + mname = prefix + "_" + propname + + if not hasattr(self, mname): + return None + + try: + m = getattr(self, mname) + r = m(cr) + return r + except AttributeError, e: + print 'Property %s not supported' % propname + print "Exception:", e return None def _child_get(self, cr, name=False, parent_id=False, domain=None): @@ -78,7 +108,7 @@ class node_calendar_collection(nodes.node_dir): res.append(node_calendar(fil.name,self,self.context,fil)) return res - def get_owner(self, cr): + def _get_dav_owner(self, cr): return False @@ -97,9 +127,90 @@ class node_calendar_collection(nodes.node_dir): def _get_ttag(self, cr): return 'calendar collection-%d' % self.dir_id - - def get_ctag(self, cr): - return self.get_etag(cr) + + def _get_dav_getctag(self, cr): + result = self.get_etag(cr) + return str(result) + + + def _get_caldav_calendar_description(self, cr): + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + ids = [self.dir_id] + res = dirobj.get_description(cr, uid, ids, context=ctx) + return res + + def _get_caldav_calendar_data(self, cr): + return self.get_data(cr) + + def _get_caldav_calendar_home_set(self, cr): + import xml.dom.minidom + import urllib + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) + root_cal_dir = dirobj._get_root_calendar_directory(cr, uid, context=ctx) + huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, root_cal_dir))) + href = doc.documentElement + href.tagName = 'D:href' + href.appendChild(huri) + return href + + def _get_caldav_calendar_user_address_set(self, cr): + import xml.dom.minidom + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + user_obj = self.context._dirobj.pool.get('res.users') + user = user_obj.browse(cr, uid, uid, context=ctx) + doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) + href = doc.documentElement + href.tagName = 'D:href' + huri = doc.createTextNode('MAILTO:' + user.email) + href.appendChild(huri) + return href + + + def _get_caldav_schedule_inbox_URL(self, cr): + import xml.dom.minidom + import urllib + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + ids = [self.dir_id] + res = collection_obj.get_schedule_inbox_URL(cr, uid, ids, context=ctx) + + doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) + href = doc.documentElement + href.tagName = 'D:href' + huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res))) + href.appendChild(huri) + return href + + + + def _get_caldav_schedule_outbox_URL(self, cr): + import xml.dom.minidom + import urllib + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + ids = [self.dir_id] + res = collection_obj.get_schedule_outbox_URL(cr, uid, ids, context=ctx) + + doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) + href = doc.documentElement + href.tagName = 'D:href' + huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res))) + href.appendChild(huri) + return href class node_calendar(nodes.node_class): diff --git a/addons/caldav/caldav_server.py b/addons/caldav/caldav_server.py deleted file mode 100644 index 77244e5d764..00000000000 --- a/addons/caldav/caldav_server.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2010 Tiny SPRL (). -# -# 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 . -# -############################################################################## -from service import http_server -from document_webdav import webdav_server -import tools -from caldav_fs import openerp_dav_handler -from tools.config import config - -class DAVHandler(webdav_server.DAVHandler): - def setup(self): - davpath = '/'+config.get_misc('webdav','vdir','webdav') - self.baseuri = "http://%s:%d/"% (self.server.server_name,self.server.server_port) - self.IFACE_CLASS = openerp_dav_handler(self, self.verbose) - - - -handler = webdav_server.handler -if handler: - handler = DAVHandler - handler.debug = config.get_misc('webdav','debug',True) - handler._config = webdav_server.conf - -if http_server.httpd and handler: - for vdir in http_server.httpd.server.vdirs: - print vdir.handler , webdav_server.DAVHandler - if vdir.handler == webdav_server.DAVHandler: - vdir.handler = handler -if http_server.httpsd and handler: - for vdir in http_server.httpsd.server.vdirs: - if vdir.handler == webdav_server.DAVHandler: - vdir.handler = handler diff --git a/addons/caldav/calendar.py b/addons/caldav/calendar.py index 6ccd5989d5c..4f672838155 100644 --- a/addons/caldav/calendar.py +++ b/addons/caldav/calendar.py @@ -31,7 +31,6 @@ import pytz import re import tools import time -import caldav_node try: import vobject @@ -410,23 +409,6 @@ class CalDAV(object): self.ical_reset('value') return res -class calendar_collection(osv.osv): - _inherit = 'document.directory' - _columns = { - 'calendar_collection' : fields.boolean('Calendar Collection'), - 'calendar_ids': fields.one2many('basic.calendar', 'collection_id', 'Calendars'), - } - _default = { - 'calendar_collection' : False, - } - def _locate_child(self, cr, uid, root_id, uri,nparent, ncontext): - """ try to locate the node in uri, - Return a tuple (node_dir, remaining_path) - """ - return (caldav_node.node_database(context=ncontext), uri) - -calendar_collection() - class Calendar(CalDAV, osv.osv): _name = 'basic.calendar' _calname = 'calendar' @@ -445,10 +427,10 @@ class Calendar(CalDAV, osv.osv): 'vtimezone': None, # Use: O-n, Type: Collection of Timezone class } _columns = { - 'name': fields.char("Name", size=64), - 'collection_id': fields.many2one('document.directory', 'Collection', \ - required=True), + 'name': fields.char("Name", size=64), 'user_id': fields.many2one('res.users', 'Owner'), + 'collection_id': fields.many2one('document.directory', 'Collection', \ + required=True), 'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'), 'create_date': fields.datetime('Created Date'), 'write_date': fields.datetime('Modifided Date'), diff --git a/addons/caldav/calendar_collection.py b/addons/caldav/calendar_collection.py new file mode 100644 index 00000000000..06e799b1686 --- /dev/null +++ b/addons/caldav/calendar_collection.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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 . +# +############################################################################## +from osv import osv, fields +from tools.translate import _ +import caldav_node + +class calendar_collection(osv.osv): + _inherit = 'document.directory' + _columns = { + 'calendar_collection' : fields.boolean('Calendar Collection'), + 'calendar_ids': fields.one2many('basic.calendar', 'collection_id', 'Calendars'), + } + _default = { + 'calendar_collection' : False, + } + def _get_root_calendar_directory(self, cr, uid, context=None): + objid = self.pool.get('ir.model.data') + try: + mid = objid._get_id(cr, uid, 'document', 'dir_calendars') + if not mid: + return False + root_id = objid.read(cr, uid, mid, ['res_id'])['res_id'] + root_cal_dir = self.browse(cr, uid, root_id, context=context) + return root_cal_dir.name + except Exception, e: + import netsvc + logger = netsvc.Logger() + logger.notifyChannel("document", netsvc.LOG_WARNING, 'Cannot set root directory for Calendars:'+ str(e)) + return False + return False + + def _locate_child(self, cr, uid, root_id, uri,nparent, ncontext): + """ try to locate the node in uri, + Return a tuple (node_dir, remaining_path) + """ + return (caldav_node.node_database(context=ncontext), uri) + + def get_description(self, cr, uid, ids, context=None): + #TODO : return description of all calendars + if not context: + context = {} + return False + + def get_schedule_inbox_URL(self, cr, uid, ids, context=None): + calendar_obj = self.pool.get('basic.calendar') + + calendar_ids = calendar_obj.search(cr, uid, [ + ('user_id', '=', uid), ('collection_id', 'in', ids) + ], limit=1, context=context) + + root_cal_dir = self._get_root_calendar_directory(cr, uid, context=context) + if not calendar_ids: + return root_cal_dir + calendar_id = calendar_ids[0] + calendar = calendar_obj.browse(cr, uid, calendar_id, + context=context) + return '%s/%s' %(root_cal_dir, calendar.name) + + def get_schedule_outbox_URL(self, cr, uid, ids, context=None): + return self.get_schedule_inbox_URL(cr, uid, ids, context=context) + +calendar_collection() diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 9be77c50daa..41a65c73bfb 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -63,7 +63,17 @@ class openerp_dav_handler(dav_interface): self.verbose = verbose def get_propnames(self,uri): - props = self.PROPS + props = self.PROPS + self.parent.log_message('get propnames: %s' % uri) + if uri[-1]=='/':uri=uri[:-1] + cr, uid, pool, dbname, uri2 = self.get_cr(uri) + if not dbname: + cr.close() + return props + node = self.uri2object(cr, uid, pool, uri2) + if node: + props.update(node.get_dav_props(cr)) + cr.close() return props def _get_dav_lockdiscovery(self, uri): @@ -71,7 +81,8 @@ class openerp_dav_handler(dav_interface): def _get_dav_supportedlock(self, uri): 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 @@ -79,8 +90,19 @@ class openerp_dav_handler(dav_interface): pname -- name of the property """ if self.M_NS.has_key(ns): - return dav_interface.get_prop(self,uri,ns,propname) - raise DAV_NotFound + return dav_interface.get_prop(self,uri,ns,propname) + 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) + if not node: + cr.close() + raise DAV_NotFound + res = node.get_dav_eprop(cr,ns,propname) + cr.close() + return res def get_db(self,uri): names=self.uri2local(uri).split('/') From 4cc0c97a1bfb43a8fed4a22ab38d853af273e0ee Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Wed, 14 Apr 2010 13:09:25 +0530 Subject: [PATCH 013/761] [FIX] caldav bzr revid: hmo@tinyerp.com-20100414073925-3qo19wm9dnv2a34t --- addons/caldav/caldav_node.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py index 9c7c73a098d..365cf6ab1ee 100644 --- a/addons/caldav/caldav_node.py +++ b/addons/caldav/caldav_node.py @@ -184,7 +184,7 @@ class node_calendar_collection(nodes.node_dir): ctx = self.context.context.copy() ctx.update(self.dctx) ids = [self.dir_id] - res = collection_obj.get_schedule_inbox_URL(cr, uid, ids, context=ctx) + res = dirobj.get_schedule_inbox_URL(cr, uid, ids, context=ctx) doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) href = doc.documentElement @@ -203,7 +203,7 @@ class node_calendar_collection(nodes.node_dir): ctx = self.context.context.copy() ctx.update(self.dctx) ids = [self.dir_id] - res = collection_obj.get_schedule_outbox_URL(cr, uid, ids, context=ctx) + res = dirobj.get_schedule_outbox_URL(cr, uid, ids, context=ctx) doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) href = doc.documentElement From 013abc77091ed4144d95dadfad7655fa8c5c80fe Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Wed, 14 Apr 2010 17:19:40 +0530 Subject: [PATCH 014/761] [FIX] document: MKCOL bzr revid: hmo@tinyerp.com-20100414114940-jkhi3ds5eskjxhej --- addons/document/nodes.py | 49 ++++++++++++++++++++++++++++++-- addons/document_webdav/dav_fs.py | 40 +++++++------------------- 2 files changed, 57 insertions(+), 32 deletions(-) diff --git a/addons/document/nodes.py b/addons/document/nodes.py index 527fda3f594..b35dd1ed1f2 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -254,8 +254,8 @@ class node_dir(node_database): pass - def get_data(self,cr): - return '' + #def get_data(self,cr): + # return '' @@ -266,6 +266,26 @@ class node_dir(node_database): def _child_get(self, cr, name = None): return super(node_dir,self)._child_get(cr, name, self.dir_id) + + def create_child_collection(self, cr, objname): + object2 = False + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + obj = dirobj.browse(cr, uid, self.dir_id) + if obj and (obj.type == 'ressource') and not object2: + raise OSError(1, 'Operation not permited.') + + #objname = uri2[-1] + val = { + 'name': objname, + 'ressource_parent_type_id': obj and obj.ressource_type_id.id or False, + 'ressource_id': object2 and object2.id or False, + 'parent_id' : obj and obj.id or False + } + + return dirobj.create(cr, uid, val) def create_child(self,cr,path,data): @@ -556,6 +576,31 @@ class node_res_obj(node_class): if dirr.type == 'ressource': res.append(node_res_dir(dirr.name, self, self.context, dirr, {'active_id': self.res_id})) return res + + def create_child_collection(self, cr, objname): + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + res_obj = dirobj.pool.get(self.context.context['res_model']) + + object2 = res_obj.browse(cr, uid, self.context.context['res_id']) or False + + obj = dirobj.browse(cr, uid, self.dir_id) + if obj and (obj.type == 'ressource') and not object2: + raise OSError(1, 'Operation not permited.') + + + val = { + 'name': objname, + 'ressource_parent_type_id': obj and obj.ressource_type_id.id or False, + 'ressource_id': object2 and object2.id or False, + 'parent_id' : False + } + if (obj and (obj.type in ('directory'))) or not object2: + val['parent_id'] = obj and obj.id or False + + return dirobj.create(cr, uid, val) def create_child(self,cr,path,data): """ API function to create a child file object and node diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 41a65c73bfb..36b7313a0fa 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -68,7 +68,7 @@ class openerp_dav_handler(dav_interface): if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: - cr.close() + if cr: cr.close() return props node = self.uri2object(cr, uid, pool, uri2) if node: @@ -94,7 +94,7 @@ class openerp_dav_handler(dav_interface): if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: - cr.close() + if cr: cr.close() raise DAV_NotFound node = self.uri2object(cr, uid, pool, uri2) if not node: @@ -360,40 +360,20 @@ class openerp_dav_handler(dav_interface): if cr: cr.close() def mkcol(self,uri): - """ create a new collection """ + """ create a new collection """ self.parent.log_message('MKCOL: %s' % uri) + uri = self.uri2local(uri)[1:] if uri[-1]=='/':uri=uri[:-1] - parent='/'.join(uri.split('/')[:-1]) - if not parent.startswith(self.baseuri): - parent=self.baseuri + ''.join(parent[1:]) - if not uri.startswith(self.baseuri): - uri=self.baseuri + ''.join(uri[1:]) - - + parent = '/'.join(uri.split('/')[:-1]) + parent = self.baseuri + parent + uri = self.baseuri + uri cr, uid, pool,dbname, uri2 = self.get_cr(uri) if not dbname: raise DAV_Error, 409 node = self.uri2object(cr,uid,pool, uri2[:-1]) - object2 = False - if isinstance(node, node_res_obj): - object2 = node and pool.get(node.context.context['res_model']).browse(cr, uid, node.context.context['res_id']) or False - - obj = node.context._dirobj.browse(cr, uid, node.dir_id) - if obj and (obj.type == 'ressource') and not object2: - raise OSError(1, 'Operation not permited.') - - objname = uri2[-1] - val = { - 'name': objname, - 'ressource_parent_type_id': obj and obj.ressource_type_id.id or False, - 'ressource_id': object2 and object2.id or False, - 'parent_id' : False - } - if (obj and (obj.type in ('directory'))) or not object2: - val['parent_id'] = obj and obj.id or False - - pool.get('document.directory').create(cr, uid, val) - cr.commit() + if node: + node.create_child_collection(cr, uri2[-1]) + cr.commit() cr.close() return True From 7aea663bb63476b3725b4d56cdfffabbfb61aaf2 Mon Sep 17 00:00:00 2001 From: "Harry (Open ERP)" Date: Thu, 15 Apr 2010 13:28:09 +0530 Subject: [PATCH 015/761] [IMP] caldav: supporting caldav protocall bzr revid: hmo@tinyerp.com-20100415075809-edzwop5gzzdi80jj --- addons/caldav/__init__.py | 1 + addons/caldav/caldav.py | 40 +++++ addons/caldav/caldav_node.py | 243 ++++++++++++++++++++----------- addons/caldav/caldav_view.xml | 6 +- addons/caldav/calendar.py | 2 + addons/document/nodes.py | 183 +++-------------------- addons/document_webdav/dav_fs.py | 10 +- 7 files changed, 228 insertions(+), 257 deletions(-) create mode 100644 addons/caldav/caldav.py diff --git a/addons/caldav/__init__.py b/addons/caldav/__init__.py index cb496d12de0..3c7bf49a8fa 100644 --- a/addons/caldav/__init__.py +++ b/addons/caldav/__init__.py @@ -21,6 +21,7 @@ import calendar import calendar_collection +import caldav import wizard # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/caldav/caldav.py b/addons/caldav/caldav.py new file mode 100644 index 00000000000..224d1ba176c --- /dev/null +++ b/addons/caldav/caldav.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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 . +# +############################################################################## + +from document_webdav import webdav +import tools +from DAV.propfind import PROPFIND + + +super_mk_prop_response = webdav.mk_prop_response +def mk_prop_response(self,uri,good_props,bad_props,doc): + res = super_mk_prop_response(self, uri,good_props,bad_props,doc) + uris = uri.split('/') + if uri[-1] in ('Calendars'): + ad = doc.createElement('calendar') + ad.setAttribute('xmlns', 'urn:ietf:params:xml:ns:caldav') + cols = res.getElementsByTagName('D:collection') + if cols: + cols[0].parentNode.appendChild(ad) + #cols[0].parentNode.appendChild(vc) + return res + +PROPFIND.mk_prop_response = mk_prop_response diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py index 365cf6ab1ee..ffc300836b7 100644 --- a/addons/caldav/caldav_node.py +++ b/addons/caldav/caldav_node.py @@ -54,16 +54,10 @@ class node_database(nodes.node_database): class node_calendar_collection(nodes.node_dir): PROPS = { "http://calendarserver.org/ns/" : ('getctag'), - "urn:ietf:params:xml:ns:caldav" : ( - 'calendar-description', - 'calendar-data', - 'calendar-home-set', - 'calendar-user-address-set', - 'schedule-inbox-URL', - 'schedule-outbox-URL',)} + } M_NS = { "http://calendarserver.org/ns/" : '_get_dav', - "urn:ietf:params:xml:ns:caldav" : '_get_caldav'} + } def get_dav_props(self, cr): return self.PROPS @@ -89,6 +83,59 @@ class node_calendar_collection(nodes.node_dir): print "Exception:", e return None + def _file_get(self,cr, nodename=False): + return [] + + + def get_domain(self, cr, filters): + res = [] + dirobj = self.context._dirobj + uid = self.context.uid + ctx = self.context.context.copy() + ctx.update(self.dctx) + calendar_obj = dirobj.pool.get('basic.calendar') + if not filters: + return res + if filters.localName == 'calendar-query': + res = [] + for filter_child in filters.childNodes: + if filter_child.nodeType == filter_child.TEXT_NODE: + continue + if filter_child.localName == 'filter': + for vcalendar_filter in filter_child.childNodes: + if vcalendar_filter.nodeType == vcalendar_filter.TEXT_NODE: + continue + if vcalendar_filter.localName == 'comp-filter': + if vcalendar_filter.getAttribute('name') == 'VCALENDAR': + for vevent_filter in vcalendar_filter.childNodes: + if vevent_filter.nodeType == vevent_filter.TEXT_NODE: + continue + if vevent_filter.localName == 'comp-filter': + if vevent_filter.getAttribute('name') == 'VEVENT': + res = [('type','=','vevent')] + if vevent_filter.getAttribute('name') == 'VTODO': + res = [('type','=','vtodo')] + + return res + elif filters.localName == 'calendar-multiget': + ids = [] + for filter_child in filters.childNodes: + if filter_child.nodeType == filter_child.TEXT_NODE: + continue + if filter_child.localName == 'href': + if not filter_child.firstChild: + continue + uri = filter_child.firstChild.data + caluri = uri.split('/') + if len(caluri): + caluri = caluri[-1] + calendar = calendar_obj.name_search(cr, uid, caluri) + if calendar: + calendar_id, calendar_name = calendar[0] + ids.append(calendar_id) + return [('id', 'in', ids)] + return res + def _child_get(self, cr, name=False, parent_id=False, domain=None): dirobj = self.context._dirobj uid = self.context.uid @@ -99,7 +146,7 @@ class node_calendar_collection(nodes.node_dir): where.append(('name','=',name)) if not domain: domain = [] - + where = where + domain fil_obj = dirobj.pool.get('basic.calendar') ids = fil_obj.search(cr,uid,where,context=ctx) res = [] @@ -130,31 +177,110 @@ class node_calendar_collection(nodes.node_dir): def _get_dav_getctag(self, cr): result = self.get_etag(cr) - return str(result) + return str(result) + + +class node_calendar(nodes.node_class): + our_type = 'file' + PROPS = { + "http://calendarserver.org/ns/" : ('getctag'), + "urn:ietf:params:xml:ns:caldav" : ( + 'calendar-description', + 'calendar-data', + 'calendar-home-set', + 'calendar-user-address-set', + 'schedule-inbox-URL', + 'schedule-outbox-URL',)} + M_NS = { + "http://calendarserver.org/ns/" : '_get_dav', + "urn:ietf:params:xml:ns:caldav" : '_get_caldav'} + + def __init__(self,path, parent, context, calendar): + super(node_calendar,self).__init__(path, parent,context) + self.calendar_id = calendar.id + self.mimetype = 'ics' + self.create_date = calendar.create_date + self.write_date = calendar.write_date or calendar.create_date + self.content_length = 0 + self.displayname = calendar.name + + def open(self, cr, mode=False): + uid = self.context.uid + if self.type in ('collection','database'): + return False + fobj = self.context._dirobj.pool.get('basic.calendar').browse(cr, uid, self.calendar_id, context=self.context.context) + s = StringIO.StringIO(self.get_data(cr, fobj)) + s.name = self + return s + + + + def get_dav_props(self, cr): + return self.PROPS + + def get_dav_eprop(self,cr, ns, propname): + if self.M_NS.has_key(ns): + prefix = self.M_NS[ns] + else: + print "No namespace:",ns, "( for prop:", propname,")" + return None + propname = propname.replace('-','_') + mname = prefix + "_" + propname + if not hasattr(self, mname): + return None + + try: + m = getattr(self, mname) + r = m(cr) + return r + except AttributeError, e: + print 'Property %s not supported' % propname + print "Exception:", e + return None + + + def get_data(self, cr, fil_obj = None): + uid = self.context.uid + calendar_obj = self.context._dirobj.pool.get('basic.calendar') + return calendar_obj.export_cal(cr, uid, [self.calendar_id]) + + def get_data_len(self, cr, fil_obj = None): + return self.content_length + + def set_data(self, cr, data, fil_obj = None): + uid = self.context.uid + calendar_obj = self.context._dirobj.pool.get('basic.calendar') + return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id) + + def _get_ttag(self,cr): + return 'calendar-%d' % self.calendar_id + + + + def _get_caldav_calendar_data(self, cr): + res = self.get_data(cr) def _get_caldav_calendar_description(self, cr): - dirobj = self.context._dirobj uid = self.context.uid + calendar_obj = self.context._dirobj.pool.get('basic.calendar') ctx = self.context.context.copy() - ctx.update(self.dctx) - ids = [self.dir_id] - res = dirobj.get_description(cr, uid, ids, context=ctx) - return res - - def _get_caldav_calendar_data(self, cr): - return self.get_data(cr) + ctx.update(self.dctx) + calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx) + return calendar.description + def _get_caldav_calendar_home_set(self, cr): import xml.dom.minidom - import urllib - dirobj = self.context._dirobj + import urllib uid = self.context.uid ctx = self.context.context.copy() ctx.update(self.dctx) doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) - root_cal_dir = dirobj._get_root_calendar_directory(cr, uid, context=ctx) - huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, root_cal_dir))) + + calendar_obj = self.context._dirobj.pool.get('basic.calendar') + calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx) + huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, calendar.collection_id.name))) href = doc.documentElement href.tagName = 'D:href' href.appendChild(huri) @@ -178,14 +304,13 @@ class node_calendar_collection(nodes.node_dir): def _get_caldav_schedule_inbox_URL(self, cr): import xml.dom.minidom - import urllib - dirobj = self.context._dirobj + import urllib uid = self.context.uid ctx = self.context.context.copy() ctx.update(self.dctx) - ids = [self.dir_id] - res = dirobj.get_schedule_inbox_URL(cr, uid, ids, context=ctx) - + calendar_obj = self.context._dirobj.pool.get('basic.calendar') + calendar = calendar_obj.browse(cr, uid, self.calendar_id, context=ctx) + res = '%s/%s' %(calendar.name, calendar.collection_id.name) doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) href = doc.documentElement href.tagName = 'D:href' @@ -196,67 +321,7 @@ class node_calendar_collection(nodes.node_dir): def _get_caldav_schedule_outbox_URL(self, cr): - import xml.dom.minidom - import urllib - dirobj = self.context._dirobj - uid = self.context.uid - ctx = self.context.context.copy() - ctx.update(self.dctx) - ids = [self.dir_id] - res = dirobj.get_schedule_outbox_URL(cr, uid, ids, context=ctx) - - doc = xml.dom.minidom.getDOMImplementation().createDocument(None, 'href', None) - href = doc.documentElement - href.tagName = 'D:href' - huri = doc.createTextNode(urllib.quote('/%s/%s' % (cr.dbname, res))) - href.appendChild(huri) - return href - - -class node_calendar(nodes.node_class): - our_type = 'file' - def __init__(self,path, parent, context, calendar): - super(node_calendar,self).__init__(path, parent,context) - self.calendar_id = calendar.id - self.mimetype = 'ics' - self.create_date = calendar.create_date - self.write_date = calendar.write_date or calendar.create_date - self.content_length = 0 - self.displayname = calendar.name - - def open(self, cr, mode=False): - uid = self.context.uid - if self.type in ('collection','database'): - return False - fobj = self.context._dirobj.pool.get('basic.calendar').browse(cr, uid, self.calendar_id, context=self.context.context) - s = StringIO.StringIO(self.get_data(cr, fobj)) - s.name = self - return s - - def get_dav_props(self, cr): - res = {} - return res - - def get_dav_eprop(self,cr,ns,prop): - return None - - - def get_data(self, cr, fil_obj = None): - uid = self.context.uid - calendar_obj = self.context._dirobj.pool.get('basic.calendar') - return calendar_obj.export_cal(cr, uid, [self.calendar_id]) - - def get_data_len(self, cr, fil_obj = None): - return self.content_length - - def set_data(self, cr, data, fil_obj = None): - uid = self.context.uid - calendar_obj = self.context._dirobj.pool.get('basic.calendar') - return calendar_obj.import_cal(cr, uid, base64.encodestring(data), self.calendar_id) - - def _get_ttag(self,cr): - return 'calendar-%d' % self.calendar_id - + return _get_caldav_schedule_inbox_URL(cr) def get_etag(self, cr): @@ -270,5 +335,5 @@ class node_calendar(nodes.node_class): if self.write_date: wtime = time.mktime(time.strptime(self.write_date, '%Y-%m-%d %H:%M:%S')) else: wtime = time.time() - return str(wtime) + return str(wtime) # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4 diff --git a/addons/caldav/caldav_view.xml b/addons/caldav/caldav_view.xml index c982d695fac..4c1003023ae 100644 --- a/addons/caldav/caldav_view.xml +++ b/addons/caldav/caldav_view.xml @@ -70,7 +70,8 @@ form
- + + @@ -112,7 +113,8 @@ tree - + + diff --git a/addons/caldav/calendar.py b/addons/caldav/calendar.py index 4f672838155..52a1e8a56e3 100644 --- a/addons/caldav/calendar.py +++ b/addons/caldav/calendar.py @@ -431,6 +431,8 @@ class Calendar(CalDAV, osv.osv): 'user_id': fields.many2one('res.users', 'Owner'), 'collection_id': fields.many2one('document.directory', 'Collection', \ required=True), + 'type': fields.selection([('vevent', 'Event'), ('vtodo', 'TODO')], \ + string="Type", size=64), 'line_ids': fields.one2many('basic.calendar.lines', 'calendar_id', 'Calendar Lines'), 'create_date': fields.datetime('Created Date'), 'write_date': fields.datetime('Modifided Date'), diff --git a/addons/document/nodes.py b/addons/document/nodes.py index b35dd1ed1f2..e10d0934eef 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -109,11 +109,11 @@ class node_class(object): s.append(self.path) return s #map(lambda x: '/' +x, s) - def children(self, cr): + def children(self, cr, domain=None): print "node_class.children()" return [] #stub - def child(self,cr, name): + def child(self,cr, name, domain=None): print "node_class.child()" return None @@ -155,6 +155,9 @@ class node_class(object): def get_dav_eprop(self,cr,ns,prop): return None + def get_domain(self, cr, filters): + return [] + class node_database(node_class): """ A node representing the database directory @@ -163,12 +166,12 @@ class node_database(node_class): def __init__(self, path=[], parent=False, context=None): super(node_database,self).__init__(path, parent, context) - def children(self,cr): - res = self._child_get(cr) + self._file_get(cr) + def children(self, cr, domain=None): + res = self._child_get(cr, domain=domain) + self._file_get(cr) return res - def child(self, cr, name): - res = self._child_get(cr,name) + def child(self, cr, name, domain=None): + res = self._child_get(cr, name, domain=None) if res: return res[0] res = self._file_get(cr,name) @@ -264,8 +267,8 @@ class node_dir(node_database): - def _child_get(self, cr, name = None): - return super(node_dir,self)._child_get(cr, name, self.dir_id) + def _child_get(self, cr, name=None, domain=None): + return super(node_dir,self)._child_get(cr, name, self.dir_id, domain=domain) def create_child_collection(self, cr, objname): object2 = False @@ -359,16 +362,16 @@ class node_res_dir(node_class): for dfld in dirr.dctx_ids: self.dctx_dict['dctx_' + dfld.field] = dfld.expr - def children(self,cr): - return self._child_get(cr) + def children(self, cr, domain=None): + return self._child_get(cr, domain=domain) - def child(self,cr, name): - res = self._child_get(cr,name) + def child(self,cr, name, domain=None): + res = self._child_get(cr, name, domain=domain) if res: return res[0] return None - def _child_get(self,cr,name = None): + def _child_get(self,cr, name = None, domain=None): """ return virtual children of resource, based on the foreign object. @@ -455,11 +458,11 @@ class node_res_obj(node_class): else: self.res_id = res_id - def children(self,cr): - return self._child_get(cr) + self._file_get(cr) + def children(self, cr, domain=None): + return self._child_get(cr, domain=domain) + self._file_get(cr) - def child(self,cr, name): - res = self._child_get(cr,name) + def child(self,cr, name, domain=None): + res = self._child_get(cr, name, domain=domain) if res: return res[0] res = self._file_get(cr,name) @@ -514,7 +517,7 @@ class node_res_obj(node_class): return ('vevent-collection','http://groupdav.org/') return None - def _child_get(self,cr,name = None): + def _child_get(self,cr, name=None, domain=None): dirobj = self.context._dirobj uid = self.context.uid ctx = self.context.context.copy() @@ -792,147 +795,3 @@ class node_content(node_class): def _get_ttag(self,cr): return 'cnt-%d%s' % (self.cnt_id,(self.act_id and ('-' + str(self.act_id))) or '') - -class old_class(): - # the old code, remove.. - def __init__(self, cr, uid, path, object, object2=False, context={}, content=False, type='collection', root=False): - self.cr = cr - def _file_get(self, nodename=False): - if not self.object: - return [] - pool = pooler.get_pool(self.cr.dbname) - fobj = pool.get('ir.attachment') - res2 = [] - where = [] - if self.object2: - where.append( ('res_model','=',self.object2._name) ) - where.append( ('res_id','=',self.object2.id) ) - else: - where.append( ('parent_id','=',self.object.id) ) - where.append( ('res_id','=',False) ) - if nodename: - where.append( (fobj._rec_name,'=',nodename) ) - for content in self.object.content_ids: - res3 = content._table._file_get(self,nodename,content) - if res3: - res2.extend(res3) - - ids = fobj.search(self.cr, self.uid, where+[ ('parent_id','=',self.object and self.object.id or False) ]) - if self.object and self.root and (self.object.type=='ressource'): - ids += fobj.search(self.cr, self.uid, where+[ ('parent_id','=',False) ]) - res = fobj.browse(self.cr, self.uid, ids, context=self.context) - return map(lambda x: node_class(self.cr, self.uid, self.path+'/'+eval('x.'+fobj._rec_name), x, False, context=self.context, type='file', root=False), res) + res2 - - def get_translation(self,value,lang): - # Must go, it works on arbitrary models and could be ambiguous. - result = value - pool = pooler.get_pool(self.cr.dbname) - translation_ids = pool.get('ir.translation').search(self.cr, self.uid, [('value','=',value),('lang','=',lang),('type','=','model')]) - if len(translation_ids): - tran_id = translation_ids[0] - translation = pool.get('ir.translation').read(self.cr, self.uid, tran_id, ['res_id','name']) - res_model,field_name = tuple(translation['name'].split(',')) - res_id = translation['res_id'] - res = pool.get(res_model).read(self.cr, self.uid, res_id, [field_name]) - if res: - result = res[field_name] - return result - - def directory_list_for_child(self,nodename,parent=False): - pool = pooler.get_pool(self.cr.dbname) - where = [] - if nodename: - nodename = self.get_translation(nodename, self.context['lang']) - where.append(('name','=',nodename)) - if (self.object and self.object.type=='directory') or not self.object2: - where.append(('parent_id','=',self.object and self.object.id or False)) - else: - where.append(('parent_id','=',False)) - if self.object: - where.append(('ressource_parent_type_id','=',self.object.ressource_type_id.id)) - else: - where.append(('ressource_parent_type_id','=',False)) - - ids = pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',0)]) - if self.object2: - ids += pool.get('document.directory').search(self.cr, self.uid, where+[('ressource_id','=',self.object2.id)]) - res = pool.get('document.directory').browse(self.cr, self.uid, ids, self.context) - return res - - def _child_get(self, nodename=False): - if self.type not in ('collection','database'): - return [] - res = self.directory_list_for_child(nodename) - result= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name, x, x.type=='directory' and self.object2 or False, context=self.context, root=self.root), res) - if self.type=='database': - pool = pooler.get_pool(self.cr.dbname) - fobj = pool.get('ir.attachment') - vargs = [('parent_id','=',False),('res_id','=',False)] - if nodename: - vargs.append((fobj._rec_name,'=',nodename)) - file_ids=fobj.search(self.cr,self.uid,vargs) - - res = fobj.browse(self.cr, self.uid, file_ids, context=self.context) - result +=map(lambda x: node_class(self.cr, self.uid, self.path+'/'+eval('x.'+fobj._rec_name), x, False, context=self.context, type='file', root=self.root), res) - if self.type=='collection' and self.object.type=="ressource": - where = self.object.domain and eval(self.object.domain, {'active_id':self.root, 'uid':self.uid}) or [] - pool = pooler.get_pool(self.cr.dbname) - obj = pool.get(self.object.ressource_type_id.model) - _dirname_field = obj._rec_name - if len(obj.fields_get(self.cr, self.uid, ['dirname'])): - _dirname_field = 'dirname' - - name_for = obj._name.split('.')[-1] - if nodename and nodename.find(name_for) == 0 : - id = int(nodename.replace(name_for,'')) - where.append(('id','=',id)) - elif nodename: - if nodename.find('__') : - nodename=nodename.replace('__','/') - for invalid in INVALID_CHARS: - if nodename.find(INVALID_CHARS[invalid]) : - nodename=nodename.replace(INVALID_CHARS[invalid],invalid) - nodename = self.get_translation(nodename, self.context['lang']) - where.append((_dirname_field,'=',nodename)) - - if self.object.ressource_tree: - if obj._parent_name in obj.fields_get(self.cr,self.uid): - where.append((obj._parent_name,'=',self.object2 and self.object2.id or False)) - ids = obj.search(self.cr, self.uid, where) - res = obj.browse(self.cr, self.uid, ids,self.context) - result+= map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, context=self.context, root=x.id), res) - return result - else : - if self.object2: - return result - else: - if self.object2: - return result - - - ids = obj.search(self.cr, self.uid, where) - res = obj.browse(self.cr, self.uid, ids,self.context) - for r in res: - if len(obj.fields_get(self.cr, self.uid, [_dirname_field])): - r.name = eval('r.'+_dirname_field) - else: - r.name = False - if not r.name: - r.name = name_for + '%d'%r.id - for invalid in INVALID_CHARS: - if r.name.find(invalid) : - r.name = r.name.replace(invalid,INVALID_CHARS[invalid]) - result2 = map(lambda x: node_class(self.cr, self.uid, self.path+'/'+x.name.replace('/','__'), self.object, x, context=self.context, root=x.id), res) - if result2: - if self.object.ressource_tree: - result += result2 - else: - result = result2 - return result - - - def path_get(self): - path = self.path - if self.path[0]=='/': - path = self.path[1:] - return path diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 36b7313a0fa..1b77ea67832 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -135,8 +135,8 @@ class openerp_dav_handler(dav_interface): cr.close() return self.db_name_list - def get_childs(self,uri): - """ return the child objects as self.baseuris for the given URI """ + def get_childs(self,uri, filters=None): + """ return the child objects as self.baseuris for the given URI """ self.parent.log_message('get childs: %s' % uri) if uri[-1]=='/':uri=uri[:-1] cr, uid, pool, dbname, uri2 = self.get_cr(uri) @@ -158,14 +158,16 @@ class openerp_dav_handler(dav_interface): fp = '/'.join(fp) else: fp = None - for d in node.children(cr): + domain = None + if filters: + domain = node.get_domain(cr, filters) + for d in node.children(cr, domain): self.parent.log_message('child: %s' % d.path) if fp: result.append( self.urijoin(dbname,fp,d.path) ) else: result.append( self.urijoin(dbname,d.path) ) if cr: cr.close() - return result def uri2local(self, uri): From 3c0443a9d366ee64fcc1cb1561e17dbcc68bb2bc Mon Sep 17 00:00:00 2001 From: "sbh (Open ERP)" Date: Thu, 15 Apr 2010 14:57:22 +0530 Subject: [PATCH 016/761] [IMP] product:convert the price_list wizard into osv_memory wizard bzr revid: sbh@tinyerp.com-20100415092722-snzdrw61zoolk367 --- addons/product/__terp__.py | 2 +- addons/product/product_wizard.xml | 11 ---- addons/product/wizard/__init__.py | 2 +- addons/product/wizard/product_price.py | 67 ++++++++++++++++++++ addons/product/wizard/product_price_view.xml | 33 ++++++++++ addons/product/wizard/wizard_price.py | 59 ----------------- 6 files changed, 102 insertions(+), 72 deletions(-) delete mode 100644 addons/product/product_wizard.xml create mode 100644 addons/product/wizard/product_price.py create mode 100644 addons/product/wizard/product_price_view.xml delete mode 100644 addons/product/wizard/wizard_price.py diff --git a/addons/product/__terp__.py b/addons/product/__terp__.py index 4128e992c82..b3e18ced10a 100644 --- a/addons/product/__terp__.py +++ b/addons/product/__terp__.py @@ -49,13 +49,13 @@ 'update_xml': [ 'security/product_security.xml', 'security/ir.model.access.csv', + 'wizard/product_price_view.xml', 'product_data.xml', 'product_report.xml', 'product_view.xml', 'pricelist_view.xml', 'partner_view.xml', 'company_view.xml', - 'product_wizard.xml', 'process/product_process.xml' ], 'installable': True, diff --git a/addons/product/product_wizard.xml b/addons/product/product_wizard.xml deleted file mode 100644 index f226cd4e543..00000000000 --- a/addons/product/product_wizard.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/addons/product/wizard/__init__.py b/addons/product/wizard/__init__.py index fed1bcf3783..47f5f2641fc 100644 --- a/addons/product/wizard/__init__.py +++ b/addons/product/wizard/__init__.py @@ -18,7 +18,7 @@ # along with this program. If not, see . # ############################################################################## -import wizard_price +import product_price # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/product/wizard/product_price.py b/addons/product/wizard/product_price.py new file mode 100644 index 00000000000..e5d73945c13 --- /dev/null +++ b/addons/product/wizard/product_price.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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 . +# +############################################################################## + +from osv import osv, fields +from tools.translate import _ + + +class product_price_list(osv.osv_memory): + _name = 'product.price_list' + _description = 'Product Price List' + + _columns = { + 'price_list': fields.many2one('product.pricelist', 'PriceList', required=True), + 'qty1': fields.integer('Quantity-1'), + 'qty2': fields.integer('Quantity-2'), + 'qty3': fields.integer('Quantity-3'), + 'qty4': fields.integer('Quantity-4'), + 'qty5': fields.integer('Quantity-5'), + } + _defaults = { + 'qty1': lambda *a: 0, + 'qty2': lambda *a: 0, + 'qty3': lambda *a: 0, + 'qty4': lambda *a: 0, + 'qty5': lambda *a: 0, + } + + def print_report(self, cr, uid, ids, context=None): + + """ + To get the date and print the report + @param self: The object pointer. + @param cr: A database cursor + @param uid: ID of the user currently logged in + @param context: A standard dictionary + @return : return report + """ + datas = {'ids': context.get('active_ids', [])} + res = self.read(cr, uid, ids, ['price_list','qty1', 'qty2','qty3','qty4','qty5'], context) + res = res and res[0] or {} + datas['form'] = res + return { + 'type': 'ir.actions.report.xml', + 'report_name': 'product.pricelist', + 'datas': datas, + } +product_price_list() +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: + diff --git a/addons/product/wizard/product_price_view.xml b/addons/product/wizard/product_price_view.xml new file mode 100644 index 00000000000..17d9010ed43 --- /dev/null +++ b/addons/product/wizard/product_price_view.xml @@ -0,0 +1,33 @@ + + + + + + + + Price List + product.price_list + form + + + + + + + + +