class ShopModule_ProductImagesSlider(ShopModule):

    class_id = 'shop_module_product_images_slider'
    class_title = MSG(u'Product images slider')
    class_views = ['edit']
    class_description = MSG(u'Product images slider')

    item_schema = {'big_img_width': Integer(default=500),
                   'big_img_height': Integer(default=600),
                   'thumb_img_width': Integer(default=90),
                   'thumb_img_height': Integer(default=90),
                   'show_cover': Boolean,
                   'show_loupe': Boolean,
                   'change_img_on_hover': Boolean,
                   'activate_lightbox': Boolean}

    item_widgets = [
      TextWidget('big_img_width', title=MSG(u'Width of big image')),
      TextWidget('big_img_height', title=MSG(u'Height of big image')),
      TextWidget('thumb_img_width', title=MSG(u'Width of thumb image')),
      TextWidget('thumb_img_height', title=MSG(u'Height of thumb image')),
      BooleanRadio('show_cover', title=MSG(u'Show cover ?')),
      BooleanRadio('show_loupe', title=MSG(u'Show loupe ?')),
      BooleanRadio('change_img_on_hover', title=MSG(u'Change img on hover ?')),
      BooleanRadio('activate_lightbox', title=MSG(u'Activate lightbox ?')),
      ]


    def render(self, resource, context):
        return ShopModule_ProductImagesSlider_View().GET(self, context)
Example #2
0
class ServerConfig(ConfigFile):

    schema = {
        'modules': Tokens,
        'listen-address': String(default=''),
        'listen-port': Integer(default=None),
        # Mailing
        'smtp-host': String(default=''),
        'smtp-from': String(default=''),
        'smtp-login': String(default=''),
        'smtp-password': String(default=''),
        # Logging
        'log-level': String(default='warning'),
        'log-email': Email(default=''),
        # Time events
        'cron-interval': Integer(default=0),
        # Security
        'session-timeout': ExpireValue(default=timedelta(0)),
        # Tuning
        'database-size': String(default='19500:20500'),
        'database-readonly': Boolean(default=False),
        'index-text': Boolean(default=True),
        'max-width': Integer(default=None),
        'max-height': Integer(default=None),
    }
Example #3
0
 def get_query_schema(self):
     # Define a huge batch limit, and the image size parameter
     schema = super(Folder_PreviewContent, self).get_query_schema()
     return merge_dicts(schema,
                        batch_size=Integer(default=0),
                        size=Integer(default=128),
                        width=String,
                        height=String)
Example #4
0
class Product_View(STLForm):

    access = 'is_allowed_to_view'
    title = MSG(u'View')

    scripts = ['/ui/shop/js/declinations.js']

    def get_template(self, resource, context):
        product_model = resource.get_product_model()
        if product_model is not None:
            return get_skin_template(context,
                        '/product/product_view_%s.xml' % product_model.name,
                        '/product/product_view.xml')
        return get_skin_template(context, '/product/product_view.xml')


    def get_schema(self, resource, context):
        return merge_dicts(STLForm.get_schema(self, resource, context),
                           resource.get_purchase_options_schema())


    def get_namespace(self, resource, context):
        context.scripts.append('/ui/shop/js/declinations.js')
        declinations = list(resource.search_resources(cls=Declination))
        javascript_products = resource.get_javascript_namespace(declinations)
        purchase_options = resource.get_purchase_options_namespace(declinations)
        return merge_dicts(resource.get_namespace(context),
                           javascript_products=javascript_products,
                           purchase_options=purchase_options)


    action_add_to_cart_schema = {'quantity': Integer(default=1)}
    def action_add_to_cart(self, resource, context, form):
        """ Add to cart """
        cart = ProductCart(context)
        # Check if we can add to cart
        if not resource.is_buyable(context):
            msg = MSG(u"This product isn't buyable")
            return context.come_back(msg)
        # Get purchase options
        declination = None
        kw = {}
        for key in resource.get_purchase_options_schema():
            if form[key] is not None:
                kw[key] = form[key]
        if kw:
            declination = resource.get_declination(kw)
            if declination is None:
                context.message = ERROR(u'Declination not exist')
                return
        # Check if product is in stock
        cart_quantity = cart.get_product_quantity_in_cart(resource.name)
        total_quantity =  cart_quantity + form['quantity']
        if not resource.is_in_stock_or_ignore_stock(total_quantity, declination):
            msg = u"Quantity in stock insufficient."
            return context.come_back(MSG(msg))
        # Add to cart
        cart.add_product(resource, form['quantity'], declination)
        # Information message
        context.message = INFO(u'Product added to cart !')
Example #5
0
class Payments_EditablePayment(object):

    action_edit_payment_schema = {
        'payment_way': String,  # XXX PaymentWaysEnumerate(mandatory=True),
        'id_payment': Integer(mandatory=True)
    }

    def action_edit_payment(self, resource, context, form):
        shop = get_shop(resource)
        # We get shipping way
        payment_way = shop.get_resource('payments/%s/' % form['payment_way'])
        # We get order_edit_view
        view = payment_way.order_edit_view
        # We get schema
        schema = view.schema
        # We get form
        try:
            form = process_form(context.get_form_value, schema)
        except FormError, error:
            context.form_error = error
            return self.on_form_error(resource, context)
        # Instanciate view
        payment_table = payment_way.get_resource('payments').handler
        record = payment_table.get_record(form['id_payment'])
        view = view(payment_way=payment_way,
                    payment_table=payment_table,
                    record=record,
                    id_payment=form['id_payment'])
        # Do actions
        return view.action_edit_payment(resource, context, form)
