#49966 Issue 49928 - Fix various small WebUI schema issues
Closed 3 years ago by spichugi. Opened 5 years ago by spichugi.
spichugi/389-ds-base schema-fix  into  master

@@ -10,6 +10,11 @@ 

       '</ul>' +

    '</div>';

  

+ var attr_btn_html_only_view =

+   '<button class="btn btn-default attr-view-btn" type="button"' +

+   ' href="#schema-tab" title="Only user-defined attributes can be modified"> View Attribute' +

+   '</button>';

+ 

  var oc_btn_html =

    '<div class="dropdown">' +

      '<button class="btn btn-default dropdown-toggle" type="button"data-toggle="dropdown">' +
@@ -17,15 +22,51 @@ 

        '<span class="caret"></span>' +

      '</button>' +

      '<ul class="dropdown-menu ds-agmt-dropdown" role="menu">' +

-       '<li role=""><a role="menuitem" tabindex="0" class="oc-edit-btn" href="#">Edit Objectclass</a></li>' +

-       '<li role=""><a role="menuitem" tabindex="1" class="oc-del-btn" href="#">Delete Objectclass</a></li>' +

+       '<li role=""><a role="menuitem" tabindex="0" class="oc-edit-btn" href="#schema-tab">Edit Objectclass</a></li>' +

+       '<li role=""><a role="menuitem" tabindex="1" class="oc-del-btn" href="#schema-tab">Delete Objectclass</a></li>' +

      '</ul>' +

    '</div>';

  

+ var oc_btn_html_only_view =

+   '<button class="btn btn-default oc-view-btn" type="button"' +

+   ' href="#schema-tab" title="Only user-defined objectClasses can be modified"> View Objectclass' +

+   '</button>';

+ 

  var schema_oc_table;

  var schema_at_table;

  var schema_mr_table;

  

+ var attr_usage_opts = ['userApplications', 'directoryOperation', 'distributedOperation', 'dSAOperation'];

+ var oc_kind_opts = ['STRUCTURAL', 'ABSTRACT', 'AUXILIARY'];

+ 

+ function is_x_origin_user_defined(x_origin) {

+   if (typeof x_origin === 'string' && x_origin.toLowerCase() !== 'user defined' || x_origin == null) {

+     return false;

+   } else {

+     return true;

+   }

+ }

+ 

+ // Leave only user defined attributes if the checkbox is crossed

+ $.fn.dataTable.ext.search.push(

+   function(settings, searchData, index, rowData, counter) {

+     var x_origin;

+     if ( $("#attr-user-defined").is(":checked") ) {

+       x_origin = rowData[10];

+       if (!is_x_origin_user_defined(x_origin)) {

+         return false;

+       }

+     }

+     if ( $("#oc-user-defined").is(":checked") ) {

+       x_origin = rowData[6];

+       if (!is_x_origin_user_defined(x_origin)) {

+         return false;

+       }

+     }

+     return true;

+   }

+ );

+ 

  function clear_oc_form() {

    // Clear input fields and reset dropboxes

    $("#add-edit-oc-header").html('Add Objectclass');
@@ -34,11 +75,14 @@ 

    $("#oc-name").val("");

    $(".ds-input").css("border-color", "initial");

    $("#oc-oid").val("");

+   $("#oc-kind").prop('selectedIndex',0);

+   $("#oc-desc").val("");

    $("#oc-parent").prop('selectedIndex',0);

    $("#schema-list").prop('selectedIndex',-1);

    $('#oc-required-list').find('option').remove();

    $('#oc-allowed-list').find('option').remove();

- };

+   $("#save-oc-button").attr('disabled', false);

+ }

  

  function clear_attr_form() {

    // Clear input fields and reset dropboxes
@@ -49,22 +93,26 @@ 

    $(".ds-input").css("border-color", "initial");

    $("#attr-syntax").val("");

    $("#attr-desc").val("");

+   $("#attr-parent").prop('selectedIndex',0);

+   $("#attr-usage").prop('selectedIndex',0);

    $("#attr-oid").val("");

    $("#attr-alias").val("");

    $('#attr-multivalued').prop('checked', false);

+   $('#attr-no-user-mod').prop('checked', false);

    $("#attr-eq-mr-select").prop('selectedIndex',0);

    $("#attr-order-mr-select").prop('selectedIndex',0);

    $("#attr-sub-mr-select").prop('selectedIndex',0);

- };

+   $("#save-attr-button").attr('disabled', false);

+ }

  

  function load_schema_objects_to_select(object, select_id) {

    var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', object, 'list'];

    console.log("CMD: Get schema: " + cmd.join(' '));

-   cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

-     var obj = JSON.parse(data);

-     var data = []

-     for (var idx in obj['items']) {

-       item = obj['items'][idx];

+   cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(select_data) {

+     var obj = JSON.parse(select_data);

+     var data = [];

+     for (var i = 0; i < obj.items.length; i++) {

+       item = obj.items[i];

        if (item.name) {

          data.push.apply(data, [item.name]);

        } else {
@@ -78,8 +126,8 @@ 

              text : item

          }));

      });

-   }).fail(function(data) {

-       console.log("failed: " + data.message);

+   }).fail(function(select_data) {

+       console.log("failed: " + select_data.message);

        check_inst_alive(1);

    });

  }
@@ -87,51 +135,45 @@ 

  function get_and_set_schema_tables() {

    console.log("Loading schema...");

  

-   // Load syntaxes

-   var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', "attributetypes", 'get_syntaxes'];

-   console.log("CMD: Get syntaxes: " + cmd.join(' '));

-   cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

-     var obj = JSON.parse(data);

-     var data = []

- 

-     load_schema_objects_to_select('matchingrules', 'attr-eq-mr-select')

-     load_schema_objects_to_select('matchingrules', 'attr-order-mr-select')

-     load_schema_objects_to_select('matchingrules', 'attr-sub-mr-select')

-     load_schema_objects_to_select('attributetypes', 'schema-list')

-     load_schema_objects_to_select('objectclasses', 'oc-parent')

- 

-     for (var idx in obj['items']) {

-       item = obj['items'][idx];

-       data.push.apply(data, [item]);

-     }

-     // Update html select

-     $.each(data, function (i, item) {

-         $("#attr-syntax").append($('<option>', {

-             value: item.id,

-             text : item.name + " (" + item.id + ")"

-         }));

-     });

-     console.log("Finished loading schema.");

-   }).fail(function(data) {

-       console.log("failed: " + data.message);

-       check_inst_alive(1);

+   // Set attribute usage select html in attribute's edit window

+   $.each(attr_usage_opts, function (i, item) {

+       $("#attr-usage").append($('<option>', {

+           value: item,

+           text : item,

+       }));

+   });

+ 

+   // Set objectClass kind select html in objectClass's edit window

+   $.each(oc_kind_opts, function (i, item) {

+       $("#oc-kind").append($('<option>', {

+           value: item,

+           text : item,

+       }));

    });

  

    // Setup the tables: standard, custom, and Matching Rules

    var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', 'objectclasses', 'list'];

    console.log("CMD: Get objectclasses: " + cmd.join(' '));

-   cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

-     var obj = JSON.parse(data);

+   cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(oc_data) {

+     var obj = JSON.parse(oc_data);

      var data = [];

-     for (var idx in obj['items']) {

-       item = obj['items'][idx];

+     // If objectClass is user defined them the action button is enabled

+     for (var i = 0; i < obj.items.length; i++) {

+       var oc_btn = oc_btn_html_only_view;

+       item = obj.items[i];

+       if (is_x_origin_user_defined(item.x_origin)) {

+         oc_btn = oc_btn_html;

+       }

        data.push.apply(data, [[

          item.name,

          item.oid,

          item.sup,

-         item["must"].join(" "),

-         item["may"].join(" "),

-         oc_btn_html

+         item.must.join(" "),

+         item.may.join(" "),

+         oc_btn,

+         item.x_origin,

+         oc_kind_opts[item.kind],

+         item.desc

        ]]);

      }

      // Update html table
@@ -148,75 +190,124 @@ 

        "columnDefs": [ {

          "targets": 5,

          "orderable": false

-       } ]

+       }, {

+         "targets": 6,

+         "visible": false

+       }]

      });

