def bindings(self): return ( Binding( 'rights', _("Přístupová práva"), self._spec_name('Rights'), condition=lambda r: pd.EQ('menu_item_id', r['menu_item_id']), prefill=lambda r: { 'menu_item_id': r['menu_item_id'].value(), 'mod_id': r['mod_id'].value() }), Binding('content', _("Content"), content=self._page_content), )
def _actions(self, req, record): actions = super(CryptoKeys, self)._actions(req, record) if record is None and req.has_param('_crypto_name'): condition = pd.EQ('name', req.param('_crypto_name')) try: count = self._data.select(condition) finally: try: self._data.close() except Exception: pass if count > 0: actions = [a for a in actions if a.id() != 'insert'] return actions
def _update_prices(self, row): # This serves for testing user transactions. true_value = pd.Value(pd.Boolean(), True) condition = pd.EQ('marked', true_value) transaction = pd.transaction() try: def process(row): return row['product_id'] product_ids = row.data().select_map(process, condition=condition) for product_id in product_ids: if not pytis.form.run_form(pytis.form.PopupEditForm, 'misc.Products', select_row=product_id, transaction=transaction): app.error("Transaction aborted") transaction.rollback() return except Exception: transaction.rollback() raise transaction.commit()
def _application_help_page_content(self, node, uri): self._data.select(condition=pd.EQ('help_id', pd.sval(uri[5:]))) row = self._data.fetchone() self._data.close() if row: if row['page_id'].value(): storage = pytis.presentation.DbAttachmentStorage( 'e_pytis_help_pages_attachments', 'page_id', row['page_id'].value(), ) return lcg.Container(lcg.Parser().parse(row['content'].value() or ''), resources=storage.resources()) if row['menu_help'].value(): return lcg.Parser().parse(row['menu_help'].value()) else: spec_name = row['spec_name'].value() # TODO: Use the default descriptions from HelpUpdater. if spec_name: content = self._spec_help_content(spec_name)[1] if content: return content return lcg.Content()
def _action_filter(self, record, mod_id): return pd.OR(pd.EQ('mod_id', record['mod_id']), pd.EQ('mod_id', pd.Value(pd.Integer(), None)))
class GenericActions(Actions): title = _("Akce společné pro všechny položky men") help = _("Výčet podporovaných akcí společných pro všechny položky menu.") condition = pd.EQ('mod_id', pd.Value(pd.Integer(), None)) access_rights = pd.AccessRights((None, ('cms_admin', pd.Permission.ALL)), (None, ('cms_user', pd.Permission.VIEW)))
def _parent_filter(self, record, lang): return pd.EQ('lang', pd.Value(pd.String(), lang))
def _reload_actions(self, record): import wiking def action_descr(module, action): if issubclass(module, wiking.PytisModule): for a in module.Spec.actions: if a.name() == action: return a.descr() or a.title() try: return dict(self._DEFAULT_ACTIONS)[action] except KeyError: method = getattr(module, 'action_' + action) docstring = method.__doc__ return docstring and docstring.splitlines()[0] or _( "Neuvedeno") module = self._module(record['modname'].value()) if module: from pytis.form import run_dialog, CheckListDialog, create_data_object data = create_data_object(self._spec_name('Actions')) data.select(condition=pd.EQ('mod_id', record['mod_id'])) existing_actions = {} while True: row = data.fetchone() if row is None: break else: existing_actions[row['name'].value()] = row['action_id'] data.close() actions = [ attr[7:] for attr in dir(module) if attr.startswith('action_') and isinstance(getattr(module, attr), collections.Callable) ] default_actions = [a[0] for a in self._DEFAULT_ACTIONS] # Order default actions first and in the order of self._DEFAULT_ACTIONS. order = lambda a: a in default_actions and (default_actions.index( a) + 1) or a actions.sort(lambda a, b: cmp(order(a), order(b))) descriptions = [action_descr(module, action) for action in actions] result = run_dialog( CheckListDialog, title=_("Nalezené akce"), message=_("Zaškrtněte akce, které chcete zpřístupnit webovým " "uživatelům:"), items=zip([a in existing_actions for a in actions], actions, descriptions), columns=(_("Action"), _("Description"))) if result is not None: # TODO: Use a transaction. Respect existing actions. for i, action in enumerate(actions): if result[i]: description_value = pd.Value(pd.String(), descriptions[i] or None) try: key = existing_actions[action] except KeyError: rowdata = [('mod_id', record['mod_id']), ('name', pd.Value(pd.String(), action)), ('description', description_value)] data.insert(pd.Row(rowdata)) else: data.update( (key, ), pd.Row((('description', description_value), )))
class Help(Specification): public = True table = 'ev_pytis_help' title = _("Help") def fields(self): return ( Field('help_id', # The computer is only used for help pages (, editable=pp.Editable.NEVER, editable=pp.Editable.NEVER, editable=pp.Editable.NEVER, editable=pp.Editable.NEVER, editable=Editable.NEVERwith page_id) so # we don't need to care about other kinds of help_id. New # record is always a new page. computer=computer(lambda r, page_id: 'page/%d' % page_id)), Field('fullname', _("Fullname"), width=50, editable=Editable.NEVER), Field('spec_name', _("Specification Name"), width=50, editable=Editable.NEVER), Field('page_id', default=nextval('e_pytis_help_pages_page_id_seq')), Field('position'), Field('position_nsub'), Field('title', _("Title"), width=20, editable=computer(self._is_page), type=_TreeOrderLTree(tree_column_id='position', subcount_column_id='position_nsub'), ), Field('description', _("Description"), width=70, editable=computer(self._is_page),), Field('content', _("Content"), width=80, height=20, compact=True, text_format=pp.TextFormat.LCG, attachment_storage=self._attachment_storage), Field('menu_help', _(u"Menu item description"), width=80, height=20, compact=True, text_format=pp.TextFormat.LCG, attachment_storage=self._attachment_storage), Field('spec_description', _("Brief form description"), width=80, height=3, compact=True), Field('spec_help', _("Detailed form help"), width=80, height=20, compact=True, text_format=pp.TextFormat.LCG, attachment_storage=self._attachment_storage), Field('parent', _("Parent item"), not_null=False, codebook='help.HelpParents', value_column='page_id', editable=computer(self._is_page), runtime_filter=computer(self._parent_filter), descr=_("Choose the directly superordinate item in menu hierarchy. Leave " "empty for pages at the top level menu.")), Field('ord', _("Ordering"), width=8, fixed=True, type=pd.Integer, maximum=999998, editable=computer(self._is_page), descr=_("Enter a number denoting the order of the item in menu between " "pages of the same hierarchy level. Leave empty to put the item " "automatically to bottom.")), Field('removed', _("Removed"), editable=Editable.NEVER), Field('changed', _("Changed"), editable=Editable.NEVER), ) def row_style(self, row): return not row['changed'].value() and pp.Style(background='#ffd') or None def _is_page(self, record, page_id): return record.new() or page_id is not None def _parent_filter(self, page_id): return pd.NE('page_id', pd.ival(None)) def _attachment_storage(self, record): if record['page_id'].value(): table, ref = ('e_pytis_help_pages_attachments', 'page_id') elif record['spec_name'].value(): table, ref = ('e_pytis_help_spec_attachments', 'spec_name') else: # The attachments are not allowed for some special pages, such as the menu root page. return None return pp.DbAttachmentStorage(table, ref, record[ref].value()) def redirect(self, record): if record['page_id'].value() is not None: return None elif record['spec_name'].value() is not None: return 'help.SpecHelp' elif record['fullname'].value() is not None: return 'help.MenuHelp' else: return 'help.NoHelp' def bindings(self): return ( Binding('content', _("Content"), uri=lambda r: 'help:'+r['help_id'].value()), Binding('fields', _("Fields"), 'help.FieldItemsHelp', 'spec_name'), Binding('profiles', _("Profiles"), 'help.ProfileItemsHelp', 'spec_name'), Binding('actions', _("Actions"), 'help.ActionItemsHelp', 'spec_name'), Binding('bindings', _("Side Forms"), 'help.BindingItemsHelp', 'spec_name'), ) layout = ('title', 'description', 'parent', 'ord', 'content') cb = CodebookSpec(display='title') columns = ('title', 'description', 'spec_name', 'changed', 'removed') sorting = ('position', pd.ASCENDENT), profiles = pp.Profiles((pp.Profile('active', _("Active"), filter=pd.EQ('removed', pd.bval(False)), columns=('title', 'description', 'spec_name', 'removed')),), default='active')
def condition(self): return pd.EQ('kind', pd.sval(self._ITEM_KIND))
def _row(self, data, **kwargs): data.select(condition=pd.AND(*[pd.EQ(k, v) for k, v in self._values(data, **kwargs)])) row = data.fetchone() data.close() return row
class Products(Specification): public = True table = dbdefs.Products title = _("Products") layout = TabGroup((_("Product"), ('product_id', 'product', 'count', 'price', 'marked')), (_("Notes"), ('since', 'notes'))) grouping_functions = ( ('f_date_year', _("Year"), pd.DateTime, pd.Integer()), ('f_date_month', _("Month"), pd.DateTime, pd.Integer()), ) profiles = ( pp.Profile('marked', _("Marked"), filter=pd.EQ('marked', pd.bval(True))), pp.Profile('unmarked', _("Unmarked"), filter=pd.EQ('marked', pd.bval(False))), ) def _customize_fields(self, fields): fields.set_property('width', product_id=3, product=30, count=12, price=12, notes=50) fields.modify('product_id', column_width=6, fixed=True, editable=Editable.ALWAYS) fields.modify('product', style=lambda r: (pp.Style(overstrike=True) if r['count'].value() == 0 else None)) fields.modify('count', style=lambda r: (pp.Style(foreground='#f00') if r['count'].value() <= 5 else None)) fields.modify('price', type=pd.Monetary(not_null=True)) fields.modify('since', descr=_("Date when the product was first included."), default=pd.DateTime.datetime) fields.modify('notes', descr=_("Arbitrary internal notes about given product."), height=3, text_format=pp.TextFormat.LCG) def prints(self): return ( PrintAction('product-page', _("Product Page"), 'Products.ProductPage', handler=self._print_handler), PrintAction('product-info', _("Product Info"), 'Products.ProductInfo'), ) def _print_handler(self, row): """Demonstration of using PrintAction handler. The output document is created by merging the output of two printout results. """ from PyPDF2 import PdfFileMerger, PdfFileReader merger = PdfFileMerger() for lang in ('cs', 'en'): output = io.BytesIO() pytis.form.printout( 'Products', 'Products.ProductPage', parameters=dict([(k, row[k].export()) for k in ('product_id', 'product', 'price')], language=lang), language=lang, output_file=output, ) merger.append(PdfFileReader(io.BytesIO(output.getvalue()))) with tempfile.NamedTemporaryFile(suffix='.pdf') as f: merger.write(f) f.flush() os.fsync(f) pytis.form.launch_file(f.name) time.sleep(1) def _content(self, record): par = os.path.pardir return pytis.util.lcg_node( ( lcg.fieldset(( (_("Price"), record['price'].export()), (_("Available since"), lcg.LocalizableDateTime(record['since'].value())), )), lcg.sec(_("Notes"), lcg.Parser().parse(record['notes'].value()), name='notes') if record['notes'].value() else lcg.Content(), ), title=record['product'].value(), resource_path=(os.path.normpath(os.path.join(__file__, par, par, par, par, 'css')),), resources=('pytis-demo-product.css',), ) def bindings(self): return ( Binding('webform', _("Product Info"), content=self._content, descr=_("Shows web page generated from LCG structured text.")), ) def actions(self): return (Action('toggle', _("Mark/unmark"), self._mark, hotkey='m'), Action('mark_all', _("Mark all"), self._mark, hotkey='Ctrl-a', mark_all=True), Action('unmark_all', _("Unmark all"), self._mark, hotkey='Ctrl-u', mark_all=True, mark=False), Action('mark_selected', _("Mark selected"), self._mark_selected, context=pp.ActionContext.SELECTION), Action('prices', _("Update prices"), self._update_prices), Action('print', _("Print price"), self._print), ) def row_style(self, row): if row['count'].value() <= row.form.query_fields.row['min_count'].value(): return pp.Style(background='#fdd') elif row['marked'].value(): return pp.Style(background='#ffd') else: return None query_fields = QueryFields( (Field('min_count', _("Highlight low count"), type=pytis.data.Integer(not_null=True), default=10),), autoinit=True, ) def _mark(self, row, mark_all=False, mark=True): if mark_all: product_id = None else: product_id = row["product_id"].value() mark = not row["marked"].value() count = pytis.form.run_procedure('misc', 'mark_products', product_id=product_id, mark=mark) app.echo(_("Marked %d rows") % count) def _mark_selected(self, rows): count = pytis.form.run_procedure('misc', 'mark_products', product_id=[r['product_id'].value() for r in rows], mark=True) app.echo(_("Marked %d rows") % count) def _update_prices(self, row): # This serves for testing user transactions. true_value = pd.Value(pd.Boolean(), True) condition = pd.EQ('marked', true_value) transaction = pd.transaction() try: def process(row): return row['product_id'] product_ids = row.data().select_map(process, condition=condition) for product_id in product_ids: if not pytis.form.run_form(pytis.form.PopupEditForm, 'misc.Products', select_row=product_id, transaction=transaction): app.error("Transaction aborted") transaction.rollback() return except Exception: transaction.rollback() raise transaction.commit() def _print(self, row): pytis.form.printout('misc.Products', 'misc.StandalonePrint', row)
def close(self, req, user, session_key): # This deletion will lead to end_time in cms_session_log_data being set to last_access # value of the deleted row. Use delete_many() because we don't know session_id. self._data.delete_many( pd.AND(pd.EQ('uid', pd.Value(pd.Integer(), user.uid())), pd.EQ('session_key', pd.Value(pd.DateTime(), session_key))))
def _country_filter(self, row, filter, switch): """Return the validity condition as pd.Operator instance.""" cond = pd.WM('name', pd.WMValue(pd.String(), filter or '*')) if switch: cond = pd.AND(cond, pd.EQ('continent', pd.Value(pd.String(), 'EU'))) return cond
def assigned_users(self, name): # Internal method for Spec class, don't use it elsewhere return self._data.select_map(lambda row: row['uid'], condition=pd.EQ('name', name))
def _country_filter(self, row, continent): if continent: return pd.EQ('continent', pd.Value(pd.String(), continent.upper())) else: return None
def params(self): return ( # Don't bother creating a separate table for testing shared params. # Simply use any existing table... SharedParams('country', 'cb.Countries', pd.EQ('id', pd.sval('CZ'))), )
def body(self): spec = self._parameter(pytis.output.P_NAME) parts = [] row = self._parameter(( spec, pytis.output.P_ROW, )) id_continent = row['id'] pcond = pd.EQ('continent', id_continent) parts.append(pytis.output.Center(self._parameter('title'))) columns = ( pytis.output.Table.Column( 'Alpha-2', lcg.UMm(10), label_alignment=pytis.output.Table.Column.ALIGN_LEFT, alignment=pytis.output.Table.Column.ALIGN_LEFT, ), pytis.output.Table.Column( 'Alpha-3', lcg.UMm(10), label_alignment=pytis.output.Table.Column.ALIGN_LEFT, alignment=pytis.output.Table.Column.ALIGN_LEFT, ), pytis.output.Table.Column( 'Numeric', lcg.UMm(10), label_alignment=pytis.output.Table.Column.ALIGN_LEFT, alignment=pytis.output.Table.Column.ALIGN_LEFT, ), pytis.output.Table.Column( 'Continent', lcg.UMm(10), label_alignment=pytis.output.Table.Column.ALIGN_LEFT, alignment=pytis.output.Table.Column.ALIGN_LEFT, ), pytis.output.Table.Column( 'Short name', lcg.UMm(60), label_alignment=pytis.output.Table.Column.ALIGN_LEFT, alignment=pytis.output.Table.Column.ALIGN_LEFT, ), pytis.output.Table.Column( 'Full name', lcg.UMm(70), label_alignment=pytis.output.Table.Column.ALIGN_LEFT, alignment=pytis.output.Table.Column.ALIGN_LEFT, ), ) def data_table(condition): def generator_init(): self._data.select(condition=condition) def generator(): row = self._data.fetchone() if row is None: return None id_ = row['id'].export() id3 = row['id3'].export() num = row['num'].export() continent = row['continent'].export() name = row['name'].export() fullname = row['fullname'].export() return (id_, id3, num, continent, name, fullname) table = pytis.output.LongTable(columns, generator, row_generator_init=generator_init, separator_height=1.2, separator_margin=2) return table table_countries = data_table(pcond) parts.append(pytis.output.VSpace(lcg.UFont(1))) parts.append(pytis.output.f_smaller(table_countries)) return pytis.output.Document(pytis.output.Group(*parts, vertical=True))