Example #6
0
class Document(CatalogAware):

    fields = {
        'name': String(is_key_field=True, is_stored=True, is_indexed=True),
        'title': Unicode(is_stored=True, is_indexed=True),
        'data': Unicode(is_indexed=True),
        'size': Integer(is_indexed=True),
        'about_wolf': Boolean(is_indexed=True),
        'is_long': Boolean(is_indexed=False, is_stored=True)
    }

    def __init__(self, abspath):
        self.abspath = abspath

    def get_catalog_values(self):
        data = lfs.open(self.abspath).read()

        return {
            'name': basename(self.abspath),
            'title': data.splitlines()[0],
            'data': data,
            'size': len(data),
            'about_wolf': re.search('wolf', data, re.I) is not None,
            'is_long': len(data) > 1024,
        }
Example #7
0
class ShippingPricesTable(BaseTable):

    record_properties = {
      'zone': CountriesZonesEnumerate(mandatory=True, is_indexed=True),
      'max-weight': Decimal(is_indexed=True),
      'max-quantity': Integer(is_indexed=True),
      'price': Decimal(mandatory=True)}
Example #8
0
class CheckPaymentBaseTable(PaymentWayBaseTable):

    record_properties = merge_dicts(
        PaymentWayBaseTable.record_properties,
        check_number=Integer(title=MSG(u'Check number')),
        bank=Unicode(title=MSG(u'Bank')),
        account_holder=Unicode(title=MSG(u'Account holder')),
        advance_state=CheckStates(title=MSG(u'Advance State')))
Example #9
0
 def decode(cls, data):
     data = data.strip()
     if not data:
         # Turn it into default value at the time of writing
         return None
     try:
         value = Integer.decode(data)
     except ValueError:
         value = data
     return value
Example #10
0
 def get_metadata_schema(cls):
     return merge_dicts(Folder.get_metadata_schema(),
                        WorkflowAware.get_metadata_schema(),
                        ctime=DateTime,
                        note=Integer(default=0),
                        remote_ip=String,
                        author=String,
                        advantages=Unicode,
                        disadvantages=Unicode,
                        images=String,
                        recommended=RecommandationEnumerate)
Example #11
0
def get_int_value(value, default=0):
    """
    Return the interger representation of value is his decoding succeed
    otherwise the default value
    """
    if not value:
        return default
    try:
        return Integer.decode(value)
    except ValueError:
        return default
Example #12
0
def get_int_value(value, default=0):
    """
    Return the interger representation of value is his decoding succeed
    otherwise the default value
    """
    if not value:
        return default
    try:
        return Integer.decode(value)
    except ValueError:
        return default
Example #13
0
    def GET(self, resource, context):
        default_icon = context.get_template(self.default_icon)
        if PILImage is None:
            # Full size but better than nothing
            data = default_icon.to_str()
            format = 'png'
        else:
            # Default icon for empty or inaccessible folders
            width = context.get_form_value('width', type=Integer(), default=48)
            height = context.get_form_value('height',
                                            type=Integer(),
                                            default=48)
            data, format = default_icon.get_thumbnail(width, height)

        # XXX Don't cache nothing here
        # The image thumbnail was cached in the image handler
        # The folder thumbnail was cached in the folder handler
        # Accessible images depend on too many parameters

        context.content_type = 'image/%s' % format
        return data
Example #14
0
 def reset(self):
     self.properties = None
     self.records = []
     self.added_properties = []
     self.added_records = []
     self.removed_records = []
     # The catalog (for index and search)
     fields = merge_dicts(self.record_properties,
                          __id__=Integer(is_key_field=True,
                                         is_stored=True,
                                         is_indexed=True))
     self.catalog = make_catalog(None, fields)
Example #15
0
class Document_2(CatalogAware):

    fields = {
        'id': Integer(is_key_field=True, is_stored=True, is_indexed=True),
        'data': Unicode(is_stored=True, is_indexed=True)
    }

    def __init__(self, id, data):
        self.id = id
        self.data = data

    def get_catalog_values(self):
        return {'id': self.id, 'data': self.data}
class SideBarProductCrossSellingBox(Box):

    class_id = 'sidebar-product-cross-selling-box'
    class_version = '20090122'
    class_title = MSG(u'Vertical item cross selling (product)')
    class_description = MSG(u"""Show on sidebar the
                                cross selling configure in product""")

    view = SideBarCrossSellingBox_View()

    # XXX Need ?
    edit_schema = {
        'thumb_width': Integer(mandatory=True),
        'thumb_height': Integer(mandatory=True)
    }

    edit_widgets = [
        TextWidget('thumb_width', size=3,
                   title=MSG(u'Largeur des miniatures')),
        TextWidget('thumb_height',
                   size=3,
                   title=MSG(u'Hauteur des miniatures'))
    ]
Example #17
0
class DBResource_GetImage(DBResource_GetFile):

    query_schema = {
        'name': String(),
        'width': Integer(),
        'height': Integer(),
        'language': String(),
        'fit': Boolean(default=False),
        'lossy': Boolean(default=False)
    }

    def GET(self, resource, context):
        field_name = self.get_field_name(context)
        language = context.query['language']
        handler = self.get_handler(resource, field_name, language)

        image_width, image_height = handler.get_size()
        fit = context.query['fit']
        lossy = context.query['lossy']
        width = context.query['width'] or image_width
        height = context.query['height'] or image_height

        format = 'jpeg'
        if lossy is False:
            format = handler.get_mimetype().split('/')[1]
        data, format = handler.get_thumbnail(width, height, format, fit)
        if data is None:
            default = context.get_template('/ui/ikaaro/icons/48x48/image.png')
            data = default.to_str()
            format = 'png'

        # Headers
        context.set_content_type('image/%s' % format)

        # Ok
        return data
