source: products/qPloneSkinDump/branches/plone_3.0/skin_template/utils.py @ 1591

Last change on this file since 1591 was 134, checked in by mylan, 18 years ago

Moved utils.py from Extensions/utils.py to root Product's directory.
Moved patch code from init.py to patch.py.
Update all related files.

  • Property svn:eol-style set to native
File size: 23.9 KB
Line 
1import transaction
2import os, sys, re, string
3from sets import Set
4from StringIO import StringIO
5from time import gmtime, strftime
6from zLOG import LOG, INFO
7from zExceptions import BadRequest
8from App.config import getConfiguration
9from Products.CMFCore.utils import getToolByName
10from Products.CMFCore.DirectoryView import addDirectoryViews
11from Products.%(SKIN_PRODUCT_NAME)s.config import *
12from fixes import fix
13from Globals import package_home
14
15######################################################################
16##                      IMPORTING UTILS                             ##
17######################################################################
18osp = os.path
19ALLOWED_IMPORT_POLICY = ["only_new", "backup", "overwrite"]
20INTRO_TO_INSTANCE = "< Started copying object files from Product import directory to Instance one."
21SUMMARY_TO_INSTANCE = "> Finished copying."
22INTRO_TO_ROOT = "< Started import %%s file[s] with '%%s' policy."
23SUMMARY_TO_ROOT = "> Finished importing."
24INTRO_CLEAN = "< Started cleaning Instance import directory."
25SUMMARY_CLEAN = "> Finished cleaning."
26CREXP_INVALID_ID = re.compile('^The id \"(.*?)\" is invalid - it is already in use.$', re.DOTALL|re.IGNORECASE|re.MULTILINE)
27CSS_BASE_IDS_QPSD053 = ['id','expression','enabled','cookable','media','rel','title','rendering']   # supporting qPSD-0.5.3 version
28################    CHECK IMPORTING    ################
29def checkIfImport():
30    """ Return if perform importing, based on checking
31        *zexp files in <SkinProduct>/import directory.
32    """
33    instance_ipath, product_ipath = getImportedPathes()
34    product_ilist = [i for i in os.listdir(product_ipath) \
35                     if osp.isfile(osp.join(product_ipath,i)) and i.endswith('.zexp')]
36    if product_ilist:
37        return 1
38    return 0
39
40################    IMPORTING TO PLONE'S IMPORT DIR   ################
41def getImportedPathes():
42    """ Return Plone instance and Skin product import pathes."""
43    # Based on instance path, construct import pathes
44    cfg = getConfiguration()
45    instance_ipath = osp.join(cfg.instancehome, "import")
46    product_ipath = osp.join(package_home(GLOBALS), "import")
47    # Check presence of Product import directory
48    if not osp.isdir(product_ipath):       
49        raise BadRequest, "Skin Product's import directory '%%s' - does not exist or is'nt direcory" %% product_ipath
50    # Check presence of Instance import directory
51    if not osp.isdir(instance_ipath):
52        raise BadRequest, "Instance import directory '%%s' - does not exist or isn't direcory" %% instance_ipath
53    return [instance_ipath, product_ipath]
54
55def copyFile(src_dir, dst_dir, f_name):
56    """ Copy file from src_dir to dst_dir under original name."""
57    try:
58        src_file = open(osp.join(src_dir, f_name),"rb")
59        dst_file = open(osp.join(dst_dir, f_name),"wb")
60        dst_file.write(src_file.read())
61        dst_file.close()
62        src_file.close()
63    except Exception, e:
64        msg = "!!! In copying files from <%%s> dir to <%%s> dir exception occur. Details: %%s." %% (src_dir,dst_dir, str(e))
65        print >> import_out, msg
66        LOG('performImportToPortal',INFO,'copyFile', msg)
67
68def moveToTemp(same_instance_files, instance_ipath, temp_dir_path):
69    """ Move samenamed files from Instanse's dir to temp dir."""
70    os.mkdir(temp_dir_path) # Create temp back_[date] dir
71    try:
72        [copyFile(instance_ipath, temp_dir_path, f_name) for f_name in same_instance_files]
73        [os.remove(osp.join(instance_ipath, f_name)) for f_name in same_instance_files]
74    except Exception, e:
75        msg = "!!! Exception occur during moving files from Instance's dir to temp dir. Detaile:%%s." %% str(e)
76        print >> import_out, msg
77        LOG('performImportToPortal',INFO,'moveToTemp', msg)
78   
79def copyToInstanceImport():
80    """ Perform copying imported files from <SkinProduct>/import dir
81        to Plone's instance import dir.
82    """
83    print >> import_out, INTRO_TO_INSTANCE
84    instance_ipath, product_ipath = getImportedPathes()
85    # Compose temp dir back_[date] dir path in Instance import directory
86    temp_dir_id = "back_%%s" %% strftime("%%Y%%m%%d%%H%%M%%S", gmtime())
87    temp_dir_path = osp.join(instance_ipath, temp_dir_id)
88    # Get *.zexp files from Skin Product's import dir and Plone's instance import dir files
89    product_ilist = [i for i in os.listdir(product_ipath) \
90                     if osp.isfile(osp.join(product_ipath,i)) and i.endswith('.zexp')]
91    instance_ilist = [i for i in os.listdir(instance_ipath) \
92                      if osp.isfile(osp.join(instance_ipath,i)) and i.endswith('.zexp')]
93    # Check for presence samenamed files in Instance and Product import directories.
94    same_instance_files = [f_name for f_name in instance_ilist if f_name in product_ilist]
95    if same_instance_files:
96        moveToTemp(same_instance_files, instance_ipath, temp_dir_path)
97    # Copy all *zexp files from Product's import dir to Instance's import dir
98    [copyFile(product_ipath, instance_ipath, f_name) for f_name in product_ilist]
99    print >> import_out, SUMMARY_TO_INSTANCE
100    return [instance_ipath, product_ipath, temp_dir_path, product_ilist]
101
102################    IMPORTING TO PORTAL   ################
103def importObject(portal, file_name):
104    """ Work around old Zope bug in importing."""
105    try:
106        portal.manage_importObject(file_name)
107    except:
108        portal._p_jar = portal.Destination()._p_jar
109        portal.manage_importObject(file_name)
110
111def makeBackUp(portal, portal_objects, temp_dir_path, obj_id):
112    """ Perfom backup same named portal objects in temp folder."""
113    # Get id of temp folder-object
114    durty_path,temp_id = osp.split(temp_dir_path)
115    if not temp_id:
116        durty_path,temp_id = osp.split(durty_path)
117    # Get temp folder-object
118    if temp_id not in portal_objects:
119        portal.invokeFactory('Large Plone Folder', id=temp_id)
120        print >> import_out, "! Created '%%s' backup directory with same-ids " \
121                             "objects from portal root." %% temp_id
122    temp_dir = getattr(portal, temp_id)
123    # Move object with same id to temp folder-object
124    #get_transaction().commit(1)
125    transaction.savepoint()
126    obj = portal.manage_cutObjects(ids=[obj_id])
127    temp_dir.manage_pasteObjects(obj)
128    print >> import_out, "! '%%s' Object moved from portal root to '%%s' backup directory." %% (obj_id, temp_id)
129
130def performImport(portal, temp_dir_path, file_name):
131    """ Importing an object to portal."""
132    portal_objects = portal.objectIds()
133    try:
134        portal.manage_importObject(file_name)
135    except Exception, e:
136        msg = str(e)
137        is_invalid_id = CREXP_INVALID_ID.match(msg)
138        if is_invalid_id:
139            obj_id = is_invalid_id.group(1)
140            if IMPORT_POLICY == "only_new":
141                msg = "! Object with '%%s' id was not importing because it's already exist " \
142                      "in portal root." %% obj_id
143                print >> import_out, msg
144            elif IMPORT_POLICY == "backup":
145                makeBackUp(portal, portal_objects, temp_dir_path, obj_id)
146                importObject(portal, file_name)
147            elif IMPORT_POLICY == "overwrite":
148                portal.manage_delObjects(ids=[obj_id])
149                importObject(portal, file_name)
150        else:
151            # work around old Zope bug in importing
152            portal._p_jar = portal.Destination()._p_jar
153            portal.manage_importObject(file_name)
154
155def importToPortalRoot(portal, product_file_names, temp_dir_path):
156    """ Import all objects from *zexp files to portal root (based on IMPORT_POLICY)."""
157    if not IMPORT_POLICY in ALLOWED_IMPORT_POLICY:
158        raise Exception("%%s - wrong import policy in '%%s/config.py' file. Must be one of the %%s" \
159                        %% (IMPORT_POLICY, PRODUCT_NAME, ALLOWED_IMPORT_POLICY) )
160    print >> import_out, INTRO_TO_ROOT %% (product_file_names, IMPORT_POLICY)
161    for file_name in product_file_names:
162        try:
163            # Temporary allow implicitly adding Large Plone Folder
164            types_tool = getToolByName(portal, 'portal_types')
165            lpf_fti = types_tool['Large Plone Folder']
166            lpf_global_setting = lpf_fti.global_allow
167            lpf_fti.global_allow = 1
168            try:
169                performImport(portal, temp_dir_path, file_name)
170            finally:
171                lpf_fti.global_allow = lpf_global_setting
172        except Exception, error:
173            msg = '!!! Under "%%s" policy importing exception occur: %%s.' %% (IMPORT_POLICY, str(error))
174            print >> import_out, msg
175            LOG('performImportToPortal',INFO,'importToPortalRoot', msg)
176    print >> import_out, SUMMARY_TO_ROOT
177
178################    CLEANING PLONE'S IMPORT DIR   ################
179def cleanInstanceImport(instance_ipath, product_file_names, temp_dir_path):
180    """ Cleaning Plone's import dir."""
181    print >> import_out, INTRO_CLEAN
182    # Erase all copied *zexp files from Instance's import dir
183    for f_name in product_file_names:
184        f_path = osp.join(instance_ipath, f_name)
185        if osp.exists(f_path) and osp.isfile(f_path):
186            os.remove(f_path)
187        else:
188            msg = '! "%%s" file was not deleted from "%%s" import directory.' %%\
189                   (f_name, osp.join(instance_ipath))
190            print >> import_out, msg
191            LOG('performImportToPortal',INFO,'cleanInstanceImport', msg)
192    # Move all files from temp back_[date] dir to Instance's import dir
193    if osp.exists(temp_dir_path) and osp.isdir(temp_dir_path):
194        f_names = os.listdir(temp_dir_path)
195        try:
196            [copyFile(temp_dir_path, instance_ipath, f_name) for f_name in f_names]
197            [os.remove(osp.join(temp_dir_path, f_name)) for f_name in f_names]
198            # Erase temp back_[date] dir
199            os.rmdir(temp_dir_path)
200        except Exception, e:
201            msg = "!!! In moving files from temp dir to Instance's import dir exception occur."
202            print >> import_out, msg
203            LOG('performImportToPortal',INFO,'moveFromTempToImport', msg)
204    print >> import_out, SUMMARY_CLEAN
205
206def fixImportingIssues(portal, beforeimporting_objects):
207    ''' Fix defects of importing process: reindexing, other'''
208    afterimporting_objects = portal.objectItems()
209    diff_objects = list(Set(afterimporting_objects)-Set(beforeimporting_objects))
210    for id, ob in diff_objects:
211        if id.startswith('back_'):
212            continue
213        fix(ob)
214
215################    MAIN    ################
216def performImportToPortal(portal):
217    """ Import objects from Skin Product to Portal root."""
218    globals()['import_out'] = StringIO()
219    instance_ipath, product_ipath, temp_dir_path, product_file_names = copyToInstanceImport()
220    if product_file_names:
221        beforeimporting_objects = portal.objectItems()
222        importToPortalRoot(portal, product_file_names, temp_dir_path)
223        fixImportingIssues(portal, beforeimporting_objects)
224        cleanInstanceImport(instance_ipath, product_file_names, temp_dir_path)
225    else:
226        print >> import_out, "!!! Failure importing: there is no file for importing to be found."
227    result = import_out
228    del globals()['import_out']
229    return result.getvalue()
230
231######################################################################
232##              INSTALLATION/UNINSTALLATION UTILS                   ##
233######################################################################
234CSS_REG_PROPS = ['id', 'expression', 'enabled', 'cookable', 'cacheable' \
235                ,'media', 'rel', 'title', 'rendering', 'compression']
236JS_REG_PROPS = ['id', 'expression', 'enabled', 'cookable', 'cacheable' \
237               ,'inline', 'compression']
238
239def installSkin(portal, pp_up, out):
240    # Checking for presense SKIN_NAME in portal_skins directory view or among Skin Names
241    skinsTool = getToolByName(portal, 'portal_skins')
242    # Get unique product_skin_name and remember it in case of differ from SKIN_NAME.
243    product_skin_name = SKIN_NAME
244    skin_names = skinsTool.getSkinSelections()
245    if product_skin_name in skin_names:
246        idx = 0
247        while product_skin_name in skin_names:
248            product_skin_name = SKIN_NAME + str(idx)
249            idx += 1
250        addProperty(pp_up, 'q_actual_skin_name', product_skin_name, 'string', out)
251    # Add directory views
252    layer_skin_name = string.lower(SKIN_NAME)
253    addDirectoryViews(skinsTool, 'skins', GLOBALS)
254    print >> out,  "- added '%%s' directory views to portal_skins." %% layer_skin_name
255    # Get Default skin and remember it for backup on uninstallig
256    default_skin = skinsTool.getDefaultSkin()
257    addProperty(pp_up, 'q_default_skin', default_skin, 'string', out)
258    # Building list of layers for NEW SKIN
259    base_path = skinsTool.getSkinPath(BASE_SKIN_NAME)
260    new_path = map( string.strip, string.split(base_path,',') )
261    if layer_skin_name in new_path :
262        print >> out, "- %%s layer already present in '%%s' skin." %% (layer_skin_name, BASE_SKIN_NAME)
263        # Remove layer_skin_name from current position.
264        del new_path[new_path.index(layer_skin_name)]
265    # Add layer_skin_name just after 'custom' position
266    try: 
267        new_path.insert(new_path.index('custom')+1, layer_skin_name)
268    except ValueError:
269        new_path.append(layer_skin_name)
270    new_path = string.join(new_path, ', ')
271    # Add NEW Skin and set it as dafault
272    skinsTool.addSkinSelection(product_skin_name, new_path, make_default=1)
273    print >> out, "Added %%s skin, bassed on %%s and set as default." %% (product_skin_name, BASE_SKIN_NAME)
274
275def uninstallSkin(skinsTool, actual_skin_name, initial_skin):
276    # Get 'portal_skins' object and list available skin names
277    # And remove SKIN_NAME from available skins, if it present
278    skin_names = skinsTool.getSkinSelections()
279    if actual_skin_name in skin_names :
280        skinsTool.manage_skinLayers(chosen=(actual_skin_name,), del_skin=1, REQUEST=None)
281        skin_names.remove(actual_skin_name)
282    # Remove product skin directory from skins tool
283    # AND Remove skin-product layer from available skins
284    skin_layer = SKIN_NAME.lower()
285    if skin_layer in skinsTool.objectIds():
286        skinsTool.manage_delObjects(skin_layer)
287    for skin_name in skin_names:
288        path = skinsTool.getSkinPath(skin_name)
289        path = [i.strip() for i in  path.split(',')]
290        if skin_layer in path:
291            path.remove(skin_layer)
292            path = ','.join(path)
293            skinsTool.addSkinSelection(skin_name, path)
294    # If current default skin == actual_skin_name
295    # Set default skin in initial one (if initial skin still exist)
296    # or in 1st from available skin names list.
297    current_default_skin = skinsTool.getDefaultSkin()
298    if current_default_skin == actual_skin_name:
299        if initial_skin in skin_names :
300            skinsTool.manage_properties(default_skin=initial_skin, REQUEST=None)
301        elif len(skin_names)>0 :
302            skinsTool.manage_properties(default_skin=skin_names[0], REQUEST=None)
303
304def addProperty(p_sheet, p_id, p_value, p_type, out):
305    if p_sheet.hasProperty(p_id):
306        p_sheet._delProperty(p_id)
307    p_sheet._setProperty(p_id, p_value, p_type)
308    print >> out, "... added %%s PropertySheet to %%s." %% (p_id, p_sheet.getId())
309
310def getResourceProperties(obj, prop_list, dflt=''):
311    """ Return list of 2 items list-[property name, property value]."""
312    properties=[]
313    for prop in prop_list:
314        accessor = getattr(obj, 'get%%s' %% prop.capitalize(), None)
315        if accessor:
316            properties.append([prop, accessor() or dflt])
317    return properties
318
319def registerResource(pp_up, portal_res, resRegisterFunction, out \
320                    ,RESOURCE_SKIN_LIST, SKIN_RES_REGDATA, UP_PROPERTY, RES_REG_PROPS):
321    """ Register resources in portal's registry, remember existant settings."""
322    # Get original registered resources
323    portal_res_srings = []
324    for r in portal_res.getResources():
325        portal_res_srings.append(";".join(['%%s::%%s'%%(r[0],str(r[1])) \
326                                for r in getResourceProperties(r, RES_REG_PROPS)]))
327    addProperty(pp_up, UP_PROPERTY, portal_res_srings, 'lines', out)
328    # Tune Resource registry according to new skin needs
329    unexistent = [] # list of default resources,
330                    # which present in Skin-product, BUT absent in portal
331    portal_res_ids = portal_res.getResourceIds()
332    for res_dict in SKIN_RES_REGDATA:
333        if res_dict['id'] not in portal_res_ids:
334            # It's interesting - Resource Registry allow adding unexistent resource - use this
335            resRegisterFunction(**res_dict)
336            if res_dict['id'] not in RESOURCE_SKIN_LIST:
337                unexistent.append(res_dict['id'])
338        else:
339            pos = portal_res.getResourcePosition(res_dict['id'])
340            portal_res.unregisterResource(res_dict['id'])
341            resRegisterFunction(**res_dict)
342            portal_res.moveResource(res_dict['id'], pos)
343    if unexistent:
344        print >> out, "!!! - BAD: your Resource Regestry have'nt %%s resource(s), which may lead to some problems." %% unexistent
345
346def getVersion(res_list):
347    """Check version of skin product generator."""
348    return (res_list and not '::' in res_list[0] and '0.5') or '0.7'
349
350def uninstallResource(portal_res, original_res_list, RESOURCE_SKIN_LIST, resRegisterFunction):
351    # Prepare Resource Registry data for backup to original state
352    original_res_regestry = {}
353    genVersion = getVersion(original_res_list)
354    for rec in original_res_list:
355        resource = {}
356        if genVersion == '0.7':
357            [resource.update({prop.split('::')[0]:prop.split('::')[1]}) for prop in rec.split(";")]
358        elif genVersion == '0.5':
359            props = rec.split(";")
360            [resource.update({CSS_BASE_IDS_QPSD053[i]:props[i]}) for i in range(len(CSS_BASE_IDS_QPSD053))]
361        original_res_regestry[resource.pop('id')] = resource
362    # Work up actual Resource Registry
363    res_dict = portal_res.getResourcesDict()
364    for res_id in res_dict.keys():
365        # Remove from Resource Registry Skin product's resources
366        if res_id in RESOURCE_SKIN_LIST \
367           and res_id not in original_res_regestry.keys():
368            portal_res.unregisterResource(res_id)
369            continue
370        # Backup 'enabled' property Registry's resourses to it's original state
371        if original_res_regestry.has_key(res_id):
372            act_Enabled_state = res_dict[res_id].getEnabled()
373            orig_Enabled_state = original_res_regestry[res_id]['enabled']
374            if act_Enabled_state != orig_Enabled_state:
375                pos = portal_res.getResourcePosition(res_id)
376                resource = res_dict[res_id]
377                res = original_res_regestry[res_id]
378                portal_res.unregisterResource(res_id)
379                resRegisterFunction(res_id, **res)
380                portal_res.moveResource(res_id, pos)
381
382def customizeSlots(portal, pp_up, out):
383    # Get original Site's column lists
384    orig_left_slots = left_column = list(portal.left_slots)
385    orig_right_slots = right_column = list(portal.right_slots)
386    # Save original Site's LEFT and RIGHT slots
387    addProperty(pp_up, 'q_left_slots', orig_left_slots, 'lines', out)
388    addProperty(pp_up, 'q_right_slots', orig_right_slots, 'lines', out)
389    # blend-with-site - to portal's slots adding only new one from skin-porduct
390    # blend-with-skin - portal slots forming in the following manner:
391    #                   first adding skin-porduct's slots, than new one from portal
392    # replace - to portal's slots forming only from the skin-porduct's slot list
393    if SLOT_FORMING == "blend_with_skin":
394        left_column, right_column = formSlotsColumn(LEFT_SLOTS, RIGHT_SLOTS, 
395                                                    orig_left_slots, orig_right_slots, MAIN_COLUMN)
396    elif SLOT_FORMING == "blend_with_site":
397        left_column, right_column = formSlotsColumn(orig_left_slots, orig_right_slots,
398                                                    LEFT_SLOTS, RIGHT_SLOTS, MAIN_COLUMN )
399    elif SLOT_FORMING == "replace":
400        left_column, right_column = formSlotsColumn(LEFT_SLOTS, RIGHT_SLOTS, [], [], MAIN_COLUMN)
401    # REPLACE SITE's column slots
402    portal.left_slots = tuple(left_column)
403    portal.right_slots = tuple(right_column)
404    print >> out, "Complited portal slots customization ..."
405
406# main_column ("left" / "right" / "both") mean which of the MAIN column is favour
407def formSlotsColumn(main_left, main_right, slave_left=[], slave_right=[], main_column="both"):
408    result_left = main_left
409    result_right = main_right
410    if main_column == "left":
411    # 1) APPEND to MAIN_LEFT list *new for main_left column* slots from slave_left list
412    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
413    # 3) REMOVE slots from MAIN_RIGHT list, which are *doubled* in MAIN_LEFT
414        [result_left.append(slot) for slot in slave_left if slot not in result_left]
415        [result_right.append(slot) for slot in slave_right \
416                                   if slot not in result_right and slot not in result_left]
417        [result_right.remove(slot) for slot in result_left if slot in result_right]
418    elif main_column == "right":
419    # 1) APPEND to MAIN_LEFT list *new for main_right column* slots from slave_left list
420    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
421    # 3) REMOVE slots from MAIN_LEFT list, which are *doubled* in MAIN_RIGHT
422        [result_right.append(slot) for slot in slave_right if slot not in result_right]
423        [result_left.append(slot) for slot in slave_left \
424                                  if slot not in result_left and slot not in result_right]
425        [result_left.remove(slot) for slot in result_right if slot in result_left]
426    elif main_column == "both":
427    # 1) APPEND to MAIN_LEFT list *new for both main columns* slots from slave_left list
428    # 2) APPEND to MAIN_RIGHT list *new for both main columns* slots from slave_right
429        [result_left.append(slot) for slot in slave_left \
430                                  if slot not in result_left and slot not in result_right]
431        [result_right.append(slot) for slot in slave_right \
432                                   if slot not in result_right and slot not in result_left]
433    return [result_left, result_right]
434
435def getProperty(pp, ps, id, default=[]):
436    """ Get property from portal_properties/[property_sheet]"""
437    res = default
438    if ps in pp.objectIds() and pp[ps].hasProperty(id):
439        res = pp[ps].getProperty(id, default)
440    return res
441
442
443###################################
444## OLD INSTALL
445
446def prepareInstallation(portal, pp, out):
447    #uninstallOtherSkinProducts(portal)
448    if not ('uninstall_properties' in pp.objectIds()) :
449        pp.addPropertySheet(id='uninstall_properties', title= 'uninstall_properties')
450        print >> out, "Created 'portal_properties.uninstall_properties' PropertySheet (UP) for backup purpose"
451    return pp.uninstall_properties
452CHECKED_MESSAGE = "The base installation checkings completed."
453
454def uninstallOtherSkinProducts(portal):
455    qi=getToolByName(portal, 'portal_quickinstaller', None)
456    if not qi:
457        raise Exception("Can't work without QuickInstaller tool.")
458    # Get installed products
459    installed_products = [getattr(qi, p_dict['id']) \
460                          for p_dict in qi.listInstalledProducts()
461                          if p_dict['id'] != PRODUCT_NAME]
462    seek_str = "%%s generated product" %% GENERATOR_PRODUCT
463    installed_skin_products = []
464    # Looking for installed skin-products
465    for p in installed_products:
466        transcript = p.getTranscriptAsText()
467        if transcript.find(seek_str) >= 0 :
468            installed_skin_products.append(p.getId())
469    # Uninstall found skin-products
470    if installed_skin_products:
471        qi.uninstallProducts(products=installed_skin_products)
472
473###################################
474## Prepare UNINSTALL
475
476def prepareUninstallSkin(portal, pp_up, out): # ??
477    # Checking for presense SKIN_NAME in portal_skins directory view or among Skin Names
478    skinsTool = getToolByName(portal, 'portal_skins')
479    # Get unique product_skin_name and remember it in case of differ from SKIN_NAME.
480    default_skin = skinsTool.getDefaultSkin()
481    addProperty(pp_up, 'q_default_skin', default_skin, 'string', out)
Note: See TracBrowser for help on using the repository browser.