Back to index

plone3  3.1.7
DateCriteria.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights Reserved.
00004 #
00005 # This software is subject to the provisions of the Zope Public License,
00006 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
00007 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00008 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00009 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00010 # FOR A PARTICULAR PURPOSE.
00011 #
00012 ##############################################################################
00013 """ Various date criteria
00014 
00015 $Id: DateCriteria.py 77186 2007-06-28 19:06:19Z yuppie $
00016 """
00017 
00018 from AccessControl import ClassSecurityInfo
00019 from DateTime.DateTime import DateTime
00020 from Globals import InitializeClass
00021 from zope.interface import implements
00022 
00023 from AbstractCriterion import AbstractCriterion
00024 from interfaces import Criterion as z2ICriterion
00025 from interfaces import ICriterion
00026 from permissions import ChangeTopics
00027 from permissions import View
00028 from Topic import Topic
00029 
00030 _as_of = DateTime  # Allow for controlled value when testing
00031 
00032 class FriendlyDateCriterion( AbstractCriterion ):
00033 
00034     """
00035         Put a friendly interface on date range searches, like
00036         'where effective date is less than 5 days old'.
00037     """
00038 
00039     implements(ICriterion)
00040     __implements__ = z2ICriterion
00041 
00042     meta_type = 'Friendly Date Criterion'
00043 
00044     security = ClassSecurityInfo()
00045 
00046     _editableAttributes = ( 'value', 'operation', 'daterange' )
00047 
00048     _defaultDateOptions = ( (     0, 'Now'      )
00049                           , (     1, '1 Day'    )
00050                           , (     2, '2 Days'   )
00051                           , (     5, '5 Days'   )
00052                           , (     7, '1 Week'   )
00053                           , (    14, '2 Weeks'  )
00054                           , (    31, '1 Month'  )
00055                           , (  31*3, '3 Months' )
00056                           , (  31*6, '6 Months' )
00057                           , (   365, '1 Year'   )
00058                           , ( 365*2, '2 years'  )
00059                           )
00060 
00061     def __init__( self, id, field ):
00062 
00063         self.id = id
00064         self.field = field
00065         self.value = None
00066         self.operation = 'min'
00067         self.daterange = 'old'
00068 
00069     security.declarePublic( 'defaultDateOptions' )
00070     def defaultDateOptions( self ):
00071         """
00072             Return a list of default values and labels for date options.
00073         """
00074         return self._defaultDateOptions
00075 
00076     security.declareProtected( ChangeTopics, 'getEditForm' )
00077     def getEditForm( self ):
00078         """
00079             Return the name of the skin method used by Topic to edit
00080             criteria of this type.
00081         """
00082         return 'friendlydatec_editform'
00083 
00084     security.declareProtected( ChangeTopics, 'edit' )
00085     def edit( self
00086             , value=None
00087             , operation='min'
00088             , daterange='old'
00089             ):
00090         """
00091             Update the values to match against.
00092         """
00093         if value in ( None, '' ):
00094             self.value = None
00095         else:
00096             try:
00097                 self.value = int( value )
00098             except:
00099                 raise ValueError, 'Supplied value should be an int'
00100 
00101         if operation in ( 'min', 'max', 'within_day' ):
00102             self.operation = operation
00103         else:
00104             raise ValueError, 'Operation type not in set {min,max,within_day}'
00105 
00106         if daterange in ( 'old', 'ahead' ):
00107             self.daterange = daterange
00108         else:
00109             raise ValueError, 'Date range not in set {old,ahead}'
00110 
00111     security.declareProtected(View, 'getCriteriaItems')
00112     def getCriteriaItems( self ):
00113         """
00114             Return a sequence of items to be used to build the catalog query.
00115         """
00116         if self.value is not None:
00117             field = self.Field()
00118             value = self.value
00119             operation = self.operation
00120 
00121             # Negate the value for 'old' days
00122             if self.daterange == 'old' and value != 0:
00123                 value = -value
00124 
00125                 # Also reverse the operator to match what a user would expect.
00126                 # Queries such as "More than 2 days ago" should match dates
00127                 # *earlier* than "today minus 2", and "Less than 2 days ago"
00128                 # would be expected to return dates *later* then "today minus
00129                 # two".
00130                 if operation == 'max':
00131                     operation = 'min'
00132                 elif operation == 'min':
00133                     operation = 'max'
00134 
00135             now = _as_of()
00136             date = now + value
00137 
00138             if operation == 'within_day':
00139                 # When items within a day are requested, the range is between
00140                 # the earliest and latest time of that particular day
00141                 range = ( date.earliestTime(), date.latestTime() )
00142                 return ( ( field, {'query': range, 'range': 'min:max'} ), )
00143 
00144             elif operation == 'min':
00145                 if value != 0:
00146                     if self.daterange == 'old':
00147                         date_range = (date, now)
00148                         return ( ( field, { 'query': date_range
00149                                           , 'range': 'min:max'
00150                                           } ), )
00151                     else:
00152                         return ( ( field, { 'query': date.earliestTime()
00153                                           , 'range': operation
00154                                           } ), )
00155                 else:
00156                     # Value 0 means "Now", so get everything from now on
00157                     return ( ( field, {'query': date,'range': operation } ), )
00158 
00159             elif operation == 'max':
00160                 if value != 0:
00161                     if self.daterange == 'old':
00162                         return ((field, {'query': date, 'range': operation}),)
00163                     else:
00164                         date_range = (now, date.latestTime())
00165                         return ( ( field, { 'query': date_range
00166                                           , 'range': 'min:max'
00167                                           } ), )
00168                 else:
00169                     # Value is 0, meaning "Now", get everything before "Now"
00170                     return ( ( field, {'query': date, 'range': operation} ), )
00171         else:
00172             return ()
00173 
00174 InitializeClass(FriendlyDateCriterion)
00175 
00176 
00177 # Register as a criteria type with the Topic class
00178 Topic._criteriaTypes.append( FriendlyDateCriterion )