Exemple #1
0
 def _product_filter(self, row, marked, filter):
     condition = pd.WM('product', pd.WMValue(pd.String(), filter
                                             or '*'))
     if marked:
         value = pd.Value(pd.Boolean(), True)
         condition = pd.AND(condition, pd.EQ('marked', value))
     return condition
Exemple #2
0
 class Specification(pp.Specification):
     table = 'grid_test'
     fields = (
         pp.Field('id', type=pd.Integer()),
         pp.Field('name', type=pd.String()),
         pp.Field('price', type=pd.Float(precision=2)),
         pp.Field('flag', type=pd.Boolean()),
     )
Exemple #3
0
 class Fruits(pytis.presentation.Specification):
     fields = (
         pp.Field('id'),
         pp.Field('title'),
         pp.Field('code', type=pd.Integer()),
         pp.Field('tropical', type=pd.Boolean()),
     )
     data_cls = pd.MemData
     data = (('apl', 'Apple', 123, False), ('ban', 'Banana', 234, True),
             ('str', 'Strawberry', 234, False), ('org', 'Orange', 456,
                                                 True))
Exemple #4
0
 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()
Exemple #5
0
 def fields(self):
     return (
         Field('filter', _("Country name filter"), default='*',
               descr=_("Enter a wildcard expression to filter only matching countries in the "
                       "codebook field below.")),
         Field('switch', _("Show only european countries"), editable=Editable.ALWAYS,
               type=pd.Boolean(), default=True,
               descr=_("Check/uncheck this checkbox to enable/disable non-european "
                       "countries in the codebook field below.")),
         Field('country', _("Country"), width=2,
               type=pd.String, not_null=True, maxlen=2,
               codebook='cb.Countries',
               runtime_filter=computer(self._country_filter),
               descr=_("Lists countries filtered by the above two fields.")),
         Field('group', _("Group"),
               enumerator=self._SystemGroups(), not_null=True,
               descr=_("Lists system user groups.")),
         Field('user', _("User"),
               enumerator=self._SystemGroupMembers(), not_null=True,
               runtime_arguments=computer(lambda record, group: dict(group=group)),
               descr=_("Lists users of the above selected group.")),
     )