-   }).fail(function(data) {

-       console.log("failed: " + data.message);

+   }).fail(function(oc_data) {

+       console.log("failed: " + oc_data.message);

        check_inst_alive(1);

    });

  

-   var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', 'attributetypes', 'list'];

-   console.log("CMD: Get attributes: " + cmd.join(' '));

-   cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

-     var obj = JSON.parse(data);

-     var data = [];

-     for (var idx in obj['items']) {

-       item = obj['items'][idx];

-       if (item.single_value) {

-           multivalued = 'no'

-       } else {

-           multivalued = 'yes'

-       }

-       data.push.apply(data, [[

-         item.name,

-         item.oid,

-         item.syntax,

-         multivalued,

-         item.equality,

-         item.ordering,

-         item.substr,

-         attr_btn_html,

-         item.desc,

-         item.aliases

-       ]]);

+   // Get syntaxes and use the data to populate the attribute's table

+   console.log("CMD: Get syntaxes: " + cmd.join(' '));

+   cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', "attributetypes", 'get_syntaxes'];

+   cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(syntax_data) {

+     var obj = JSON.parse(syntax_data);

+     var syntax_list = [];

+ 

+     load_schema_objects_to_select('matchingrules', 'attr-eq-mr-select');

+     load_schema_objects_to_select('matchingrules', 'attr-order-mr-select');

+     load_schema_objects_to_select('matchingrules', 'attr-sub-mr-select');

+     load_schema_objects_to_select('attributetypes', 'schema-list');

+     load_schema_objects_to_select('objectclasses', 'oc-parent');

+     load_schema_objects_to_select('attributetypes', 'attr-parent');

+ 

+     for (var i = 0; i < obj.items.length; i++) {

+       item = obj.items[i];

+       syntax_list.push.apply(syntax_list, [item]);

      }

-     // Update html table

-     schema_at_table = $('#attr-table').DataTable({

-       "data": data,

-       "paging": true,

-       "bAutoWidth": false,

-       "dom": '<"pull-left"f><"pull-right"l>tip', // Moves the search box to the left

-       "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],

-       "language": {

-         "emptyTable": "No attributes defined",

-         "search": "Search Attributes"

-       },

-       "columnDefs": [ {

-         "targets": 7,

-         "orderable": false

-       }, {

-         "targets": 8,

-         "visible": false

-        }]

+     // Update syntax select html in attribute's edit window

+     $.each(syntax_list, function (i, item) {

+         $("#attr-syntax").append($('<option>', {

+             value: item.id,

+             text : item.name + " (" + item.id + ")"

+         }));

      });

-   }).fail(function(data) {

-       console.log("failed: " + data.message);

+ 

+     var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', 'attributetypes', 'list'];

+     console.log("CMD: Get attributes: " + cmd.join(' '));

+     cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(at_data) {

+       var obj = JSON.parse(at_data);

+       var data = [];

+       var syntax_name;

+       for (var i = 0; i < obj.items.length; i++) {

+         var attr_btn = attr_btn_html_only_view;

+         item = obj.items[i];

+         if (item.single_value) {

+             multivalued = 'no';

+         } else {

+             multivalued = 'yes';

+         }

+         $.each(syntax_list, function (i, syntax) {

+           if (syntax.id === item.syntax) {

+             syntax_name = '<div title="' + syntax.id + '">' + syntax.name + '</div>';

+           }

+         });

+         // If attribute is user defined them the action button is enabled

+         if (is_x_origin_user_defined(item.x_origin)) {

+           attr_btn = attr_btn_html;

+         }

+         data.push.apply(data, [[

+           item.name,

+           item.oid,

+           syntax_name,

+           multivalued,

+           item.equality,

+           item.ordering,

+           item.substr,

+           attr_btn,

+           item.desc,

+           item.aliases,

+           item.x_origin,

+           attr_usage_opts[item.usage],

+           item.no_user_mod,

+           item.sup

+         ]]);

+       }

+       // Update html table

+       schema_at_table = $('#attr-table').DataTable({

+         "data": data,

+         "paging": true,

+         "bAutoWidth": false,

+         "dom": '<"pull-left"f><"pull-right"l>tip', // Moves the search box to the left

+         "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],

+         "language": {

+           "emptyTable": "No attributes defined",

+           "search": "Search Attributes"

+         },

+         "columnDefs": [ {

+           "targets": 7,

+           "orderable": false

+         }, {

+           "targets": 8,

+           "visible": false

+         }]

+       });

+     }).fail(function(at_data) {

+         console.log("failed: " + at_data.message);

+         check_inst_alive(1);

+     });

+ 

+   }).fail(function(syntax_data) {

+       console.log("failed: " + syntax_data.message);

        check_inst_alive(1);

    });

  

-   var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', 'matchingrules', 'list'];

+   cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', 'matchingrules', 'list'];

    console.log("CMD: Get matching rules: " + cmd.join(' '));

-   cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

-     var obj = JSON.parse(data);

+   cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(mr_data) {

+     var obj = JSON.parse(mr_data);

      var data = [];

-     for (var idx in obj['items']) {

-       item = obj['items'][idx];

+     for (var i = 0; i < obj.items.length; i++) {

+       item = obj.items[i];

        data.push.apply(data, [[

          item.name,

          item.oid,

          item.syntax,

-         item.desc]])

-     };

+         item.desc]]);

+     }

      schema_mr_table = $('#schema-mr-table').DataTable({

        "paging": true,

        "data": data,
@@ -229,8 +320,10 @@ 

        "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]],

      });

  

-   }).fail(function(data) {

-       console.log("failed: " + data.message);

+     console.log("Finished loading schema.");

+ 

+   }).fail(function(mr_data) {

+       console.log("failed: " + mr_data.cmd);

        check_inst_alive(1);

    });

  }
@@ -257,6 +350,13 @@ 

        $("#schema-mr").show();

      });

  

+     $('#attr-user-defined').change(function() {

+       schema_at_table.draw();

+     });

+     $('#oc-user-defined').change(function() {

+       schema_oc_table.draw();

+     });

+ 

      //

      // Modals/Forms

      //
