Hello community,

here is the log from the commit of package yast2-ldap for openSUSE:Factory 
checked in at 2014-10-05 20:27:24
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/yast2-ldap (Old)
 and      /work/SRC/openSUSE:Factory/.yast2-ldap.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "yast2-ldap"

Changes:
--------
--- /work/SRC/openSUSE:Factory/yast2-ldap/yast2-ldap.changes    2014-08-08 
10:10:06.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.yast2-ldap.new/yast2-ldap.changes       
2014-10-05 20:27:29.000000000 +0200
@@ -1,0 +2,6 @@
+Thu Sep 25 10:21:52 UTC 2014 - vark...@suse.com
+
+- bnc#897997 YaST2 User authentication not enumerating LDAP options
+- 3.1.13
+
+-------------------------------------------------------------------

Old:
----
  yast2-ldap-3.1.12.tar.bz2

New:
----
  yast2-ldap-3.1.13.tar.bz2

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ yast2-ldap.spec ++++++
--- /var/tmp/diff_new_pack.b1FL5c/_old  2014-10-05 20:27:30.000000000 +0200
+++ /var/tmp/diff_new_pack.b1FL5c/_new  2014-10-05 20:27:30.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           yast2-ldap
-Version:        3.1.12
+Version:        3.1.13
 Release:        0
 
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
@@ -59,6 +59,8 @@
 %{yast_moduledir}/*
 %{yast_clientdir}/*
 %{yast_scrconfdir}/*.scr
+%dir %{yast_yncludedir}/ldap/
+%{yast_yncludedir}/ldap/*
 %{yast_plugindir}/libpy2ag_ldap.so.*
 %{yast_plugindir}/libpy2ag_ldap.so
 %{yast_plugindir}/libpy2ag_ldap.la

++++++ yast2-ldap-3.1.12.tar.bz2 -> yast2-ldap-3.1.13.tar.bz2 ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-ldap-3.1.12/MAINTAINER 
new/yast2-ldap-3.1.13/MAINTAINER
--- old/yast2-ldap-3.1.12/MAINTAINER    2014-08-06 09:57:44.000000000 +0200
+++ new/yast2-ldap-3.1.13/MAINTAINER    2014-10-01 11:24:56.000000000 +0200
@@ -1 +1 @@
-Peter Varkoly <vark...@suse.com>
+Deprecated file. Use `osc maintainer yast2-ldap` instead.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-ldap-3.1.12/package/yast2-ldap.changes 
new/yast2-ldap-3.1.13/package/yast2-ldap.changes
--- old/yast2-ldap-3.1.12/package/yast2-ldap.changes    2014-08-06 
09:57:44.000000000 +0200
+++ new/yast2-ldap-3.1.13/package/yast2-ldap.changes    2014-10-01 
12:20:54.000000000 +0200
@@ -1,4 +1,10 @@
 -------------------------------------------------------------------
+Thu Sep 25 10:21:52 UTC 2014 - vark...@suse.com
+
+- bnc#897997 YaST2 User authentication not enumerating LDAP options
+- 3.1.13
+
+-------------------------------------------------------------------
 Tue Aug  5 13:02:04 UTC 2014 - vark...@suse.com
 
 - Set member_attribute to 'member'. We only use rfc2307bis.schema
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-ldap-3.1.12/package/yast2-ldap.spec 
new/yast2-ldap-3.1.13/package/yast2-ldap.spec
--- old/yast2-ldap-3.1.12/package/yast2-ldap.spec       2014-08-06 
09:57:44.000000000 +0200
+++ new/yast2-ldap-3.1.13/package/yast2-ldap.spec       2014-10-01 
12:20:54.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           yast2-ldap
-Version:        3.1.12
+Version:        3.1.13
 Release:        0
 
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
@@ -52,6 +52,8 @@
 %{yast_moduledir}/*
 %{yast_clientdir}/*
 %{yast_scrconfdir}/*.scr
+%dir %{yast_yncludedir}/ldap/
+%{yast_yncludedir}/ldap/*
 %{yast_plugindir}/libpy2ag_ldap.so.*
 %{yast_plugindir}/libpy2ag_ldap.so
 %{yast_plugindir}/libpy2ag_ldap.la
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-ldap-3.1.12/src/Ldap.rb 
new/yast2-ldap-3.1.13/src/Ldap.rb
--- old/yast2-ldap-3.1.12/src/Ldap.rb   2014-08-06 09:57:44.000000000 +0200
+++ new/yast2-ldap-3.1.13/src/Ldap.rb   2014-10-01 12:20:54.000000000 +0200
@@ -1410,6 +1410,89 @@
       deep_copy(@groups_dn)
     end
 
+    # Check if given DN exist and if it points to some template
+    # @param [String] dn
+    # @return [Hash,nil] empty map if DN don't exist, template map if DN points
+    #  to template object, nil if object with given DN is not template
+    def CheckTemplateDN(dn)
+      object = GetLDAPEntry(dn)
+      return object if object.nil? || object == {}
+      cls = Builtins.maplist(Ops.get_list(object, "objectClass", [])) do |c|
+        Builtins.tolower(c)
+      end
+      if Builtins.contains(cls, "suseobjecttemplate")
+        # exists as a template -> return object
+        object = ConvertDefaultValues(object)
+        Ops.set(object, "modified", "edited")
+        return AddMissingAttributes(object)
+      else
+        # error message
+        Popup.Error(
+          _(
+            "An object with the selected DN exists, but it is not a template 
object.\nSelect another one.\n"
+          )
+        )
+        return nil
+      end
+    end
+
+    # Save the edited map of configuration modules to global map
+    def CommitConfigModules(modules)
+      modules = deep_copy(modules)
+      Builtins.foreach(
+        Convert.convert(modules, :from => "map", :to => "map <string, map>")
+      ) do |dn, modmap|
+        if !Builtins.haskey(@config_modules, dn)
+          Ops.set(@config_modules, dn, Builtins.eval(modmap))
+          @ldap_modified = true
+          next
+        end
+        # 'val' can be list (most time), map (default_values), string
+        Builtins.foreach(
+          Convert.convert(modmap, :from => "map", :to => "map <string, any>")
+        ) do |attr, val|
+          if Ops.get(@config_modules, [dn, attr]) != val
+            Ops.set(@config_modules, [dn, attr], val)
+            if !Builtins.haskey(modmap, "modified")
+              Ops.set(@config_modules, [dn, "modified"], "edited")
+            end
+            @ldap_modified = true
+            Builtins.y2debug("modified value: %1", val)
+          end
+        end
+      end
+      true
+    end
+
+    # Save the edited map of templates to global map
+    def CommitTemplates(templs)
+      templs = deep_copy(templs)
+      Builtins.foreach(
+        Convert.convert(templs, :from => "map", :to => "map <string, map>")
+      ) do |dn, template|
+        if !Builtins.haskey(@templates, dn)
+          # dn changed
+          Ops.set(@templates, dn, Builtins.eval(template))
+          @ldap_modified = true
+          next
+        end
+        # 'val' can be list (most time), map (default_values), string
+        Builtins.foreach(
+          Convert.convert(template, :from => "map", :to => "map <string, any>")
+        ) do |attr, val|
+          if Ops.get(@templates, [dn, attr]) != val
+            Ops.set(@templates, [dn, attr], val)
+            if !Builtins.haskey(template, "modified")
+              Ops.set(@templates, [dn, "modified"], "edited")
+            end
+            @ldap_modified = true
+            Builtins.y2debug("modified value: %1", val)
+          end
+        end
+      end
+      true
+    end
+
     # Writes map of objects to LDAP
     # @param [Hash] objects map of objects to write. It is in the form:
     # $[ DN: (map) attribute_values]
@@ -1848,6 +1931,9 @@
     publish :function => :GetDefaultObjectClasses, :type => "list (map)"
     publish :function => :ReadDN, :type => "list <string> (string, string)"
     publish :function => :GetGroupsDN, :type => "list (string)"
+    publish :function => :CheckTemplateDN, :type => "map (string)"
+    publish :function => :CommitConfigModules, :type => "boolean (map)"
+    publish :function => :CommitTemplates, :type => "boolean (map)"
     publish :function => :WriteToLDAP, :type => "map (map)"
     publish :function => :WriteLDAP, :type => "boolean (map)"
     publish :function => :WritePlusLine, :type => "boolean (boolean)"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-ldap-3.1.12/src/Makefile.am 
new/yast2-ldap-3.1.13/src/Makefile.am
--- old/yast2-ldap-3.1.12/src/Makefile.am       2014-08-06 09:57:45.000000000 
+0200
+++ new/yast2-ldap-3.1.13/src/Makefile.am       2014-10-01 12:20:54.000000000 
+0200
@@ -26,10 +26,17 @@
 
 module_DATA =          \
   LdapServerAccess.pm \
-  LdapPopup.rb  Ldap.rb
+  LdapPopup.rb  \
+  Ldap.rb
 
 client_DATA = \
-  ldap_browser.rb 
+  ldap_browser.rb \
+  ldap_config.rb
 
-EXTRA_DIST = $(module_DATA) $(client_DATA)
+yncludedir = @yncludedir@/ldap
+ynclude_DATA = \
+  routines.rb \
+  ui.rb
+
+EXTRA_DIST = $(module_DATA) $(client_DATA) $(ynclude_DATA)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-ldap-3.1.12/src/ldap_config.rb 
new/yast2-ldap-3.1.13/src/ldap_config.rb
--- old/yast2-ldap-3.1.12/src/ldap_config.rb    1970-01-01 01:00:00.000000000 
+0100
+++ new/yast2-ldap-3.1.13/src/ldap_config.rb    2014-10-01 12:20:54.000000000 
+0200
@@ -0,0 +1,65 @@
+# encoding: utf-8
+
+# 
------------------------------------------------------------------------------
+# Copyright (c) 2006-2012 Novell, Inc. All Rights Reserved.
+#
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of version 2 of the GNU General Public License as published by the
+# Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, contact Novell, Inc.
+#
+# To contact Novell about this file by physical or electronic mail, you may 
find
+# current contact information at www.novell.com.
+# 
------------------------------------------------------------------------------
+
+# File:        clients/ldap.ycp
+# Module:      Configuration of LDAP client
+# Summary:     Manage the configuration stored in LDAP directory
+#              (e.g. user/group templates)
+# Authors:     Jiri Suchomel <jsuch...@suse.cz>
+#
+# $Id$
+module Yast
+  class LdapConfigClient < Client
+    def main
+      Yast.import "UI"
+      Yast.import "Ldap"
+      Yast.import "Wizard"
+
+      Yast.include self, "ldap/ui.rb"
+
+      @param = ""
+      # Check arguments
+      if Ops.greater_than(Builtins.size(WFM.Args), 0) &&
+          Ops.is_string?(WFM.Args(0))
+        @param = Convert.to_string(WFM.Args(0))
+      end
+      Builtins.y2debug("param=%1", @param)
+
+      @ret = LDAPReadDialog()
+      return deep_copy(@ret) if @ret != :next
+
+      Wizard.CreateDialog
+      Wizard.SetDesktopTitleAndIcon("ldap")
+
+      @ret = ModuleConfigurationDialog()
+
+      if @ret == :next && Ldap.ldap_modified
+        Ldap.WriteLDAP(Ldap.templates) if Ldap.WriteLDAP(Ldap.config_modules)
+      end
+
+      Wizard.CloseDialog
+
+      deep_copy(@ret)
+    end
+  end
+end
+
+Yast::LdapConfigClient.new.main
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-ldap-3.1.12/src/routines.rb 
new/yast2-ldap-3.1.13/src/routines.rb
--- old/yast2-ldap-3.1.12/src/routines.rb       1970-01-01 01:00:00.000000000 
+0100
+++ new/yast2-ldap-3.1.13/src/routines.rb       2014-10-01 12:20:54.000000000 
+0200
@@ -0,0 +1,81 @@
+# encoding: utf-8
+
+# 
------------------------------------------------------------------------------
+# Copyright (c) 2006-2012 Novell, Inc. All Rights Reserved.
+#
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of version 2 of the GNU General Public License as published by the
+# Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, contact Novell, Inc.
+#
+# To contact Novell about this file by physical or electronic mail, you may 
find
+# current contact information at www.novell.com.
+# 
------------------------------------------------------------------------------
+
+# File:        include/ldap/routines.ycp
+# Package:     Configuration of LDAP
+# Summary:     Helper routines for string manupulations
+# Authors:     Jiri Suchomel <jsuch...@suse.cz>
+#
+# $Id$
+#
+module Yast
+  module LdapRoutinesInclude
+    def initialize_ldap_routines(include_target)
+      textdomain "ldap-client"
+
+      Yast.import "Ldap"
+    end
+
+    # Get RDN (relative distinguished name) from dn
+    def get_rdn(dn)
+      dn_list = Builtins.splitstring(dn, ",")
+      Ops.get_string(dn_list, 0, dn)
+    end
+
+    # Get first value from dn (don't have to be "cn")
+    def get_cn(dn)
+      rdn = get_rdn(dn)
+      Builtins.issubstring(rdn, "=") ?
+        Builtins.substring(rdn, Ops.add(Builtins.search(rdn, "="), 1)) :
+        rdn
+    end
+
+    # Create DN from cn by adding base config DN
+    # (Can't work in general cases!)
+    def get_dn(cn)
+      Builtins.sformat("cn=%1,%2", cn, Ldap.base_config_dn)
+    end
+
+    # Create new DN from DN by changing leading cn value
+    # (Can't work in general cases!)
+    def get_new_dn(cn, dn)
+      Builtins.tolower(
+        Builtins.sformat(
+          "cn=%1%2",
+          cn,
+          Builtins.issubstring(dn, ",") ?
+            Builtins.substring(dn, Builtins.search(dn, ",")) :
+            ""
+        )
+      )
+    end
+
+    # Get string value of attribute from map.
+    # (Generaly, it is supposed to be list or string.)
+    def get_string(object, attr)
+      object = deep_copy(object)
+      if Ops.is_list?(Ops.get(object, attr))
+        return Ops.get_string(object, [attr, 0], "")
+      end
+      Ops.get_string(object, attr, "")
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/yast2-ldap-3.1.12/src/ui.rb 
new/yast2-ldap-3.1.13/src/ui.rb
--- old/yast2-ldap-3.1.12/src/ui.rb     1970-01-01 01:00:00.000000000 +0100
+++ new/yast2-ldap-3.1.13/src/ui.rb     2014-10-01 12:20:54.000000000 +0200
@@ -0,0 +1,815 @@
+# encoding: utf-8
+
+# 
------------------------------------------------------------------------------
+# Copyright (c) 2006-2012 Novell, Inc. All Rights Reserved.
+#
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of version 2 of the GNU General Public License as published by the
+# Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, contact Novell, Inc.
+#
+# To contact Novell about this file by physical or electronic mail, you may 
find
+# current contact information at www.novell.com.
+# 
------------------------------------------------------------------------------
+
+# File:        include/ldap/ui.ycp
+# Package:     Configuration of LDAP
+# Summary:     User interface functions.
+# Authors:     Thorsten Kukuk <ku...@suse.de>
+#              Anas Nashif <nas...@suse.de>
+#
+# $Id$
+#
+# All user interface functions.
+module Yast
+  module LdapUiInclude
+    def initialize_ldap_ui(include_target)
+      Yast.import "UI"
+      textdomain "ldap-client"
+
+      Yast.import "Address"
+      Yast.import "Autologin"
+      Yast.import "Directory"
+      Yast.import "FileUtils"
+      Yast.import "Label"
+      Yast.import "Ldap"
+      Yast.import "LdapPopup"
+      Yast.import "Message"
+      Yast.import "Mode"
+      Yast.import "Package"
+      Yast.import "Pam"
+      Yast.import "Popup"
+      Yast.import "Report"
+      Yast.import "Service"
+      Yast.import "SLPAPI"
+      Yast.import "Stage"
+      Yast.import "Wizard"
+
+      Yast.include include_target, "ldap/routines.rb"
+    end
+
+    def Modified
+      Ldap.modified || Ldap.ldap_modified
+    end
+
+    # The dialog that appears when the [Abort] button is pressed.
+    # @return `abort if user really wants to abort, `back otherwise
+    def ReallyAbort
+      ret = Modified() || Stage.cont ? Popup.ReallyAbort(true) : true
+
+      if ret
+        return :abort
+      else
+        return :back
+      end
+    end
+
+    # Read settings dialog
+    # @return `abort if aborted and `next otherwise
+    def ReadDialog
+      ret = Ldap.Read
+      ret ? :next : :abort
+    end
+
+    # Write settings dialog
+    # @return `next
+    def WriteDialog
+      # popup text
+      abort = lambda do
+        if UI.PollInput == :abort &&
+            # popup text
+            Popup.YesNo(_("Really abort the writing process?"))
+          next true
+        end
+        false
+      end
+
+      if Modified()
+        # help text
+        Wizard.RestoreHelp(_("Writing LDAP Client Settings"))
+        return Ldap.Write(abort)
+      end
+      :next
+    end
+
+    # Initialize connection to LDAP server, bind and read the settings.
+    # Everything is done before entering the Module Configuration Dialog.
+    def LDAPReadDialog
+      msg = ""
+      read_now = false
+
+      if !Ldap.bound || Modified()
+        if !Ldap.bound || Ldap.modified
+          # re-init/re-bind only when server information was changed (#39908)
+          if !Ldap.bound || Ldap.old_server != Ldap.server || 
Ldap.BaseDNChanged
+            msg = Ldap.LDAPInitWithTLSCheck({})
+            if msg != ""
+              Ldap.LDAPErrorMessage("init", msg)
+              return :back
+            end
+          end
+
+          if !Ldap.bound || Ldap.old_server != Ldap.server
+            # Ldap::bind_pass might exist from server proposal...
+            if Stage.cont && Ldap.bind_pass != nil
+              msg = Ldap.LDAPBind(Ldap.bind_pass)
+              if msg != ""
+                Ldap.LDAPErrorMessage("bind", msg)
+                Ldap.bind_pass = Ldap.LDAPAskAndBind(true)
+              end
+            else
+              Ldap.bind_pass = Ldap.LDAPAskAndBind(true)
+            end
+            return :back if Ldap.bind_pass == nil
+
+            read_now = true
+
+            msg = Ldap.InitSchema
+            Ldap.LDAPErrorMessage("schema", msg) if msg != ""
+          end
+        end
+        return :back if !Ldap.CheckBaseConfig(Ldap.base_config_dn)
+        if read_now || Ldap.modified && !Ldap.ldap_modified ||
+            Ldap.ldap_modified &&
+              Popup.AnyQuestion(
+                Popup.NoHeadline,
+                # yes/no popup
+                _(
+                  "If you reread settings from the server,\nall changes will 
be lost. Really reread?\n"
+                ),
+                Label.YesButton,
+                Label.NoButton,
+                :focus_no
+              )
+          msg = Ldap.ReadConfigModules
+          Ldap.LDAPErrorMessage("read", msg) if msg != ""
+
+          msg = Ldap.ReadTemplates
+          Ldap.LDAPErrorMessage("read", msg) if msg != ""
+
+          Ldap.ldap_modified = false
+        end
+        Ldap.bound = true
+      end
+      :next
+    end
+
+    # Dialog for configuration one object template
+    def TemplateConfigurationDialog(templ)
+      templ = deep_copy(templ)
+      # help text 1/3
+      help_text = _(
+        "<p>Configure the template used for creating \nnew objects (like users 
or groups).</p>\n"
+      ) +
+        # help text 2/3
+        _(
+          "<p>Edit the template attribute values with <b>Edit</b>.\nChanging 
the <b>cn</b> value renames the template.</p>\n"
+        ) +
+        # help text 3/3
+        _(
+          "<p>The second table contains a list of <b>default values</b> 
used\n" +
+            "for new objects. Modify the list by adding new values, editing 
or\n" +
+            "removing current ones.</p>\n"
+        )
+
+      template_dn = Ldap.current_template_dn
+
+      table_items = []
+      template = Convert.convert(
+        Builtins.eval(templ),
+        :from => "map",
+        :to   => "map <string, any>"
+      )
+
+      # helper function converting list value to string
+      to_table = lambda do |attr, val|
+        val = deep_copy(val)
+        if Ldap.SingleValued(attr) || attr == "cn"
+          return Ops.get(val, 0, "")
+        elsif Builtins.contains(
+            ["susesecondarygroup", "susedefaulttemplate"],
+            Builtins.tolower(attr)
+          )
+          return Builtins.mergestring(val, " ")
+        else
+          return Builtins.mergestring(val, ",")
+        end
+      end
+
+      Builtins.foreach(template) do |attr, value|
+        val = deep_copy(value)
+        # do not show internal attributes
+        if Builtins.contains(
+            [
+              "susedefaultvalue",
+              "default_values",
+              "objectclass",
+              "modified",
+              "old_dn"
+            ],
+            Builtins.tolower(attr)
+          )
+          next
+        end
+        if Ops.is_list?(value)
+          val = to_table.call(
+            attr,
+            Convert.convert(val, :from => "any", :to => "list <string>")
+          )
+        end
+        table_items = Builtins.add(table_items, Item(Id(attr), attr, val))
+      end
+
+      default_items = []
+      default_values = Ops.get_map(template, "default_values", {})
+      Builtins.foreach(default_values) do |attr, value|
+        default_items = Builtins.add(default_items, Item(Id(attr), attr, 
value))
+      end
+
+      contents = HBox(
+        HSpacing(1.5),
+        VBox(
+          VSpacing(0.5),
+          Table(
+            Id(:table),
+            Opt(:notify),
+            Header(
+              # table header 1/2
+              _("Attribute"),
+              # table header 2/2
+              _("Value")
+            ),
+            table_items
+          ),
+          HBox(PushButton(Id(:edit), Label.EditButton), HStretch()),
+          # label (table folows)
+          Left(Label(_("Default Values for New Objects"))),
+          Table(
+            Id(:defaults),
+            Opt(:notify),
+            Header(
+              # table header 1/2
+              _("Attribute of Object"),
+              # table header 2/2
+              _("Default Value")
+            ),
+            default_items
+          ),
+          HBox(
+            # button label (with non-default shortcut)
+            PushButton(Id(:add_dfl), Opt(:key_F3), _("A&dd")),
+            # button label
+            PushButton(Id(:edit_dfl), Opt(:key_F4), _("&Edit")),
+            PushButton(Id(:delete_dfl), Opt(:key_F5), Label.DeleteButton),
+            HStretch()
+          ),
+          VSpacing(0.5)
+        ),
+        HSpacing(1.5)
+      )
+
+      Wizard.OpenNextBackDialog
+      # dialog label
+      Wizard.SetContentsButtons(
+        _("Object Template Configuration"),
+        contents,
+        help_text,
+        Label.CancelButton,
+        Label.OKButton
+      )
+      Wizard.HideAbortButton
+
+      UI.SetFocus(Id(:table)) if Ops.greater_than(Builtins.size(table_items), 
0)
+      UI.ChangeWidget(Id(:edit_dfl), :Enabled, default_items != [])
+      UI.ChangeWidget(Id(:delete_dfl), :Enabled, default_items != [])
+
+      result = nil
+      while true
+        result = UI.UserInput
+        attr = Convert.to_string(UI.QueryWidget(Id(:table), :CurrentItem))
+
+        # edit attribute
+        if result == :edit || result == :table
+          next if attr == nil
+          value = Ops.get_list(template, attr, [])
+          offer = []
+          conflicts = []
+          if Builtins.tolower(attr) == "susesecondarygroup"
+            offer = Ldap.GetGroupsDN(Ldap.GetBaseDN)
+          end
+          if Builtins.tolower(attr) == "susenamingattribute"
+            classes = Ldap.GetDefaultObjectClasses(template)
+            offer = Ldap.GetObjectAttributes(classes)
+          end
+          if attr == "cn"
+            base = Builtins.issubstring(template_dn, ",") ?
+              Builtins.substring(
+                template_dn,
+                Ops.add(Builtins.search(template_dn, ","), 1)
+              ) :
+              ""
+            Builtins.foreach(Ldap.ReadDN(base, "")) do |dn|
+              if Builtins.substring(dn, 0, 3) == "cn="
+                conflicts = Builtins.add(conflicts, get_cn(dn))
+              end
+            end
+          end
+          value = LdapPopup.EditAttribute(
+            {
+              "attr"      => attr,
+              "value"     => value,
+              "conflicts" => conflicts,
+              "single"    => Ldap.SingleValued(attr) || attr == "cn",
+              "offer"     => offer,
+              "browse"    => Builtins.tolower(attr) == "susesecondarygroup"
+            }
+          )
+
+          next if value == Ops.get_list(template, attr, [])
+          UI.ChangeWidget(
+            Id(:table),
+            term(:Item, attr, 1),
+            to_table.call(attr, value)
+          )
+          Ops.set(template, attr, value)
+        end
+        # add default value
+        if result == :add_dfl
+          conflicts = Builtins.maplist(default_values) { |attr3, val| attr3 }
+          classes = Ldap.GetDefaultObjectClasses(template)
+          available = Ldap.GetObjectAttributes(classes)
+          # filter out objectclass
+          dfl = LdapPopup.AddDefaultValue(
+            Builtins.sort(available),
+            Builtins.add(conflicts, "objectClass")
+          )
+          next if Ops.get_string(dfl, "value", "") == ""
+          attr2 = Ops.get_string(dfl, "attr", "")
+          Ops.set(default_values, attr2, Ops.get_string(dfl, "value", ""))
+          default_items = Builtins.add(
+            default_items,
+            Item(Id(attr2), attr2, Ops.get_string(dfl, "value", ""))
+          )
+          UI.ChangeWidget(Id(:defaults), :Items, default_items)
+          UI.ChangeWidget(Id(:edit_dfl), :Enabled, default_items != [])
+          UI.ChangeWidget(Id(:delete_dfl), :Enabled, default_items != [])
+        end
+        # edit default value
+        if result == :edit_dfl || result == :defaults
+          attr = Convert.to_string(UI.QueryWidget(Id(:defaults), :CurrentItem))
+          next if attr == nil
+          value = Ops.get(default_values, attr, "")
+          l_value = LdapPopup.EditAttribute(
+            { "attr" => attr, "value" => [value], "single" => true }
+          )
+          next if Ops.get_string(l_value, 0, "") == value
+          value = Ops.get_string(l_value, 0, "")
+          UI.ChangeWidget(Id(:defaults), term(:Item, attr, 1), value)
+          Ops.set(default_values, attr, value)
+        end
+        # delete default value
+        if result == :delete_dfl
+          attr = Convert.to_string(UI.QueryWidget(Id(:defaults), :CurrentItem))
+          next if attr == nil
+          # yes/no popup, %1 is name
+          if !Popup.YesNo(
+              Builtins.sformat(
+                _("Really delete default attribute \"%1\"?"),
+                attr
+              )
+            )
+            next
+          end
+          default_values = Builtins.remove(default_values, attr)
+          default_items = Builtins.filter(default_items) do |it|
+            Ops.get_string(it, 1, "") != attr
+          end
+          UI.ChangeWidget(Id(:defaults), :Items, default_items)
+          UI.ChangeWidget(Id(:edit_dfl), :Enabled, default_items != [])
+          UI.ChangeWidget(Id(:delete_dfl), :Enabled, default_items != [])
+        end
+        if Ops.is_symbol?(result) &&
+            Builtins.contains(
+              [:back, :cancel, :abort],
+              Convert.to_symbol(result)
+            )
+          break
+        end
+        if result == :next
+          cont = false
+
+          # check the template required attributes...
+          Builtins.foreach(Ops.get_list(template, "objectClass", [])) do |oc|
+            next if cont
+            Builtins.foreach(Ldap.GetRequiredAttributes(oc)) do |attr2|
+              val = Ops.get(template, attr2)
+              if !cont && val == nil || val == [] || val == ""
+                #error popup, %1 is attribute name
+                Popup.Error(
+                  Builtins.sformat(
+                    _("The \"%1\" attribute is mandatory.\nEnter a value."),
+                    attr2
+                  )
+                )
+                UI.SetFocus(Id(:table))
+                cont = true
+              end
+            end
+          end
+          next if cont
+          Ops.set(template, "default_values", default_values)
+          break
+        end
+      end
+      Wizard.CloseDialog
+      deep_copy(template)
+    end
+
+    # Dialog for configuration of one "configuration module"
+    def ModuleConfigurationDialog
+      # helptext 1/4
+      help_text = _(
+        "<p>Manage the configuration stored in the LDAP directory.</p>"
+      ) +
+        # helptext 2/4
+        _(
+          "<p>Each configuration set is called a \"configuration module.\" If 
there\n" +
+            "is no configuration module in the provided location (base 
configuration),\n" +
+            "create one with <b>New</b>. Delete the current module\n" +
+            "using <b>Delete</b>.</p>\n"
+        ) +
+        # helptext 3/4
+        _(
+          "<p>Edit the values of attributes in the table with <b>Edit</b>.\n" +
+            "Some values have special meanings, for example, changing the 
<b>cn</b> value renames the\n" +
+            "current module.</p>\n"
+        ) +
+        # helptext 4/4
+        _(
+          "<p>To configure the default template of the current module,\n" +
+            "click <b>Configure Template</b>.\n" +
+            "</p>\n"
+        )
+
+      current_dn = Ldap.current_module_dn
+      modules_attrs_items = {} # map of list (table items), index is cn
+      modules = Convert.convert(
+        Ldap.GetConfigModules,
+        :from => "map",
+        :to   => "map <string, map <string, any>>"
+      )
+      templates = Convert.convert(
+        Ldap.GetTemplates,
+        :from => "map",
+        :to   => "map <string, map <string, any>>"
+      )
+      names = []
+      templates_dns = Builtins.maplist(templates) { |dn, t| dn }
+
+      # Helper for creating table items in ModuleConfiguration Dialog
+      create_attrs_items = lambda do |cn|
+        attrs_items = []
+        dn = get_dn(cn)
+        dn = Builtins.tolower(dn) if !Builtins.haskey(modules, dn)
+        Builtins.foreach(Ops.get(modules, dn, {})) do |attr, value|
+          val = deep_copy(value)
+          if Builtins.contains(
+              ["objectclass", "modified", "old_dn"],
+              Builtins.tolower(attr)
+            )
+            next
+          end
+          if Ops.is_list?(value)
+            lvalue = Convert.to_list(value)
+            if Ldap.SingleValued(attr) || attr == "cn"
+              val = Ops.get_string(lvalue, 0, "")
+            else
+              val = Builtins.mergestring(
+                Convert.convert(value, :from => "any", :to => "list <string>"),
+                ","
+              )
+            end
+          end
+          attrs_items = Builtins.add(attrs_items, Item(Id(attr), attr, val))
+        end
+
+        deep_copy(attrs_items)
+      end
+
+      Builtins.foreach(modules) do |dn, mod|
+        cn = get_string(mod, "cn")
+        next if cn == ""
+        names = Builtins.add(names, cn)
+        # attributes for table
+        Ops.set(modules_attrs_items, cn, create_attrs_items.call(cn))
+        current_dn = dn if current_dn == ""
+      end
+      current_cn = Ops.get_string(modules, [current_dn, "cn", 0]) do
+        get_cn(current_dn)
+      end
+
+      # Helper for updating widgets in ModuleConfiguration Dialog
+      replace_module_names = lambda do
+        modules_items = [] # list of module names
+        Builtins.foreach(names) do |cn|
+          if Builtins.tolower(cn) == Builtins.tolower(current_cn)
+            modules_items = Builtins.add(modules_items, Item(Id(cn), cn, true))
+          else
+            modules_items = Builtins.add(modules_items, Item(Id(cn), cn))
+          end
+        end
+        UI.ReplaceWidget(
+          Id(:rp_modnames),
+          Left(
+            ComboBox(
+              Id(:modules),
+              Opt(:notify),
+              # combobox label
+              _("Configuration &Module"),
+              modules_items
+            )
+          )
+        )
+        ena = names != []
+        UI.ChangeWidget(Id(:delete), :Enabled, ena)
+        UI.ChangeWidget(Id(:edit), :Enabled, ena)
+        UI.ChangeWidget(Id(:modules), :Enabled, ena)
+
+        nil
+      end
+
+      # Helper for updating widgets in ModuleConfiguration Dialog
+      replace_templates_items = lambda do
+        items = Builtins.maplist(
+          Ops.get_list(modules, [current_dn, "suseDefaultTemplate"], [])
+        ) { |dn| Item(Id(dn), dn) }
+        UI.ReplaceWidget(
+          Id(:rp_templs),
+          PushButton(
+            Id(:templ_pb),
+            Opt(:key_F7),
+            # button label
+            _("C&onfigure Template")
+          )
+        )
+        UI.ChangeWidget(Id(:templ_pb), :Enabled, items != [])
+
+        nil
+      end
+
+      contents = HBox(
+        HSpacing(1.5),
+        VBox(
+          VSpacing(0.5),
+          HBox(
+            ReplacePoint(Id(:rp_modnames), Empty())
+          ),
+          VSpacing(0.5),
+          Table(
+            Id(:table),
+            Opt(:notify),
+            Header(
+              # table header 1/2
+              _("Attribute"),
+              # table header 2/2
+              _("Value")
+            ),
+            Ops.get_list(modules_attrs_items, current_cn, [])
+          ),
+          HBox(
+            PushButton(Id(:edit), Opt(:key_F4), Label.EditButton),
+            HStretch(),
+            ReplacePoint(Id(:rp_templs), Empty())
+          ),
+          VSpacing(0.5)
+        ),
+        HSpacing(1.5)
+      )
+
+      # dialog label
+      Wizard.SetContentsButtons(
+        _("Module Configuration"),
+        contents,
+        help_text,
+        Label.CancelButton,
+        Label.OKButton
+      )
+      Wizard.HideAbortButton
+
+      if Ops.greater_than(
+          Builtins.size(Ops.get_list(modules_attrs_items, current_cn, [])),
+          0
+        )
+        UI.SetFocus(Id(:table))
+      end
+      replace_templates_items.call
+      replace_module_names.call
+
+      # result could be symbol or string
+      result = nil
+      while true
+        result = UI.UserInput
+        attr = Convert.to_string(UI.QueryWidget(Id(:table), :CurrentItem))
+
+        # check the correctness of entry
+        if Builtins.contains(
+            Ops.get_list(modules, [current_dn, "suseDefaultTemplate"], []),
+            result
+          ) ||
+            result == :next ||
+            result == :modules 
+          Builtins.foreach(
+            Ops.get_list(modules, [current_dn, "objectClass"], [])
+          ) { |oc| Builtins.foreach(Ldap.GetRequiredAttributes(oc)) do |attr2|
+            val = Ops.get(modules, [current_dn, attr2])
+            if val == nil || val == [] || val == ""
+              #error popup, %1 is attribute name
+              Popup.Error(
+                Builtins.sformat(
+                  _("The \"%1\" attribute is mandatory.\nEnter a value."),
+                  attr2
+                )
+              )
+              UI.SetFocus(Id(:table))
+              result = :notnext
+              next
+            end
+          end }
+        end
+        # change the focus to new module
+        if result == :modules
+          current_cn = Convert.to_string(UI.QueryWidget(Id(:modules), :Value))
+          current_dn = get_dn(current_cn)
+          if !Builtins.haskey(modules, current_dn)
+            current_dn = Builtins.tolower(current_dn)
+          end
+          UI.ChangeWidget(
+            Id(:table),
+            :Items,
+            Ops.get_list(modules_attrs_items, current_cn, [])
+          )
+          replace_templates_items.call
+        end
+
+        # module attribute modification
+        if result == :edit || result == :table
+          next if attr == nil
+          value = Ops.get_list(modules, [current_dn, attr], [])
+          offer = []
+          conflicts = []
+          conflicts = deep_copy(names) if attr == "cn"
+          if Builtins.tolower(attr) == "susedefaulttemplate"
+            offer = deep_copy(templates_dns)
+          elsif Builtins.tolower(attr) == "susepasswordhash"
+            offer = deep_copy(Ldap.hash_schemas)
+          end
+
+          value = LdapPopup.EditAttribute(
+            {
+              "attr"      => attr,
+              "value"     => value,
+              "conflicts" => conflicts,
+              "single"    => Ldap.SingleValued(attr) || attr == "cn",
+              "offer"     => offer,
+              "browse" =>
+                # TODO function, that checks if value should be DN
+                Builtins.tolower(attr) == "susedefaultbase" ||
+                  Builtins.tolower(attr) == "susedefaulttemplate"
+            }
+          )
+
+          if value == Ops.get_list(modules, [current_dn, attr], []) #nothing 
was changed
+            next
+          end
+          Ops.set(modules, [current_dn, attr], value)
+          Ops.set(
+            modules_attrs_items,
+            current_cn,
+            create_attrs_items.call(current_cn)
+          )
+          UI.ChangeWidget(
+            Id(:table),
+            :Items,
+            Ops.get_list(modules_attrs_items, current_cn, [])
+          )
+          UI.ChangeWidget(Id(:table), :CurrentItem, attr)
+          if attr == "cn" && value != []
+            cn = Ops.get(value, 0, current_cn)
+            Ops.set(
+              modules_attrs_items,
+              cn,
+              Ops.get_list(modules_attrs_items, current_cn, [])
+            )
+            modules_attrs_items = Builtins.remove(
+              modules_attrs_items,
+              current_cn
+            )
+            if Ops.get_string(modules, [current_dn, "modified"], "") != 
"added" &&
+                Ops.get_string(modules, [current_dn, "modified"], "") != 
"renamed"
+              Ops.set(modules, [current_dn, "modified"], "renamed")
+              Ops.set(modules, [current_dn, "old_dn"], current_dn)
+            end
+            Ops.set(modules, get_dn(cn), Ops.get(modules, current_dn, {}))
+            if Builtins.tolower(get_dn(cn)) != Builtins.tolower(current_dn)
+              modules = Builtins.remove(modules, current_dn)
+            end
+            names = Builtins.filter(names) { |n| n != current_cn }
+            names = Builtins.add(names, cn)
+            current_cn = cn
+            current_dn = get_dn(cn)
+            replace_module_names.call
+          end
+          if Builtins.tolower(attr) == "susedefaulttemplate"
+            replace_templates_items.call
+          end
+        end
+        # configure template
+        if result == :templ_pb
+          template_dn = Ops.get_string(
+            modules,
+            [current_dn, "suseDefaultTemplate", 0],
+            ""
+          )
+          Ldap.current_template_dn = template_dn
+          template = Builtins.eval(Ops.get(templates, template_dn, {}))
+          # template not loaded, check DN:
+          if template == {}
+            template = Ldap.CheckTemplateDN(template_dn)
+            if template == nil
+              next
+            elsif template == {}
+              next if !Ldap.ParentExists(template_dn)
+              template = Ldap.CreateTemplate(
+                get_cn(template_dn),
+                Ops.get_list(modules, [current_dn, "objectClass"], [])
+              )
+            end
+            templates_dns = Builtins.add(templates_dns, template_dn)
+          end
+          Ops.set(templates, template_dn, 
TemplateConfigurationDialog(template))
+          # check for template renaming
+          if Ops.get_list(templates, [template_dn, "cn"], []) !=
+              Ops.get_list(template, "cn", [])
+            cn = get_string(Ops.get(templates, template_dn, {}), "cn")
+            new_dn = get_new_dn(cn, template_dn)
+
+            Ops.set(templates, new_dn, Ops.get(templates, template_dn, {}))
+            if new_dn != template_dn
+              templates = Builtins.remove(templates, template_dn)
+            end
+            if Ops.get_string(templates, [new_dn, "modified"], "") != "added"
+              Ops.set(templates, [new_dn, "modified"], "renamed")
+              Ops.set(templates, [new_dn, "old_dn"], template_dn)
+            end
+            templates_dns = Builtins.filter(templates_dns) do |dn|
+              dn != template_dn
+            end
+            templates_dns = Builtins.add(templates_dns, new_dn)
+            # update list of templates
+            Ops.set(
+              modules,
+              [current_dn, "suseDefaultTemplate"],
+              Builtins.maplist(
+                Ops.get_list(modules, [current_dn, "suseDefaultTemplate"], [])
+              ) do |dn|
+                next new_dn if dn == template_dn
+                dn
+              end
+            )
+            Ops.set(
+              modules_attrs_items,
+              current_cn,
+              create_attrs_items.call(current_cn)
+            )
+            UI.ChangeWidget(
+              Id(:table),
+              :Items,
+              Ops.get_list(modules_attrs_items, current_cn, [])
+            )
+            replace_templates_items.call
+          end
+          UI.SetFocus(Id(:table))
+        end
+        if result == :next
+          Ldap.current_module_dn = current_dn
+          # save the edited values to global map...
+          Ldap.CommitConfigModules(modules)
+          # commit templates here!
+          Ldap.CommitTemplates(templates)
+          break
+        end
+        result = :not_next if result == :cancel && ReallyAbort() != :abort
+        break if result == :back || result == :cancel
+      end
+
+      Convert.to_symbol(result)
+    end
+  end
+end

-- 
To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org
For additional commands, e-mail: opensuse-commit+h...@opensuse.org

Reply via email to