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), }
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, }
class PaymentWay_Configure(DBResource_Edit): access = 'is_admin' schema = { 'title': Unicode(mandatory=True, multilingual=True), 'logo': ImagePathDataType(mandatory=True, multilingual=True), 'data': XHTMLBody(mandatory=True, multilingual=True), 'only_this_groups': UserGroup_Enumerate(multiple=True), 'enabled': Boolean(mandatory=True) } widgets = [ TextWidget('title', title=MSG(u'Title')), ImageSelectorWidget('logo', title=MSG(u'Logo')), BooleanRadio('enabled', title=MSG(u'Enabled ?')), RTEWidget('data', title=MSG(u"Description")), SelectWidget('only_this_groups', title=MSG(u"Only for this groups")) ] submit_value = MSG(u'Edit configuration') def get_value(self, resource, context, name, datatype): language = resource.get_content_language(context) return resource.get_property(name, language=language) def action(self, resource, context, form): language = resource.get_content_language(context) for key, datatype in self.schema.items(): if getattr(datatype, 'multilingual', False): resource.set_property(key, form[key], language=language) else: resource.set_property(key, form[key]) return context.come_back(messages.MSG_CHANGES_SAVED, goto='./')
def get_metadata_schema(cls): return merge_dicts(ShopFolder.get_metadata_schema(), data=XHTMLBody(multilingual=True), title=Unicode(multilingual=True), enabled=Boolean(default=True), only_this_groups=UserGroup_Enumerate(multiple=True), logo=ImagePathDataType(multilingual=True))
def get_metadata_schema(cls): schema = ShopFolder.get_metadata_schema() schema.update(WorkflowAware.get_metadata_schema()) schema['total_price'] = Decimal(title=MSG(u'Total price')) schema['shipping_price'] = Decimal schema['total_weight'] = Decimal schema['creation_datetime'] = ISODateTime(title=MSG(u'Creation date')) schema['customer_id'] = Users_Enumerate schema['payment_mode'] = PaymentWaysEnumerate schema['shipping'] = ShippingWaysEnumerate schema['delivery_address'] = Integer schema['bill_address'] = Integer # States schema['is_payed'] = Boolean(default=False) schema['is_sent'] = Boolean(default=False) return schema
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 }
class ITWSHOPConfig(ConfigFile): schema = { 'url': String(default=''), 'source_language': LanguageTag(default=('en', 'EN')), 'target_languages': Tokens(default=(('en', 'EN'), )), 'skin_path': String(default=''), 'show_language_title': Boolean(default=False) }
class PaymentWayBaseTable(BaseTable): record_properties = { 'ref': String(is_indexed=True, is_stored=True), 'user': String(is_indexed=True), 'state': Boolean(is_indexed=True,), 'amount': Decimal(title=MSG(u'Payment amount')), 'resource_validator': String, 'description': Unicode(title=MSG(u'Payment description'))}
def rest(self): rest = {'type': self.rest_type} # From the datatype datatype = self.get_datatype() for key in 'multiple', 'multilingual', 'indexed', 'stored': value = getattr(datatype, key) rest[key] = Boolean.encode(value) # Default value default = self.get_default() if default is not None: rest['default'] = datatype.encode(default) # Other for key in 'required', 'readonly': value = getattr(self, key) rest[key] = Boolean.encode(value) # Ok return rest
class DBResource_GetImage(DBResource_GetFile): query_schema = { 'name': String, 'width': Integer, 'height': Integer, 'fit': Boolean(default=False), 'lossy': Boolean(default=False) } def GET(self, resource, context): field_name = self.get_field_name(context) handler = self.get_handler(resource, field_name) 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/icons/48x48/image.png') data = default.to_str() format = 'png' # Headers context.set_content_type('image/%s' % format) # filename = resource.get_value('filename') # if filename: # context.set_content_disposition('inline', filename) # Ok return data
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 actions: columns_ns.append({'is_checkbox': True}) elif title is None: # Type: nothing continue elif not sortable: # Type: nothing or not sortable columns_ns.append({ 'is_checkbox': False, 'title': title, 'href': None }) else: # Type: normal kw = {'sort_by': name} if name == sort_by: col_reverse = (not reverse) order = 'up' if reverse else 'down' else: col_reverse = False order = 'none' kw['reverse'] = Boolean.encode(col_reverse) columns_ns.append({ 'is_checkbox': False, 'title': title, 'order': order, 'href': context.uri.replace(**kw), })
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 actions: columns_ns.append({'is_checkbox': True}) elif title is None: # Type: nothing continue elif not sortable: # Type: nothing or not sortable columns_ns.append({ 'is_checkbox': False, 'title': title, 'href': None}) else: # Type: normal kw = {'sort_by': name} if name == sort_by: col_reverse = (not reverse) order = 'up' if reverse else 'down' else: col_reverse = False order = 'none' kw['reverse'] = Boolean.encode(col_reverse) columns_ns.append({ 'is_checkbox': False, 'title': title, 'order': order, 'href': context.uri.replace(**kw), })
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 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}
class LoginView(STLView): access = True title = MSG(u'Login') template = '/ui/ikaaro/base/login.xml' meta = [('robots', 'noindex, follow', None)] query_schema = {'loginname': String(), 'no_password': Boolean()} schema = { 'loginname': String(mandatory=True), 'password': String(), 'no_password': Boolean() } def GET(self, resource, context): if context.user: msg = MSG(u'You are already connected') goto = str(context.user.abspath) return context.come_back(msg, goto) return super(LoginView, self).GET(resource, context) def POST(self, resource, context): if context.status == 401: # Don't submit login with data from another form return self.GET return super(LoginView, self).POST(resource, context) def get_value(self, resource, context, name, datatype): if name == 'loginname': return context.query['loginname'] proxy = super(LoginView, self) return proxy.get_value(resource, context, name, datatype) def get_namespace(self, resource, context): namespace = super(LoginView, self).get_namespace(resource, context) namespace['no_password'] = context.query['no_password'] # Register user = context.user register = context.root.is_allowed_to_register(user, resource) namespace['register'] = register # Login name cls = context.database.get_resource_class('user') field = cls.get_field(cls.login_name_property) namespace['login_name_title'] = field.title # Ok return namespace def action(self, resource, context, form): # Get the user loginname = form['loginname'].strip() user = context.root.get_user_from_login(loginname) # Case 1: Forgotten password if form['no_password']: # 1.1 Send email if user: email = user.get_value('email') if user.get_value('user_state') == 'inactive': email_id = None # TODO else: user.update_pending_key() email_id = 'forgotten-password-ask-for-confirmation' else: email_id = None # TODO Which is the email address? if email_id: send_email(email_id, context, email, user=user) # 1.2 Show message (we show the same message even if the user # does not exist, because privacy wins over usability) path = '/ui/ikaaro/website/forgotten_password.xml' handler = context.get_template(path) return stl(handler) # Case 2: Login if user is None: context.message = MSG_LOGIN_WRONG_NAME_OR_PASSWORD return error = user._login(form['password'], context) if error: context.message = error return return self.get_goto(user) def get_goto(self, user): context = self.context # Check if user account is completed for name, field in user.get_fields(): if field.required and user.get_value(name) is None: msg = MSG(u'You must complete your account informations') goto = '/users/%s/;edit_account' % user.name return context.come_back(msg, goto) # Come back referrer = context.get_referrer() if referrer is None: goto = get_reference('./') else: path = get_uri_path(referrer) if path.endswith(';login') or path.endswith(';register'): goto = get_reference('./') else: goto = referrer return context.come_back(INFO(u"Welcome!"), goto)
context.message = INFO(u'Transition done.') action_cancel_order_schema = {} def action_cancel_order(self, resource, context, form): try: resource.make_transition('open_to_cancel', None) except WorkflowError, excp: log_error(excp.message, domain='ikaaro') context.message = ERROR(unicode(excp.message, 'utf-8')) return context.message = INFO(u'Order has been canceled') action_add_message_schema = { 'message': Unicode(mandatory=True), 'private': Boolean(mandatory=True) } def action_add_message(self, resource, context, form): messages = resource.get_resource('messages') messages.add_new_record({ 'author': context.user.name, 'private': form['private'], 'message': form['message'], 'seen': True }) if form['private'] is False: resource.notify_new_message(form['message'], context) context.message = INFO(u'Your message has been sent') action_change_message_state_schema = {
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 OrdersView(SearchTableFolder_View): access = 'is_admin' title = MSG(u'Orders') # Configuration table_actions = [MergeOrderButton, MergeBillButton, RegeneratePDFButton] context_menus = [] table_columns = [ ('checkbox', None), ('name', None), ('nb_msg', img_mail), ('customer_id', MSG(u'Customer')), ('state', MSG(u'State')), ('total_price', MSG(u'Total price')), ('creation_datetime', MSG(u'Date and Time')), ('order_pdf', None), ('bill', None), ] query_schema = merge_dicts(Folder_BrowseContent.query_schema, batch_size=Integer(default=50), sort_by=String(default='creation_datetime'), reverse=Boolean(default=True), reference=Integer) batch_msg1 = MSG(u"There's one order.") batch_msg2 = MSG(u"There are {n} orders.") search_schema = { 'name': String, 'workflow_state': OrderStates_Enumerate(default=['payment_ok'], multiple=True) } search_widgets = [ TextWidget('name', title=MSG(u'Référence')), OrdersWidget('workflow_state', title=MSG(u'State')) ] def get_item_value(self, resource, context, item, column): item_brain, item_resource = item if column == 'name': state = item_brain.workflow_state href = context.resource.get_pathto(item_resource) name = item_resource.get_reference() return XMLParser(numero_template % (states_color[state], href, name)) elif column == 'state': state = item_brain.workflow_state state_title = states[state].gettext().encode('utf-8') href = context.resource.get_pathto(item_resource) return XMLParser(numero_template % (states_color[state], href, state_title)) elif column == 'total_price': price = item_resource.get_property(column) return format_price(price) elif column == 'order_pdf': if item_resource.get_resource('order', soft=True) is None: return img = """ <a href="./%s/order/;download"> <img src="/ui/icons/16x16/select_none.png"/> </a> """ % item_brain.name return XMLParser(img) elif column == 'bill': if item_resource.get_resource('bill', soft=True) is None: return img = """ <a href="./%s/bill/;download"> <img src="/ui/icons/16x16/pdf.png"/> </a> """ % item_brain.name return XMLParser(img) proxy = super(OrdersView, self) return proxy.get_item_value(resource, context, item, column) def get_items(self, resource, context, *args): abspath = str(resource.get_canonical_path()) query = [ PhraseQuery('parent_path', abspath), PhraseQuery('format', 'order') ] return SearchTableFolder_View.get_items(self, resource, context, query=query) def action_merge_pdfs(self, resource, context, form, pdf_name): context.set_content_type('application/pdf') context.set_content_disposition('attachment; filename="Document.pdf"') list_pdf = [] for id in form['ids']: pdf = resource.get_resource('%s/%s' % (id, pdf_name), soft=True) if pdf is None: continue path = context.database.fs.get_absolute_path(pdf.handler.key) list_pdf.append(path) # Join pdf pdf = join_pdfs(list_pdf) return pdf def action_merge_bill(self, resource, context, form): return self.action_merge_pdfs(resource, context, form, 'bill') def action_merge_orders(self, resource, context, form): return self.action_merge_pdfs(resource, context, form, 'order') def action_regenerate_pdf(self, resource, context, form): for order_id in form['ids']: order = resource.get_resource(order_id) order.generate_pdf_bill(context) order.generate_pdf_order(context) return context.come_back(MSG(u'PDF has been regenerated'))
class Folder_BrowseContent(BrowseForm): access = 'is_allowed_to_view' title = MSG(u'Browse Content') context_menus = [] query_schema = merge_dicts(BrowseForm.query_schema, sort_by=String(default='mtime'), reverse=Boolean(default=True)) schema = {'ids': String(multiple=True, mandatory=True)} # Search Form search_widgets = [ TextWidget('text', title=MSG(u'Text')), SelectWidget('format', title=MSG(u'Type')) ] search_schema = {'text': Unicode, 'format': SearchTypes_Enumerate} # Table table_columns = [('checkbox', None), ('icon', None), ('abspath', MSG(u'Path')), ('title', MSG(u'Title')), ('format', MSG(u'Type')), ('mtime', MSG(u'Last Modified')), ('last_author', MSG(u'Last Author'))] table_actions = [ Remove_BrowseButton, RenameButton, CopyButton, CutButton, PasteButton, ZipButton ] def search_content_only(self, resource, context): return resource.is_content def get_scripts(self, context): scripts = [] if self.search_widgets: for widget in self.search_widgets: for script in widget.scripts: if script not in scripts: scripts.append(script) return scripts def get_styles(self, context): styles = [] if self.search_widgets: for widget in self.search_widgets: for style in widget.styles: if style not in styles: styles.append(style) return styles depth = None base_classes = None def get_items_query(self, resource, context): # Search in subtree query = get_base_path_query(resource.abspath, max_depth=self.depth) # Base classes base_classes = self.base_classes if base_classes is not None: base_classes_query = OrQuery( *[PhraseQuery('base_classes', x) for x in base_classes]) query = AndQuery(query, base_classes_query) # Exclude non-content if self.search_content_only(resource, context) is True: query = AndQuery(query, PhraseQuery('is_content', True)) return query def get_search_query(self, resource, context): query = AndQuery() form = context.query for key, datatype in self.search_schema.items(): value = form[key] if value is None or value == '': continue # Special case: search on text, title and name AS AndQuery if key == 'text': text_query = [] value = value.split(' ') for v in value: t_query = OrQuery(TextQuery('title', v), TextQuery('text', v), PhraseQuery('name', v)) text_query.append(t_query) if len(text_query) == 1: text_query = text_query[0] else: text_query = AndQuery(*text_query) query.append(text_query) # Special case: type elif key == 'format': squery = [PhraseQuery('format', x) for x in value.split(',')] squery = squery[0] if len(squery) == 1 else OrQuery(*squery) query.append(squery) # Multiple elif datatype.multiple is True: query.append(OrQuery(*[PhraseQuery(key, x) for x in value])) # Singleton else: if value is False: # FIXME No value means False in xapian query.append(NotQuery(PhraseQuery(key, True))) else: query.append(PhraseQuery(key, value)) return query def get_items(self, resource, context): # Base query query = self.get_items_query(resource, context) # Search form search_query = self.get_search_query(resource, context) if search_query: query = AndQuery(query, search_query) # Search return context.search(query) def _get_key_sorted_by_unicode(self, field): def key(item): return getattr(item, field).lower().translate(transmap) return key def _get_key_sorted_by_user(self, field): get_user_title = self.context.root.get_user_title def key(item, cache={}): user = getattr(item, field) if user in cache: return cache[user] if user: title = get_user_title(user) value = title.lower().translate(transmap) else: value = None cache[user] = value return value return key def get_key_sorted_by_title(self): return self._get_key_sorted_by_unicode('title') def get_key_sorted_by_format(self): database = self.context.database def key(item, cache={}): format = item.format if format in cache: return cache[format] cls = database.get_resource_class(format) value = cls.class_title.gettext().lower().translate(transmap) cache[format] = value return value return key def get_key_sorted_by_last_author(self): return self._get_key_sorted_by_user('last_author') def sort_and_batch(self, resource, context, results): start = context.query['batch_start'] size = context.query['batch_size'] sort_by = context.query['sort_by'] reverse = context.query['reverse'] if sort_by is None: get_key = None else: get_key = getattr(self, 'get_key_sorted_by_' + sort_by, None) # Case 1: Custom but slower sort algorithm if get_key: items = results.get_documents() items.sort(key=get_key(), reverse=reverse) if size: items = items[start:start + size] elif start: items = items[start:] database = resource.database return [database.get_resource(x.abspath) for x in items] # Case 2: Faster Xapian sort algorithm items = results.get_resources(sort_by, reverse, start, size) return list(items) def get_item_value(self, resource, context, item, column): if column == 'checkbox': # checkbox parent = item.parent if parent is None: return None if item.name in parent.__fixed_handlers__: return None resource_id = str(item.abspath) return resource_id, False elif column == 'icon': # icon path_to_icon = item.get_resource_icon(16) if not path_to_icon: return None if path_to_icon.startswith(';'): path_to_icon = Path('%s/' % item.name).resolve(path_to_icon) return path_to_icon elif column == 'abspath': # Name resource_id = str(item.abspath) view = item.get_view(None) if view is None: return resource_id return resource_id, context.get_link(item) elif column == 'format': # Type return item.class_title.gettext() elif column == 'mtime': # Last Modified mtime = item.get_value('mtime') if mtime: return context.format_datetime(mtime) return None elif column == 'last_author': # Last author author = item.get_value('last_author') return context.root.get_user_title(author) if author else None elif column == 'row_css': return None # Default return item.get_value_title(column) ####################################################################### # Form Actions ####################################################################### def action_remove(self, resource, context, form): ids = form['ids'] # Remove resources removed = [] referenced = [] not_removed = [] user = context.user root = context.root # We sort and reverse ids in order to # remove the childs then their parents ids.sort() ids.reverse() for name in ids: child = resource.get_resource(name, soft=True) if child and root.is_allowed_to_remove(user, child): # Remove resource try: resource.del_resource(name) except ConsistencyError: referenced.append(name) continue removed.append(name) else: not_removed.append(name) message = [] if removed: resources = ', '.join(removed) msg = messages.MSG_RESOURCES_REMOVED(resources=resources) message.append(msg) if referenced: items = [] for name in referenced: item = resource.get_resource(name) view = item.get_view('backlinks') if context.is_access_allowed(item, view): items.append({ 'title': item.get_title(), 'href': '%s/;backlinks' % item.abspath }) msg = messages.MSG_RESOURCES_REFERENCED_HTML(resources=items) message.append(msg) if not_removed: resources = ', '.join(not_removed) msg = messages.MSG_RESOURCES_NOT_REMOVED(resources=resources) message.append(msg) if not removed and not referenced and not not_removed: message.append(messages.MSG_NONE_REMOVED) context.message = message def action_rename(self, resource, context, form): ids = form['ids'] # Filter names which the authenticated user is not allowed to move root = context.root user = context.user # Check if file to rename exists & user is allowed to move paths = [] for x in ids: r_to_rename = resource.get_resource(x, soft=True) if r_to_rename and root.is_allowed_to_move(user, r_to_rename): paths.append(x) # Check input data if not paths: context.message = messages.MSG_NONE_SELECTED return # FIXME Hack to get rename working. The current user interface forces # the rename_form to be called as a form action, hence with the POST # method, but it should be a GET method. Maybe it will be solved after # the needed folder browse overhaul. ids_list = '&'.join(['ids=%s' % x for x in paths]) uri = '%s/;rename?%s' % (context.get_link(resource), ids_list) return get_reference(uri) def action_copy(self, resource, context, form): ids = form['ids'] # Filter names which the authenticated user is not allowed to copy root = context.root user = context.user names = [ x for x in ids if root.is_allowed_to_copy(user, resource.get_resource(x)) ] # Check input data if not names: context.message = messages.MSG_NONE_SELECTED return abspath = resource.abspath cp = (False, [str(abspath.resolve2(x)) for x in names]) cp = CopyCookie.encode(cp) context.set_cookie('ikaaro_cp', cp, path='/') # Ok context.message = messages.MSG_COPIED def action_cut(self, resource, context, form): ids = form['ids'] # Filter names which the authenticated user is not allowed to move root = context.root user = context.user # Check if file to cut exists & user is allowed to move names = [] for x in ids: r_to_move = resource.get_resource(x, soft=True) if r_to_move and root.is_allowed_to_move(user, r_to_move): names.append(x) # Check input data if not names: context.message = messages.MSG_NONE_SELECTED return abspath = resource.abspath cp = (True, [str(abspath.resolve2(x)) for x in names]) cp = CopyCookie.encode(cp) context.set_cookie('ikaaro_cp', cp, path='/') context.message = messages.MSG_CUT action_paste_schema = {} def action_paste(self, resource, context, form): # Check there is something to paste cut, paths = context.get_cookie('ikaaro_cp', datatype=CopyCookie) if len(paths) == 0: context.message = messages.MSG_NO_PASTE return # Paste target = resource pasted = [] not_allowed = [] for path in paths: # Check the source resource still exists source = target.get_resource(path, soft=True) if source is None: continue # If cut&paste in the same place, do nothing if cut is True: if target == source.parent: pasted.append(source.name) continue name = generate_name(source.name, target.get_names(), '_copy_') if cut is True: # Cut&Paste try: target.move_resource(path, name) except ConsistencyError: not_allowed.append(source.name) continue else: pasted.append(name) else: # Copy&Paste try: target.copy_resource(path, name) except ConsistencyError: not_allowed.append(source.name) continue else: pasted.append(name) # Cut, clean cookie if cut is True: context.del_cookie('ikaaro_cp') message = [] if pasted: resources = ', '.join(pasted) message.append(messages.MSG_RESOURCES_PASTED(resources=resources)) if not_allowed: resources = ', '.join(not_allowed) msg = messages.MSG_RESOURCES_NOT_PASTED(resources=resources) message.append(msg) context.message = message def action_zip(self, resource, context, form): names = sorted(form['ids'], reverse=True) data = resource.export_zip(names) # Content-Type & Content-Disposition context.set_content_type('application/zip') filename = 'archive.zip' context.set_content_disposition('inline', filename) # Ok return data
def get_query_schema(self): return { 'sort_by': String(default='title'), 'reverse': Boolean(default=False), 'reference': Integer }
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 SystemPay(PaymentWay): class_id = 'systempay' class_title = MSG(u'Paybox payment Module') class_description = MSG(u'Secured payment paybox') # Views class_views = ['configure', 'payments'] logo = '/ui/backoffice/payments/paybox/images/logo.png' # payment_table = PayboxTable # Views configure = PaymentWay_Configure() # confirm_payment = Paybox_ConfirmPayment() # end = Paybox_End() # # # Admin order views # order_view = Paybox_RecordView # order_edit_view = Paybox_Record_Edit # Schema base_schema = { 'PBX_SITE': StringFixSize(size=7), 'PBX_RANG': StringFixSize(size=2), 'PBX_IDENTIFIANT': String, 'PBX_DIFF': StringFixSize(size=2), 'real_mode': Boolean(default=False) } @classmethod def get_metadata_schema(cls): schema = PaymentWay.get_metadata_schema() # Paybox account configuration schema.update(cls.base_schema) return schema test_configuration = { 'PBX_SITE': 1999888, 'PBX_RANG': 99, 'PBX_IDENTIFIANT': 2 } uri = 'https://systempay.cyberpluspaiement.com/vads-payment/' def get_signature(self, kw): # Build signature signature = '' for key in [ 'version', 'site_id', 'ctx_mode', 'trans_id', 'trans_date', 'validation_mode', 'capture_delay' ]: signature += '%s+' % kw[key] # Add key signature += '1122334455667788' # SHA1 sign = sha1(signature) print 'SIGNATURE ', signature print 'SIGNATURE ', sign.hexdigest() return sign.hexdigest() def _show_payment_form(self, context, payment): kw = { 'amout': '25', 'currency': '978', # Euros, 'capture_delay': '3', 'ctx_mode': 'TEST', 'payment_cards': 'AMEX;CB;MASTERCARD;VISA', 'payment_config': 'SINGLE', 'site_id': '12345678', 'trans_date': '20100303105332', 'url_return': 'http://shop:8080', 'trans_id': '1', 'validation_mode': '0', #Validation automatique 'version': 'V1' } # Get signature kw['signature'] = self.get_signature(kw) # Return URI uri = get_reference(self.uri) uri.query = kw print '======>', uri return context.uri.resolve(uri)
def get_query_schema(self): return merge_dicts(SearchTable_View.get_query_schema(self), batch_size=Integer(default=500), reverse=Boolean(default=False), sort_by=String(default='title'))
# Import from standard library from decimal import Decimal as decimal # Import from itools from itools.core import merge_dicts from itools.datatypes import Decimal, Boolean from itools.gettext import MSG # Import from ikaaro from ikaaro.forms import BooleanRadio, TextWidget # Import from shop from shop.payments.payment_way_views import PaymentWay_Configure deposit_schema = { 'percent': Decimal(default=decimal('100.0'), mandatory=True), 'pay_tax': Boolean(mandatory=True) } deposit_widgets = [ TextWidget('percent', title=MSG(u'Deposit amount (in %)')), BooleanRadio('pay_tax', title=MSG(u'Pay deposite with tax ?')) ] class Deposit_Configure(PaymentWay_Configure): title = MSG(u'Configure deposite module') schema = merge_dicts(PaymentWay_Configure.schema, deposit_schema) widgets = PaymentWay_Configure.widgets + deposit_widgets
def test_Boolean(self): for x in [True, False]: data = Boolean.encode(x) self.assertEqual(x, Boolean.decode(data))
class ConfigAccess_Browse(Folder_BrowseContent): query_schema = merge_dicts(Folder_BrowseContent.query_schema, sort_by=String(default='abspath'), reverse=Boolean(default=False)) # Search form _columns = ['group', 'permission', 'search_path', 'search_format'] @proto_property def _search_fields(self): cls = AccessRule for name in self._columns: yield name, cls.get_field(name) @proto_property def search_widgets(self): widgets = [] for name, field in self._search_fields: if is_prototype(field, Select_Field): widget = field.widget widgets.append( widget(name, has_empty_option=True, title=field.title)) return widgets @proto_property def search_schema(self): schema = {} for name, field in self._search_fields: if is_prototype(field, Select_Field): schema[name] = field.datatype(default=None) return schema @proto_property def table_columns(self): columns = [('checkbox', None), ('abspath', MSG(u'Num.'))] for name, field in self._search_fields: columns.append((name, field.title)) return columns table_actions = [Remove_BrowseButton] def get_key_sorted_by_abspath(self): def key(item): return int(item.name) return key def get_key_sorted_by_group(self): def key(item, cache={}): title = Groups_Datatype.get_value(item.group) if isinstance(title, MSG): title = title.gettext() return title.lower() return key def get_item_value(self, resource, context, item, column): if column == 'search_path': path = item.get_value('search_path') if not path or not resource.get_resource(path, soft=True): return None depth = item.get_value('search_path_depth') if depth == '0': title = path else: title = '%s (%s)' % (path, depth) return title, path proxy = super(ConfigAccess_Browse, self) value = proxy.get_item_value(resource, context, item, column) if column == 'group': group = item.get_value('group') if group[0] == '/': return value, group return value
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)
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
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)
def get_query_schema(self): return merge_dicts(SearchTableFolder_View.get_query_schema(self), reverse=Boolean(default=True), sort_by=String(default='ctime'))
def get_query_schema(self): return merge_dicts(Table_View.get_query_schema(self), reverse=Boolean(default=True), sort_by=String(default='ts'))