source: products/quintagroup.referencedatagridfield/branches/plone4/quintagroup/referencedatagridfield/_field.py @ 2347

Last change on this file since 2347 was 2347, checked in by mylan, 14 years ago

Remove records with links to unexistent objects on getting data from the field

  • Property svn:eol-style set to native
File size: 6.9 KB
RevLine 
[2259]1#from Products.Archetypes import atapi
[2263]2import re
[2260]3import logging
[2263]4import urlparse
5from urllib import quote
6from types import ListType, TupleType
7
[2260]8from AccessControl import ClassSecurityInfo
[2263]9
10from Products.CMFCore.utils import getToolByName
11from Products.validation import validation #validators import baseValidators
[2266]12from Products.Archetypes.Field import encode, ReferenceField
[2259]13from Products.Archetypes.Registry import registerField, registerWidget
14
[2308]15from archetypes.referencebrowserwidget.widget import ReferenceBrowserWidget
[2266]16
[2282]17from Products.DataGridField.Column import Column
[2259]18from Products.DataGridField.DataGridField import DataGridField
19from Products.DataGridField.DataGridWidget import DataGridWidget
20
[2287]21from quintagroup.referencedatagridfield.columns import BlockColumn
22from quintagroup.referencedatagridfield.columns import HiddenColumn
[2291]23from quintagroup.referencedatagridfield.columns import StyledColumn
[2263]24
[2260]25# Logger object
26#logger = logging.getLogger('ReferenceDataGridField')
27#logger.debug("ReferenceDataGrid loading")
28
[2266]29class ReferenceDataGridWidget(DataGridWidget, ReferenceBrowserWidget):
30    _properties = ReferenceBrowserWidget._properties.copy()
31    _properties.update(DataGridWidget._properties.copy())
[2260]32    _properties.update({
[2266]33        'macro': "referencedatagridwidget",
[2287]34        'helper_css': ('datagridwidget.css','referencedatagridwidget.css'),
[2312]35        'helper_js': ('referencebrowser.js', 'datagridwidget.js', 'referencedatagridwidget.js'),
[2274]36        'force_close_on_insert': True,
[2308]37        'popup_name': 'datagridref_popup',
[2282]38        'columns': {
[2300]39            'title': StyledColumn("Title", trigger_key="default_title",
[2291]40                                  blur_handler="triggerTitleClass",
41                                  focus_handler="triggerOnFocusStyles",
42                                  class_no=None,
43                                  class_changed="changed-title-field",
44                                  class_not_changed="not-changed-title-field"),
[2287]45            'link': BlockColumn("Link", column_on_class="hidden-field",
46                                columns=['link','uid'], read_only=True),
[2282]47            'uid': HiddenColumn("UID", visible=False)},
[2260]48        })
[2259]49
[2263]50isURL = validation.validatorFor('isURL')
51
[2266]52class ReferenceDataGridField(DataGridField, ReferenceField):
53    _properties = ReferenceField._properties.copy()
54    _properties.update(DataGridField._properties.copy())
[2259]55    _properties.update({
[2278]56        'columns': ('title', 'link', 'uid'),
[2259]57        'widget': ReferenceDataGridWidget,
[2274]58        'multiValued' : True,
[2259]59        })
60
[2263]61    security = ClassSecurityInfo()
62
63    security.declarePrivate('isRemoteURL')
64    def isRemoteURL(self, url):
[2264]65        return isURL(url) == 1 and True or False
[2263]66
67    security.declarePrivate('set')
68    def set(self, instance, value, **kwargs):
69        """
70        The passed in object should be a records object, or a sequence of dictionaries
[2278]71        About link data:
[2263]72          * interpretations:
[2278]73            * if data not starts with standard protocol names (http://, ftp://) than
74              *uid* field data will be used as reference
[2263]75          * record removed if:
76            * no data;
77            * data contains UID of not existent object
78        About title:
[2278]79          * if there is UID of existent object and record has same title to the original
80            object - title will not be saved.
[2263]81        """
82        catalog = getToolByName(instance, "uid_catalog")
83
84        if value is None:
85            value = ()
86
87        if not isinstance(value, (ListType, TupleType)):
88            value = value,
89
90        result = []
91        for row in value:
[2278]92            data = {"title":"", "link":"", "uid":""}
[2263]93
[2278]94            uid = str(row.get("uid", "")).strip()
95            link = str(row.get("link", "")).strip()
[2299]96            title = str(row.get('title', ""))
[2278]97
[2263]98            if not title == "":
99                data["title"] = title
100
[2278]101            if link == "":
[2263]102                continue
[2278]103            elif self.isRemoteURL(link):
104                data["link"] = urlparse.urlunparse(urlparse.urlparse(link))
[2263]105            else:
[2278]106                if uid == '':
107                    continue
108
109                brains = catalog(UID=uid)
[2263]110                if len(brains) == 0:
111                    continue
[2274]112                # Found objects with pointed UID
113                brain = brains[0]
[2278]114                data["uid"] = uid
115                # Fix title for uid
116                if data['title'] == getattr(brain, "Title", ""):
117                    data['title'] = ""
[2263]118            result.append(data)
119
120        DataGridField.set(self, instance, result, **kwargs)
[2278]121
122        uids = [r['uid'] for r in result if r['uid']!=""]
[2274]123        ReferenceField.set(self, instance, uids, **kwargs)
124       
[2263]125    security.declarePrivate('get')
126    def get(self, instance, **kwargs):
127        """ Return DataGridField value
128
129        Value is a list object of rows.
[2278]130        Row id dictionary object with standard 'link', 'uid' and 'title' keys
131        plus extra informal *url* and *url_title* keys
[2263]132        """
133        purl = getToolByName(instance, "portal_url")
[2278]134        # use portal_catalog to hide protected object for the logged in user.
[2275]135        catalog = getToolByName(instance, "portal_catalog")
[2263]136
137        result = []
[2275]138        uids = {}
[2263]139        rows = DataGridField.get(self, instance, **kwargs)
140        for row in rows:
[2343]141            uid = row.get("uid","")
142            link = row.get("link","")
143            title = row.get("title","")
[2276]144            result.append({
145                # DataGridField row data
[2343]146                "uid": uid, "link": link, "title": title,
[2276]147                # View data
[2343]148                "url": "", "default_title": None})
[2275]149            data = result[-1]
150            # Process remote URL and collect UIDs
[2343]151            if link:
152                data["url"] = quote(link, safe='?$#@/:=+;$,&%')
153                data["default_title"] = link
[2275]154                # if title not set for remote url - set it equals to url
[2281]155                if not data["title"]:
[2300]156                    data["title"] = data["default_title"]
[2263]157            else:
[2343]158                uids[uid] = data
[2275]159        # Process UIDs
160        if uids:
161            brains = catalog(UID=uids.keys())
162            for b in brains:
163                data = uids[b.UID]
[2278]164                data["url"] = b.getURL()
[2281]165                data["link"] = b.getPath()
[2300]166                data["default_title"] = self._brains_title_or_id(b, instance)
[2275]167                # If title not set - get it from the brain
[2281]168                if not data["title"]:
[2300]169                    data["title"] = data["default_title"]
[2347]170            # Remove records with links to unexistent objects
171            del_uids = set(uids.keys()) - set([b.UID for b in brains])
172            result = filter(lambda r: not r["uid"] in del_uids, result)
[2263]173
174        return result
175
[2274]176
[2259]177registerWidget(
178    ReferenceDataGridWidget,
179    title='DataGrid Reference',
180    used_for=('quintagroup.referencedatagridfield.ReferenceDataGridField',)
181    )
182
183registerField(
184    ReferenceDataGridField,
185    title="DataGrid Reference Field",
186    description=("Reference DataGrid field.")
187    )
Note: See TracBrowser for help on using the repository browser.