Example #18
0
class Document(Resource):

    fields = {
        'abspath': String(indexed=True, stored=True),
        'name': String(indexed=True),
        'lang': String(indexed=True, stored=True),
        'title': Unicode(stored=True, indexed=True),
        'data': Unicode(indexed=True),
        'about_wolf': Boolean(indexed=True),
        'is_long': Boolean(indexed=False, stored=True),
        'count': Integer(stored=True, multiple=True),
    }

    def __init__(self, abspath):
        self.abspath = abspath

    def get_catalog_values(self):
        # Filename
        filename = basename(self.abspath)
        name, ext, lang = FileName.decode(filename)
        # Content
        with open(self.abspath) as f:
            data = f.read()
            data = unicode(data, 'utf-8')
        title = data.splitlines()[0]
        wolf = re.search('wolf', data, re.I) is not None
        count = [
            len(data.splitlines()),  # lines
            len(data.split()),  # words
            len(data)
        ]  # chars
        # Multilingual
        if lang:
            data = {lang: data}
            title = {lang: title}

        # Ok
        return {
            'abspath': filename,  # oid
            'name': name,
            'lang': lang,
            'title': title,
            'data': data,
            'count': count,
            'about_wolf': wolf,
            'is_long': count[2] > 1024
        }
Example #19
0
 def reset(self):
     self.lines = []
     self.n_lines = 0
     # Initialize the catalog if needed (Index&Search)
     # (we look if we have at least one indexed field in schema/columns)
     self.catalog = None
     schema = self.schema
     if schema is not None:
         for name in self.columns:
             field_cls = schema[name]
             if getattr(field_cls, 'is_indexed', False):
                 fields = merge_dicts(schema,
                                      __number__=Integer(is_key_field=True,
                                                         is_stored=True,
                                                         is_indexed=True))
                 self.catalog = make_catalog(None, fields)
                 break
Example #20
0
 def get_metadata_schema(cls):
     schema = ShopFolder.get_metadata_schema()
     schema['shop_uri'] = String
     schema['shop_backoffice_uri'] = String
     schema['order_notification_mails'] = Email(multiple=True)
     schema['shop_default_zone'] = CountriesZonesEnumerate(default=0)
     schema['shop_sort_by'] = SortBy_Enumerate
     schema['shop_sort_reverse'] = Boolean
     schema['categories_batch_size'] = Integer(default=20)
     schema['devise'] = Devises(default='978')
     schema['bill_logo'] = ImagePathDataType
     schema['pdf_signature'] = Unicode
     schema['barcode_format'] = BarcodesFormat
     schema['show_sub_categories'] = Boolean
     schema['hide_not_buyable_products'] = Boolean
     schema['product_cover_is_mandatory'] = Boolean
     schema['log_authentification'] = Boolean
     schema['registration_need_email_validation'] = Boolean
     return schema
Example #21
0
class DBResource_Links(Folder_BrowseContent):
    """Links are the list of resources used by this resource."""

    access = 'is_allowed_to_view'
    title = MSG(u"Links")
    icon = 'rename.png'

    query_schema = merge_dicts(Folder_BrowseContent.query_schema,
                               batch_size=Integer(default=0))

    search_schema = {}
    search_widgets = []

    table_actions = []

    def get_table_columns(self, resource, context):
        proxy = super(DBResource_Links, self)
        cols = proxy.get_table_columns(resource, context)
        return [x for x in cols if x[0] != 'checkbox']

    def get_items(self, resource, context):
        links = resource.get_links()
        query = OrQuery(*[PhraseQuery('abspath', link) for link in links])
        return context.database.search(query)
Example #22
0
# Import from shop
from enumerate import DeclinationImpact
from dynamic_folder import DynamicFolder
from widgets import DeclinationPricesWidget
from shop.enumerate_table import EnumerateTable_to_Enumerate
from shop.utils import get_shop


declination_schema = {#General informations
                      'reference': String,
                      'title': Unicode,
                      # Default declination ?
                      'is_default': Boolean,
                      # Stock
                      'stock-quantity': Integer(default=0),
                      # Weight
                      'impact-on-weight': DeclinationImpact,
                      'weight-impact-value': Decimal(default=decimal(0)),
                      # Price
                      'impact_on_price': Decimal(default=decimal(0)),
                      'pro-impact_on_price': Decimal(default=decimal(0)),
                      # Associated images
                      #'associated-image': ImagesEnumerate
                      # XXX Old to delete
                      'pro-price-impact-value': Decimal(default=decimal(0)),
                      'impact-on-price': DeclinationImpact,
                      'price-impact-value': Decimal(default=decimal(0)),
                      }

