TemplateTool.py 7.94 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2 3
##############################################################################
#
# Copyright (c) 2002 Nexedi SARL and Contributors. All Rights Reserved.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
4
#                    Jean-Paul Smets-Solanes <jp@nexedi.com>
Jean-Paul Smets's avatar
Jean-Paul Smets committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
#
# 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.
#
##############################################################################

29 30
import cStringIO
from webdav.client import Resource
Jean-Paul Smets's avatar
Jean-Paul Smets committed
31 32
from Products.CMFCore.utils import UniqueObject

Yoshinori Okuji's avatar
Yoshinori Okuji committed
33 34 35
from App.config import getConfiguration
import os

36
from Acquisition import Implicit
Jean-Paul Smets's avatar
Jean-Paul Smets committed
37
from AccessControl import ClassSecurityInfo
38
from Globals import InitializeClass, DTMLFile, PersistentMapping
Jean-Paul Smets's avatar
Jean-Paul Smets committed
39
from Products.ERP5Type.Tool.BaseTool import BaseTool
Jean-Paul Smets's avatar
Jean-Paul Smets committed
40 41 42 43 44 45
from Products.ERP5Type import Permissions

from Products.ERP5 import _dtmldir

from zLOG import LOG

46 47 48 49 50 51 52 53 54 55
class LocalConfiguration(Implicit):
  """
    Holds local configuration information
  """
  def __init__(self, **kw):
    self.__dict__.update(kw)

  def update(self, **kw):
    self.__dict__.update(kw)

Jean-Paul Smets's avatar
Jean-Paul Smets committed
56
class TemplateTool (BaseTool):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
57
    """
58
      TemplateTool manages Business Templates.
Jean-Paul Smets's avatar
Jean-Paul Smets committed
59

60
      TemplateTool provides some methods to deal with Business Templates:
Jean-Paul Smets's avatar
Jean-Paul Smets committed
61

62
        - download
Jean-Paul Smets's avatar
Jean-Paul Smets committed
63

64
        - publish
Jean-Paul Smets's avatar
Jean-Paul Smets committed
65

66
        - install
Jean-Paul Smets's avatar
Jean-Paul Smets committed
67

68
        - update
Jean-Paul Smets's avatar
Jean-Paul Smets committed
69

70
        - save
Jean-Paul Smets's avatar
Jean-Paul Smets committed
71 72 73
    """
    id = 'portal_templates'
    meta_type = 'ERP5 Template Tool'
Jean-Paul Smets's avatar
Jean-Paul Smets committed
74
    portal_type = 'Template Tool'
75
    allowed_types = ( 'ERP5 Business Template',)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
76 77 78 79 80 81 82

    # Declarative Security
    security = ClassSecurityInfo()

    security.declareProtected( Permissions.ManagePortal, 'manage_overview' )
    manage_overview = DTMLFile( 'explainRuleTool', _dtmldir )

83 84 85 86 87 88 89 90 91 92 93 94
    def getInstalledBusinessTemplate(self, title, **kw):
      """
        Return a installed business template if any.
      """
      # This can be slow if, say, 10000 business templates are present.
      # However, that unlikely happens, and using a Z SQL Method has a potential danger
      # because business templates may exchange catalog methods, so the database could be
      # broken temporarily.
      for bt in self.contentValues(filter={'portal_type':'Business Template'}):
        if bt.getInstallationState() == 'installed' and bt.getTitle() == title:
          return bt
      return None
95

96 97
    # Import a business template
    def importURL(self, url):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
98
      """
99
        Import a business template
Jean-Paul Smets's avatar
Jean-Paul Smets committed
100
      """
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
      # Copy it to import directory
      # and import in self

    def updateLocalConfiguration(self, template, **kw):
      template_id = template.getId()
      if not hasattr(self, '_local_configuration'): self._local_configuration = PersistentMapping()
      if not self._local_configuration.has_key(template_id):
        self._local_configuration[template_id] = LocalConfiguration(**kw)
      else:
        self._local_configuration[template_id].update(**kw)

    def getLocalConfiguration(self, template):
      template_id = template.getId()
      if not hasattr(self, '_local_configuration'): self._local_configuration = PersistentMapping()
      local_configuration = self._local_configuration.get(template_id, None)
      if local_configuration is not None:
        return local_configuration.__of__(self)
      return None

120 121
    security.declareProtected( 'Import/Export objects', 'save' )
    def save(self, business_template, REQUEST=None, RESPONSE=None):
