// ======================================================================== // Copyright 2006 - Volian Enterprises, Inc. All rights reserved. // Volian Enterprises - Proprietary Information - DO NOT COPY OR DISTRIBUTE // ------------------------------------------------------------------------ // $Workfile: $ $Revision: $ // $Author: $ $Date: $ // // $History: $ // ======================================================================== using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Windows.Forms; using System.Text; using VEPROMS.CSLA.Library; using Config; namespace DataLoader { /// /// Summary description for Security. /// /// #region OldVeSamClasses // do a temp plant - we may keep this for loading in data. It will be migrated // to a folders record. #region Options public class PlantOptions { private UInt16 _id; private UInt32 _plopts; public List poList = new List(); public UInt16 Id { get {return _id;} set {if (_id != value) _id = value;} } public UInt32 Options { get {return _plopts;} set {if (_plopts != value) _plopts = value;} } } public class ProcOptions { private UInt16 _id; private UInt16 _selected; public UInt32 [] Options = new UInt32[4]; public UInt16 Id { get {return _id;} set {if (_id != value)_id = value;} } public UInt16 Selected { get {return _selected;} set {if (_selected != value)_selected = value;} } } #endregion #region OldFolders public class Plant { private string _name; private string _path; private UInt16 _id; public Dictionary psDic = new Dictionary(); public string Name { get {return _name;} set { if (value == null) value = string.Empty; if (_name != value) _name = value; } } public string Path { get {return _path;} set { if (value == null) value = string.Empty; if (_path != value)_path = value; } } public UInt16 Id { get {return _id;} set {if (_id != value) _id = value;} } public Plant() { } public Plant(string nm, string pth, UInt16 idn) { _name = nm; _path = pth; _id = idn; } } public class ProcSet { private string _name; private string _path; private UInt16 _id; public string Name { get {return _name;} set { if (value == null) value = string.Empty; if (_name != value)_name = value; } } public string Path { get {return _path;} set { if (value == null) value = string.Empty; if (_path != value)_path = value; } } public UInt16 Id { get {return _id;} set {if (_id != value) _id = value;} } public ProcSet() { } public ProcSet(string nm, string pth, UInt16 idn) { _name = nm; _path = pth; _id = idn; } } #endregion #region OldUser // The OldUser class stores data from the vesam input. The User class migrates // and saves data to the new sql database. public class OldUser { private UInt32 _systemopts; private string _username; private bool _blockaccessflag = false; public List PlantOpts = new List(); public UInt32 SystemOpts { get { return _systemopts; } set { if (_systemopts != value) _systemopts = value; } } public string UserName { get { return _username; } set { if (value == null) value = string.Empty; if (_username != value) _username = value; } } public bool BlockAccessFlag { get { return _blockaccessflag; } set { if (_blockaccessflag != value) _blockaccessflag = value; } } public bool PermissionToManageFlag { get { return (_systemopts & VESamOpt.DOCMAINT)==0?false:true; } //set { if (_permissiontomanageflag != value) _permissiontomanageflag = value; } } public bool SystemAdminFlag { get { return (_systemopts & VESamOpt.SYSADMIN)==0 ? false:true; } //set { if (_systemadminflag != value) _systemadminflag = value; } } public bool PermissionToLockFlag { get { return (_systemopts & VESamOpt.LOCKSYSTEM)==0 ? false:true; } //set { if (_permissiontolockflag != value) _permissiontolockflag = value; } } public bool RoEditorFlag { get { return (_systemopts & VESamOpt.ROEDITOR) == 0 ? false : true; } } public OldUser(string nm) { _username = nm; } } #endregion #region VESam public class VESamOpt { #region Log4Net private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); #endregion public const long VIEW = 0x00000001L; public const long PRINT = 0x00000002L; public const long PRINTDRAFT = 0x00000004L; public const long PRINTCHANGES = 0x00000008L; public const long EDIT = 0x00000010L; public const long SEARCH = 0x00000020L; public const long STANDARDSTEPS = 0x00000040L; public const long APPROVE = 0x00000080L; public const long APPROVESINGLE = 0x00000100L; public const long LIBRARYDOCS = 0x00000200L; public const long ADDMODDEL = 0x00000400L; public const long CLEAN = 0x00000800L; public const long LOCKPROC = 0x00001000L; public const long LOCKSET = 0x00000001L; public const long UCF = 0x00000002L; public const long LOCKSYSTEM = 0x00000001L; public const long DOCMAINT = 0x00000002L; public const long ROEDITOR = 0x00000004L; public const long SYSADMIN = 0x00000008L; public const int SUPERUSER = 1000; public const long SUPERACCESS = 0xFFFFFFFFL; private bool _blockAccess; public int userid = -1; public string initials; private const string samoptname = "vesam.opt"; public FileStream fs; public BinaryReader bw; public bool isDemoMode = false; List plntList = new List(); List userList = new List(); Dictionary plntDic = new Dictionary(); public bool BlockAccess { get { return _blockAccess; } set { if (_blockAccess != value) _blockAccess = value; } } public bool OpenFile(string oname) { try { fs = new FileStream(oname, FileMode.Open, FileAccess.Read, FileShare.Read, 1, false); bw = new BinaryReader(fs); return true; } catch (Exception e) { MessageBox.Show(e.Message, "Security File"); return false; } } public void CloseFile() { bw.Close(); fs.Close(); bw = null; fs = null; } public Dictionary LoadPlants() { UInt16 ui16; UInt32 ui32; try { byte x; // read past some header stuff. for (int jj = 0; jj < 8; jj++) x = bw.ReadByte(); long nxtPl = bw.ReadUInt32(); uint nmPlant = bw.ReadUInt16(); ui16 = bw.ReadUInt16(); // not needed here, but need to read past this... long nxtUs = bw.ReadUInt32(); uint nmUser = bw.ReadUInt16(); ui16 = bw.ReadUInt16(); long nxtGr = bw.ReadUInt32(); uint nmGrp = bw.ReadUInt16(); ui16 = bw.ReadUInt16(); BlockAccess = bw.ReadUInt16()==0?false:true; string pname, ppth; for (int i = 0; i < nmPlant; i++) { if (nxtPl == 0xFFFFFFFEL) { log.Error("Reading in VESAM options file - cannot find next plant in list"); break; } fs.Seek(nxtPl, SeekOrigin.Begin); nxtPl = bw.ReadUInt32(); Plant pl = new Plant(); pl.Id = bw.ReadUInt16(); ui16 = bw.ReadUInt16(); byte[] stmp = new byte[256]; stmp = bw.ReadBytes(ui16); pname = Encoding.ASCII.GetString(stmp, 0, ui16); pl.Name = pname; ui16 = bw.ReadUInt16(); stmp = bw.ReadBytes(ui16); ppth = Encoding.ASCII.GetString(stmp, 0, ui16); pl.Path = ppth; // read in any sets within this plant. UInt16 nmPrcDr = bw.ReadUInt16(); ui32 = bw.ReadUInt32(); UInt32 nxtPr = bw.ReadUInt32(); for (int j = 0; j < nmPrcDr; j++) { ProcSet ps = new ProcSet(); ps.Id = bw.ReadUInt16(); ui16 = bw.ReadUInt16(); stmp = bw.ReadBytes(ui16); pname = Encoding.ASCII.GetString(stmp, 0, ui16); ps.Name = pname; ui16 = bw.ReadUInt16(); stmp = bw.ReadBytes(ui16); ppth = Encoding.ASCII.GetString(stmp, 0, ui16); ps.Path = ppth; ui32 = bw.ReadUInt32(); if (nxtPr == 0xFFFFFFFDL && j + 1 < nmPrcDr) { log.ErrorFormat("Loading vesam.opt - procedure sets for {0}", ps.Name); return null; } try { pl.psDic.Add(ps.Id, ps); } catch (Exception ex) { log.ErrorFormat("Adding to set dictionary - {0}. Error: {1}" + ps.Path, ex.Message); } if (nxtPr != 0xFFFFFFFDL) { fs.Seek(nxtPr, SeekOrigin.Begin); nxtPr = bw.ReadUInt32(); } } try { if (!plntDic.ContainsKey(pl.Id))plntDic.Add(pl.Id, pl); } catch (Exception ex) { log.ErrorFormat("Adding to plant dictionary - {0}. Error: {1}", pl.Path, ex.Message); } } } catch (Exception ex) { log.ErrorFormat("Loading plants from vesam.opt: {0}", ex.Message); return null; } return plntDic; } public List LoadUserList() { UInt16 ui16; UInt32 ui32; try { byte x; fs.Seek(0, SeekOrigin.Begin); // read past some header stuff. for (int jj = 0; jj < 8; jj++) x = bw.ReadByte(); long nxtPl = bw.ReadUInt32(); uint nmPlant = bw.ReadUInt16(); ui16 = bw.ReadUInt16(); // get info in header for users long nxtUs = bw.ReadUInt32(); uint nmUser = bw.ReadUInt16(); ui16 = bw.ReadUInt16(); long nxtGr = bw.ReadUInt32(); uint nmGrp = bw.ReadUInt16(); ui16 = bw.ReadUInt16(); bool localblockAccess = bw.ReadUInt16()==0?false:true; // Now read in all of the user information UInt16 uid; string fName, fPass; for (int i = 0; i < nmUser; i++) { if (nxtUs == 0xFFFFFFFCL && i + 1 < nmUser) { log.Error("Loading vesam.opt - reading in user list."); return null; } fs.Seek((long)nxtUs, SeekOrigin.Begin); nxtUs = bw.ReadUInt32(); uid = bw.ReadUInt16(); ui16 = bw.ReadUInt16(); // user's group? byte[] test = new byte[10]; test = bw.ReadBytes(10); // get ve-proms (vesam) username & password fName = Encoding.ASCII.GetString(test, 0, 10); int indx = fName.IndexOf("\0"); string fNameTrim = fName.Substring(0, indx); test = bw.ReadBytes(10); fPass = Encoding.ASCII.GetString(test, 0, 10); indx = fPass.IndexOf("\0"); string fPassTrim = fPass.Substring(0, indx); OldUser usr = new OldUser(fNameTrim); usr.SystemOpts = bw.ReadUInt32(); usr.BlockAccessFlag = localblockAccess; ui32 = bw.ReadUInt32(); // now get plant & proc set options. nmPlant = bw.ReadUInt16(); for (int j = 0; j < nmPlant; j++) { PlantOptions plO = new PlantOptions(); plO.Id = bw.ReadUInt16(); plO.Options = bw.ReadUInt32(); ui32 = bw.ReadUInt32(); UInt16 nmPrcDr = bw.ReadUInt16(); for (int k = 0; k < nmPrcDr; k++) { ProcOptions prO = new ProcOptions(); prO.Id = bw.ReadUInt16(); prO.Selected = bw.ReadUInt16(); for (int kk = 0; kk < 4; kk++) prO.Options[kk] = bw.ReadUInt32(); plO.poList.Add(prO); } usr.PlantOpts.Add(plO); } userList.Add(usr); } } catch (Exception ex) { log.ErrorFormat("Error Loading (old) User info from vesam.opt: {0}", ex.Message); return null ; } return userList; } } #endregion #endregion #region SecurityMigration public class Security { #region Log4Net private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); #endregion Dictionary plntDic = new Dictionary(); List userList = new List(); private string _VePromsPath = null; private string optfilename; private string[] prflags ={ "Vfw", "Prnt", "Prnt Drft", "Prnt Chgs", "Edit", "Srch", "St Stp", "App", "App Sel", "Lib", "AMD", "Clean", "Lock" }; private string[] sysflags ={ "NetworkLock", "SysMaint", "ROEditor", "SysAdmin" }; #region NewMig public Security(string pathname, string vepromspath) { if (File.Exists(pathname) == false) { MessageBox.Show("Could not locate the Security Options file:\n\n" + pathname, "Security Access Error"); optfilename = null; return; } _VePromsPath = vepromspath; optfilename = pathname; } public bool Migrate() { VESamOpt vso = new VESamOpt(); bool suc = vso.OpenFile(optfilename); if (!suc) return false; plntDic = vso.LoadPlants(); if (plntDic == null) return false; suc = VerifyFolders(plntDic); if (!suc) return suc; userList = vso.LoadUserList(); if (userList == null) return false; vso.CloseFile(); vso = null; log.Info("Original vesam.opt loaded successfully - next step is to migrate security information to new database"); //WriteOutSummary(plntDic, userList); suc = TranslateToNew(vso, plntDic, userList); log.Info("Migrated vesam successfully"); return suc ; } #endregion #region WriteVESamSummary private void WriteOutSummary(Dictionary plntDic, List userList) { foreach (OldUser usr in userList) { log.InfoFormat("User = {0}", usr.UserName); StringBuilder sb = new StringBuilder(); for (int i = 0; i < 4; i++) { if ((usr.SystemOpts & (1L << i)) != 0) sb.Append(sysflags[i] + " "); } if (sb.Length > 0) log.InfoFormat(" System Options = {0}", sb.ToString()); // for now, don't worry about system options. // for each plant, list any permissions of the plant or its proc sets. If // none set, nothing will be listed. foreach (PlantOptions po in usr.PlantOpts) { bool plntout = false; Plant pl = (Plant)plntDic[po.Id]; if (po.Options != 0) { plntout = true; log.InfoFormat(" Plant = {0}. Options = {1}", pl.Name, po.Options); } foreach (ProcOptions psO in po.poList) { ProcSet ps = (ProcSet)pl.psDic[psO.Id]; if (psO.Options[0] != 0 || psO.Options[1] != 0 || psO.Options[2] != 0 || psO.Options[3] != 0) { if (!plntout) log.InfoFormat(" Plant = {0}.", pl.Name); log.InfoFormat(" Procedure Set = {0}", ps.Name); sb.Length = 0; int nm = 0; for (int i1 = 0; i1 < 4; i1++) { for (int j1 = 0; j1 < 16; j1++) { if ((psO.Options[i1] & (1L << j1)) != 0) sb.Append(prflags[nm] + " "); nm++; } } if (sb.Length > 0) log.InfoFormat(" {0}", sb.ToString()); } } } } } #endregion #region MigrateCode private string[] defaultRole ={ "Administrator", "User Administrator", "RO Manager", "Writer", "Reviewer", "Guest" }; private string[] defaultRoleTitle = { "Manages Data - Backups, Approval etc.", "Maintains User Security", "Maintains Referenced Objects", "Can Edit", "Can potentially add comments", "Read-Only access to approved procedures" }; // defaultPermData sets the permission data (Permissions table) - columns are // PermLevel, VersionType, PermValue (Note for vesam migration, PermAD is always allow, i.e. 0) private int[,] defaultPermData = { {2, 3, 15}, // Administrator {1, 3, 15}, // User Administrator {3, 3, 15}, // RO Manager {5, 1, 15}, // Writer {7, 3, 15}, // Reviewer {2, 2, 1}}; // Guest private int[] accessLevelSetup = { -1, 5, 4, 3, 0, 0, 2, 1 }; private int[] accessLevelTrans; private Dictionary AddDefaultRoles() { Dictionary rdic = new Dictionary(); try { accessLevelTrans = new int[accessLevelSetup.Length]; for (int i = 0; i < 6; i++) { Role role = Role.New(); role.Name = defaultRole[i]; role.Title = defaultRoleTitle[i]; if (!role.IsSavable) ErrorRpt.ErrorReport(role); role.Save(); Permission perm = Permission.New(); perm.MyRole = role; perm.PermLevel = defaultPermData[i, 0]; perm.VersionType = defaultPermData[i, 1]; perm.PermValue = defaultPermData[i, 2]; if (!perm.IsSavable) ErrorRpt.ErrorReport(perm); perm.Save(); rdic.Add(role.RID, role); for (int j = 1; j < accessLevelSetup.Length; j++) { if (accessLevelSetup[j] == i) accessLevelTrans[j] = role.RID; } } } catch (Exception ex) { log.ErrorFormat("Error setting default roles & permissions: {0}", ex.Message); return null; } return rdic; } public bool VerifyFolders(Dictionary dicPlants) { try { // For each folder from vesam, see if there is a matching folder already // migrated... FolderInfoList fil = FolderInfoList.Get(); // add the titles to a dictionary for quick checking List folderlist = new List(); foreach (FolderInfo fi in fil) { folderlist.Add(fi.Title.ToUpper()); } foreach (ushort u in dicPlants.Keys) { Plant pl = dicPlants[u]; bool foundplant = false; if (folderlist.Contains(pl.Path.ToUpper())) foundplant=true; if (!foundplant) log.InfoFormat("Plant from vesam.opt not found in folder data: {0}", pl.Path); else // if found, check for sets { foreach (ushort uu in pl.psDic.Keys) { ProcSet pr = pl.psDic[uu]; bool foundprocset = false; foreach (FolderInfo fi in fil) { string tstpath = pl.Path.ToUpper() + "\\" + pr.Path.ToUpper(); if (tstpath == fi.Title.ToUpper()) { foundprocset = true; break; } } if (!foundprocset) log.InfoFormat("Procedure Set from vesam.opt not found in folder data: {0}\\{1}", pl.Path, pr.Path); } } } } catch (Exception ex) { log.ErrorFormat("error mapping vesam directories to data directories, error = {0}", ex.Message); return false; } return true; } private Dictionary LoadFolders() { FolderInfoList fldlist = FolderInfoList.Get(); Dictionary fdic = new Dictionary(); foreach (FolderInfo fi in fldlist) { fdic.Add(fi.Title.ToUpper(), fi.FolderID); } return fdic; } private bool TranslateToNew(VESamOpt vso, Dictionary plntDic, List userList) { Dictionary rlpdic = AddDefaultRoles(); AddUsrGrpAsgnRecs(plntDic, userList); return true; } private string VersionName(string s) { return s.Substring(s.LastIndexOf(" - ") + 3); } private string SetName(string s) { return s.Substring(0, s.LastIndexOf(" - ")); } private string FixName(string s) { s = s.Replace(" - Working Draft (Unit 1)", " (Unit 1) - Working Draft"); s = s.Replace(" - Working Draft (Unit 2)", " (Unit 2) - Working Draft"); s = s.Replace(" - Current Approved Version", " - Approved Version"); return s.Replace(" - Working Draft", " - Working Draft"); } private int CalcAccessLevel(int iBase, uint options, string sVersion) { if (sVersion == "Working Draft") { if (options == 0) return 0; if ((options & 6528) != 0) return 5; if ((options & 1024) != 0) return 4; if ((options & 528) != 0) return 3; return 2; } else { if (iBase != 0) return iBase; else if (options != 0) return 1; return 0; } } private string SystemOption(uint options) { if ((options & 11) != 0) return "\"Admin\""; if (options == 4) return "\"RO\""; return ""; } private void AddAccessRights(Dictionary> dic, int folderId, int roleId) { if (!dic.ContainsKey(folderId)) dic[folderId] = new List(); dic[folderId].Add(roleId); } private void AddUsrGrpAsgnRecs(Dictionary plntDic, List userList) { Dictionary> dicGroups = new Dictionary>(); Dictionary dicGroupIds = new Dictionary(); Dictionary dicOldFolders = new Dictionary(); int oldFolderCount = 1; dicOldFolders.Add("system", oldFolderCount++); Dictionary dicNewFolders = LoadFolders(); List lstVersions = new List(); StringBuilder sb; OldUser frst = userList[0]; string[] accessLevel = { "", "\"Guest\"", "\"Reviewer\"", "\"Writer\"", "\"Admin\"", "\"Admin\"" }; foreach (OldUser usr in userList) { int sysAccess = 5; Dictionary plantAccess = new Dictionary(); if ((usr.SystemOpts & 11) == 0) { foreach (PlantOptions po in usr.PlantOpts) { plantAccess[po] = 5; Plant pl = (Plant)plntDic[po.Id]; if (!dicOldFolders.ContainsKey(pl.Path.ToUpper()))dicOldFolders.Add(pl.Path.ToUpper(), oldFolderCount++); string sSetLast = ""; int iAccessLevel = 0; foreach (ProcOptions psO in po.poList) { ProcSet ps = null; try { ps = (ProcSet)pl.psDic[psO.Id]; } catch (Exception ex) { MessageBox.Show("here: " + ex.Message); } if (!dicOldFolders.ContainsKey(pl.Path.ToUpper()+"\\"+ps.Path.ToUpper()))dicOldFolders.Add(pl.Path.ToUpper()+"\\"+ps.Path.ToUpper(), oldFolderCount++); string sName = FixName(ps.Name); string sVersion = VersionName(sName); string sSet = SetName(sName); if (sSet != sSetLast) { if (sSetLast != "") { // if the proc access is lower than the plant, reset plant level. if (iAccessLevel < plantAccess[po]) plantAccess[po] = iAccessLevel; iAccessLevel = 0; } sSetLast = sSet; } iAccessLevel = CalcAccessLevel(iAccessLevel, psO.Options[0], sVersion); } // do one last check to see if plant level should be lowered. Also // check if the system level should be lowered. if (iAccessLevel < plantAccess[po]) plantAccess[po] = iAccessLevel; if (plantAccess[po] < sysAccess) sysAccess = plantAccess[po]; } } // set the system level access, i.e. User Admin, System Admin & RO Editor roles if // necessary. int systemid = dicOldFolders["system"]; Dictionary> accessRights = new Dictionary>(); if (usr.SystemOpts != 0) AddAccessRights(accessRights, systemid, accessLevelTrans[6]); // add ro editor if ((usr.SystemOpts & 11) != 0) { AddAccessRights(accessRights, systemid, accessLevelTrans[5]); // add sys admin rights AddAccessRights(accessRights, systemid, accessLevelTrans[7]); // and add user admin rights } else { // the user has a role at the system level that is not an admin, // such as reviewer or guest - add it in. if (sysAccess > 0) AddAccessRights(accessRights, systemid, accessLevelTrans[sysAccess]); } sb = new StringBuilder(string.Format("{0},{1}", (usr.SystemOpts == 0 ? "" : "Admin"), accessLevel[sysAccess])); if ((usr.SystemOpts & 11) == 0) { foreach (PlantOptions po in usr.PlantOpts) { Plant pl = plntDic[po.Id]; // Need logic for po.Options in combination with PlantAccess[po] //sb.Append(string.Format(",{0}", po.Options)); if (plantAccess[po] > sysAccess) { AddAccessRights(accessRights, dicOldFolders[pl.Path.ToUpper()], accessLevelTrans[plantAccess[po]]); sb.Append(string.Format(",{0}", accessLevel[plantAccess[po]])); } else sb.Append(","); string sSetLast = ""; string sPathLast = ""; int iAccessLevel = 0; string sPath = ""; foreach (ProcOptions psO in po.poList) { ProcSet ps = pl.psDic[psO.Id]; string sName = FixName(ps.Name); string sVersion = VersionName(sName); if (sVersion == "Working Draft") sPath = pl.Path + "\\" + ps.Path; string sSet = SetName(sName); if (sSet != sSetLast) { if (sSetLast != "") { if (iAccessLevel > plantAccess[po]) { AddAccessRights(accessRights, dicOldFolders[sPathLast.ToUpper()], accessLevelTrans[iAccessLevel]); sb.Append(string.Format(",{0}", accessLevel[iAccessLevel])); } else sb.Append(","); iAccessLevel = 0; } sSetLast = sSet; sPathLast = sPath; } iAccessLevel = CalcAccessLevel(iAccessLevel, psO.Options[0], sVersion); } if (iAccessLevel > plantAccess[po]) { AddAccessRights(accessRights, dicOldFolders[sPathLast.ToUpper()], accessLevelTrans[iAccessLevel]); sb.Append(string.Format(",{0}", accessLevel[iAccessLevel])); } else sb.Append(","); } } string s = sb.ToString(); if (!dicGroups.ContainsKey(s)) { dicGroups[s] = new List(); Group grp = Group.New(); grp.GroupName = "Group " + dicGroups.Count.ToString(); int pathInData = -1; foreach (int folderId in accessRights.Keys) { // see if this folderId exists in the data (rather // than the list from vesam). If not, don't do an // assignments record pathInData = 0; foreach (KeyValuePair kvp in dicOldFolders) { if (kvp.Value == folderId) { string path = kvp.Key; if (dicNewFolders.ContainsKey(path.ToUpper())) pathInData = dicNewFolders[path.ToUpper()]; } } if (pathInData>0) { if (!grp.IsSavable) ErrorRpt.ErrorReport(grp); grp.Save(); Folder tmpfld = Folder.Get(pathInData); foreach (int roleId in accessRights[folderId]) { Role tmprole = Role.Get(roleId); grp.GroupAssignments.Add(tmprole, tmpfld); } } } if (!grp.IsSavable) ErrorRpt.ErrorReport(grp); grp.Save(); dicGroupIds[s] = grp.GID; } dicGroups[s].Add(usr.UserName); } foreach (string s in dicGroups.Keys) { foreach (string sUser in dicGroups[s]) { // add user record & membership record. User newusr = User.New(); newusr.UserID = sUser; ConfigFile cfg = new ConfigFile(); cfg.LoadUsrCfg(newusr, _VePromsPath); Group tmpgrp = Group.Get(dicGroupIds[s]); newusr.UserMemberships.Add(tmpgrp); if (!newusr.IsSavable) ErrorRpt.ErrorReport(newusr); newusr.Save(); } } } #endregion } #endregion }