@@ -268,13 +368,16 @@ 

       */

      $("#add-oc-button").on("click", function() {

        clear_oc_form();

-       document.getElementById("oc-parent").value = 'top'

+       document.getElementById("oc-parent").value = 'top';

      });

  

      $("#save-oc-button").on("click", function() {

        var oc_name = $("#oc-name").val();

        var oc_oid = $("#oc-oid").val();

        var oc_parent = $("#oc-parent").val();

+       var oc_kind = $("#oc-kind").val();

+       var oc_desc = $("#oc-desc").val();

+       var oc_x_origin = $("#oc-x-origin").val();

        var oc_required_list = $('#oc-required-list option').map(function() { return $(this).val(); }).get();

        var oc_allowed_list = $('#oc-allowed-list option').map(function() { return $(this).val(); }).get();

  
@@ -292,15 +395,26 @@ 

        // Process and validate parameters

        cmd.push.apply(cmd, ["--oid", oc_oid]);

        cmd.push.apply(cmd, ["--sup", oc_parent]);

-       cmd.push.apply(cmd, ["--must", oc_required_list]);

-       cmd.push.apply(cmd, ["--may", oc_allowed_list]);

+       cmd.push.apply(cmd, ["--kind", oc_kind]);

+       cmd.push.apply(cmd, ["--desc", oc_desc]);

+       cmd.push.apply(cmd, ["--x-origin", oc_x_origin]);

+       cmd.push.apply(cmd, ["--must"]);

+       if (oc_required_list.length !== 0) {

+         cmd.push.apply(cmd, oc_required_list);

+       } else {

+         cmd.push.apply(cmd, [""]);

+       }

+       cmd.push.apply(cmd, ["--may"]);

+       if (oc_allowed_list.length !== 0) {

+         cmd.push.apply(cmd, oc_allowed_list);

+       } else {

+         cmd.push.apply(cmd, [""]);

+       }

  

        $("#save-oc-spinner").show();

        console.log("CMD: Save objectclass: " + cmd.join(' '));

        cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).

        done(function(data) {

-         $("#save-oc-spinner").hide();

-         popup_success("The objectClass was saved in DS");

          $("#oc-name").attr('disabled', false);

  

          // Update html table (if edit: delete old then add new)
@@ -308,33 +422,43 @@ 

            var selector = $('tr:contains(' + oc_name + ')');

            schema_oc_table.row(selector).remove().draw(false);

          }

-         if (oc_required_list) {

-           oc_required_list = oc_required_list.join(" ")

-         }

-         if (oc_allowed_list) {

-           oc_allowed_list = oc_allowed_list.join(" ")

-         }

- 

-         schema_oc_table.row.add( [

-           oc_name,

-           oc_oid,

-           oc_parent,

-           oc_required_list,

-           oc_allowed_list,

-           oc_btn_html

-         ] ).draw( false );

+         var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', 'objectclasses', 'query', oc_name];

+         console.log("CMD: Query objectclass: " + cmd.join(' '));

+         cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).

+         done(function(oc_data) {

+           var obj = JSON.parse(oc_data);

+           var item = obj.oc;

+           schema_oc_table.row.add( [

+             item.name,

+             item.oid,

+             item.sup,

+             item.must.join(" "),

+             item.may.join(" "),

+             oc_btn_html,

+             item.x_origin,

+             oc_kind_opts[item.kind],

+             item.desc

+           ] ).draw( false );

+         }).

+         fail(function(oc_data) {

+           popup_err("err", oc_data.message);

+           console.log("failed: " + oc_data.message);

+           check_inst_alive(1);

+         });

          // Replace the option in 'Edit objectClass' window

          if (!edit) {

            var option = $('<option></option>').attr("value", oc_name).text(oc_name);

            $("#oc-parent").append(option);

          }

+         $("#save-oc-spinner").hide();

+         popup_success("The objectClass was saved in DS");

          $("#add-edit-oc-form").modal('toggle');

        }).

        fail(function(data) {

          $("#save-oc-spinner").hide();

          popup_err("Error", "Failed to save the objectClass\n" + data.message);

          $("#add-edit-oc-form").modal('toggle');

-       })

+       });

      });

  

      // Required Attributes
@@ -394,13 +518,17 @@ 

       */

      $("#create-attr-button").on("click", function() {

        clear_attr_form();

-     })

+     });

  

      $("#save-attr-button").on("click", function() {

        var attr_name = $("#attr-name").val();

        var attr_oid = $("#attr-oid").val();

        var attr_syntax = $("#attr-syntax").val();

+       var attr_syntax_text = $("#attr-syntax :selected").text();

+       var attr_usage = $('#attr-usage').val();

        var attr_desc = $('#attr-desc').val();

+       var attr_x_origin= $('#attr-x-origin').val();

+       var attr_parent = $('#attr-parent').val();

        var attr_aliases = $('#attr-alias').val().split(" ");

        var eq_mr= $('#attr-eq-mr-select').val();

        var order_mr = $('#attr-order-mr-select').val();
@@ -408,7 +536,11 @@ 

        var multiple = 'no';

        if ( $("#attr-multivalued").is(":checked") ) {

          multiple = 'yes';

-       };

+       }

+       var no_user_mod = false;

+       if ( $("#attr-no-user-mod").is(":checked") ) {

+         no_user_mod = true;

+       }

        var action = 'add';

        var edit = false;

        if ( $("#add-edit-attr-header").text().indexOf("Edit Attribute") != -1){
@@ -439,95 +571,156 @@ 

        } else {

          cmd.push.apply(cmd, ["--multi-value"]);

        }

+       if (no_user_mod) {

+         cmd.push.apply(cmd, ["--no-user-mod"]);

+       } else {

+         cmd.push.apply(cmd, ["--user-mod"]);

+       }

        cmd.push.apply(cmd, ["--oid", attr_oid]);

+       cmd.push.apply(cmd, ["--usage", attr_usage]);

+       cmd.push.apply(cmd, ["--sup", attr_parent]);

        cmd.push.apply(cmd, ["--desc", attr_desc]);

-       cmd.push.apply(cmd, ["--equality", eq_mr]);

-       cmd.push.apply(cmd, ["--substr", order_mr]);

-       cmd.push.apply(cmd, ["--ordering", sub_mr]);

+       cmd.push.apply(cmd, ["--x-origin", attr_x_origin]);

+       cmd.push.apply(cmd, ["--equality"]);

+       if (eq_mr) {

+         cmd.push.apply(cmd, [eq_mr]);

+       } else {

+         cmd.push.apply(cmd, [""]);

+       }

+       cmd.push.apply(cmd, ["--substr"]);

+       if (sub_mr) {

+         cmd.push.apply(cmd, [sub_mr]);

+       } else {

+         cmd.push.apply(cmd, [""]);

+       }

+       cmd.push.apply(cmd, ["--ordering"]);

+       if (order_mr) {

+         cmd.push.apply(cmd, [order_mr]);

+       } else {

+         cmd.push.apply(cmd, [""]);

+       }

        $("#save-attr-spinner").show();

        console.log("CMD: Save attribute: " + cmd.join(' '));

        cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).

        done(function(data) {

-         $("#save-attr-spinner").hide();

-         popup_success("The attribute was saved in DS");

+         var attr_syntax_name = '<div title="' + attr_syntax + '">' +

+                                attr_syntax_text.substr(0, attr_syntax_text.indexOf(" (")) + '</div>';

          $("#attr-name").attr('disabled', false);

          // Update html table (if edit: delete old then add new)

          if ( edit ) {

            var selector = $('tr:contains(' + attr_name + ')');

            schema_at_table.row(selector).remove().draw(false);

          }

- 

-         // Create attribute row to dataTable

-         schema_at_table.row.add( [

-               attr_name,

-               attr_oid,

-               attr_syntax,

-               multiple,

-               eq_mr,

-               order_mr,

-               sub_mr,

-               attr_btn_html,

-               attr_desc,

-               attr_aliases

-          ] ).draw( false );

-          if (!edit) {

-            var option = $('<option></option>').attr("value", attr_name).text(attr_name);

-            $("#schema-list").append(option);

-          }

+         var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', 'attributetypes', 'query', attr_name];

+         console.log("CMD: Query attribute: " + cmd.join(' '));

+         cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).

+         done(function(at_data) {

+           var obj = JSON.parse(at_data);

+           var item = obj.at;

+           schema_at_table.row.add( [

+             item.name,

+             item.oid,

+             attr_syntax_name,

+             multiple,

+             item.equality,

+             item.ordering,

+             item.substr,

+             attr_btn_html,

+             item.desc,

+             item.aliases,

+             item.x_origin,

+             attr_usage_opts[item.usage],

+             item.no_user_mod,

+             item.sup

+           ] ).draw( false );

+           $("#attr-name").attr('disabled', false);

+         }).

+         fail(function(at_data) {

+           popup_err("err", at_data.message);

+           console.log("failed: " + at_data.message);

+           check_inst_alive(1);

+         });

+         if (!edit) {

+           var option = $('<option></option>').attr("value", attr_name).text(attr_name);

+           $("#schema-list").append(option);

+         }

+         $("#save-attr-spinner").hide();

+         popup_success("The attribute was saved in DS");

          $("#add-edit-attr-form").modal('toggle');

        }).

        fail(function(data) {

          $("#save-attr-spinner").hide();

          popup_err("Error", "Failed to save the attribute\n" + data.message);

          $("#add-edit-attr-form").modal('toggle');

-      })

