def encode_inner_components(self, name, property_values, encoding='utf-8'): lines = [] for property_value in property_values: record = self.get_record(property_value.value) if record is not None: seq = 0 c_type = record.type for version in record: line = 'BEGIN:%s\n' % c_type lines.append(Unicode.encode(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 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 return lines
def _make_start_format(tag_uri, tag_name, attributes, encoding): # We must search for translatable attributes result = [(u'<%s' % get_qname(tag_uri, tag_name), False, None)] for attr_uri, attr_name in attributes: qname = get_attribute_qname(attr_uri, attr_name) qname = Unicode.decode(qname, encoding=encoding) value = attributes[(attr_uri, attr_name)] value = Unicode.decode(value, encoding=encoding) value = XMLAttribute.encode(value) datatype = get_attr_datatype(tag_uri, tag_name, attr_uri, attr_name, attributes) if issubclass(datatype, Unicode): result[-1] = (result[-1][0] + u' %s="' % qname, False, None) context = _get_attr_context(datatype, tag_name, attr_name) result.append((value, True, context)) result.append((u'"', False, None)) else: result[-1] = (result[-1][0] + u' %s="%s"' % (qname, value), False, None) # Close the start tag if is_empty(tag_uri, tag_name): result[-1] = (result[-1][0] + u'/>', False, None) else: result[-1] = (result[-1][0] + u'>', False, None) return result
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 to_str(self, encoding='UTF-8'): lines = [] lines.append('BEGIN:VCALENDAR\n') # Calendar properties for key in self.properties: value = self.properties[key] line = self.encode_property(key, value, encoding) lines.extend(line) # Calendar components for uid in self.components: component = self.components[uid] c_type = component.c_type for sequence in component.get_sequences(): version = component.versions[sequence] # Begin line = u'BEGIN:%s\n' % c_type lines.append(Unicode.encode(line)) # UID, SEQUENCE lines.append('UID:%s\n' % uid) lines.append('SEQUENCE:%s\n' % sequence) # Properties for key in version: value = version[key] line = self.encode_property(key, value, encoding) lines.extend(line) # Insert inner components for c_inner_component in component.c_inner_components: c_inner_type = c_inner_component.c_inner_type # sequence not supported into inner components version = c_inner_component.versions[0] # Begin line = u'BEGIN:%s\n' % c_inner_type lines.append(Unicode.encode(line)) # Properties for key in version: value = version[key] line = self.encode_property(key, value, encoding) lines.extend(line) # End line = u'END:%s\n' % c_inner_type lines.append(Unicode.encode(line)) # End line = u'END:%s\n' % c_type lines.append(Unicode.encode(line)) lines.append('END:VCALENDAR\n') return ''.join(lines)
def to_str(self, encoding='UTF-8', separator=',', newline='\n'): def escape(data): return '"%s"' % data.replace('"', '""') lines = [] # Header if self.has_header: line = [ escape(Unicode.encode(x, encoding)) for x in self.header ] line = separator.join(line) lines.append(line) # When schema or columns (or both) are None there is plain # string to string conversion schema = self.schema columns = self.columns if schema and columns: datatypes = [ (i, schema[x]) for i, x in enumerate(columns) ] for row in self.get_rows(): line = [] for i, datatype in datatypes: try: data = datatype.encode(row[i], encoding=encoding) except TypeError: data = datatype.encode(row[i]) line.append(escape(data)) lines.append(separator.join(line)) else: for row in self.get_rows(): line = [ escape(x) for x in row ] lines.append(separator.join(line)) return newline.join(lines)
class Product_SendToFriend(AutoForm): access = True title = MSG(u'Send to a friend') submit_value = MSG(u'Send to my friend') meta = [('robots', 'noindex, follow', None)] schema = { 'widget': String, # XXX not used 'my_email': Email(mandatory=True), 'my_name': Unicode(mandatory=True), 'email': Email(mandatory=True), 'message': Unicode} widgets = [MiniProductWidget('widget', title=MSG(u"Product")), TextWidget('my_email', title=MSG(u"Your email")), TextWidget('my_name', title=MSG(u"Your name")), TextWidget('email', title=MSG(u"Email of your friend")), MultilineWidget('message', title=MSG(u"You can write a message for your friend"))] mail_subject = MSG(u"{my_name} advice you this product: {product_title}") mail_body = MSG(u"Your friend {my_name} advice you this product: \n\n" u" {product_title}\n\n" u"All details are here:\n\n" u" {product_uri}\n\n" u" {message}\n\n") def get_value(self, resource, context, name, datatype): if context.user: if name == 'my_email': return context.user.get_property('email') elif name == 'my_name': return context.user.get_title() return AutoForm.get_value(self, resource, context, name, datatype) def action(self, resource, context, form): kw = {'product_uri': context.uri.resolve('./'), 'product_title': resource.get_title(), 'message': form['message'], 'my_name': form['my_name']} subject = self.mail_subject.gettext(**kw) body = self.mail_body.gettext(**kw) context.root.send_email(form['email'], subject, from_addr=form['my_email'], text=body) msg = u'An email has been send to your friend' return context.come_back(MSG(msg), goto='./')
def normalize(data): """ Normalize data http://www.w3.org/TR/html401/struct/text.html#h-9.1 collapse input white space sequences when producing output inter-word space. """ # decode the data data = Unicode.decode(data, encoding) return ' '.join(data.split())
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 CustomerSchemaTable(OrderedTableFile): record_properties = { 'name': String(unique=True, is_indexed=True), 'title': Unicode(mandatory=True, multiple=True), 'mandatory': Boolean, 'is_public': Boolean, 'multiple': Boolean, 'datatype': Datatypes(mandatory=True, index='keyword'), 'show_on_register': Boolean, 'tip': Unicode, 'default': Unicode, }
class SchemaHandler(CSVFile): # Don't store default values here because any value needs to be written # down in case the default value changes later. skip_header = True has_header = True class_csv_guess = True schema = { 'title': Unicode(mandatory=True, title=MSG(u"Title")), 'name': Variable(mandatory=True, title=MSG(u"Variable")), 'type': Type(mandatory=True, title=MSG(u"Type")), 'help': Unicode(title=MSG(u"Online Help")), 'length': ValidInteger(title=MSG(u"Length")), 'enum_options': EnumerateOptions(mandatory=True, title=MSG(u"Enumerate Options")), 'enum_repr': EnumerateRepresentation( title=MSG(u"Enumerate Representation")), 'decimals': ValidInteger(title=MSG(u"Decimals")), 'mandatory': Mandatory(title=MSG(u"Mandatory")), 'size': ValidInteger(title=MSG(u"Input Size")), 'dependency': Expression(title=MSG(u"Dependent Field")), 'formula': Expression(title=MSG(u"Formula")), 'default': String(default='', title=MSG(u"Default Value"))} columns = [ 'title', 'name', 'type', 'help', 'length', 'enum_options', 'enum_repr', 'decimals', 'mandatory', 'size', 'dependency', 'formula', 'default']
def decode(cls, data): # Neither upper() nor lower() to preserve enumerates value = Unicode.decode(data.strip()) # Allow single "=" as equals value = single_eq.sub(ur"==", value) value = (value # Alternative to name variables .replace(u'#', u'') # Non-break spaces .replace(u'\u00a0', u'') # F*****g replacement .replace(u'«', u'"').replace(u'»', u'"')) return value
class CartBox(Box): class_id = 'vertical-item-cart-box' class_title = MSG(u'Boîte panier') view = CartBox_View() edit_schema = {'order_title': Unicode(multilingual=True), 'show_if_empty': Boolean} edit_widgets = [TextWidget('order_title', title=MSG(u'Order title')), BooleanRadio('show_if_empty', title=MSG(u'Show cart if empty ?'))]
def get_schema(self, resource, context): schema = merge_dicts(resource.base_schema, resource.get_dynamic_schema()) group = resource.get_group(context) # Lastname mandatory ? l_mandatory = group.get_property('lastname_is_mandatory_on_registration') schema['lastname'] = Unicode(mandatory=l_mandatory) # Phone mandatory ? p_mandatory = group.get_property('phone_is_mandatory_on_registration') schema['phone1'] = String(mandatory=p_mandatory) del schema['password'] del schema['user_must_confirm'] return schema
class ProductTypeTable(OrderedTableFile): record_properties = { # XXX To remove 'name': String(unique=True, is_indexed=True), 'title': Unicode(mandatory=True, multiple=True), 'mandatory': Boolean, 'multiple': Boolean, 'multilingual': Boolean, 'visible': Boolean, # XXX To remove 'is_purchase_option': Boolean, 'datatype': Datatypes(mandatory=True, is_indexed=True, index='keyword'), }
def get_schema(self, resource, context): group = self.get_group(context) base_schema = deepcopy(self.base_schema) # Inject address schema ? address_schema = {} if group.get_property('hide_address_on_registration') is False: address_schema = self.address_schema # Lastname mandatory ? l_mandatory = group.get_property( 'lastname_is_mandatory_on_registration') base_schema['lastname'] = Unicode(mandatory=l_mandatory) # Phone mandatory ? p_mandatory = group.get_property('phone_is_mandatory_on_registration') base_schema['phone1'] = String(mandatory=p_mandatory) # Return schema return merge_dicts(base_schema, group.get_dynamic_schema(), address_schema)
class ShopForm(OrderedTable): class_id = 'shop-form' class_title = MSG(u'Shop form') class_version = '20090609' class_handler = ShopFormTable class_views = ['display', 'edit', 'view', 'add_record'] display = ShopForm_Display() view = OrderedTable_View(search_template=None, access='is_admin') edit = AutomaticEditView() add_product = AddProduct_View() form = [ TextWidget('name', title=MSG(u'Name')), TextWidget('title', title=MSG(u'Title')), BooleanCheckBox('mandatory', title=MSG(u'Mandatory')), BooleanCheckBox('multiple', title=MSG(u'Multiple')), SelectWidget('datatype', title=MSG(u'Data Type')), SelectWidget('widget', title=MSG(u'Widget')), ] edit_widgets = [ TextWidget('submit_value', title=MSG(u'Submit value')), TextWidget('to_addr', title=MSG(u'To addr')), RTEWidget('introduction', title=MSG(u'Introduction')), RTEWidget('final_message', title=MSG(u'Final message')), BooleanRadio('must_be_authentificated', title=MSG(u'Must be authentificated to see form')) ] edit_schema = { 'submit_value': Unicode(multilingual=True, mandatory=True), 'to_addr': Email(mandatory=True), 'introduction': XHTMLBody(multilingual=True), 'final_message': XHTMLBody(multilingual=True), 'must_be_authentificated': Boolean } @classmethod def get_metadata_schema(cls): return merge_dicts(OrderedTable.get_metadata_schema(), cls.edit_schema)
class Post_View(STLView): access = 'is_allowed_to_view' title = MSG(u'View') template = '/ui/blog/Post_view.xml' schema = {'comment': Unicode(required=True)} def get_namespace(self, resource, context): return { 'title': resource.get_value('title'), 'data': resource.get_html_data(), 'date': resource.get_value('date'), 'comments': CommentsView().GET(resource, context) } def action(self, resource, context, form): resource.add_comment(form['comment']) context.message = MSG_CHANGES_SAVED
def split_reference(ref): """Return the reference associated to the path, the path and the optional view without query/fragment. ref: Reference path: Path view: string """ # XXX specific case for the menu # Be robust if the path is multilingual type_ref = type(ref) if type_ref is unicode: ref = Unicode.encode(ref) if type_ref is not Reference: ref = get_reference(ref) # Split path and view path = ref.path view = '' name = path.get_name() # Strip the view if name and name[0] == ';': view = '/' + name path = path[:-1] return ref, path, view
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))
class Shop_Login(STLForm): access = True title = MSG(u'Login') meta = [('robots', 'noindex, follow', None)] schema = { 'username': Unicode(mandatory=True), 'password': String(mandatory=True) } def get_template(self, resource, context): hostname = context.uri.authority if hostname[:6] == 'admin.': # Backoffice login template template = '/ui/backoffice/login.xml' return resource.get_resource(template) return get_skin_template(context, 'shop_login.xml') def get_namespace(self, resource, context): namespace = STLForm.get_namespace(self, resource, context) # Register link register_link = '/;register' if getattr(resource, 'register', None): register_link = './;register' namespace['register_link'] = register_link # Progress bar ? progress = None if context.resource.name == 'shop': # If user is in shop, it's a payment process, # so we have to show a progress bar progress = Shop_Progress(index=2).GET(resource, context) namespace['progress'] = progress # Go back here on register ? if getattr(resource, 'go_back_here_on_register', False) is True: goto = context.uri.path namespace['register_link'] += '?goto=%s' % goto return namespace def action(self, resource, context, form): email = form['username'].strip() password = form['password'] # Check the user exists root = context.root user = root.get_user_from_login(email) if user is None: message = ERROR(u'The user "{username}" does not exist.', username=email) goto = context.get_referrer() return context.come_back(message, goto) # Check the password is right if not user.authenticate(password, clear=True): message = ERROR(u'The password is wrong.') goto = context.get_referrer() return context.come_back(message, goto) # Check user is enabled ac = resource.get_access_control() if not user.get_property('is_enabled') and \ not ac.is_admin(user, resource): message = ERROR(u"""Your account isn't validated, please contact the webmaster""") goto = context.get_referrer() return context.come_back(message, goto) # Check user has confirm is registration if user.get_property('user_must_confirm'): message = ERROR(u"""Your account has not been confirmed.""") goto = '/users/%s/;confirm_registration' % user.name return context.come_back(message, goto) # We log authentification if resource != context.root: shop = get_shop(resource) if shop.get_property('log_authentification'): logs = shop.get_resource('customers/authentification_logs') logs.log_authentification(user.name) user.set_property('last_time', datetime.now()) # Set cookie user.set_auth_cookie(context, password) # Set context context.user = user # Come back referrer = context.get_referrer() if referrer is None: goto = get_reference('./') else: path = get_uri_path(referrer) if path.endswith(';login'): goto = get_reference('./') else: goto = referrer return context.come_back(INFO(u"Welcome!"), goto)
def to_text(self): result = {} site_root = self.get_site_root() languages = site_root.get_property('website_languages') product_model = self.get_product_model() schema = {} if product_model: schema = product_model.get_model_schema() purchase_options_schema = self.get_purchase_options_schema() declinations = list(self.search_resources(cls=Declination)) for language in languages: texts = result.setdefault(language, []) for key in ('title', 'description'): value = self.get_property(key, language=language) if value: texts.append(value) # Parent category current_category = self.parent while current_category.class_id == 'category': texts.append(current_category.get_title(language=language)) current_category = current_category.parent # data (html) events = self.get_property('data', language=language) if events: text = [ unicode(value, 'utf-8') for event, value, line in events if event == TEXT ] if text: texts.append(u' '.join(text)) # Dynamic properties for key, datatype in schema.iteritems(): value = self.get_property(key) if value: text = None multiple = datatype.multiple if issubclass(datatype, Unicode): if multiple: text = ' '.join([ x for x in value ]) else: text = value elif issubclass(datatype, String): if multiple: text = ' '.join([ Unicode.decode(x) for x in value ]) else: text = Unicode.decode(value) elif issubclass(datatype, Enumerate): values = value if multiple is False: values = [value] # XXX use multilingual label text = ' '.join(values) if text: texts.append(text) # Manufacturer manufacturer = self.get_property('manufacturer') if manufacturer: manufacturer = site_root.get_resource(manufacturer) texts.append(manufacturer.get_title()) # Purchase options for declination in declinations: for key, datatype in purchase_options_schema.iteritems(): name = declination.get_property(key) value = datatype.to_text(name, languages) if value: texts.append(value) # Join for language, texts in result.iteritems(): result[language] = u'\n'.join(texts) return result
class Shop_Register(RegisterForm): access = True meta = [('robots', 'noindex, follow', None)] query_schema = {'goto': String} base_schema = { 'goto': String, 'email': Email(mandatory=True), 'lastname': Unicode(mandatory=True), 'firstname': Unicode(mandatory=True), 'gender': Civilite(mandatory=True), 'password': String(mandatory=True), 'password_check': String(mandatory=True), 'phone1': String(mandatory=True), 'phone2': String } address_schema = { 'address_1': Unicode(mandatory=True), 'address_2': Unicode, 'zipcode': String(mandatory=True), 'town': Unicode(mandatory=True), 'country': CountriesEnumerate(mandatory=True) } base_widgets = [ HiddenWidget('goto', title=None), TextWidget('email', title=MSG(u"Email")), SelectRadio('gender', title=MSG(u"Civility"), has_empty_option=False), TextWidget('lastname', title=MSG(u"Lastname")), TextWidget('firstname', title=MSG(u"Firstname")), TextWidget('phone1', title=MSG(u"Phone number")), TextWidget('phone2', title=MSG(u"Mobile")), PasswordWidget('password', title=MSG(u"Password")), PasswordWidget('password_check', title=MSG(u"Repeat password")) ] address_widgets = [ TextWidget('address_1', title=MSG(u"Address")), TextWidget('address_2', title=MSG(u"Address")), TextWidget('zipcode', title=MSG(u"Zip code")), TextWidget('town', title=MSG(u"Town")), SelectWidget('country', title=MSG(u"Pays")) ] def GET(self, resource, context): # If a user is connected redirect on his account if context.user is not None: link = context.get_link(context.user) return context.uri.resolve(link) # RegisterForm return RegisterForm.GET(self, resource, context) def get_value(self, resource, context, name, datatype): proxy = super(Shop_Register, self) if name == 'goto' and context.method == 'GET': return context.query['goto'] value = proxy.get_value(resource, context, name, datatype) return value def get_title(self, context): group = self.get_group(context) return group.get_property('register_title') or MSG(u'Register') def get_schema(self, resource, context): group = self.get_group(context) base_schema = deepcopy(self.base_schema) # Inject address schema ? address_schema = {} if group.get_property('hide_address_on_registration') is False: address_schema = self.address_schema # Lastname mandatory ? l_mandatory = group.get_property( 'lastname_is_mandatory_on_registration') base_schema['lastname'] = Unicode(mandatory=l_mandatory) # Phone mandatory ? p_mandatory = group.get_property('phone_is_mandatory_on_registration') base_schema['phone1'] = String(mandatory=p_mandatory) # Return schema return merge_dicts(base_schema, group.get_dynamic_schema(), address_schema) def get_widgets(self, resource, context): widgets = self.base_widgets[:] # Group widgets group = self.get_group(context) widgets.extend(group.get_dynamic_widgets()) # Address widget address_widgets = [] if group.get_property('hide_address_on_registration') is False: address_widgets = self.address_widgets widgets.extend(address_widgets) return widgets def get_group(self, context): root = context.root query = [ PhraseQuery('format', 'user-group'), PhraseQuery('name', 'default') ] search = root.search(AndQuery(*query)) documents = search.get_documents() group = documents[0] return root.get_resource(group.abspath) def get_namespace(self, resource, context): namespace = RegisterForm.get_namespace(self, resource, context) # Add register body group = self.get_group(context) register_body = group.get_property('register_body') if register_body is not None: namespace['required_msg'] = (register_body + list(XMLParser('<br/><br/>')) + list(namespace['required_msg'])) return namespace def action(self, resource, context, form): shop = get_shop(resource) root = context.root site_root = resource.get_site_root() # Check the new password matches password = form['password'].strip() if password != form['password_check']: context.message = ERROR(u"The two passwords are different.") return if shop.get_property('registration_need_email_validation') is False: msg = MSG(u'Your inscription has been validaded.') else: msg = MSG(u'Your inscription has been validaded, ' u'you will receive an email to confirm it.') # Do we already have a user with that email? email = form['email'].strip() user = root.get_user_from_login(email) if user is not None: context.message = ERROR(u'This email address is already used.') return # Add the user users = root.get_resource('users') user = users.set_user(email, password) # Set user group (do it befor save_form for dynanic schema) group = self.get_group(context) user.set_property('user_group', str(group.get_abspath())) # Save properties user.save_form(self.get_schema(resource, context), form) # Save address in addresses table if group.get_property('hide_address_on_registration') is False: kw = {'user': user.name} addresses = shop.get_resource('addresses') for key in [ 'gender', 'lastname', 'firstname', 'address_1', 'address_2', 'zipcode', 'town', 'country' ]: kw[key] = form[key] kw['title'] = MSG(u'Your address').gettext() addresses.handler.add_record(kw) # Clean cart, if another user already login before cart = ProductCart(context) cart.clean() # Set the role site_root.set_user_role(user.name, 'guests') # We log authentification shop = get_shop(resource) logs = shop.get_resource('customers/authentification_logs') logs.log_authentification(user.name) user.set_property('last_time', datetime.now()) # Send confirmation email need_email_validation = shop.get_property( 'registration_need_email_validation') user.send_register_confirmation(context, need_email_validation) # User is enabled ? user_is_enabled = group.get_property('user_is_enabled_when_register') user.set_property('is_enabled', user_is_enabled) # Create modules if needed search = context.root.search(is_shop_user_module=True) for brain in search.get_documents(): shop_user_module = root.get_resource(brain.abspath) shop_user_module.initialize(user) # If user not enabled, send mail to webmaster to validate user if user_is_enabled is False: subject = MSG( u'A customer must be validated in your shop').gettext() shop_backoffice_uri = shop.get_property('shop_backoffice_uri') body = registration_notification_body.gettext( name=user.name, email=email, shop_backoffice_uri=shop_backoffice_uri) for to_addr in shop.get_property('order_notification_mails'): root.send_email(to_addr, subject, text=body) # If need_email_validation or user not enable redirect on Welcome if need_email_validation is True or user_is_enabled is False: goto = '%s/welcome/' % context.get_link(group) return context.come_back(msg, goto=goto) ######################## # Do authentification ######################## # Set cookie user.set_auth_cookie(context, form['password']) # Set context context.user = user # Redirect shop = get_shop(resource) if form['goto']: goto = context.query['goto'] elif resource == shop: goto = './;addresses' elif resource.class_id == shop.product_class.class_id: goto = './' else: goto = '/users/%s' % user.name return context.come_back(msg, goto)
abspath = self.get_canonical_path() query = AndQuery(PhraseQuery('parent_paths', str(abspath)), PhraseQuery('format', 'category')) return len(root.search(query)) @property def nb_products(self): return self.get_nb_products() @property def nb_categories(self): return self.get_nb_categories() ############################# # Export ############################# export = Export(export_resource=Product, access='is_allowed_to_edit', file_columns=[ 'reference', 'state', 'frontoffice_uri', 'cover_uri', 'manufacturer', 'price_with_tax', 'description' ]) register_resource_class(Category) # Add m_title field if it does not already exist if 'm_title' in get_register_fields() is False: register_field('m_title', Unicode(is_stored=True, is_indexed=True)) register_field('m_breadcrumb_title', Unicode(is_stored=True, is_indexed=True))
class Category(ShopFolder): class_id = 'category' class_title = MSG(u'Category') # Edit configuration edit_show_meta = True edit_schema = { 'data': XHTMLBody(multilingual=True), 'breadcrumb_title': Unicode(multilingual=True), 'image_category': ImagePathDataType(multilingual=True), 'default_product_cover': ImagePathDataType(multilingual=True) } edit_widgets = [ TextWidget('breadcrumb_title', title=MSG(u'Breadcrumb title')), ImageSelectorWidget('image_category', title=MSG(u'Category image')), ImageSelectorWidget('default_product_cover', title=MSG(u'Default cover for products')), RTEWidget('data', title=MSG(u"Description")) ] # Views view = Category_View() browse_content = Products_View() view_categories = Category_BackofficeView() edit = AutomaticEditView() batch_edition = Category_BatchEdition() new_product = Product_NewProduct() new_category = NewCategory_Form() comparator = Category_Comparator() @property def class_views(self): context = get_context() # Back-Office hostname = context.uri.authority if hostname[:6] == 'admin.': return [ 'browse_content', 'new_product', 'view_categories', 'new_category', 'edit' ] return ['view', 'edit'] @classmethod def get_metadata_schema(cls): return merge_dicts( ShopFolder.get_metadata_schema(), data=XHTMLBody(multilingual=True), breadcrumb_title=Unicode(multilingual=True), image_category=ImagePathDataType(multilingual=True), default_product_cover=ImagePathDataType(multilingual=True)) def _get_catalog_values(self): # Get the languages site_root = self.get_site_root() languages = site_root.get_property('website_languages') # Titles m_title = {} m_breadcrumb_title = {} for language in languages: value = self.get_property('title', language=language) if value: m_title[language] = value value = self.get_property('breadcrumb_title', language=language) if value: m_breadcrumb_title[language] = value # Data data = self.get_property('data') if data is not None: data = xml_to_text(data) return merge_dicts( super(Category, self)._get_catalog_values(), data=data, # XXX Hack to be on sitemap workflow_state='public', m_title=m_title, m_breadcrumb_title=m_breadcrumb_title) def get_document_types(self): return [Product, Category] #################################### # Computed fields #################################### computed_schema = { 'nb_products': Integer(title=MSG(u'Nb products')), 'nb_categories': Integer(title=MSG(u'Nb sub categories')) } def get_nb_products(self, only_public=False): root = self.get_root() shop = get_shop(self) abspath = self.get_canonical_path() query = [ PhraseQuery('parent_paths', str(abspath)), PhraseQuery('format', shop.product_class.class_id) ] if shop.get_property('hide_not_buyable_products') is True: context = get_context() group_name = get_group_name(shop, context) query.append( NotQuery(PhraseQuery('not_buyable_by_groups', group_name))) if only_public is True: query.append(PhraseQuery('workflow_state', 'public')) return len(root.search(AndQuery(*query))) def get_nb_categories(self): root = self.get_root() abspath = self.get_canonical_path() query = AndQuery(PhraseQuery('parent_paths', str(abspath)), PhraseQuery('format', 'category')) return len(root.search(query)) @property def nb_products(self): return self.get_nb_products() @property def nb_categories(self): return self.get_nb_categories() ############################# # Export ############################# export = Export(export_resource=Product, access='is_allowed_to_edit', file_columns=[ 'reference', 'state', 'frontoffice_uri', 'cover_uri', 'manufacturer', 'price_with_tax', 'description' ])
def decode(cls, data): value = Unicode.decode(data) return { #'name': checkid(value) or '', 'name': value, 'value': value}
def test_Unicode(self): x = u'العربيه 中文 Español Français' data = Unicode.encode(x) self.assertEqual(x, Unicode.decode(data))
'scheme': String, 'scope': String, 'scrolling': String, 'selected': Boolean, 'shape': String, 'size': String, 'span': Integer(default=1), 'src': URI, 'standby': Unicode, 'start': Integer, 'style': String, 'summary': Unicode, 'tabindex': Integer, 'target': String, 'text': String, 'title': Unicode(context="title attribute"), 'type': String, 'usemap': URI, 'valign': String, 'value': String, 'valuetype': String, 'version': String, 'vlink': String, 'vspace': Integer, 'width': String, # FIXME Not standard 'autocomplete': String, # <input> 'pluginspage': String, # <embed> 'quality': String, # <embed> 'autoplay': Boolean, # <embed> 'wrap': String,
class ShopUser_Group(ShopFolder): class_id = 'user-group' class_views = ['edit', 'goto_categories', 'register', 'schema', 'welcome'] class_version = '20100719' class_title = MSG(u'User group') edit = AutomaticEditView() schema = GoToSpecificDocument(specific_document='schema', title=MSG(u'Schema')) welcome = GoToSpecificDocument(specific_document='welcome', title=MSG(u'Edit welcome page')) goto_categories = GoToSpecificDocument( specific_document='../../../categories', title=MSG(u'Revenir aux catégories')) register = Group_Register() edit_schema = {'register_title': Unicode(multilingual=True), 'register_body': XHTMLBody(multilingual=True), 'register_mail_subject': Unicode(multilingual=True), 'register_mail_body': Unicode(multilingual=True), 'validation_mail_subject': Unicode(multilingual=True), 'validation_mail_body': Unicode(multilingual=True), 'invalidation_mail_subject': Unicode(multilingual=True), 'invalidation_mail_body': Unicode(multilingual=True), 'hide_address_on_registration': Boolean, 'user_is_enabled_when_register': Boolean, 'use_default_price': Boolean, 'show_ht_price': Boolean, 'phone_is_mandatory_on_registration': Boolean, 'lastname_is_mandatory_on_registration': Boolean} edit_widgets = [TextWidget('register_title', title=MSG(u'Register view title ?')), RTEWidget('register_body', title=MSG(u'Register body')), TextWidget('register_mail_subject', title=MSG(u'Register mail subject')), MultilineWidget('register_mail_body', title=MSG(u'Register mail body')), TextWidget('validation_mail_subject', title=MSG(u'Validation mail subject')), MultilineWidget('validation_mail_body', title=MSG(u'Validation mail body')), TextWidget('invalidation_mail_subject', title=MSG(u'Invalidation mail subject')), MultilineWidget('invalidation_mail_body', title=MSG(u'Invalidation mail body')), BooleanRadio('hide_address_on_registration', title=MSG(u'Hide address on registration')), BooleanRadio('user_is_enabled_when_register', title=MSG(u'User is enabled ?')), BooleanRadio('use_default_price', title=MSG(u'Use default price ?')), BooleanRadio('show_ht_price', title=MSG(u'Show HT price ?')), BooleanRadio('lastname_is_mandatory_on_registration', title=MSG(u'Lastname is mandatory on registration ?')), BooleanRadio('phone_is_mandatory_on_registration', title=MSG(u'Phone is mandatory on registration ?'))] __fixed_handlers__ = ShopFolder.__fixed_handlers__ + ['welcome'] @staticmethod def _make_resource(cls, folder, name, *args, **kw): # Create group ShopFolder._make_resource(cls, folder, name, *args, **kw) # Group schema cls = CustomerSchema cls._make_resource(cls, folder, '%s/schema' % name) # Welcome Page cls = WebPage cls._make_resource(cls, folder, '%s/welcome' % name, title={'en': u'Welcome'}, state='public') @classmethod def get_metadata_schema(cls): return merge_dicts(ShopFolder.get_metadata_schema(), cls.edit_schema) def get_dynamic_schema(self): schema = self.get_resource('schema') return schema.get_model_schema() def get_dynamic_widgets(self): schema = self.get_resource('schema') return schema.get_model_widgets() def get_register_mail_subject(self): subject = self.get_property('register_mail_subject') if subject: return subject return MSG(u"Inscription confirmation.").gettext() def get_register_mail_body(self): body = self.get_property('register_mail_body') if body: return body return MSG(u"Your inscription has been validated").gettext() def get_prefix(self): # Price prefix # XXX for future we should add group property to price if self.name == 'default': return '' return '%s-' % self.name
def get_quantity_in_stock(self): return self.get_property('stock-quantity') def get_reference(self): return self.get_property('reference') def get_price_impact(self, prefix): if prefix is None: prefix = self.parent.get_price_prefix() return self.get_property('%simpact_on_price' % prefix) def get_weight(self): base_weight = self.parent.get_property('weight') weight_impact = self.get_property('impact-on-weight') weight_value = self.get_property('weight-impact-value') if weight_impact == 'none': return base_weight elif weight_impact == 'increase': return base_weight + weight_value elif weight_impact == 'decrease': return base_weight - weight_value def get_document_types(self): return [] register_resource_class(Declination) register_field('declination_title', Unicode(is_indexed=True, is_stored=True)) register_field('is_default', Boolean(is_indexed=True))
class EnumerateTable_Handler(OrderedTableFile): record_properties = { 'name': String(unique=True, is_indexed=True), 'title': Unicode(mandatory=True, multiple=True), }
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))
def encode(cls, value): if value is None: return None return Unicode.encode(value['value'])
class PO_Edit(STLView): access = 'is_allowed_to_edit' title = MSG(u'Edit') template = '/ui/PO_edit.xml' schema = { 'msgctxt': Unicode, 'msgid': Unicode(mandatory=True), 'msgstr': Unicode(mandatory=True) } def get_namespace(self, resource, context): # Get the translation units (all but the header) handler = resource.handler units = handler.get_units() units.sort(key=lambda x: x.source) if units and ''.join(units[0].source) == '': units = units[1:] # Total, index, etc. total = len(units) index = context.get_form_value('messages_index', default='1') index = int(index) previous = max(index - 1, 1) next = min(index + 1, total) # Msgid and msgstr if units: unit = units[index - 1] msgctxt = u'' if unit.context is None else ''.join(unit.context) msgid = u''.join(unit.source) msgstr = u''.join(unit.target) else: msgctxt = None msgid = None msgstr = None # Ok uri = context.uri return { 'messages_total': total, 'messages_index': index, 'messages_first': uri.replace(messages_index='1'), 'messages_last': uri.replace(messages_index=str(total)), 'messages_previous': uri.replace(messages_index=str(previous)), 'messages_next': uri.replace(messages_index=str(next)), 'msgctxt': msgctxt, 'msgid': msgid, 'msgstr': msgstr } def action(self, resource, context, form): msgctxt = None if not form['msgctxt'] else form['msgctxt'] msgid = form['msgid'].replace('\r', '') msgstr = form['msgstr'].replace('\r', '') resource.handler.set_msgstr(msgid, msgstr, msgctxt) # Events, change context.database.change_resource(resource) # Ok context.message = messages.MSG_CHANGES_SAVED
class ShopModule_AReview_NewInstance(NewInstance): title = MSG(u'Add a review') query_schema = {'abspath': String} schema = freeze({ 'name': String, 'abspath': String, 'title': Unicode(mandatory=True), 'note': NoteEnumerate, 'description': Unicode(mandatory=True), 'advantages': Unicode, 'disadvantages': Unicode, 'images': FileDataType(multiple=False), 'recommended': RecommandationEnumerate, 'cgu': Boolean(mandatory=True) }) styles = ['/ui/modules/review/style.css'] @property def access(self): context = get_context() module = get_module(context.resource, ShopModule_Review.class_id) if module.get_property('must_be_authenticated_to_post'): return 'is_authenticated' return True def get_widgets(self, resource, context): cgu_description = MSG(u"I'm agree with the conditions general of use") if context.query['abspath']: # on review module review_module = resource else: # on product review review_module = get_module(resource, ShopModule_Review.class_id) cgu = review_module.get_resource('cgu') cgu_link = context.get_link(cgu) return [ HiddenWidget('abspath', title=None), TextWidget('title', title=MSG(u'Review title')), NoteWidget('note', title=MSG(u'Note'), has_empty_option=False), MultilineWidget('description', title=MSG(u'Your review')), TextWidget('advantages', title=MSG(u'Advantages')), TextWidget('disadvantages', title=MSG(u'Disadvantages')), FileWidget('images', title=MSG(u'Images')), SelectRadio('recommended', title=MSG(u'Recommendation'), has_empty_option=False, is_inline=True), BooleanCheckBox_CGU('cgu', title=MSG(u'Conditions of use'), link=cgu_link, description=cgu_description) ] def _get_current_reviews_query(self, context, form): if form['abspath']: product = context.root.get_resource(form['abspath']) abspath = product.get_canonical_path().resolve2('reviews') else: abspath = context.resource.get_canonical_path() query = AndQuery(PhraseQuery('parent_path', str(abspath)), PhraseQuery('format', 'shop_module_a_review')) return query def get_new_resource_name(self, form): context = get_context() query = self._get_current_reviews_query(context, form) search = context.root.search(query) if len(search): doc = search.get_documents(sort_by='name', reverse=True)[0] id_review = int(doc.name) + 1 else: id_review = 1 return str(id_review) def get_value(self, resource, context, name, datatype): if name == 'abspath': return context.query['abspath'] return NewInstance.get_value(self, resource, context, name, datatype) def _get_form(self, resource, context): form = NewInstance._get_form(self, resource, context) # Check if the user has already fill a review query = self._get_current_reviews_query(context, form) author_query = PhraseQuery('shop_module_review_author', context.user.name) query = AndQuery(query, author_query) if len(context.root.search(query)): raise FormError, ERROR(u'You already have filled a review.') # form = NewInstance._get_form(self, resource, context) # Check images image = form['images'] # XXX not yet multiple if image: filename, mimetype, body = image if mimetype.startswith('image/') is False: raise FormError, MSG_UNEXPECTED_MIMETYPE(mimetype=mimetype) return form def action(self, resource, context, form): name = self.get_new_resource_name(form) # Get product in which we have to add review if form['abspath']: product = context.root.get_resource(form['abspath']) # Does product has a container for reviews ? reviews = product.get_resource('reviews', soft=True) if reviews is None: cls = ShopModule_Reviews reviews = product.make_resource(cls, product, 'reviews') else: reviews = resource product = reviews.parent # Create the reviews cls = ShopModule_AReview child = cls.make_resource(cls, reviews, name) # The metadata metadata = child.metadata language = resource.get_content_language(context) # Anonymous, if user is not authenticated, the review is set # as anonymous. if context.user: metadata.set_property('author', context.user.name) # Workflow review_module = get_module(resource, ShopModule_Review.class_id) state = review_module.get_property('areview_default_state') metadata.set_property('title', form['title']) metadata.set_property('ctime', datetime.now()) metadata.set_property('state', state) metadata.set_property('remote_ip', context.get_remote_ip()) metadata.set_property('description', form['description'], language) metadata.set_property('note', int(form['note'])) metadata.set_property('recommended', form['recommended']) for key in ['advantages', 'disadvantages']: metadata.set_property(key, form[key]) # Add images image = form['images'] # XXX not yet multiple if image: image = review_module.create_new_image(context, image) metadata.set_property('images', str(child.get_pathto(image))) # XXX Alert webmaster if state == 'private': # XXX Add pending message. goto = context.get_link(product) message = MSG(u'Your review has been added.') else: goto = context.get_link(reviews) message = MSG(u'Review has been added') return context.come_back(message, goto=goto)
class ShopModule_AReport_NewInstance(NewInstance): title = MSG(u'Do a report') access = 'is_authenticated' schema = freeze({ 'name': String, 'title': Unicode, 'description': Unicode(mandatory=True), 'cgu': Boolean(mandatory=True) }) def get_widgets(self, resource, context): cgu_description = MSG(u"I'm agree with the conditions general of use") review_module = get_module(resource, ShopModule_Review.class_id) cgu = review_module.get_resource('cgu') cgu_link = context.get_link(cgu) return [ MultilineWidget('description', title=MSG(u'Your report')), BooleanCheckBox_CGU('cgu', title=MSG(u'Conditions of use'), link=cgu_link, description=cgu_description) ] def get_new_resource_name(self, form): context = get_context() root = context.root abspath = context.resource.get_canonical_path() query = AndQuery(PhraseQuery('parent_path', str(abspath)), PhraseQuery('format', 'shop_module_a_report')) search = root.search(query) id_report = len(search.get_documents()) + 1 return str('report_%s' % id_report) def action(self, resource, context, form): name = self.get_new_resource_name(form) cls = ShopModule_AReport child = cls.make_resource(cls, resource, name) # The metadata metadata = child.metadata language = resource.get_content_language(context) # Anonymous ? Accepted XXX if context.user: metadata.set_property('author', context.user.name) # Workflow metadata.set_property('ctime', datetime.now()) metadata.set_property('description', form['description'], language) metadata.set_property('remote_ip', context.get_remote_ip()) # Notification shop = get_shop(resource) subject = MSG(u'A report on a review has been made').gettext() body = MSG(u'Go on your backoffice to see it.').gettext() for to_addr in shop.get_property('order_notification_mails'): context.root.send_email(to_addr, subject, text=body) goto = context.get_link(resource.parent) message = MSG(u'Your report has been added') return context.come_back(message, goto=goto)
def join_content(data): data = ''.join(data) data = Unicode.decode(data, encoding) return data
class BaseCountriesZones(OrderedTableFile): record_properties = {'title': Unicode(mandatory=True), 'has_tax': Boolean}