diff --git a/include/znc/User.h b/include/znc/User.h index 6e375dcb..5caceac9 100644 --- a/include/znc/User.h +++ b/include/znc/User.h @@ -91,6 +91,7 @@ public: CString AddTimestamp(const CString& sStr) const; CString AddTimestamp(time_t tm, const CString& sStr) const; + void CloneNetworks(const CUser& User); bool Clone(const CUser& User, CString& sErrorRet, bool bCloneNetworks = true); void BounceAllClients(); diff --git a/modules/data/webadmin/tmpl/add_edit_user.tmpl b/modules/data/webadmin/tmpl/add_edit_user.tmpl index 883ca937..7e5a8b3f 100644 --- a/modules/data/webadmin/tmpl/add_edit_user.tmpl +++ b/modules/data/webadmin/tmpl/add_edit_user.tmpl @@ -11,6 +11,9 @@
Username:
+ + + @@ -104,9 +107,7 @@

Networks

- - You will be able to add + modify networks here after you created the user.
- +
@@ -135,6 +136,8 @@
+ + You will be able to add + modify networks here after you have clonedcreated the user.
@@ -261,7 +264,7 @@
- +
diff --git a/modules/data/webadmin/tmpl/listusers.tmpl b/modules/data/webadmin/tmpl/listusers.tmpl index 2e3ef583..ed2f9301 100644 --- a/modules/data/webadmin/tmpl/listusers.tmpl +++ b/modules/data/webadmin/tmpl/listusers.tmpl @@ -22,6 +22,7 @@ [Edit] + [Clone] [Delete] diff --git a/modules/webadmin.cpp b/modules/webadmin.cpp index 15f919b7..f32f56aa 100644 --- a/modules/webadmin.cpp +++ b/modules/webadmin.cpp @@ -865,6 +865,18 @@ public: Tmpl["Action"] = "edituser"; Tmpl["Title"] = "Edit User [" + pUser->GetUserName() + "]"; Tmpl["Edit"] = "true"; + } else { + CString sUsername = WebSock.GetParam("clone", false); + pUser = CZNC::Get().FindUser(sUsername); + + if (pUser) { + Tmpl["Title"] = "Clone User [" + pUser->GetUserName() + "]"; + Tmpl["Clone"] = "true"; + Tmpl["CloneUsername"] = pUser->GetUserName(); + } + } + + if (pUser) { Tmpl["Username"] = pUser->GetUserName(); Tmpl["Nick"] = pUser->GetNick(); Tmpl["AltNick"] = pUser->GetAltNick(); @@ -1049,6 +1061,11 @@ public: CString sAction; if (!pUser) { + CString sClone = WebSock.GetParam("clone"); + if (CUser *pCloneUser = CZNC::Get().FindUser(sClone)) { + pNewUser->CloneNetworks(*pCloneUser); + } + // Add User Submission if (!CZNC::Get().AddUser(pNewUser, sErr)) { delete pNewUser; diff --git a/src/User.cpp b/src/User.cpp index 52d1309e..882dfd8a 100644 --- a/src/User.cpp +++ b/src/User.cpp @@ -566,6 +566,44 @@ void CUser::UserDisconnected(CClient* pClient) { } } +void CUser::CloneNetworks(const CUser& User) { + const vector& vNetworks = User.GetNetworks(); + for (vector::const_iterator it = vNetworks.begin(); it != vNetworks.end(); ++it) { + CIRCNetwork *pNetwork = FindNetwork((*it)->GetName()); + + if (pNetwork) { + pNetwork->Clone(*(*it)); + } else { + new CIRCNetwork(this, *(*it)); + } + } + + set ssDeleteNetworks; + for (vector::const_iterator it = m_vIRCNetworks.begin(); it != m_vIRCNetworks.end(); ++it) { + if (!(User.FindNetwork((*it)->GetName()))) { + ssDeleteNetworks.insert((*it)->GetName()); + } + } + + for (set::const_iterator it = ssDeleteNetworks.begin(); it != ssDeleteNetworks.end(); ++it) { + // The following will move all the clients to the user. + // So the clients are not disconnected. The client could + // have requested the rehash. Then when we do + // client->PutStatus("Rehashing succeeded!") we would + // crash if there was no client anymore. + vector& vClients = FindNetwork(*it)->GetClients(); + + while (vClients.begin() != vClients.end()) { + CClient *pClient = vClients.front(); + // This line will remove pClient from vClients, + // because it's a reference to the internal Network's vector. + pClient->SetNetwork(NULL); + } + + DeleteNetwork(*it); + } +} + bool CUser::Clone(const CUser& User, CString& sErrorRet, bool bCloneNetworks) { unsigned int a = 0; sErrorRet.clear(); @@ -619,41 +657,7 @@ bool CUser::Clone(const CUser& User, CString& sErrorRet, bool bCloneNetworks) { // Networks if (bCloneNetworks) { - const vector& vNetworks = User.GetNetworks(); - for (vector::const_iterator it = vNetworks.begin(); it != vNetworks.end(); ++it) { - CIRCNetwork *pNetwork = FindNetwork((*it)->GetName()); - - if (pNetwork) { - pNetwork->Clone(*(*it)); - } else { - new CIRCNetwork(this, *(*it)); - } - } - - set ssDeleteNetworks; - for (vector::const_iterator it = m_vIRCNetworks.begin(); it != m_vIRCNetworks.end(); ++it) { - if (!(User.FindNetwork((*it)->GetName()))) { - ssDeleteNetworks.insert((*it)->GetName()); - } - } - - for (set::const_iterator it = ssDeleteNetworks.begin(); it != ssDeleteNetworks.end(); ++it) { - // The following will move all the clients to the user. - // So the clients are not disconnected. The client could - // have requested the rehash. Then when we do - // client->PutStatus("Rehashing succeeded!") we would - // crash if there was no client anymore. - vector& vClients = FindNetwork(*it)->GetClients(); - - while (vClients.begin() != vClients.end()) { - CClient *pClient = vClients.front(); - // This line will remove pClient from vClients, - // because it's a reference to the internal Network's vector. - pClient->SetNetwork(NULL); - } - - DeleteNetwork(*it); - } + CloneNetworks(User); } // !Networks