+      });

      });

  

-     $(document).on('click', '.attr-edit-btn', function(e) {

-         e.preventDefault();

-         clear_attr_form();

-         var data = schema_at_table.row( $(this).parents('tr') ).data();

-         var edit_attr_name = data[0];

-         var edit_attr_oid = data[1];

-         var edit_attr_syntax = data[2];

-         var edit_attr_multivalued = data[3];

-         var edit_attr_eq_mr = data[4];

-         var edit_attr_order_mr = data[5];

-         var edit_attr_sub_mr = data[6];

-         var edit_attr_desc = data[8];

-         var edit_attr_aliases = data[9];

-         if (edit_attr_eq_mr) {

-           edit_attr_eq_mr = data[4]

-         }

-         if (edit_attr_order_mr) {

-           edit_attr_order_mr = data[5]

-         }

-         if (edit_attr_sub_mr) {

-           edit_attr_sub_mr = data[6]

-         }

+     function load_attr_form(element) {

+       clear_attr_form();

+       var data = schema_at_table.row(element.parents('tr') ).data();

+       var edit_attr_name = data[0];

+       var edit_attr_oid = data[1];

+       var edit_attr_syntax = $.parseHTML(data[2])[0].title;

+       var edit_attr_multivalued = data[3];

+       var edit_attr_eq_mr = data[4];

+       var edit_attr_order_mr = data[5];

+       var edit_attr_sub_mr = data[6];

+       var edit_attr_desc = data[8];

+       var edit_attr_aliases = data[9];

+       var edit_attr_x_origin = data[10];

+       var edit_attr_usage = data[11];

+       var edit_attr_no_user_mod = data[12];

+       var edit_attr_parent = data[13];

+       if (edit_attr_eq_mr) {

+         edit_attr_eq_mr = data[4];

+       }

+       if (edit_attr_order_mr) {

+         edit_attr_order_mr = data[5];

+       }

+       if (edit_attr_sub_mr) {

+         edit_attr_sub_mr = data[6];

+       }

  

-         $("#add-edit-attr-header").html('Edit Attribute: ' + edit_attr_name);

-         $("#attr-name").val(edit_attr_name);

-         $("#attr-name").attr('disabled', true);

-         $("#attr-oid").val(edit_attr_oid);

-         $("#attr-desc").val(edit_attr_desc);

-         if (edit_attr_aliases) {

-           $("#attr-alias").val(edit_attr_aliases.join(" "));

-         }

-         $("#attr-syntax").val(edit_attr_syntax);

-         $("#attr-multivalued").val(edit_attr_syntax);

-         $("#attr-multivalued").prop('checked', false);

-         if (edit_attr_multivalued == "yes") {

-           $("#attr-multivalued").prop('checked', true);

-         }

-         $("#save-attr-spinner").show();

-         $("#attr-eq-mr-select")[0].value = edit_attr_eq_mr;

-         $("#attr-order-mr-select")[0].value = edit_attr_order_mr;

-         $("#attr-sub-mr-select")[0].value = edit_attr_sub_mr;

-         $("#save-attr-spinner").hide();

+       $("#add-edit-attr-header").html('Edit Attribute: ' + edit_attr_name);

+       $("#attr-name").val(edit_attr_name);

+       $("#attr-name").attr('disabled', true);

+       $("#attr-oid").val(edit_attr_oid);

+       $("#attr-usage")[0].value = edit_attr_usage;

+       $("#attr-parent")[0].value = edit_attr_parent;

+       $("#attr-desc").val(edit_attr_desc);

+       $("#attr-x-origin").val(edit_attr_x_origin);

+       if (edit_attr_aliases) {

+         $("#attr-alias").val(edit_attr_aliases.join(" "));

+       }

+       $("#attr-syntax").val(edit_attr_syntax);

+       $("#attr-multivalued").prop('checked', false);

+       if (edit_attr_multivalued == "yes") {

+         $("#attr-multivalued").prop('checked', true);

+       }

+       $("#attr-no-user-mod").prop('checked', false);

+       if (edit_attr_no_user_mod) {

+         $("#attr-no-user-mod").prop('checked', true);

+       }

+       $("#save-attr-spinner").show();

+       $("#attr-eq-mr-select")[0].value = edit_attr_eq_mr;

+       $("#attr-order-mr-select")[0].value = edit_attr_order_mr;

+       $("#attr-sub-mr-select")[0].value = edit_attr_sub_mr;

+       $("#save-attr-spinner").hide();

  

-         $("#add-edit-attr-form").modal('toggle');

-     } );

+       $("#add-edit-attr-form").modal('toggle');

+     }

+ 

+     $(document).on('click', '.attr-view-btn', function(e) {

+       e.preventDefault();

+       load_attr_form($(this));

+       $("#save-attr-button").attr('title', 'Only user-defined attributes can be modified');

+       $("#save-attr-button").attr('disabled', true);

+     });

+ 