Yoshinori Okuji's avatar
Yoshinori Okuji committed
122 123 124 125
      """
        Save in a format or another
      """
      cfg = getConfiguration()
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
      path = os.path.join(cfg.clienthome, '%s.bt5' % business_template.getTitle())
      export_string = self.manage_exportObject(id=business_template.getId(), toxml=1, download=1)
      f = open(path, 'wb')
      try:
        f.write(export_string)
      finally:
        f.close()

      if REQUEST is not None:
        ret_url = business_template.absolute_url() + '/' + REQUEST.get('form_id', 'view')
        qs = '?portal_status_message=Saved+in+%s+.' % path
        if RESPONSE is None: RESPONSE = REQUEST.RESPONSE
        return REQUEST.RESPONSE.redirect( ret_url + qs )

    security.declareProtected( 'Import/Export objects', 'export' )
    def export(self, business_template, REQUEST=None, RESPONSE=None):
      """
        Export in a format or another
      """
      export_string = self.manage_exportObject(id=business_template.getId(), toxml=1, download=1)
      if RESPONSE is not None:
        RESPONSE.setHeader('Content-type','application/data')
        RESPONSE.setHeader('Content-Disposition',
                           'inline;filename=%s.bt5' % business_template.getTitle())
      return export_string
Yoshinori Okuji's avatar
Yoshinori Okuji committed
151

152 153 154 155 156 157 158
    def publish(self, business_template, url, username=None, password=None):
      """
        Publish in a format or another
      """
      business_template.build()
      export_string = self.manage_exportObject(id=business_template.getId(), download=1)
      bt = Resource(url, username=username, password=password)
159
      bt.put(file=export_string, content_type='application/x-erp5-business-template')
160
      business_template.setPublicationUrl(url)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
161

162 163 164 165 166 167 168 169 170 171 172
    def update(self, business_template):
      """
        Update an existing template
      """
      url = business_template.getPublicationUrl()
      id = business_template.getId()
      bt = Resource(url)
      export_string = bt.get().get_body()
      self.deleteContent(id)
      self._importObjectFromFile(cStringIO.StringIO(export_string), id=id)

Jean-Paul Smets's avatar
Jean-Paul Smets committed
173
    def download(self, url, id=None, REQUEST=None):
174 175 176 177 178 179
      """
        Update an existing template
      """
      from urllib import urlretrieve
      file, headers = urlretrieve(url)
      self._importObjectFromFile(file, id=id)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
180 181
      bt = self[id]
      bt.id = id # Make sure id is consistent
182
      #LOG('Template Tool', 0, 'Indexing %r, isIndexable = %r' % (bt, bt.isIndexable))
Jean-Paul Smets's avatar
Jean-Paul Smets committed
183 184 185 186 187
      bt.immediateReindexObject()

      if REQUEST is not None:
        REQUEST.RESPONSE.redirect("%s?portal_status_message=Business+Template+Downloaded+Successfully"
                           % self.absolute_url())
Jean-Paul Smets's avatar
Jean-Paul Smets committed
188

Alexandre Boeglin's avatar
Alexandre Boeglin committed
189
    def importFile(self, import_file=None, id=None, REQUEST=None, **kw):
190 191 192
      """
        Update an existing template
      """
Alexandre Boeglin's avatar
Alexandre Boeglin committed
193 194 195 196 197 198 199 200
      if (import_file is None) or (len(import_file.read()) == 0) :
        if REQUEST is not None :
          REQUEST.RESPONSE.redirect("%s?portal_status_message=No+file+or+an+empty+file+was+specified"
              % self.absolute_url())
          return
        else :
          raise 'Error', 'No file or an empty file was specified'
      import_file.seek(0) #Rewind to the beginning of file
201 202 203
      from tempfile import mkstemp
      tempid, temppath = mkstemp()
      tempfile = open(temppath, 'w')
Alexandre Boeglin's avatar
Alexandre Boeglin committed
204
      tempfile.write(import_file.read())
205 206 207 208 209 210 211 212 213
      tempfile.close()
      self._importObjectFromFile(temppath, id=id)
      os.remove(temppath)
      bt = self[id]
      bt.id = id # Make sure id is consistent
      #LOG('Template Tool', 0, 'Indexing %r, isIndexable = %r' % (bt, bt.isIndexable))
      bt.immediateReindexObject()

      if REQUEST is not None:
Alexandre Boeglin's avatar
Alexandre Boeglin committed
214
        REQUEST.RESPONSE.redirect("%s?portal_status_message=Business+Template+Imported+Successfully"
215 216
                           % self.absolute_url())

Jean-Paul Smets's avatar
Jean-Paul Smets committed
217
InitializeClass(TemplateTool)