Exemple #6
0
    def fields(self):
        return (
            # Basic fields
            Field('text', _("Text"), type=pd.String(maxlen=50), width=30,
                  editable=computer(self._editable)),
            Field('completion', _("Completion"), type=pd.String(maxlen=20),
                  editable=computer(self._editable),
                  completer=('John', 'Jane', 'Joe', 'Judith', 'Jeremy',
                             'Peter', 'Paul', 'Paula', 'Richard', 'Samantha', 'Samuel',
                             'Steve', 'Sue'),
                  descr=_("Text entry with autocompletion.  The 'completer' provides "
                          "available completions.  As opposed to enumerator (which "
                          "also provides autocompletion values), completer has no "
                          "effect on validation. You can define a static (like here), "
                          "dynamic or database connected list of completions.")),
            Field('multiline', _("Multiline"), type=pd.String(), width=30, height=4,
                  editable=computer(self._editable)),
            Field('password', _("Password"), type=pd.Password(maxlen=20, verify=True),
                  editable=computer(self._editable), width=14,
                  descr=_("Password field doesn't display the current value.  If 'verify' "
                          "is set to True in field's type, the field requires the value to "
                          "be entered twice and validation makes sure both values match.")),
            Field('number', _("Number"), type=pd.Integer(), default=0,
                  editable=computer(self._editable),
                  descr=_("A simple numeric field.")),
            Field('slider', _("Slider"), type=pd.Integer(minimum=20, maximum=50),
                  default=30, slider=True, width=2,
                  editable=computer(self._editable),
                  descr=_("A simple numeric field.")),
            Field('float', _("Decimal"), type=pd.Float(precision=2), default=0,
                  editable=computer(self._editable)),
            Field('date', _("Date"), default=pd.Date.datetime, type=pd.Date(),
                  editable=computer(self._editable),
                  descr=_("Date entry field with a calendar control and a default value.")),
            Field('time', _("Time"), type=pytis.data.Time(),
                  editable=computer(self._editable)),
            Field('datetime', _("Date and time"), type=pytis.data.DateTime(),
                  editable=computer(self._editable)),
            Field('file', _("File"), type=pytis.data.Binary(),
                  editable=computer(self._editable)),
            Field('image', _("Image"), type=pytis.data.Image(),
                  editable=computer(self._editable)),
            Field('color', _("Color"), type=pytis.data.Color(),
                  editable=computer(self._editable)),

            # Enumeration fields
            Field('editable', _("Check box"), type=pd.Boolean(), default=True,
                  descr=_("Check/uncheck this checkbox to enable/disable all other "
                          "form fields.  This field demonstrates a simple boolean "
                          "checkbox field.  It also demonstrates how to make fields "
                          "editable based on the values of some other fields (any "
                          "more complicated logic is possible in the 'computer' of "
                          "the 'editable' property in field specification). "
                          "Finally it demonstrates how all field types look in the "
                          "editable and non-editable state.")),
            Field('choice', _("Choice"), type=pd.String(not_null=True, maxlen=2),
                  codebook='cb.Continents',
                  selection_type=SelectionType.CHOICE,
                  editable=computer(self._editable),
                  descr=_("Simple pull-down menu selection.")),
            Field('radio', _("Radio box"), not_null=True,
                  enumerator=self._Fruits,
                  editable=computer(self._editable),
                  selection_type=SelectionType.RADIO,
                  descr=_("Radio box selection.  The enumeration is defined statically by "
                          "an Enumeration class.")),
            Field('listbox', _("List box"), not_null=True,
                  enumerator=self._Fruits,
                  selection_type=SelectionType.LISTBOX,
                  editable=computer(self._editable),
                  descr=_("List selection which becomes scrollable when the number of "
                          "items exceeds its height.")),
            Field('codebook', _("Codebook"), type=pd.String(not_null=True, maxlen=2),
                  codebook='cb.Countries', width=2,
                  # SelectionType.CODEBOOK is actually the default when 'codebook' is set.
                  selection_type=SelectionType.CODEBOOK,
                  post_process=PostProcess.UPPER,
                  editable=computer(self._editable),
                  descr=_(
                      "This field provides a text entry for writing down the code directly.  "
                      "It most convenient when the codebook contains a relatively large number of "
                      "items while their codes are short and simple.  Then the user most often "
                      "knows the codes without looking them up.  Right from the text entry field, "
                      "there is a codebook invocation button, which allows the user to select the "
                      "item from a codebook form (when he doesn't remember the code or wants to "
                      "see the full listing of all available items for some other reason).  "
                      "Further on the right, there is a gray field called `display'.  It shows "
                      "the description of the currently selected item (eg. the full name for the "
                      "selected code).  Thus it provides immediate feedback when the user "
                      "modifies the value.  It is empty when the entered code is invalid (not "
                      "contained in the codebook).  It is updated with any change of the field "
                      "value.")),
            Field('listfield', _("List Field"), type=pd.String(not_null=True, maxlen=2),
                  codebook='cb.Countries', compact=True, height=6,
                  selection_type=SelectionType.LIST,
                  editable=computer(self._editable),
                  descr=_("This field also allows direct codebook manipulations through the row "
                          "context menu.")),

            # Range fields
            Field('intrange', _("Numeric range"), type=pytis.data.IntegerRange(),
                  editable=computer(self._editable)),
            Field('daterange', _("Date range"), type=pytis.data.DateRange(),
                  editable=computer(self._editable)),

        )
