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