+     $(document).on('click', '.attr-edit-btn', function(e) {

+       e.preventDefault();

+       load_attr_form($(this));

+     });

  

      $(document).on('click', '.attr-del-btn', function(e) {

        e.preventDefault();
@@ -537,9 +730,9 @@ 

        popup_confirm("Are you sure you want to delete attribute: <b>" + del_attr_name + "</b>", "Confirmation", function (yes) {

          if (yes) {

            var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', 'attributetypes', 'remove', del_attr_name];

-           console.log("CMD: remove attribute: " + cmd.join(' '));

+           console.log("CMD: Remove attribute: " + cmd.join(' '));

            cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

-             popup_success("Attribute was successfully removed!")

+             popup_success("Attribute was successfully removed!");

              schema_at_table.row( at_row.parents('tr') ).remove().draw( false );

              $("#schema-list option[value='" + del_attr_name + "']").remove();

            }).fail(function(data) {
@@ -549,17 +742,19 @@ 

        });

      });

  

-     $(document).on('click', '.oc-edit-btn', function(e) {

-       e.preventDefault();

+     function load_oc_form(element) {

        clear_oc_form();

-       var data = schema_oc_table.row( $(this).parents('tr') ).data();

+       var data = schema_oc_table.row(element.parents('tr') ).data();

        var edit_oc_name = data[0];

        var edit_oc_oid = data[1];

-       var edit_oc_parent = data[2]

+       var edit_oc_parent = data[2];

        var edit_oc_required = data[3].split(" ");

        var edit_oc_allowed = data[4].split(" ");

+       var edit_oc_x_origin = data[6];

+       var edit_oc_kind = data[7];

+       var edit_oc_desc = data[8];

          if (edit_oc_parent) {

-           edit_oc_parent = data[2]

+           edit_oc_parent = data[2];

          }

  

        $("#save-oc-spinner").show();
@@ -567,24 +762,42 @@ 

        $("#oc-name").attr('disabled', true);

        $("#oc-name").val(edit_oc_name);

        $("#oc-oid").val(edit_oc_oid);

+       $("#oc-kind")[0].value = edit_oc_kind;

+       $("#oc-desc").val(edit_oc_desc);

+       $("#oc-x-origin").val(edit_oc_x_origin);

        $("#oc-parent")[0].value = edit_oc_parent;

        $.each(edit_oc_required, function (i, item) {

-         $("#oc-required-list").append($('<option>', {

-           value: item,

-           text : item

-         }));

+         if (item) {

+           $("#oc-required-list").append($('<option>', {

+             value: item,

+             text : item

+           }));

+         }

        });

        $.each(edit_oc_allowed, function (i, item) {

-         $("#oc-allowed-list").append($('<option>', {

-           value: item,

-           text : item

-         }));

+         if (item) {

+           $("#oc-allowed-list").append($('<option>', {

+             value: item,

+             text : item

+           }));

+         }

        });

        $("#save-oc-spinner").hide();

  

        // Update modal html header and fields and show()

        $("#add-edit-oc-form").modal('toggle');

+     }

  

+     $(document).on('click', '.oc-view-btn', function(e) {

+       e.preventDefault();

+       load_oc_form($(this));

+       $("#save-oc-button").attr('title', 'Only user-defined objectClasses can be modified');

+       $("#save-oc-button").attr('disabled', true);

+     });

+ 

+     $(document).on('click', '.oc-edit-btn', function(e) {

+       e.preventDefault();

+       load_oc_form($(this));

      });

  

      $(document).on('click', '.oc-del-btn', function(e) {
@@ -598,7 +811,7 @@ 

            var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'schema', 'objectclasses', 'remove', del_oc_name];

            console.log("CMD: Remove objectclass: " + cmd.join(' '));

            cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {

-             popup_success("ObjectClass was successfully removed!")

+             popup_success("ObjectClass was successfully removed!");

              schema_oc_table.row( oc_row.parents('tr') ).remove().draw( false );

              $("#oc-parent option[value='" + del_oc_name + "']").remove();

            }).fail(function(data) {
@@ -613,6 +826,3 @@ 

  });

  

  

- 

- 

- 

@@ -2,6 +2,10 @@ 

  <div id="schema-content">

    <div id="objectclass-page" class="all-pages" hidden>

      <h3 class="ds-config-header">Objectclasses</h3>

+     <div>

+       <input type="checkbox" class="ds-config-checkbox" id="oc-user-defined"><label

+             for="oc-user-defined" class="ds-label">Only Non-standard Schema (objectClasses with X-ORIGIN: "user defined")</label>

+     </div>

      <table id="oc-table" class="display ds-repl-table" cellspacing="0" width="100%">

        <thead>

          <tr class="ds-table-header">
@@ -20,6 +24,10 @@ 

    </div>

    <div id="attribute-page" class="all-pages" hidden>

      <h3 class="ds-config-header">Attributes</h3>

+     <div>

+       <input type="checkbox" class="ds-config-checkbox" id="attr-user-defined"><label

+             for="attr-user-defined" class="ds-label">Only Non-standard Schema (attributes with X-ORIGIN: "user defined")</label>

+     </div>

      <table id="attr-table" class="display ds-repl-table" cellspacing="0" width="100%">

        <thead>

          <tr class="ds-table-header">
@@ -73,53 +81,73 @@ 

            <div class="ds-inline">

              <p class="ds-modal-error"></p>

              <div>

+               <label for="attr-parent" class="ds-config-label-lrg" title="The parent attribute"><b>Parent Attribute</b></label><select

+                     class="btn btn-default dropdown ds-oc-dropdown" id="attr-parent">

+               <option value=""></option>

+             </select>

+             </div>

+             <div>

                <label for="attr-name" class="ds-config-label-lrg" title="The attribute name"><b

                  >Attribute Name</b></label><input class="ds-input" type="text" id="attr-name" size="40"/>

              </div>

              <div>

+               <label for="attr-desc" class="ds-config-label-lrg" title="The attribute description"><b

+               >Attribute Description</b></label><input class="ds-input" type="text" id="attr-desc" size="40"/>

+             </div>

+             <div>

+               <label for="attr-oid" class="ds-config-label-lrg" title="The attribute name"><b

+               >Attribute OID</b></label><input class="ds-input" type="text" id="attr-oid" size="40"/>

+             </div>

+             <div>

                <label for="attr-syntax" class="ds-config-label-lrg" title="The attribute syntax"><b>Attribute Syntax</b></label><select

                  class="btn btn-default dropdown ds-oc-dropdown" id="attr-syntax">

                  <option value="">Make a selection</option>

                </select>

              </div>

              <div>

-               <input type="checkbox" class="ds-config-checkbox" id="attr-multivalued"><label

-                 for="attr-multivalued" class="ds-label"> Attribute Multi-Valued </label>

+               <label for="attr-usage" class="ds-config-label-lrg" title="The parent attribute"><b>Attribute Usage</b></label><select

+                     class="btn btn-default dropdown ds-oc-dropdown" id="attr-usage">

+               </select>

              </div>

              <div>

-               <label for="attr-desc" class="ds-config-label-lrg" title="The attribute description"><b

-                 >Attribute Description</b></label><input class="ds-input" type="text" id="attr-desc" size="40"/>

+               <input type="checkbox" class="ds-config-checkbox" id="attr-multivalued"><label

+                 for="attr-multivalued" class="ds-label"> Attribute Multi-Valued </label>

              </div>

              <div>

-               <label for="attr-oid" class="ds-config-label-lrg" title="The attribute name"><b

-                 >Attribute OID</b></label><input class="ds-input" type="text" id="attr-oid" size="40"/>

+               <input type="checkbox" class="ds-config-checkbox" id="attr-no-user-mod"><label

+                     for="attr-no-user-mod" class="ds-label"> Read-only (NO-USER-MODIFICATION flag) </label>

              </div>

              <div>

                <label for="attr-alias" class="ds-config-label-lrg" title="The attribute alias list separated by space"><b

                  >Attribute Aliases</b></label><input class="ds-input" type="text" id="attr-alias" size="40"/>

              </div>

-               <div class="panel panel-default">

-               <div class="panel-heading"><strong>Matching rules</strong></div>

-               <div class="panel-body">

-                 <div>

-                   <label for="attr-eq-mr-select" class="ds-config-label-lrg"><b>Equality</b></label><select

-                         class="btn btn-default dropdown ds-oc-dropdown" id="attr-eq-mr-select">

-                   <option></option>

-                 </select>

-                 </div>

-                 <div>

-                   <label for="attr-order-mr-select" class="ds-config-label-lrg"><b>Ordering</b></label><select

-                         class="btn btn-default dropdown ds-oc-dropdown" id="attr-order-mr-select">

-                   <option></option>

-                 </select>

-                 </div>

-                 <div>

-                   <label for="attr-sub-mr-select" class="ds-config-label-lrg"><b>Substring</b></label><select

-                         class="btn btn-default dropdown ds-oc-dropdown" id="attr-sub-mr-select">

-                   <option></option>

-                 </select>

-                 </div>

+             <div class="panel panel-default">

+             <div class="panel-heading"><strong>Matching rules</strong></div>

+             <div class="panel-body">

+               <div>

+                 <label for="attr-eq-mr-select" class="ds-config-label-lrg"><b>Equality</b></label><select

+                       class="btn btn-default dropdown ds-oc-dropdown" id="attr-eq-mr-select">

+                 <option></option>

+               </select>

+               </div>

+               <div>

+                 <label for="attr-order-mr-select" class="ds-config-label-lrg"><b>Ordering</b></label><select

+                       class="btn btn-default dropdown ds-oc-dropdown" id="attr-order-mr-select">

+                 <option></option>

+               </select>

                </div>

+               <div>

+                 <label for="attr-sub-mr-select" class="ds-config-label-lrg"><b>Substring</b></label><select

+                       class="btn btn-default dropdown ds-oc-dropdown" id="attr-sub-mr-select">

+                 <option></option>

+               </select>

+               </div>

+             </div>

+             </div>

+             <div>

+               <label for="attr-x-origin" class="ds-config-label-lrg"

+               title="The attribute X-ORIGIN (keep 'user defined' if it's a non-standard attribute)"><b

+               >Attribute X-ORIGIN</b></label><input class="ds-input" type="text" id="attr-x-origin" size="40"/>

              </div>

            </div>

            <div id="save-attr-spinner" class="ds-center" hidden>
@@ -151,17 +179,27 @@ 

              <div class="ds-inline">

                <p class="ds-modal-error"></p>

                <div>

+                 <label for="oc-parent" class="ds-label-sm" title="The parent objectclass"><b>Parent Objectclass</b></label><select

+                       class="btn btn-default dropdown ds-oc-dropdown" id="oc-parent">

+               </select>

+               </div>

+               <div>

                  <label for="oc-name" class="ds-label-sm" title="The objectclass name"><b

                    >Objectclass Name</b></label><input class="ds-input" type="text" id="oc-name" size="40" required />

                </div>

                <div>

+                 <label for="oc-desc" class="ds-label-sm" title="The objectClass description"><b

+                 >ObjectClass Description</b></label><input class="ds-input" type="text" id="oc-desc" size="40"/>

+               </div>

+               <div>

                  <label for="oc-oid" class="ds-label-sm" title="Objectclass OID (optional)"><b

                    >OID (optional)</b></label><input class="ds-input" value="" type="text" id="oc-oid" size="40"/>

                </div>

                <div>

-                 <label for="oc-parent" class="ds-label-sm" title="The parent objectclass"><b>Parent Objectclass</b></label><select

-                   class="btn btn-default dropdown ds-oc-dropdown" id="oc-parent">

-                   </select>

+                 <label for="oc-kind" class="ds-label-sm" title="The parent objectclass"><b>Objectclass Kind</b></label><select

+                       class="btn btn-default dropdown ds-oc-dropdown" id="oc-kind">

+                 <option value=""></option>

+               </select>

                </div>

                <hr>

                <div class="ds-container">
@@ -195,6 +233,11 @@ 

                    </select>

                  </div>

                </div>

+               <div>

+                 <label for="oc-x-origin" class="ds-config-label-lrg"

+                        title="The objectClass X-ORIGIN (keep 'user defined' if it's a non-standard objectClass)"><b

+                 >ObjectClass X-ORIGIN</b></label><input class="ds-input" type="text" id="oc-x-origin" size="40"/>

+               </div>

              </div>

            </form>

            <div id="save-oc-spinner" class="ds-center" hidden>

@@ -8,7 +8,7 @@ 

  

  from json import dumps as dump_json

  from lib389.cli_base import _get_arg

- from lib389.schema import Schema

+ from lib389.schema import Schema, AttributeUsage, ObjectclassKind

  

  

  def _validate_dual_args(enable_arg, disable_arg):
@@ -176,7 +176,7 @@ 

      if args.json:

          print(dump_json(result))

      else:

-         for name, id in result.items():

+         for id, name in result.items():

              log.info("%s (%s)", name, id)

  

  
@@ -187,26 +187,45 @@ 

      parameters = {'names': [args.name,],

                    'oid': args.oid,

                    'desc': args.desc,

-                   'obsolete': _validate_dual_args(args.obsolete, args.not_obsolete)}

+                   'x_origin': args.x_origin,

+                   'obsolete': None}

  

      if type == 'attributetypes':

+         if args.usage is not None:

+             usage = args.usage

+             if usage in [item.name for item in AttributeUsage]:

+                 usage = AttributeUsage[usage].value

+             else:

+                 raise ValueError("Attribute usage should be one of the next: "

+                                  "userApplications, directoryOperation, distributedOperation, dSAOperation")

+         else:

+             usage = None

+ 

          parameters.update({'single_value': _validate_dual_args(args.single_value, args.multi_value),

                             'aliases': args.aliases,

                             'syntax': args.syntax,

                             'syntax_len': None,  # We need it for

                             'x_ordered': None,   # the correct ldap.schema.models work

-                            'no_user_mod': _validate_dual_args(args.no_user_mod, args.with_user_mod),

+                            'collective': None,

+                            'no_user_mod': _validate_dual_args(args.no_user_mod, args.user_mod),

                             'equality': args.equality,

                             'substr': args.substr,

                             'ordering': args.ordering,

-                            'x_origin': args.x_origin,

-                            'collective': _validate_dual_args(args.collective, args.not_collective),

-                            'usage': args.usage,

+                            'usage': usage,

                             'sup': args.sup})

      elif type == 'objectclasses':

+         if args.kind is not None:

+             kind = args.kind.upper()

+             if kind in [item.name for item in ObjectclassKind]:

+                 kind = ObjectclassKind[kind].value

+             else:

+                 raise ValueError("ObjectClass kind should be one of the next: STRUCTURAL, ABSTRACT, AUXILIARY")

+         else:

+             kind = None

+ 

          parameters.update({'must': args.must,

                             'may': args.may,

-                            'kind': args.kind,

+                            'kind': kind,

                             'sup': args.sup})

  

      return parameters
@@ -219,16 +238,9 @@ 

      parser.add_argument('name',  help='NAME of the object')

      parser.add_argument('--oid', help='OID assigned to the object')

      parser.add_argument('--desc', help='Description text(DESC) of the object')

-     parser.add_argument('--obsolete', action='store_true',

-                         help='True if the object is marked as OBSOLETE in the schema.'

-                              'Only one of the flags this or --not-obsolete should be specified')

-     parser.add_argument('--not-obsolete', action='store_true',

-                         help='True if the OBSOLETE mark should be removed'

-                              'object is marked as OBSOLETE in the schema'

-                              'Only one of the flags this or --obsolete should be specified')

+     parser.add_argument('--x-origin',

+                         help='Provides information about where the attribute type is defined')

      if type == 'attributetypes':

-         parser.add_argument('--syntax', required=True,

-                             help='OID of the LDAP syntax assigned to the attribute')

          parser.add_argument('--aliases', nargs='+', help='Additional NAMEs of the object.')

          parser.add_argument('--single-value', action='store_true',

                              help='True if the matching rule must have only one value'
@@ -238,8 +250,8 @@ 

                                   'Only one of the flags this or --single-value should be specified')

          parser.add_argument('--no-user-mod', action='store_true',

                              help='True if the attribute is not modifiable by a client application'

-                                  'Only one of the flags this or --with-user-mod should be specified')

-         parser.add_argument('--with-user-mod', action='store_true',

+                                  'Only one of the flags this or --user-mod should be specified')

+         parser.add_argument('--user-mod', action='store_true',

                              help='True if the attribute is modifiable by a client application (default)'

                                   'Only one of the flags this or --no-user-mode should be specified')

          parser.add_argument('--equality',
@@ -251,24 +263,15 @@ 

          parser.add_argument('--ordering',

                              help='NAME or OID of the matching rule used for checking'

                                   'whether attribute values are lesser - equal than')

-         parser.add_argument('--x-origin',

-                             help='Provides information about where the attribute type is defined')

-         parser.add_argument('--collective',

-                             help='True if the attribute is assigned their values by virtue in their membership in some collection'

-                                  'Only one of the flags this or --not-collective should be specified')

-         parser.add_argument('--not-collective',

-                             help='True if the attribute is not assigned their values by virtue in their membership in some collection (default)'

-                                  'Only one of the flags this or --collective should be specified')

          parser.add_argument('--usage',

-                             help='The flag indicates how the attribute type is to be used.'

-                                  'userApplications - user, directoryOperation - directory operational,'

-                                  'distributedOperation - DSA-shared operational, dSAOperation - DSA - specific operational')

-         parser.add_argument('--sup', nargs='?', help='The list of NAMEs or OIDs of attribute types'

+                             help='The flag indicates how the attribute type is to be used. Choose from the list: '

+                                  'userApplications (default), directoryOperation, distributedOperation, dSAOperation')

+         parser.add_argument('--sup', nargs='+', help='The list of NAMEs or OIDs of attribute types'

                                                       'this attribute type is derived from')

      elif type == 'objectclasses':

          parser.add_argument('--must', nargs='+', help='NAMEs or OIDs of all attributes an entry of the object must have')

          parser.add_argument('--may', nargs='+', help='NAMEs or OIDs of additional attributes an entry of the object may have')

-         parser.add_argument('--kind', help='Kind of an object. 0 = STRUCTURAL (default), 1 = ABSTRACT, 2 = AUXILIARY')

+         parser.add_argument('--kind', help='Kind of an object. STRUCTURAL (default), ABSTRACT, AUXILIARY')

          parser.add_argument('--sup', nargs='+', help='NAMEs or OIDs of object classes this object is derived from')

      else:

          raise ValueError("Wrong parser type: %s" % type)
@@ -291,9 +294,11 @@ 

      at_add_parser = attributetypes_subcommands.add_parser('add', help='Add an attribute type to this system')

      at_add_parser.set_defaults(func=add_attributetype)

      _add_parser_args(at_add_parser, 'attributetypes')

+     at_add_parser.add_argument('--syntax', required=True, help='OID of the LDAP syntax assigned to the attribute')

      at_edit_parser = attributetypes_subcommands.add_parser('edit', help='Edit an attribute type on this system')

      at_edit_parser.set_defaults(func=edit_attributetype)

      _add_parser_args(at_edit_parser, 'attributetypes')

+     at_edit_parser.add_argument('--syntax', help='OID of the LDAP syntax assigned to the attribute')

      at_remove_parser = attributetypes_subcommands.add_parser('remove', help='Remove an attribute type on this system')

      at_remove_parser.set_defaults(func=remove_attributetype)

      at_remove_parser.add_argument('name',  help='NAME of the object')

file modified
+47 -33
@@ -13,6 +13,7 @@ 

  import glob

  import ldap

  import ldif

+ from itertools import count

  from json import dumps as dump_json

  from operator import itemgetter

  from ldap.schema.models import AttributeType, ObjectClass, MatchingRule
@@ -22,38 +23,45 @@ 

  from lib389._mapped_object import DSLdapObject

  from lib389.tasks import SchemaReloadTask

  

- OBJECT_MODEL_PARAMS = {ObjectClass: {'names': (), 'oid': None, 'desc': None, 'obsolete': 0,

-                                      'kind': 0, 'sup': (), 'must': (), 'may': ()},

-                        AttributeType: {'names': (), 'oid': None, 'desc': None, 'obsolete': 0,

-                                        'sup': (), 'equality': None, 'ordering': None, 'substr': None,

-                                        'syntax': None, 'syntax_len': None, 'single_value': 0, 'collective': 0,

-                                        'no_user_mod': 0, 'usage': 0, 'x_origin': None, 'x_ordered': None}}

- ATTR_SYNTAXES = {"Binary": "1.3.6.1.4.1.1466.115.121.1.5",

-                  "Bit String": "1.3.6.1.4.1.1466.115.121.1.6",

-                  "Boolean": "1.3.6.1.4.1.1466.115.121.1.7",

-                  "Country String": "1.3.6.1.4.1.1466.115.121.1.11",

-                  "DN": "1.3.6.1.4.1.1466.115.121.1.12",

-                  "Delivery Method": "1.3.6.1.4.1.1466.115.121.1.14",

-                  "Directory String": "1.3.6.1.4.1.1466.115.121.1.15",

-                  "Enhanced Guide": "1.3.6.1.4.1.1466.115.121.1.21",

-                  "Facsimile": "1.3.6.1.4.1.1466.115.121.1.22",

-                  "Fax": "1.3.6.1.4.1.1466.115.121.1.23",

-                  "Generalized Time": "1.3.6.1.4.1.1466.115.121.1.24",

-                  "Guide": "1.3.6.1.4.1.1466.115.121.1.25",

-                  "IA5 String": "1.3.6.1.4.1.1466.115.121.1.26",

-                  "Integer": "1.3.6.1.4.1.1466.115.121.1.27",

-                  "JPEG": "1.3.6.1.4.1.1466.115.121.1.28",

-                  "Name and Optional UID": "1.3.6.1.4.1.1466.115.121.1.34",

-                  "Numeric String": "1.3.6.1.4.1.1466.115.121.1.36",

-                  "OctetString": "1.3.6.1.4.1.1466.115.121.1.40",

-                  "Object Class Description": "1.3.6.1.4.1.1466.115.121.1.37",

-                  "OID": "1.3.6.1.4.1.1466.115.121.1.38",

-                  "Postal Address": "1.3.6.1.4.1.1466.115.121.1.41",

-                  "Printable String": "1.3.6.1.4.1.1466.115.121.1.44",

-                  "Space-Insensitive String": "2.16.840.1.113730.3.7.1",

-                  "TelephoneNumber": "1.3.6.1.4.1.1466.115.121.1.50",

-                  "Teletex Terminal Identifier": "1.3.6.1.4.1.1466.115.121.1.51",

-                  "Telex Number": "1.3.6.1.4.1.1466.115.121.1.52"}

+ # Count should start with 0 because of the python-ldap API

+ ObjectclassKind = Enum("Objectclass kind",

+                        zip(["STRUCTURAL", "ABSTRACT", "AUXILIARY"], count()))

+ AttributeUsage = Enum("Attribute usage",

+                       zip(["userApplications", "directoryOperation", "distributedOperation", "dSAOperation"], count()))

+ 

+ OBJECT_MODEL_PARAMS = {ObjectClass: {'names': (), 'oid': None, 'desc': None, 'x_origin': None, 'obsolete': 0,

+                                      'kind': ObjectclassKind.STRUCTURAL.value, 'sup': (), 'must': (), 'may': ()},

+                        AttributeType: {'names': (), 'oid': None, 'desc': None, 'sup': (), 'obsolete': 0,

+                                        'equality': None, 'ordering': None, 'substr': None, 'collective': 0,

+                                        'syntax': None, 'syntax_len': None, 'single_value': 0,

+                                        'no_user_mod': 0, 'usage': AttributeUsage.userApplications.value,

+                                        'x_origin': None, 'x_ordered': None}}

+ ATTR_SYNTAXES = {"1.3.6.1.4.1.1466.115.121.1.5": "Binary",

+                  "1.3.6.1.4.1.1466.115.121.1.6": "Bit String",

+                  "1.3.6.1.4.1.1466.115.121.1.7": "Boolean",

+                  "1.3.6.1.4.1.1466.115.121.1.11": "Country String",

+                  "1.3.6.1.4.1.1466.115.121.1.12": "DN",

+                  "1.3.6.1.4.1.1466.115.121.1.14":  "Delivery Method",

+                  "1.3.6.1.4.1.1466.115.121.1.15": "Directory String",

+                  "1.3.6.1.4.1.1466.115.121.1.21": "Enhanced Guide",

+                  "1.3.6.1.4.1.1466.115.121.1.22": "Facsimile",

+                  "1.3.6.1.4.1.1466.115.121.1.23": "Fax",

+                  "1.3.6.1.4.1.1466.115.121.1.24": "Generalized Time",

+                  "1.3.6.1.4.1.1466.115.121.1.25": "Guide",

+                  "1.3.6.1.4.1.1466.115.121.1.26": "IA5 String",

+                  "1.3.6.1.4.1.1466.115.121.1.27": "Integer",

+                  "1.3.6.1.4.1.1466.115.121.1.28": "JPEG",

+                  "1.3.6.1.4.1.1466.115.121.1.34": "Name and Optional UID",

+                  "1.3.6.1.4.1.1466.115.121.1.36": "Numeric String",

+                  "1.3.6.1.4.1.1466.115.121.1.40": "OctetString",

+                  "1.3.6.1.4.1.1466.115.121.1.37": "Object Class Description",

+                  "1.3.6.1.4.1.1466.115.121.1.38": "OID",

+                  "1.3.6.1.4.1.1466.115.121.1.41": "Postal Address",

+                  "1.3.6.1.4.1.1466.115.121.1.44": "Printable String",

+                  "2.16.840.1.113730.3.7.1": "Space-Insensitive String",

+                  "1.3.6.1.4.1.1466.115.121.1.50": "TelephoneNumber",

+                  "1.3.6.1.4.1.1466.115.121.1.51": "Teletex Terminal Identifier",

+                  "1.3.6.1.4.1.1466.115.121.1.52": "Telex Number"}

  

  

  class Schema(DSLdapObject):
@@ -97,7 +105,7 @@ 

  

          if json:

              attr_syntaxes_list = []

-             for name, id in ATTR_SYNTAXES.items():

+             for id, name in ATTR_SYNTAXES.items():

                  attr_syntaxes_list.append({'name': name, 'id': id})

              result = {'type': 'list', 'items': attr_syntaxes_list}

          else:
@@ -122,6 +130,12 @@ 

                      obj_i['aliases'] = obj_i['names'][1:]

                  else:

                      obj_i['name'] = ""

+                 # Temporary workaround for X-ORIGIN in ObjectClass objects.

+                 # It should be removed after https://github.com/python-ldap/python-ldap/pull/247 is merged

+                 if "x_origin" not in obj_i and object_model != MatchingRule:

+                     for object_str in results:

+                         if obj_i['names'] == vars(object_model(object_str))['names'] and "X-ORIGIN" in object_str:

+                             obj_i['x_origin'] = object_str.split("X-ORIGIN '")[1].split("'")[0]

              object_insts = sorted(object_insts, key=itemgetter('name'))

              result = {'type': 'list', 'items': object_insts}

  

Description: Make standard schema attributes non-editable.
Attribute table should contain string representation of
syntax attributes, and if you point a cursor on them you can see ID.
MAY and MUST attributes list shouldn't contain empty lines.

https://pagure.io/389-ds-base/issue/49928

Reviewed by: ?

rebased onto b278c12cbf5ac328ab02bc5a49c8a29e6e370952

5 years ago

rebased onto d4835c4f3035ec702273b53925302dec763c542d

5 years ago

rebased onto 8c71cb76c02a031706e170460967de5bb8507633

5 years ago

This should be removed after we have the change in python-ldap package.
https://github.com/python-ldap/python-ldap/pull/247

Hey mate,

This looks like a really good idea, but I think the way we actually do the checking is going to cause some issues potentially. When we open the schema.c from 99user.ldif do we add "X-ORIGIN user-defined" to it?

What if a user supplies '98-myschema.ldif'?

It would be good to check the schema.c behaviour with content from 99user.ldif to be sure we have a consistent X-ORIGIN (even if one is supplied).

Thanks!

Hey mate,
This looks like a really good idea, but I think the way we actually do the checking is going to cause some issues potentially. When we open the schema.c from 99user.ldif do we add "X-ORIGIN user-defined" to it?
What if a user supplies '98-myschema.ldif'?
It would be good to check the schema.c behaviour with content from 99user.ldif to be sure we have a consistent X-ORIGIN (even if one is supplied).

This is a good point and one that caused me some grief with early versions of the UI... We can not rely on X-ORIGIN == USER_DEFINED to determine what is custom schema(editable) vs system/standard schema(non-editable).

If this is the only option(using x-origin), and unfortunately it might be, then it needs to be documented somewhere ( we'll be in touch @mmuehlfeldrh )

Hey mate,
This looks like a really good idea, but I think the way we actually do the checking is going to cause some issues potentially. When we open the schema.c from 99user.ldif do we add "X-ORIGIN user-defined" to it?

Yes. " X-ORIGIN 'user-defined' " is added for 99user.ldif.

What if a user supplies '98-myschema.ldif'?

It isn't added for something like '98-myschema.ldif' though...

It would be good to check the schema.c behaviour with content from 99user.ldif to be sure we have a consistent X-ORIGIN (even if one is supplied).

This is a good point and one that caused me some grief with early versions of the UI... We can not rely on X-ORIGIN == USER_DEFINED to determine what is custom schema(editable) vs system/standard schema(non-editable).

I agree... It is not a perfect solution but it is the only solution I found currently.

If this is the only option(using x-origin), and unfortunately it might be, then it needs to be documented somewhere ( we'll be in touch @mmuehlfeldrh )

So that's what I think:
- WebUI has a limited administration scope as I see it. So it is okay if WebUI will support only basic schema manipulations (still it is a pretty vast). We should document the part about X-ORIGIN of course. Also, I explicitly mentioned in the UI that it is about " X-ORIGIN 'user-defined' " exist or not exist thing (not like in Java console - standard/non-standard schema);
- dsconf CLI has bigger capabilities and you can do a bit more than you can do in WebUI, and construct the schema objects with all details. Also, it doesn't have any mentioning of 'user defined';
- and ldapmodify is for very experienced admins.

@spichugi Perhaps this is okay then, given it's added for 99user.ldif, but the issue there is that IPA on upgrade will sometimes write schema to 99user.ldif as part of replication ... so that means we can then edit system schema until the replica has a yum/dnf upgade and the schema update runs.

Saying that you shouldn't be using our command tools on IPA, so maybe non-issue?

For now I can't think of anything better, unless we went the other way - instead of adding X-ORIGIN to everything, we add a new schema element in schema.c (SYSTEMSCHEMA or whatever) to anything we read from /usr/share, then when it replicates from host A -> B, that SYSTEMSCHEMA is maintained even into 99user.ldif?

Risk there is breaking replication between 1.4 -> 1.3 that may not understand the new schema element type ....

rebased onto 208ec4046a3cdf7a3453c1ef7a282df6f0794f12

5 years ago

rebased onto 208ec4046a3cdf7a3453c1ef7a282df6f0794f12

5 years ago

I've made all the changes that were needed (applied @mhonek and @mreynolds requests).
Please, review.

@firstyear I think it makes sense to wait for IPA to make the feature request if they require it. I am not sure that they need it (or their users)... And it will go to the next big build anyway (now we have limited time and resources for such improvements)

LGTM for now. Lets get this in and play around with it more. We have time to make changes...

rebased onto 55c1e89fdbfcd789db8c0d47c80e05c5a1d9d128

5 years ago

rebased onto e881d1ae91c68e7c55e9e069be5b232d7d3e8bca

5 years ago

Is this really needed? Doesn't seem to do much

Is this really needed? Doesn't seem to do much

Yeap, it needed because of the how CLI tools work.
Let me give an example:

We have 'oc1' :

( oc1-oid NAME 'oc1' SUP top STRUCTURAL )

We want to add 'DESC' and we run schema objectclasses edit oc1 --desc "Hello world". So we have:

( oc1-oid NAME 'oc1' DESC 'Hello world' SUP top STRUCTURAL )

If we run schema objectclasses edit oc1 --sup Organization it won't change description
But if we run schema objectclasses edit oc1 --sup Organization --desc "" it will remove the DESC:

( oc1-oid NAME 'oc1' SUP Organization STRUCTURAL )

So if a user have cleared DESC form it will remove DESC from the objectclass. And it is why I have cmd.push.apply(cmd, [""]);

rebased onto 21af54b

5 years ago

Pull-Request has been merged by spichugi

5 years ago

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/3025

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

3 years ago