Exemple #7
0
class CryptoKeys(CMSExtensionModule):
    """Management of keys and users.

    It uses a special set of actions that resemble standard editing actions but
    are different from them:

    - Insert new key: This creates initial key for an encryption area.  This
      can be done only once for each of the areas.  The inserted keys can be
      given to other users using copy action.

    - Copy key: Copy an existing key to another user.

    - Change password: Change password of the key for the given user.

    - Delete key: Remove a user from the given key.  This can be only done if
      another copy of the key exists.

    All the actions are performed using special database functions.

    """
    class Spec(wiking.Specification):
        table = 'cms_crypto_keys'
        title = _("Users and Encryption Keys")

        def fields(self):
            return (
                Field('key_id', _("Id"), editable=Editable.NEVER),
                Field('name',
                      _("Name"),
                      not_null=True,
                      codebook='CryptoNames',
                      editable=Editable.NEVER),
                Field('uid',
                      _("User"),
                      not_null=True,
                      codebook='Users',
                      selection_type=SelectionType.CHOICE,
                      editable=Editable.ONCE),
                Field('new_uid',
                      _("New user"),
                      not_null=True,
                      codebook='Users',
                      selection_type=SelectionType.CHOICE,
                      type=pd.Integer,
                      virtual=True,
                      runtime_filter=computer(self._new_uid_filter)),
                Field('key', _("Key")),
                Field('remove',
                      _("Action"),
                      virtual=True,
                      computer=computer(lambda r: _("Remove"))),
                Field('old_password',
                      _("Current password"),
                      type=pd.Password,
                      verify=False,
                      virtual=True),
                Field('new_password',
                      _("New password"),
                      type=pd.Password,
                      virtual=True),
                Field('delete',
                      virtual=True,
                      computer=computer(lambda row: _("Remove"))),
            )

        def _new_uid_filter(self, row, name):
            assigned_users = wiking.module(self._resolver).assigned_users(
                row['name'])
            return pd.AND(*[pd.NE('uid', u) for u in assigned_users])

        sorting = (
            (
                'uid',
                pd.ASCENDENT,
            ),
            (
                'name',
                pd.ASCENDENT,
            ),
        )
        columns = (
            'uid',
            'name',
            'delete',
        )
        actions = (
            Action('password',
                   _("Change password"),
                   descr=_("Change key password")),
            Action('adduser',
                   _("Copy to user"),
                   descr=_("Add another user of the key")),
        )

    _DB_FUNCTIONS = dict(
        CMSExtensionModule._DB_FUNCTIONS,
        cms_crypto_delete_key=(
            (
                'name_',
                pd.String(),
            ),
            (
                'uid_',
                pd.Integer(),
            ),
            (
                'force',
                pd.Boolean(),
            ),
        ),
        cms_crypto_insert_key=(
            (
                'name_',
                pd.String(),
            ),
            (
                'uid_',
                pd.Integer(),
            ),
            (
                'key_',
                pd.String(),
            ),
            (
                'psw',
                pd.String(),
            ),
        ),
        cms_crypto_copy_key=(
            (
                'name_',
                pd.String(),
            ),
            (
                'from_uid',
                pd.Integer(),
            ),
            (
                'to_uid',
                pd.Integer(),
            ),
            (
                'from_psw',
                pd.String(),
            ),
            (
                'to_psw',
                pd.String(),
            ),
        ),
        cms_crypto_change_password=(
            (
                'id_',
                pd.Integer(),
            ),
            (
                'old_psw',
                pd.String(),
            ),
            (
                'new_psw',
                pd.String(),
            ),
        ),
    )

    _TITLE_COLUMN = 'uid'
    _INSERT_LABEL = _("Create key")

    def _authorized(self, req, action, record=None, **kwargs):
        if action == 'view':
            return req.check_roles(Roles.CRYPTO_ADMIN) or self._check_uid(
                req, record, 'uid')
        elif action == 'password':
            return self._check_uid(req, record, 'uid')
        elif action in ('list', 'insert', 'delete', 'adduser'):
            return req.check_roles(Roles.CRYPTO_ADMIN)
        else:
            return False

    def _prefill(self, req):
        return dict(super(CryptoKeys, self)._prefill(req),
                    uid=req.user().uid())

    def _layout(self, req, action, record=None):
        if action == 'insert':
            layout = (
                'name',
                'uid',
                'new_password',
            )
        elif action == 'adduser':
            layout = (
                'key_id',
                'name',
                'uid',
                'new_uid',
                'old_password',
                'new_password',
            )
        elif action == 'password':
            layout = (
                'key_id',
                'name',
                'uid',
                'old_password',
                'new_password',
            )
        else:
            layout = (
                'name',
                'uid',
            )
        return layout

    def _columns(self, req):
        columns = super(CryptoKeys, self)._columns(req)
        if not req.has_param('_crypto_name'):
            columns = [c for c in columns if c != 'delete']
        return columns

    def _link_provider(self, req, uri, record, cid, **kwargs):
        if cid == 'delete':
            return req.make_uri(uri,
                                key_id=record['key_id'].value(),
                                action='delete')
        else:
            return super(CryptoKeys,
                         self)._link_provider(req, uri, record, cid, **kwargs)

    def _list_form_kwargs(self, req, form_cls):
        kwargs = super(CryptoKeys, self)._list_form_kwargs(req, form_cls)
        if issubclass(form_cls, pw.ItemizedView) and req.check_roles(
                Roles.USER_ADMIN):
            kwargs['template'] = lcg.TranslatableText("%%(%s)s [%%(delete)s]" %
                                                      self._TITLE_COLUMN)
        return kwargs

    def related(self, req, binding, record, uri):
        if 'name' in record:
            req.set_param('_crypto_name', record['name'])
        return super(CryptoKeys, self).related(req, binding, record, uri)

    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 _insert(self, req, record, transaction):
        key = wiking.generate_random_string(256)
        if not self._call_db_function('cms_crypto_insert_key',
                                      record['name'].value(),
                                      record['uid'].value(),
                                      key,
                                      record['new_password'].value(),
                                      transaction=transaction):
            raise pd.DBException(
                _("New key not created. Maybe it already exists?"))

    def _update(self, req, record, transaction):
        action = req.param('action')
        if action == 'password':
            if not self._call_db_function('cms_crypto_change_password',
                                          record['key_id'].value(),
                                          record['old_password'].value(),
                                          record['new_password'].value(),
                                          transaction=transaction):
                raise pd.DBException(
                    _("Password not changed. Maybe invalid old password?"))
        elif action == 'adduser':
            if not self._call_db_function('cms_crypto_copy_key',
                                          record['name'].value(),
                                          record['uid'].value(),
                                          record['new_uid'].value(),
                                          record['old_password'].value(),
                                          record['new_password'].value(),
                                          transaction=transaction):
                raise pd.DBException(
                    _("User not added. Maybe invalid old password?"))
        else:
            raise Exception('Unexpected action', action)

    def _delete(self, req, record, transaction):
        if not self._call_db_function('cms_crypto_delete_key',
                                      record['name'].value(),
                                      record['uid'].value(),
                                      False,
                                      transaction=transaction):
            raise pd.DBException(
                _("The user couldn't be deleted. "
                  "Maybe he is the last key holder?"))

    def action_adduser(self, req, record, action='adduser'):
        return super(CryptoKeys, self).action_update(req,
                                                     record,
                                                     action=action)

    def action_password(self, req, record=None):
        return self.action_update(req, record=record, action='password')

    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 assigned_names(self, uid):
        """Return sequence of crypto names assigned to user identified by uid.

        Arguments:

          uid -- user uid, integer

        """
        return self._data.select_map(lambda row: row['name'],
                                     condition=pd.EQ('uid', pd.ival(uid)))

    def clear_crypto_passwords(self, req, user):
        # Just a hack to allow clearing passwords on logout
        req.set_cookie(self._CRYPTO_COOKIE, None, secure=True)
        self._call_db_function('cms_crypto_lock_passwords', user.uid())