declination_widgets = [
Example #23
0
    def render_for_user(self, resource, context):
        # Get review that belong to user
        query = [
            PhraseQuery('shop_module_review_author', resource.name),
            PhraseQuery('workflow_state', 'public'),
            PhraseQuery('format', 'shop_module_a_review')
        ]
        search = context.root.search(AndQuery(*query))
        brains = list(search.get_documents(sort_by='mtime', reverse=True))
        nb_reviews = len(brains)
        # Get viewboxes
        viewboxes = []
        for brain in brains[:5]:
            review = context.root.get_resource(brain.abspath)
            viewbox = Review_Viewbox().GET(review, context)
            viewboxes.append(viewbox)
        # Return namespace
        return {'nb_reviews': nb_reviews, 'viewboxes': viewboxes}

    def get_document_types(self):
        return []


register_resource_class(ShopModule_Review)
register_resource_class(ShopModule_AReview)
register_field('shop_module_review_author', String(is_indexed=True))
register_field('shop_module_review_note',
               Integer(is_indexed=True, is_stored=True))
register_field('shop_module_review_description', Unicode(is_stored=True))
Example #24
0
class icalendarTable(BaseCalendar, Table):
    """An icalendarTable is a handler for calendar data, generally used as an
    ical file but here as a table object.
    """

    record_class = Record

    record_properties = merge_dicts(record_properties,
                                    type=String(is_indexed=True),
                                    inner=Integer(multiple=True))

    #########################################################################
    # API
    #########################################################################
    def load_state_from_ical_file(self, file):
        """Load state from the given ical file.
        """
        self.reset()
        self.set_changed()

        components = {}

        # Read the data
        data = file.read()

        # Parse
        lines = []
        for name, value, parameters in parse_table(data):
            # Timestamp (ts), Schema, or Something else
            datatype = self.get_record_datatype(name)
            value = datatype.decode(value)
            property = Property(value, **parameters)
            # Append
            lines.append((name, property))

        # Read first line
        first = lines[0]
        if (first[0] != 'BEGIN' or first[1].value != 'VCALENDAR'
                or len(first[1].parameters) != 0):
            raise ValueError, 'icalendar must begin with BEGIN:VCALENDAR'

        lines = lines[1:]

        ###################################################################
        # Skip properties
        # TODO Currently tables are not able to handler global properties,
        # we must implement this feature to be able to load from ical files.
        n_line = 0
        for name, value in lines:
            if name == 'BEGIN':
                break
            elif name == 'END':
                break
            n_line += 1

        lines = lines[n_line:]

        ###################################################################
        # Read components
        c_type = None
        c_inner_type = None
        uid = None
        records = self.records
        record_properties = self.record_properties
        id = 0
        uids = {}

        for prop_name, prop_value in lines[:-1]:
            if prop_name in ('PRODID', 'VERSION'):
                raise ValueError, 'PRODID and VERSION must appear before '\
                                  'any component'
            if prop_name == 'BEGIN':
                if c_type is None:
                    c_type = prop_value.value
                    c_properties = {}
                    c_inner_components = []
                else:
                    # Inner component like DAYLIGHT or STANDARD
                    c_inner_type = prop_value.value
                    c_inner_properties = {}
                continue

            if prop_name == 'END':
                value = prop_value.value
                if value == c_type:
                    if uid is None:
                        raise ValueError, 'UID is not present'

                    record = self.get_record(id) or Record(
                        id, record_properties)
                    c_properties['type'] = Property(c_type)
                    c_properties['UID'] = Property(uid)
                    sequence = c_properties.get('SEQUENCE', None)
                    c_properties['SEQUENCE'] = sequence or Property(0)
                    c_properties['ts'] = Property(datetime.now())
                    # Add ids of inner components
                    if c_inner_components:
                        c_inner_components = [
                            Property(x) for x in c_inner_components
                        ]
                        c_properties['inner'] = c_inner_components
                    record.append(c_properties)
                    if uid in uids:
                        n = uids[uid] + 1
                        uids[uid] = n
                    else:
                        n = 0
                        uids[uid] = 0
                    self.added_records.append((id, n))
                    records.append(record)

                    # Next
                    c_type = None
                    uid = None
                    if n == 0:
                        id = id + 1

                # Inner component
                elif value == c_inner_type:
                    record = self.get_record(id) or Record(
                        id, record_properties)
                    c_inner_properties['type'] = Property(c_inner_type)
                    sequence = c_inner_properties.get('SEQUENCE', None)
                    c_inner_properties['SEQUENCE'] = sequence or Property(0)
                    c_inner_properties['ts'] = Property(datetime.now())
                    record.append(c_inner_properties)
                    c_inner_components.append(id)
                    self.added_records.append((id, 0))
                    records.append(record)
                    # Next
                    c_inner_type = None
                    id = id + 1
                else:
                    raise ValueError, 'Component %s found, %s expected' \
                                      % (value, c_inner_type)
            else:
                datatype = self.get_record_datatype(prop_name)
                if c_inner_type is None:
                    if prop_name in ('UID', 'TZID'):
                        uid = prop_value.value
                    else:
                        if getattr(datatype, 'multiple', False) is True:
                            value = c_properties.setdefault(prop_name, [])
                            value.append(prop_value)
                        else:
                            # Check the property has not yet being found
                            if prop_name in c_properties:
                                raise ValueError, \
                                    "property '%s' can occur only once" % name
                            # Set the property
                            c_properties[prop_name] = prop_value
                else:
                    # Inner component properties
                    if getattr(datatype, 'multiple', False) is True:
                        value = c_inner_properties.setdefault(prop_name, [])
                        value.append(prop_value)
                    else:
                        # Check the property has not yet being found
                        if prop_name in c_inner_properties:
                            msg = ('the property %s can be assigned only one'
                                   ' value' % prop_name)
                            raise ValueError, msg
                        # Set the property
                        c_inner_properties[prop_name] = prop_value

        # Index the records
        for record in records:
            if record is not None:
                self.catalog.index_document(record)

    def to_ical(self):
        """Serialize as an ical file, generally named .ics
        """
        lines = []

        line = 'BEGIN:VCALENDAR\n'
        lines.append(Unicode.encode(line))

        # Calendar properties
        properties = (('VERSION', u'2.0'),
                      ('PRODID',
                       u'-//itaapy.com/NONSGML ikaaro icalendar V1.0//EN'))
        for name, value in properties:
            value = Property(value)
            line = self.encode_property(name, value)
            lines.append(line[0])

        # Calendar components
        for record in self.records:
            if record is not None:
                seq = 0
                c_type = record.type
                # Ignore some components (like DAYLIGHT, STANDARD, ...)
                # keeping only VEVENT, VTIMEZONE, V.., and x-name ones
                if not c_type.startswith('V') and not c_type.startswith('X'):
                    continue
                for version in record:
                    line = 'BEGIN:%s\n' % c_type
                    lines.append(Unicode.encode(line))
                    line = ''
                    # Properties
                    names = version.keys()
                    names.sort()
                    for name in names:
                        if name in ('id', 'ts', 'type'):
                            continue
                        elif name == 'DTSTAMP':
                            value = version['ts']
                        else:
                            value = version[name]
                        if name == 'SEQUENCE':
                            value.value += seq
                        # Insert inner components
                        elif name == 'inner':
                            line = self.encode_inner_components(name, value)
                        else:
                            name = name.upper()
                            line = self.encode_property(name, value)
                        lines.extend(line)
                    line = 'END:%s\n' % c_type
                    lines.append(Unicode.encode(line))
                    seq += 1

        line = 'END:VCALENDAR\n'
        lines.append(Unicode.encode(line))

        return ''.join(lines)

    def add_record(self, kw):
        if 'UID' not in kw:
            type = kw.get('type', 'UNKNOWN')
            kw['UID'] = self.generate_uid(type)

        id = len(self.records)
        record = Record(id, self.record_properties)
        version = self.properties_to_dict(kw)
        version['ts'] = Property(datetime.now())
        record.append(version)
        # Change
        self.set_changed()
        self.added_records.append((id, 0))
        self.records.append(record)
        self.catalog.index_document(record)
        # Back
        return record

    def get_component_by_uid(self, uid):
        """Return components with the given uid, None if it doesn't appear.
        """
        return self.search(UID=uid)

    # Deprecated
    def get_components(self, type=None):
        """Return a dict {component_type: Record[], ...}
        or
        Return Record[] of given type.
        """
        if type is None:
            return self.records

        return self.search(type=type)

    # Get some events corresponding to arguments
    def search_events(self, subset=None, **kw):
        """Return a list of Record objects of type 'VEVENT' corresponding to
        the given filters.

        It should be used like this, for example:

            events = cal.search_events(
                STATUS='TENTATIVE',
                PRIORITY=1,
                ATTENDEE=['mailto:[email protected]',
                          'mailto:[email protected]'])

        ** With a list of values, events match if at least one value matches

        It searches into all components or in the provided subset list of
        components.
        """
        res_events = []

        # Get the list of differents property names used to filter
        filters = kw.keys()

        # For each event
        events = subset or self.search(type='VEVENT')
        for event in events:
            if event in res_events:
                continue
            version = self.get_record(id=event.id)[-1]

            # For each filter
            for filter in filters:
                # If filter not in component, go to next one
                if filter not in version:
                    break
                # Test filter
                expected = kw.get(filter)
                value = version[filter]
                datatype = self.get_record_datatype(filter)

                if getattr(datatype, 'multiple', False) is True:
                    value = [
                        isinstance(x, Property) and x or Property(x)
                        for x in value
                    ]
                    if not isinstance(expected, list):
                        expected = [
                            expected,
                        ]
                    for item in value:
                        if item.value in expected:
                            break
                        elif item.value == expected:
                            break
                    else:
                        break
                else:
                    if not isinstance(value, Property):
                        value = Property(value)
                    if value.value != expected:
                        break
            else:
                res_events.append(event)
        return res_events

    def search_events_in_range(self, dtstart, dtend, sortby=None, **kw):
        """Return a list of Records objects of type 'VEVENT' matching the
        given dates range and sorted if requested.  If kw is filled, it calls
        search_events on the found subset to return only components matching
        filters.

        RangeSearch is [left, right[
        """
        # Check type of dates, we need datetime for method in_range
        if not isinstance(dtstart, datetime):
            dtstart = datetime(dtstart.year, dtstart.month, dtstart.day)
        if not isinstance(dtend, datetime):
            dtend = datetime(dtend.year, dtend.month, dtend.day)
            # dtend is include into range
            dtend = dtend + timedelta(days=1) - resolution

        # Get only the events which matches
        dtstart_limit = dtstart + resolution
        dtend_limit = dtend + resolution
        dtstart = dtstart
        dtend = dtend
        query = AndQuery(
            PhraseQuery('type', 'VEVENT'),
            OrQuery(
                RangeQuery('DTSTART', dtstart, dtend),
                RangeQuery('DTEND', dtstart_limit, dtend_limit),
                AndQuery(RangeQuery('DTSTART', None, dtstart),
                         RangeQuery('DTEND', dtend, None))))
        results = self.search(query)

        if results == []:
            return []

        # Check filters
        if kw:
            results = self.search_events(subset=results, **kw)

        # Nothing to sort or inactive
        if sortby is None or len(results) <= 1:
            return results

        # Get results as a dict to sort them
        res_events = []
        for event in results:
            version = event[-1]
            value = {
                'dtstart': version['DTSTART'].value,
                'dtend': version['DTEND'].value,
                'event': event
            }
            res_events.append(value)
        # Sort by dtstart
        res_events = sorted(res_events, key=itemgetter('dtstart'))
        # Sort by dtend
        res = []
        current = [res_events[0]]
        for e in res_events[1:]:
            if e['dtstart'] == current[0]['dtstart']:
                current.append(e)
            else:
                res.extend(x['event']
                           for x in sorted(current, key=itemgetter('dtend')))
                current = [e]
        res.extend(x['event']
                   for x in sorted(current, key=itemgetter('dtend')))
        return res

    def search_events_in_date(self, date, sortby=None, **kw):
        """Return a list of Component objects of type 'VEVENT' matching the
        given date and sorted if requested.
        """
        dtstart = datetime(date.year, date.month, date.day)
        dtend = dtstart + timedelta(days=1) - resolution
        return self.search_events_in_range(dtstart, dtend, sortby=sortby, **kw)

    # Test if any event corresponds to a given date
    def has_event_in_date(self, date):
        """Return True if there is at least one event matching the given date.
        """
        return self.search_events_in_date(date) != []

    def get_conflicts(self, start_date, end_date=None):
        """Returns a list of uid couples which happen at the same time.
        We check only last occurrence of events.
        """
        if end_date is not None:
            events = self.search_events_in_range(start_date, end_date)
        else:
            events = self.search_events_in_date(start_date)
        if len(events) <= 1:
            return None

        conflicts = []
        # We take each event as a reference
        for i, event_ref in enumerate(events):
            version = event_ref[-1]
            dtstart_ref = version['DTSTART'].value
            dtend_ref = version['DTEND'].value
            # For each other event, we test if there is a conflict
            for j, event in enumerate(events):
                if j <= i:
                    continue
                version = event[-1]
                dtstart = version['DTSTART'].value
                dtend = version['DTEND'].value

                if dtstart >= dtend_ref or dtend <= dtstart_ref:
                    continue
                conflicts.append((i, j))

        # Replace index of components by their UID
        if conflicts != []:
            for index, (i, j) in enumerate(conflicts):
                conflicts[index] = (events[i].id, events[j].id)

        return conflicts
Example #25
0
    rest_login = Rest_Login
    rest_query = Rest_Query
    rest_create = Rest_Create
    rest_read = Rest_Read
    rest_update = Rest_Update
    rest_delete = Rest_Delete
    rest_schema = Rest_Schema


###########################################################################
# Register read-only fields
###########################################################################

# Path related fields
register_field('abspath', String(indexed=True, stored=True))
register_field('abspath_depth', Integer(indexed=True, stored=True))
register_field('parent_paths', String(multiple=True, indexed=True))
register_field('name', String(stored=True, indexed=True))
# Class related fields
register_field('format', String(indexed=True, stored=True))
register_field('base_classes', String(multiple=True, indexed=True))
# Referential integrity
register_field('links', String(multiple=True, indexed=True))
register_field('onchange_reindex', String(multiple=True, indexed=True))
# Full text search
register_field('text', Unicode(indexed=True))
# Various classifications
register_field('is_content', Boolean(indexed=True))
# Time events
register_field('next_time_event', DateTime(stored=True))
register_field('next_time_event_payload', String(stored=True))
Example #26
0
class CSV_View(BrowseForm):

    # FIXME We need different permissions for GET and POST
    access = 'is_allowed_to_edit'
    title = MSG(u'View')
    schema = {
        'ids': Integer(mandatory=True, multiple=True),
    }

    search_schema = {}
    search_widgets = []

    def get_items(self, resource, context):
        return list(resource.handler.get_rows())

    def sort_and_batch(self, resource, context, items):
        # Sort
        sort_by = context.query['sort_by']
        reverse = context.query['reverse']
        if sort_by:
            handler = resource.handler
            if handler.schema is None:
                sort_by = int(sort_by)
            else:
                sort_by = handler.columns.index(sort_by)
            items.sort(key=itemgetter(sort_by), reverse=reverse)

        # Batch
        start = context.query['batch_start']
        size = context.query['batch_size']
        return items[start:start + size]

    def get_table_columns(self, resource, context):
        columns = resource.get_columns()
        columns.insert(0, ('checkbox', None))
        columns.insert(1, ('index', None))
        return columns

    def get_item_value(self, resource, context, item, column):
        if column == 'checkbox':
            return item.number, False
        elif column == 'index':
            index = item.number
            return index, ';edit_row?index=%s' % index

        # A value from the schema
        handler = resource.handler
        datatype = handler.get_datatype(column)
        if handler.schema is None:
            value = item[int(column)]
        else:
            value = item.get_value(column)

        # Columns
        is_enumerate = getattr(datatype, 'is_enumerate', False)
        if is_enumerate:
            return datatype.get_value(value)
        return value

    table_actions = [Remove_BrowseButton]

    def action_remove(self, resource, context, form):
        ids = form['ids']
        resource.handler.del_rows(ids)
        # Ok
        context.message = INFO(u'Row deleted.')
Example #27
0
class Shop_Configure(DBResource_Edit):

    access = 'is_admin'
    title = MSG(u'Configure shop')

    schema = {
        'shop_uri': String(mandatory=True),
        'shop_backoffice_uri': String(mandatory=True),
        'order_notification_mails': MultiLinesTokens(mandatory=True),
        'shop_default_zone': CountriesZonesEnumerate(mandatory=True),
        'shop_sort_by': SortBy_Enumerate(mandatory=True),
        'shop_sort_reverse': Boolean(mandatory=True),
        'devise': Devises(mandatory=True),
        'hide_not_buyable_products': Boolean(mandatory=True),
        'categories_batch_size': Integer(mandatory=True),
        'show_sub_categories': Boolean,
        'product_cover_is_mandatory': Boolean,
        'log_authentification': Boolean,
        'registration_need_email_validation': Boolean,
        'bill_logo': ImagePathDataType,
        'pdf_signature': Unicode,
        'barcode_format': BarcodesFormat
    }

    widgets = [
        TextWidget('shop_uri', title=MSG(u'Website uri')),
        TextWidget('shop_backoffice_uri',
                   title=MSG(u'Website backoffice uri')),
        MultilineWidget(
            'order_notification_mails',
            title=MSG(u'New order notification emails (1 per line)'),
            rows=8,
            cols=50),
        MultilineWidget('pdf_signature',
                        title=MSG(u'PDF signature'),
                        rows=8,
                        cols=50),
        SelectWidget('shop_default_zone', title=MSG(u'Shop default zone')),
        SelectWidget('devise', title=MSG(u'Devises'), has_empty_option=False),
        TextWidget('categories_batch_size',
                   title=MSG(u'Batch size for categories ?')),
        SelectWidget('shop_sort_by',
                     title=MSG(u'Sort products by ...'),
                     has_empty_option=False),
        BooleanRadio('shop_sort_reverse', title=MSG(u'Reverse sort ?')),
        BooleanRadio('show_sub_categories',
                     title=MSG(u'Show sub categories ?')),
        BooleanRadio('product_cover_is_mandatory',
                     title=MSG(u'Product cover is mandatory ?')),
        BooleanRadio('hide_not_buyable_products',
                     title=MSG(u'Hide not buyable products ?')),
        BooleanRadio('log_authentification',
                     title=MSG(u'Log users authentification ?')),
        BooleanRadio('registration_need_email_validation',
                     title=MSG(u'Ask for mail validation on registration ?')),
        ImageSelectorWidget('bill_logo', title=MSG(u'Bill logo')),
        SelectWidget('barcode_format',
                     title=MSG(u'Barcode format'),
                     has_empty_option=False),
    ]

    submit_value = MSG(u'Edit configuration')

    def action(self, resource, context, form):
        for key in self.schema.keys():
            if key == 'order_notification_mails':
                continue
            resource.set_property(key, form[key])
        values = [x.strip() for x in form['order_notification_mails']]
        resource.set_property('order_notification_mails', values)
        context.message = MSG_CHANGES_SAVED
        return
Example #28
0
 def test_Integer(self):
     for x in range(-10,11):
         data = Integer.encode(x)
         self.assertEqual(x, Integer.decode(data))
Example #29
0
 'cellpadding': String,
 'cellspacing': String,
 'char': String,
 'charoff': String,
 'charset': String,
 'checked': Boolean,
 'cite': URI,
 'class': String,
 'classid': URI,
 'clear': String,
 'code': String,
 'codebase': URI,
 'codetype': String,
 'color': String,
 'cols': Integer,
 'colspan': Integer(default=1),
 'compact': Boolean,
 'content': String,
 'coords': String,
 'data': URI,
 'datetime': String,
 'declare': Boolean,
 'defer': Boolean,
 'dir': String,
 'disabled': Boolean,
 'enctype': String,
 'face': String,
 'for': String,
 'frame': String,
 'frameborder': String,
 'headers': String,
Example #30
0
class BrowseForm(STLView):

    template = '/ui/ikaaro/generic/browse.xml'

    query_schema = {
        'batch_start': Integer(default=0),
        'batch_size': Integer(default=20),
        'sort_by': String,
        'reverse': Boolean(default=False)}

    # Batch
    batch = Batch

    # Search configuration
    search_form_id = 'form-search'
    search_form_css = ''
    search_template = '/ui/ikaaro/auto_form.xml'
    search_template_field = '/ui/ikaaro/auto_form_field.xml'
    search_schema = {}
    search_widgets = []

    # Content
    table_template = '/ui/ikaaro/generic/browse_table.xml'
    table_form_id = 'form-table'
    table_css = None
    table_columns = []
    table_actions = []
    # Actions are external to current form
    external_form = False

    # Keep the batch in the canonical URL
    canonical_query_parameters = (STLView.canonical_query_parameters
                                  + ['batch_start'])


    def get_query_schema(self):
        proxy = super(BrowseForm, self)
        return merge_dicts(proxy.get_query_schema(), self.search_schema)


    def get_namespace(self, resource, context):
        batch = None
        table = None
        # Batch
        items = self.get_items(resource, context)
        if self.batch is not None:
            total = len(items)
            batch = self.batch(context=context, total=total).render()

        # Content
        items = self.sort_and_batch(resource, context, items)
        if self.table_template is not None:
            template = context.get_template(self.table_template)
            namespace = self.get_table_namespace(resource, context, items)
            table = stl(template, namespace)

        # The Search Form
        search = None
        if self.search_widgets:
            search = self.get_search_namespace(resource, context)

        return {'batch': batch, 'table': table, 'search': search}


    ##################################################
    # Search
    ##################################################
    def get_search_actions(self, resource, context):
        search_button = Button(access=True,
            resource=resource, context=context,
            css='button-search', title=MSG(u'Search'))
        return [search_button]


    def get_search_namespace(self, resource, context):
        form = AutoForm(
            form_id=self.search_form_id,
            form_css=self.search_form_css,
            template=self.search_template,
            template_field=self.search_template_field,
            title=MSG(u'Search'),
            method='get',
            schema=self.search_schema,
            widgets=self.search_widgets,
            actions=self.get_search_actions(resource, context))
        return form.GET(resource, context)


    #######################################################################
    # Private API (to override)
    def get_table_columns(self, resource, context):
        return self.table_columns


    def _get_table_columns(self, resource, context):
        """ Always return a tuple of 4 elements. """
        table_columns = []
        for column in self.get_table_columns(resource, context):
            if len(column) == 2:
                name, title = column
                column = (name, title, True, None)
            elif len(column) == 3:
                name, title, sortable = column
                column = (name, title, sortable, None)
            table_columns.append(column)
        return table_columns


    def get_items(self, resource, context):
        name = 'get_items'
        raise NotImplementedError, "the '%s' method is not defined" % name


    def sort_and_batch(self, resource, context, items):
        name = 'sort_and_batch'
        raise NotImplementedError, "the '%s' method is not defined" % name


    def get_item_value(self, resource, context, item, column):
        if column == 'row_css':
            return None

        # Default
        raise ValueError, 'unexpected "%s"' % column


    def get_table_actions(self, resource, context):
        return self.table_actions


    #######################################################################
    # Table
    def get_table_head(self, resource, context, items):
        actions = self.actions_namespace

        # Get from the query
        query = context.query
        sort_by = query['sort_by']
        reverse = query['reverse']

        columns = self._get_table_columns(resource, context)
        columns_ns = []
        for name, title, sortable, css in columns:
            if name == 'checkbox':
                # Type: checkbox
                if self.external_form or actions:
                    columns_ns.append({'is_checkbox': True})
            elif title is None or not sortable:
                # Type: nothing or not sortable
                columns_ns.append({
                    'is_checkbox': False,
                    'title': title,
                    'css': 'thead-%s' % name.replace('_', '-'),
                    'href': None,
                    'sortable': False})
            else:
                # Type: normal
                base_href = context.uri.replace(sort_by=name, batch_start=None)
                if name == sort_by:
                    sort_up_active = reverse is False
                    sort_down_active = reverse is True
                else:
                    sort_up_active = sort_down_active = False
                columns_ns.append({
                    'is_checkbox': False,
                    'title': title,
                    'css': 'thead-%s' % name.replace('_', '-'),
                    'sortable': True,
                    'href': context.uri.path,
                    'href_up': base_href.replace(reverse=0),
                    'href_down': base_href.replace(reverse=1),
                    'sort_up_active': sort_up_active,
                    'sort_down_active': sort_down_active
                    })
        return columns_ns


    @proto_lazy_property
    def actions_namespace(self):
        resource = self.resource
        context = self.context
        items = self._items

        actions = []
        for button in self.get_table_actions(resource, context):
            button = button(resource=resource, context=context, items=items)
            if button.show:
                actions.append(button)

        return actions


    def get_column_css(self, resource, context, column):
        return None


    def get_table_namespace(self, resource, context, items):
        # (1) Actions (submit buttons)
        self._items = items
        actions = self.actions_namespace
        # (2) Table Head: columns
        table_head = self.get_table_head(resource, context, items)

        # (3) Table Body: rows
        columns = self.get_table_columns(resource, context)
        rows = []
        for item in items:
            row_columns = []
            for column in columns:
                column = column[0]
                # Skip the checkbox column if there are not any actions
                if column == 'checkbox':
                    if not self.external_form and not actions:
                        continue

                value = self.get_item_value(resource, context, item, column)
                column_ns = {
                    'is_checkbox': False,
                    'is_icon': False,
                    'is_link': False,
                    'css': self.get_column_css(resource, context, column),
                }
                # Type: empty
                if value is None:
                    pass
                # Type: checkbox
                elif column == 'checkbox':
                    value, checked = value
                    column_ns['is_checkbox'] = True
                    column_ns['value'] = value
                    column_ns['checked'] = checked
                # Type: icon
                elif column == 'icon':
                    column_ns['is_icon'] = True
                    column_ns['src'] = value
                # Type: normal
                else:
                    column_ns['is_link'] = True
                    if type(value) is tuple:
                        value, href = value
                    else:
                        href = None
                    column_ns['value'] = value
                    column_ns['href'] = href
                row_columns.append(column_ns)
            # Row css
            row_css = self.get_item_value(resource, context, item, 'row_css')

            # Append
            rows.append({'css': row_css, 'columns': row_columns})

        # Ok
        return {
            'css': self.table_css,
            'form_id': self.table_form_id,
            'columns': table_head,
            'rows': rows,
            'actions': actions,
            'external_form': self.external_form or not actions}
Example #31
0
class TimetablesForm(STLView):

    access = 'is_allowed_to_edit'
    title = MSG(u'Timetables')
    template = '/ui/ikaaro/agenda/edit_timetables.xml'
    styles = ['/ui/ikaaro/agenda/style.css']

    def get_namespace(self, resource, context):
        # Show current timetables only if previously set in metadata
        if resource.has_property('timetables'):
            timetables = resource.get_value('timetables')
            timetables_ns = [{
                'index': index,
                'startname': '%s_start' % index,
                'endname': '%s_end' % index,
                'start': Time.encode(start),
                'end': Time.encode(end)
            } for index, (start, end) in enumerate(timetables)]
        else:
            timetables_ns = []

        # Ok
        return {'timetables': timetables_ns}

    action_add_schema = {'new_start': Time, 'new_end': Time}

    def action_add(self, resource, context, form):
        # Check start time is before end time
        start = form['new_start']
        end = form['new_end']
        if start >= end:
            message = ERROR(u'Start time must be earlier than end time.')
            context.message = message
            return

        # Check the given range is not defined yet
        timetables = resource.get_value('timetables')
        if (start, end) in timetables:
            context.message = ERROR(u'The given range is already defined.')
            return

        # Add new range
        timetables.append((start, end))
        timetables.sort()
        resource.set_value('timetables', timetables)
        # Ok
        context.message = messages.MSG_CHANGES_SAVED

    action_remove_schema = {'ids': Integer(multiple=True)}

    def action_remove(self, resource, context, form):
        ids = form['ids']
        if len(ids) == 0:
            context.message = ERROR(u'Nothing to remove.')
            return

        # New timetables
        timetables = resource.get_value('timetables')
        timetables = [
            timetable for index, timetable in enumerate(timetables)
            if index not in ids
        ]
        resource.set_property('timetables', timetables)
        # Ok
        context.message = INFO(u'Timetable(s) removed successfully.')

    def action_update(self, resource, context, form):
        timetables = resource.get_value('timetables')
        if len(timetables) == 0:
            context.message = ERROR(u'Nothing to change.')
            return

        # Update timetable or just set index to next index
        new_timetables = []
        for index in range(len(timetables)):
            try:
                start = context.get_form_value('%s_start' % index, type=Time)
                end = context.get_form_value('%s_end' % index, type=Time)
            except:
                context.message = ERROR(u'Wrong time selection (HH:MM).')
                return

            if start >= end:
                message = ERROR(u'Start time must be earlier than end time.')
                context.message = message
                return

            new_timetables.append((start, end))

        new_timetables.sort()
        resource.set_property('timetables', new_timetables)
        # Ok
        context.message = messages.MSG_CHANGES_SAVED