def reset(self): self.properties = {} self.components = {} # A Catalog "in memory" fields = { '__uid__': String(is_key_field=True, is_stored=True, is_indexed=True), 'type': String(is_indexed=True), 'dtstart': DateTime(is_stored=True, is_indexed=True), 'dtend': DateTime(is_stored=True, is_indexed=True) } self.catalog = make_catalog(None, fields)
class ShopModule_Edit(DBResource_Edit): title = MSG(u'Edit') access = 'is_allowed_to_edit' base_schema = {'title': Unicode, 'timestamp': DateTime(readonly=True)} base_widgets = [timestamp_widget, title_widget] def get_schema(self, resource, context): return merge_dicts(self.base_schema, resource.item_schema) def get_widgets(self, resource, context): return self.base_widgets + resource.item_widgets def action(self, resource, context, form): # Check edit conflict self.check_edit_conflict(resource, context, form) if context.edit_conflict: return # Save changes title = form['title'] language = resource.get_content_language(context) resource.set_property('title', title, language=language) for key, datatype in resource.item_schema.items(): if getattr(datatype, 'multilingual', False) is True: resource.set_property(key, form[key], language) else: resource.set_property(key, form[key]) # Ok context.message = messages.MSG_CHANGES_SAVED
class End_Field(Datetime_Field): datatype = DateTime(time_is_required=False) stored = True title = MSG(u'End') required = True widget = Datetime_Field.widget(value_time_default=time(10, 0))
def get_datatype(self, name): # Table schema if name == 'ts': return DateTime(multiple=False) if name in self.schema: return self.schema[name] return String(multiple=True)
def get_record_datatype(self, name): # Record schema if name == 'ts': return DateTime(multiple=False) if name in self.record_properties: return self.record_properties[name] # FIXME Probably we should raise an exception here return String(multiple=True)
def _get_schema(self, resource, context): schema = {'timestamp': DateTime(readonly=True), 'referrer': URI} # Add schema from the resource for name in self.get_fields(): datatype = self._get_datatype(resource, context, name) # Special case: datetime if issubclass(datatype, DateTime): schema['%s_time' % name] = Time # Special case: birthdate elif issubclass(datatype, BirthDate): schema['%s_day' % name] = Days schema['%s_month' % name] = Months schema['%s_year' % name] = Years # Standard case schema[name] = datatype return schema
class Password_Field(Metadata_Field): datatype = Password_Datatype() parameters_schema = { 'algo': String(), 'salt': String(), 'date': DateTime() } widget = PasswordWidget def access(self, mode, resource): return mode == 'write' def set_value(self, resource, name, value, language=None, **kw): if value is not None: algo = 'sha256' value, salt = get_secure_hash(value, algo) kw['algo'] = algo kw['salt'] = salt kw['date'] = get_context().timestamp # super proxy = super(Password_Field, self) return proxy.set_value(resource, name, value, language, **kw)
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_id = 'orders' class_title = MSG(u'Orders') class_views = ['view'] # 'export'] class_version = '20091127' # Views view = OrdersView() def get_document_types(self): return [Order] ############################# # Export ############################# export = Export( export_resource=Order, access='is_allowed_to_edit', file_columns=['name', 'state', 'total_price', 'creation_datetime']) # Register catalog fields register_field('customer_id', String(is_indexed=True)) register_field('is_payed', Boolean(is_stored=True)) register_field('creation_datetime', DateTime(is_stored=True, is_indexed=True)) # Register resources register_resource_class(Order) register_resource_class(Orders) register_resource_class(OrdersProducts)
stock = Products_Stock() new_product = Product_NewProduct() def can_paste(self, source): return isinstance(source, Product) def get_document_types(self): return [] # Register fields register_field('reference', String(is_indexed=True, is_stored=True)) register_field('stock_quantity', Integer(is_indexed=True, is_stored=True)) register_field('manufacturer', String(is_indexed=True)) register_field('supplier', String(is_indexed=True, multiple=True)) register_field('product_model', String(is_indexed=True, is_stored=True)) register_field('has_images', Boolean(is_indexed=True, is_stored=True)) register_field('has_reduction', Boolean(is_indexed=True)) register_field('not_buyable_by_groups', String(is_indexed=True, multiple=True)) register_field('ctime', DateTime(is_stored=True, is_indexed=True)) register_field('data', Unicode(is_indexed=True)) register_field('ht_price', Decimal(is_indexed=True, is_stored=True)) register_field('ttc_price', Decimal(is_indexed=True, is_stored=True)) # XXX xapian can't sort decimal register_field('stored_price', Integer(is_indexed=False, is_stored=True)) register_field('stored_weight', Integer(is_indexed=False, is_stored=True)) # Register resources register_resource_class(Product) register_resource_class(Products)
class Datetime_Field(Metadata_Field): datatype = DateTime() widget = DatetimeWidget rest_type = 'datetime'
class ShopUser(User, DynamicFolder): class_version = '20100720' class_id = 'user' # Views manage = ShopUser_Manage() profile = ShopUser_Profile() public_profile = ShopUser_PublicProfile() edit_account = ShopUser_EditAccount() edit_group = ShopUser_EditGroup() viewbox = ShopUser_Viewbox() # Confirm registration confirm_registration = Shop_UserConfirmRegistration() send_confirmation_view = Shop_UserSendConfirmation() # Orders views orders_view = ShopUser_OrdersView() order_view = ShopUser_OrderView() # Addresses views addresses_book = Addresses_Book(access='is_allowed_to_edit') edit_address = ShopUser_EditAddress() add_address = ShopUser_AddAddress() add_image = CurrentFolder_AddImage() # Base schema / widgets base_schema = merge_dicts( User.get_metadata_schema(), lastname=Unicode(title=MSG(u'Lastname')), firstname=Unicode(title=MSG(u'Firstname')), email=Email(title=MSG(u'Email')), ctime=DateTime(title=MSG(u'Register date')), last_time=DateTime(title=MSG(u'Last connection')), gender=Civilite(title=MSG(u"Civility")), phone1=String(mandatory=True, title=MSG(u'Phone1')), phone2=String(title=MSG(u'Phone2'))) base_widgets = [ 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")) ] base_items = [{ 'name': 'account', 'title': MSG(u"Edit my account"), 'href': ';edit_account', 'img': '/ui/icons/48x48/card.png' }, { 'name': 'preferences', 'title': MSG(u'Edit my preferences'), 'href': ';edit_preferences', 'img': '/ui/icons/48x48/preferences.png' }, { 'name': 'password', 'title': MSG(u'Edit my password'), 'href': ';edit_password', 'img': '/ui/icons/48x48/lock.png' }, { 'name': 'addresses', 'title': MSG(u'My addresses book'), 'href': ';addresses_book', 'img': '/ui/icons/48x48/tasks.png' }, { 'name': 'orders', 'title': MSG(u'Orders history'), 'href': ';orders_view', 'img': '/ui/shop/images/bag_green.png' }] @staticmethod def _make_resource(cls, folder, name, *args, **kw): ctime = datetime.now() User._make_resource(cls, folder, name, ctime=ctime, *args, **kw) base_class_views = [ 'profile', 'addresses_book', 'edit_account', 'orders_view', 'edit_preferences', 'edit_password' ] @property def class_views(self): context = get_context() # Back-Office hostname = context.uri.authority if hostname[:6] == 'admin.': return ['manage'] + self.base_class_views if hostname[:6] == 'www.aw': # XXX Add a configurator for public profil return ['public_profile'] + self.base_class_views return self.base_class_views @classmethod def get_metadata_schema(cls): return merge_dicts(DynamicFolder.get_metadata_schema(), cls.base_schema, is_enabled=Boolean(title=MSG(u'Enabled')), user_group=UserGroup_Enumerate(title=MSG(u'Group'))) @classmethod def get_dynamic_schema(cls): context = get_context() self = context.resource if (hasattr(context, 'view') and issubclass(context.view.__class__, RegisterForm)): group = context.view.get_group(context) return group.get_dynamic_schema() if not isinstance(self, User): self = context.user if self is None: group = context.site_root.get_resource('shop/groups/default') else: group = self.get_group(context) # By default we use default group if group is None: group = context.site_root.get_resource('shop/groups/default') return group.get_dynamic_schema() @classmethod def get_dynamic_widgets(cls): context = get_context() self = context.resource if issubclass(context.view.__class__, RegisterForm): group = context.view.get_group(context) return group.get_dynamic_widgets() if not isinstance(self, User): self = context.user if self is None: return [] group = self.get_group(context) return group.get_dynamic_widgets() def _get_catalog_values(self): values = User._get_catalog_values(self) values['ctime'] = self.get_property('ctime') values['last_time'] = self.get_property('last_time') values['user_group'] = str(self.get_property('user_group')) values['is_enabled'] = self.get_property('is_enabled') return values def get_public_title(self): try: return self.get_dynamic_property('pseudo') except: # XXX Fix that bug return MSG(u'Unknow') def get_document_types(self): return [] def save_form(self, schema, form): dynamic_schema = self.get_dynamic_schema() metadata_schema = self.get_metadata_schema() for key in schema: if key in ['password', 'user_must_confirm']: continue elif (key not in metadata_schema and key not in dynamic_schema): continue value = form[key] if value is None: self.del_property(value) continue datatype = schema[key] if issubclass(datatype, (String, Unicode)): value = value.strip() self.set_property(key, value) confirmation_txt = MSG( u"To finalize your inscription you have to confirm your identity " u"by clicking this link:" u"\n" u"\n {uri}\n" u"\n" u"(Your identity confirmation key is {key})") def send_register_confirmation(self, context, need_email_validation=False): # Get group group = self.get_group(context) # Get mail subject and body subject = group.get_register_mail_subject() text = group.get_register_mail_body() # Registration need validation ? if need_email_validation: key = generate_password(30) self.set_property('user_must_confirm', key) # Build the confirmation link confirm_url = deepcopy(context.uri) path = '/users/%s/;confirm_registration' % self.name confirm_url.path = Path(path) confirm_url.query = {'key': key, 'username': self.get_login_name()} confirm_url = str(confirm_url) text += '\n\n' text += self.confirmation_txt.gettext(uri=confirm_url, key=key) # Send mail context.root.send_email(to_addr=self.get_property('email'), subject=subject, text=text) def get_group(self, context): user_group = self.get_property('user_group') return context.root.get_resource(user_group) def to_text(self): texts = [] for key, datatype in (self.get_dynamic_schema().items() + self.get_metadata_schema().items()): if key == 'password': continue value = self.get_property(key) if value: value = datatype.encode(value) value = unicode(value, 'utf-8') texts.append(value) return u'\n'.join(texts) def get_namespace(self, context): root = context.root # Get dynamic user values dynamic_user_value = ResourceDynamicProperty() dynamic_user_value.schema = self.get_dynamic_schema() dynamic_user_value.resource = self # Module shop_module = ModuleLoader() shop_module.context = context shop_module.here = self # Get modules items modules_items = [] search = context.root.search(is_shop_user_module=True) for brain in search.get_documents(): shop_user_module = root.get_resource(brain.abspath) modules_items.append({ 'name': shop_user_module.element_name, 'title': shop_user_module.element_title, 'href': shop_user_module.element_name, 'img': shop_user_module.class_icon48 }) # Ctime ctime = self.get_property('ctime') accept = context.accept_language # ACLS ac = self.get_access_control() is_authenticated = ac.is_authenticated(context.user, self) is_owner = context.user is not None and context.user.name == self.name # Build namespace return { 'name': self.name, 'link': context.get_link(self), 'module': shop_module, 'dynamic_user_value': dynamic_user_value, 'is_owner': is_owner, 'is_authenticated': is_authenticated, 'ctime': format_datetime(ctime, accept) if ctime else None, # XXX Why ? 'items': self.base_items + modules_items } ############################# # Api ############################# def send_confirm_url(self, context, email, subject, text, view): # XXX We override send_confirm_url to send mail # without setting subject with host, to use shop_uri # and not backoffice_uri (Since webmaster click from backoffice uri) # and to use good from_addr # Set the confirmation key if self.has_property('user_must_confirm'): key = self.get_property('user_must_confirm') else: key = generate_password(30) self.set_property('user_must_confirm', key) # Build the confirmation link shop = get_shop(context.resource) base_uri = shop.get_property('shop_uri') confirm_url = get_reference(base_uri) path = '/users/%s/%s' % (self.name, view) confirm_url.path = Path(path) confirm_url.query = {'key': key, 'username': self.get_login_name()} confirm_url = str(confirm_url) text = text.gettext(uri=confirm_url, key=key) # Get from_addr site_root = context.site_root if site_root.get_property('emails_from_addr'): user_name = site_root.get_property('emails_from_addr') user = self.get_resource('/users/%s' % user_name) from_addr = user.get_title(), user.get_property('email') else: from_addr = context.server.smtp_from # Subject subject = u'[%s] %s' % (base_uri, subject.gettext()) # Send email context.root.send_email(email, subject, from_addr=from_addr, text=text, subject_with_host=False) ############################### # Computed schema ############################### computed_schema = { 'nb_orders': Integer(title=MSG(u'Nb orders (even cancel)')), 'address': Unicode(title=MSG(u'Last known user address')) } @property def nb_orders(self): # XXX Orders states root = self.get_root() queries = [ PhraseQuery('format', 'order'), PhraseQuery('customer_id', self.name) ] return len(root.search(AndQuery(*queries))) @property def address(self): # XXX We should have a default address ? context = get_context() shop = get_shop(context.resource) addresses_h = shop.get_resource('addresses').handler records = addresses_h.search(user=self.name) if len(records) == 0: return None record = records[0] addresse = addresses_h.get_record_namespace(record.id) addr = u'' for key in ['address_1', 'address_2', 'zipcode', 'town', 'country']: try: addr += u'%s ' % addresse[key] except Exception: # XXX Why ? addr += u'XXX' return addr
# Set the email and paswword if email is not None: user.set_property('email', email) if password is not None: user.set_password(password) # Set default group root = context.root query = [ PhraseQuery('format', 'user-group'), PhraseQuery('name', 'default') ] search = root.search(AndQuery(*query)) documents = search.get_documents() group = documents[0] group = root.get_resource(group.abspath) user.set_property('user_group', str(group.get_abspath())) user_is_enabled = group.get_property('user_is_enabled_when_register') user.set_property('is_enabled', user_is_enabled) # Return the user return user register_resource_class(ShopUser) register_resource_class(ShopUserFolder) register_resource_class(Customers) register_resource_class(AuthentificationLogs) register_field('last_time', DateTime(is_stored=True)) register_field('user_group', String(is_indexed=True)) register_field('is_enabled', Boolean(is_indexed=True))