Exemple #8
0
    (pp.Field('multiline', type=pd.String(),
              height=4), ('xxx\nxxx', 'xxx\nxxx')),
    (pp.Field('date', type=pd.Date()), (datetime.date(2016, 8,
                                                      30), '30.08.2016')),
    (pp.Field('datetime',
              type=pd.DateTime()), (datetime.datetime(2016,
                                                      8,
                                                      30,
                                                      12,
                                                      40,
                                                      tzinfo=Timezone()),
                                    '30.08.2016 12:40:00')),
    (pp.Field('daterange', type=pd.DateRange()), (pd.DateRange().adjust_value(
        (datetime.date(1975, 8, 30),
         datetime.date(2016, 8, 30))), ('30.08.1975', '30.08.2016'))),
    (pp.Field('boolean', type=pd.Boolean()), (True, 'T'), (False, 'F')),
    (pp.Field('checklist',
              type=pd.Array(inner_type=pd.Integer()),
              enumerator=pd.FixedEnumerator(range(10)),
              selection_type=pp.SelectionType.CHECKLIST),
     ((pd.ival(1), pd.ival(4)), ('1', '4'))),
    (pp.Field('choice',
              type=pd.Integer(),
              enumerator=pd.FixedEnumerator(range(10)),
              selection_type=pp.SelectionType.CHOICE), (5, '5')),
    (pp.Field('radio',
              type=pd.Integer(),
              enumerator=pd.FixedEnumerator(range(10)),
              selection_type=pp.SelectionType.RADIO), (5, '5')),
)
Exemple #9
0
 def fields(self):
     return (
         Field('id'),
         Field(
             'continent',
             _("Continent"),
             width=3,
             codebook='Continents',
             selection_type=SelectionType.RADIO,
             not_null=True,
             descr=_(
                 "Select continent to limit country selection below to "
                 "given continent.")),
         Field(
             'country',
             _("Country"),
             codebook='Countries',
             selection_type=SelectionType.CHOICE,
             runtime_filter=computer(self._country_filter),
             not_null=True,
             editable=computer(
                 lambda r, continent: continent is not None),
             descr=_(
                 "Select the country. Use the radio buttons above to limit the "
                 "available options to countries of given continent.")),
         Field(
             'filter',
             _("Product filter"),
             default='*',
             descr=_(
                 "Enter a wildcard expression to filter only matching products in "
                 "the codebook field below."),
             virtual=True),
         Field(
             'marked',
             _("Marked products only"),
             type=pd.Boolean(),
             virtual=True,
             descr=_(
                 "Check this checkbox if you want to filter the products in the list "
                 "below to contain only marked products.")),
         Field('product_id',
               _("Product"),
               codebook='Products',
               display='product',
               not_null=True,
               runtime_filter=computer(self._product_filter),
               descr=_("Select the product to set the price for.")),
         Field('price',
               _("Price"),
               editable=Editable.NEVER,
               computer=CbComputer('product_id', 'price'),
               virtual=True),
         Field(
             'expense',
             _("Expense"),
             editable=Editable.NEVER,
             computer=computer(self._expense),
             virtual=True,
             enumerator=pd.FixedEnumerator(('low', 'medium', 'high')),
             not_null=True,
             # Uncomment to test runtime editability for radio buttons:
             # editable=computer(lambda r, marked: not marked),
             display=lambda x: x.capitalize(),
             selection_type=SelectionType.RADIO),
     )