entities/adapters.py
changeset 5556 9ab2b4c74baf
child 5574 e082a57c2207
equal deleted inserted replaced
5555:a64f48dd5fe4 5556:9ab2b4c74baf
       
     1 # copyright 2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 """some basic entity adapter implementations, for interfaces used in the
       
    19 framework itself.
       
    20 """
       
    21 
       
    22 __docformat__ = "restructuredtext en"
       
    23 
       
    24 from cubicweb.view import EntityAdapter, implements_adapter_compat
       
    25 from cubicweb.selectors import implements, relation_possible
       
    26 from cubicweb.interfaces import IDownloadable
       
    27 
       
    28 
       
    29 class IEmailableAdapter(EntityAdapter):
       
    30     __regid__ = 'IEmailable'
       
    31     __select__ = relation_possible('primary_email') | relation_possible('use_email')
       
    32 
       
    33     def get_email(self):
       
    34         if getattr(self.entity, 'primary_email', None):
       
    35             return self.entity.primary_email[0].address
       
    36         if getattr(self.entity, 'use_email', None):
       
    37             return self.entity.use_email[0].address
       
    38         return None
       
    39 
       
    40     def allowed_massmail_keys(self):
       
    41         """returns a set of allowed email substitution keys
       
    42 
       
    43         The default is to return the entity's attribute list but you might
       
    44         override this method to allow extra keys.  For instance, a Person
       
    45         class might want to return a `companyname` key.
       
    46         """
       
    47         return set(rschema.type
       
    48                    for rschema, attrtype in self.entity.e_schema.attribute_definitions()
       
    49                    if attrtype.type not in ('Password', 'Bytes'))
       
    50 
       
    51     def as_email_context(self):
       
    52         """returns the dictionary as used by the sendmail controller to
       
    53         build email bodies.
       
    54 
       
    55         NOTE: the dictionary keys should match the list returned by the
       
    56         `allowed_massmail_keys` method.
       
    57         """
       
    58         return dict( (attr, getattr(self.entity, attr))
       
    59                      for attr in self.allowed_massmail_keys() )
       
    60 
       
    61 
       
    62 class INotifiableAdapter(EntityAdapter):
       
    63     __regid__ = 'INotifiable'
       
    64     __select__ = implements('Any')
       
    65 
       
    66     @implements_adapter_compat('INotifiableAdapter')
       
    67     def notification_references(self, view):
       
    68         """used to control References field of email send on notification
       
    69         for this entity. `view` is the notification view.
       
    70 
       
    71         Should return a list of eids which can be used to generate message
       
    72         identifiers of previously sent email(s)
       
    73         """
       
    74         itree = self.entity.cw_adapt_to('ITree')
       
    75         if itree is not None:
       
    76             return itree.path()[:-1]
       
    77         return ()
       
    78 
       
    79 
       
    80 class IFTIndexableAdapter(EntityAdapter):
       
    81     __regid__ = 'IFTIndexable'
       
    82     __select__ = implements('Any')
       
    83 
       
    84     def fti_containers(self, _done=None):
       
    85         if _done is None:
       
    86             _done = set()
       
    87         entity = self.entity
       
    88         _done.add(entity.eid)
       
    89         containers = tuple(entity.e_schema.fulltext_containers())
       
    90         if containers:
       
    91             for rschema, target in containers:
       
    92                 if target == 'object':
       
    93                     targets = getattr(entity, rschema.type)
       
    94                 else:
       
    95                     targets = getattr(entity, 'reverse_%s' % rschema)
       
    96                 for entity in targets:
       
    97                     if entity.eid in _done:
       
    98                         continue
       
    99                     for container in entity.cw_adapt_to('IFTIndexable').fti_containers(_done):
       
   100                         yield container
       
   101                         yielded = True
       
   102         else:
       
   103             yield entity
       
   104 
       
   105     def get_words(self):
       
   106         """used by the full text indexer to get words to index
       
   107 
       
   108         this method should only be used on the repository side since it depends
       
   109         on the logilab.database package
       
   110 
       
   111         :rtype: list
       
   112         :return: the list of indexable word of this entity
       
   113         """
       
   114         from logilab.database.fti import tokenize
       
   115         # take care to cases where we're modyfying the schema
       
   116         entity = self.entity
       
   117         pending = self._cw.transaction_data.setdefault('pendingrdefs', set())
       
   118         words = []
       
   119         for rschema in entity.e_schema.indexable_attributes():
       
   120             if (entity.e_schema, rschema) in pending:
       
   121                 continue
       
   122             try:
       
   123                 value = entity.printable_value(rschema, format='text/plain')
       
   124             except TransformError:
       
   125                 continue
       
   126             except:
       
   127                 self.exception("can't add value of %s to text index for entity %s",
       
   128                                rschema, entity.eid)
       
   129                 continue
       
   130             if value:
       
   131                 words += tokenize(value)
       
   132         for rschema, role in entity.e_schema.fulltext_relations():
       
   133             if role == 'subject':
       
   134                 for entity in getattr(entity, rschema.type):
       
   135                     words += entity.cw_adapt_to('IFTIndexable').get_words()
       
   136             else: # if role == 'object':
       
   137                 for entity in getattr(entity, 'reverse_%s' % rschema.type):
       
   138                     words += entity.cw_adapt_to('IFTIndexable').get_words()
       
   139         return words
       
   140 
       
   141 
       
   142 class IDownloadableAdapter(EntityAdapter):
       
   143     """interface for downloadable entities"""
       
   144     __regid__ = 'IDownloadable'
       
   145     __select__ = implements(IDownloadable) # XXX for bw compat, else should be abstract
       
   146 
       
   147     @implements_adapter_compat('IDownloadable')
       
   148     def download_url(self): # XXX not really part of this interface
       
   149         """return an url to download entity's content"""
       
   150         raise NotImplementedError
       
   151     @implements_adapter_compat('IDownloadable')
       
   152     def download_content_type(self):
       
   153         """return MIME type of the downloadable content"""
       
   154         raise NotImplementedError
       
   155     @implements_adapter_compat('IDownloadable')
       
   156     def download_encoding(self):
       
   157         """return encoding of the downloadable content"""
       
   158         raise NotImplementedError
       
   159     @implements_adapter_compat('IDownloadable')
       
   160     def download_file_name(self):
       
   161         """return file name of the downloadable content"""
       
   162         raise NotImplementedError
       
   163     @implements_adapter_compat('IDownloadable')
       
   164     def download_data(self):
       
   165         """return actual data of the downloadable content"""
       
   166         raise NotImplementedError