[Freeipa-devel] [PATCH] 028 Code cleanup of HBAC, Sudo rules

Endi Sukma Dewata edewata at redhat.com
Thu Oct 27 21:51:56 UTC 2011


On 10/27/2011 8:39 AM, Petr Vobornik wrote:
> But still I think it would be better to be able to get container
> (facet/dialog) for a widget. As you wrote, that.entity.get_facet() may
> not always be what we want.

One possibility is to convert the facet & dialog into subclasses of an 
abstract container class. The container needs to provide functions such 
as refresh() so the widget doesn't need to know whether it's a facet or 
dialog.

>>> Btw similar topic could be: "How to get current entity's pkey?'.
>>> Dependancy on facet.get_primary_key() or
>>> IPA.nav.get_state(that.entity.name+'-pkey') seems wrong too.
>>
>> Yes. Ideally we should have a path (REST-style URL) instead of the
>> current parameter-based URL. We should get the pkey from that path.
>
>  From dependency point of view, widgets would be still dependant on the
> implementation of navigation (IMHO bad).
>
> But it seems that using entity.get_primary key partially solves the
> problem.

It could be argued that since this is a web app everything will have a 
path, but for now getting primary key from entity is fine since 
everything also has an associated entity.

> Maybe it would be better if navigation would inject pkey to entity.
> Entity wouldn't be that much dependant on navigation implementation.

We might need to distinguish 2 different usages of 'entity'. The first 
one represents a collection of entries:

   var users = IPA.get_entity('user');
   users.add([ 'test' ], { givenName: 'Test', ... });
   var result = users.find('t*');

The second one represents individual entry:

   var user = result.result[0];
   user.update({ sn: 'User' });

The entity collection should be 'stateless', it will be used in search 
pages. The individual entity will be 'stateful', it contains the pkey 
and the values of its attributes, and it will be used in the details page.

The entity.get_primary_key() is an interface to get the primary keys for 
a particular entity from the current path. So when you open a URL for an 
entry's details facet, it will execute the following command:

   var pkeys = entity.get_primary_key();
   var object = entity.get(pkeys);

Then the facet will use the object to populate the page.

> The priority could be part of update info. As there is a field_info we
> can create a command_info: { command, priority }.

> Before adding commands to batch_command, array of command_info objects
> would joined with 'mod' command with default priority and then sorted by
> priority.
>
> If the priority was set on each widget, priority management will be on
> facet level, which may be fine. There can be some corner case like
> dynamic change of priority.

I'd have to see how it's implemented.

>> One other solution is to split widgets into non-visual fields and purely
>> HTML components. Then in the facet we use separate lists for the fields
>> and HTML components. The fields will have a reference to the
>> corresponding HTML components. There can be more HTML components than
>> fields. But this will require a significant restructuring.
>
> Maybe we can use hybrid solution: html widgets would be simple object
> with some properties and create() method. They should not be called
> widgets. They would not be part of sections fields. Rendering would be
> done in widgets/sections create() method (as it is now).

I'm not very clear, we could be talking about the same thing. The 
(non-HTML) fields could be defined like this:

   fields: [
       {
           name: 'cn',
           widget: 'identity.cn'
       },
       {
           name: 'email',
           widget: 'identity.email'
       },
       {
           factory: IPA.password_field,
           name: 'userpassword',
           widgets: [ 'account.password1', 'account.password2' ]
       }
   ]

The specs above will be used to create IPA.field objects (not widget) to 
assist loading/saving attributes. Then we could also define the HTML 
components (let's call it widget) separately:

   widgets: [
       {
           factory: IPA.table_section,
           name: 'identity',
           label: 'Identity'
           widgets: [
               {
                   factory: IPA.text_widget,
                   name: 'cn'
               },
               {
                   factory: IPA.multivalued_widget,
                   name: 'email',
                   widget: IPA.text_widget
               }
           ]
       }
   ]

The specs above will be used to create IPA.widget objects to generate 
the HTML content. If there is no widget specs specified, we could 
generate it automatically from the field specs.

> Pros:
> - reusable layouts, headers...
> - not polluting field names
> Cons:
> - not so declarative - need to override update method, create custom
> section/widget factories - same as now

The above example should be quite declarative.

> Question:
> - what with widget nesting? rule_details_section is in fact a composite
> widget. I would like to keep the concept, because it offers better code
> reuse.

As shown above, widget (not field) nesting is possible.

A section is a composite widget with a specific layout: it has a header, 
it's collapsible, and it has nested widgets.

A table section is a section that uses 2 columns to display the nested 
widgets: one for the field label and the other for the widget itself.

A multivalued widget is a composite widget with one type of nested 
widgets and it has an Add and Undo All links.

The rule_details_section is a section with radio buttons (for the 
category) and some tables.

>> I think the decision to use mod or batch should be separate from details
>> facet. I'm thinking to create a separate class IPA.client which we can
>> add commands into it and execute them either individually or as a batch.
>
> What would be the IPA.client's responsibilities? It'll be only a
> container for commands with different executing strategies?

The IPA.client will represent a connection to the IPA server. In a 
browser IPA.client can only connect to the server it's loaded from:

   var client = IPA.client();

but in a JS engine like Rhino the IPA.client can connect to any IPA server:

    var client = IPA.client('ipa.example.com');

The IPA.client can be used to execute commands:

    var command = IPA.command(...);
    client.execute(command);

or start a batch:

    client.start_batch();
    client.execute(command1);
    client.execute(command2);
    client.end_batch();

or get the entities:

    var users = client.get_entity('user');

-- 
Endi S. Dewata




More information about the Freeipa-devel mailing list