[Nmailserver-commits] SF.net SVN: nmailserver: [182] NMail/trunk/NMail
Brought to you by:
dframpton-oss,
tmyroadctfig
|
From: <tmy...@us...> - 2007-04-11 04:58:47
|
Revision: 182
http://svn.sourceforge.net/nmailserver/?rev=182&view=rev
Author: tmyroadctfig
Date: 2007-04-10 21:58:48 -0700 (Tue, 10 Apr 2007)
Log Message:
-----------
Further work on localstore data.
Modified Paths:
--------------
NMail/trunk/NMail/DataTypes/LocalStore/ILocalStore.cs
NMail/trunk/NMail/DataTypes/LocalStore/ILocalStoreData.cs
NMail/trunk/NMail.ImapService/State/AuthenticatedState.cs
NMail/trunk/NMail.LocalStore/LocalStore.cs
NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs
NMail/trunk/NMail.LocalStoreData.NHibernate/NHibernateLocalStoreData.cs
Modified: NMail/trunk/NMail/DataTypes/LocalStore/ILocalStore.cs
===================================================================
--- NMail/trunk/NMail/DataTypes/LocalStore/ILocalStore.cs 2007-04-11 02:50:01 UTC (rev 181)
+++ NMail/trunk/NMail/DataTypes/LocalStore/ILocalStore.cs 2007-04-11 04:58:48 UTC (rev 182)
@@ -111,21 +111,26 @@
LocalStoreFolderResult DeleteFolder(IAuthenticationToken authToken, int folderId);
/// <summary>
- /// Renames an existing folder in the local store.
+ /// Moves an existing folder in the local store to another location.
/// </summary>
/// <remarks>
- /// It is a requirement of the local store that a renamed folder and all its sub-folder get a new
+ /// It is a requirement of the local store that a moved folder and all its sub-folder get a new
/// folder Id. Futher, this new Id number cannot have been used previously.
///
- /// Thus any existing folder Ids for the rename folder or its childed obtained before the rename may
- /// be altered and must be reaquired from the local store.
+ /// Thus any existing folder Ids for the moved folder or its children obtained before the move may
+ /// be invalid and must be reaquired from the local store.
/// </remarks>
/// <param name="authToken">The authentication credentials.</param>
- /// <param name="folder">The folder to rename.</param>
- /// <param name="newFolder">The new folder name.</param>
- /// <returns>The result of the rename attempt.</returns>
- LocalStoreFolderResult RenameFolder(IAuthenticationToken authToken, StoreFolder folder, string newFolder);
-
+ /// <param name="folderId">The Id of the folder to move.</param>
+ /// <param name="parentId">The Id of the new parent folder if any.</param>
+ /// <param name="newFolderName">
+ /// The new folder name. Note: this is <b>not</b> the full folder name or the qualified folder name.
+ /// </param>
+ /// <exception cref="System.Data.DuplicateNameException">If a folder with the same name already exists.</exception>
+ /// <exception cref="System.InvalidOperationException">Changes to the folder are not permitted.</exception>
+ /// <exception cref="System.ArgumentException">The folder Id or parent Id or folder name is invalid.</exception>
+ void MoveFolder(IAuthenticationToken authToken, int folderId, int? parentId, string newFolderName);
+
/// <summary>
/// Gets a list of folders that match the query folder.
/// </summary>
Modified: NMail/trunk/NMail/DataTypes/LocalStore/ILocalStoreData.cs
===================================================================
--- NMail/trunk/NMail/DataTypes/LocalStore/ILocalStoreData.cs 2007-04-11 02:50:01 UTC (rev 181)
+++ NMail/trunk/NMail/DataTypes/LocalStore/ILocalStoreData.cs 2007-04-11 04:58:48 UTC (rev 182)
@@ -89,19 +89,24 @@
void DeleteFolder(int folderId, bool deleteChildren);
/// <summary>
- /// Renames an existing folder in the local store.
+ /// Moves an existing folder in the local store to another location.
/// </summary>
/// <remarks>
- /// It is a requirement of the local store that a renamed folder and all its sub-folder get a new
+ /// It is a requirement of the local store that a moved folder and all its sub-folder get a new
/// folder Id. Futher, this new Id number cannot have been used previously.
///
- /// Thus any existing folder Ids for the rename folder or its childed obtained before the rename may
- /// be altered and must be reaquired from the local store.
+ /// Thus any existing folder Ids for the moved folder or its children obtained before the move may
+ /// be invalid and must be reaquired from the local store.
/// </remarks>
- /// <param name="folder">The folder to rename.</param>
- /// <param name="newFolder">The new folder name.</param>
- /// <returns>The result of the rename attempt.</returns>
- LocalStoreFolderResult RenameFolder(StoreFolder folder, string newFolder);
+ /// <param name="folderId">The Id of the folder to move.</param>
+ /// <param name="parentId">The Id of the new parent folder if any.</param>
+ /// <param name="newFolderName">
+ /// The new folder name. Note: this is <b>not</b> the full folder name or the qualified folder name.
+ /// </param>
+ /// <exception cref="System.Data.DuplicateNameException">If a folder with the same name already exists.</exception>
+ /// <exception cref="System.InvalidOperationException">Changes to the folder are not permitted.</exception>
+ /// <exception cref="System.ArgumentException">The folder Id or parent Id or folder name is invalid.</exception>
+ void MoveFolder(int folderId, int? parentId, string newFolderName);
/// <summary>
/// Gets a list of child folders for the given parent folder.
Modified: NMail/trunk/NMail.ImapService/State/AuthenticatedState.cs
===================================================================
--- NMail/trunk/NMail.ImapService/State/AuthenticatedState.cs 2007-04-11 02:50:01 UTC (rev 181)
+++ NMail/trunk/NMail.ImapService/State/AuthenticatedState.cs 2007-04-11 04:58:48 UTC (rev 182)
@@ -17,6 +17,7 @@
using System;
using System.Collections.Generic;
+using System.Data;
using System.Globalization;
using System.Text;
@@ -310,9 +311,19 @@
StoreFolder folder = LocalStore.GetStoreFolder(Session.AuthenticationToken, cmd.CurrentFolder);
if (folder != null) {
- LocalStoreFolderResult result = LocalStore.RenameFolder(Session.AuthenticationToken, folder, cmd.NewFolder);
+ try {
+ int? parentId = null;
+ Folder newFolder = new Folder(cmd.NewFolder);
- if (result == LocalStoreFolderResult.OkSuccessful) {
+ // Get the parent folder Id if any
+ if (newFolder.Parent != null) {
+ StoreFolder parent = LocalStore.GetStoreFolder(Session.AuthenticationToken, newFolder.Parent.FullyQualifiedName);
+ parentId = parent.FolderId;
+ }
+
+ // Move the folder
+ LocalStore.MoveFolder(Session.AuthenticationToken, folder.FolderId, parentId, newFolder.FolderName);
+
// Renaming INBOX creates a new empty INBOX.
if (LocalStore.GetStoreFolder(Session.AuthenticationToken, Folder.Inbox) == null) {
LocalStore.CreateFolder(Session.AuthenticationToken, Folder.Inbox);
@@ -320,16 +331,16 @@
QueueResponse(new SimpleResponse(cmd.Tag, ResponseType.Ok, "RENAME Completed."));
- } else if (result == LocalStoreFolderResult.AlreadyExists) {
+ } catch (DuplicateNameException) {
QueueResponse(new SimpleResponse(cmd.Tag, ResponseType.No, "RENAME: Folder:[" + cmd.NewFolder + "] already exists."));
- } else if (result == LocalStoreFolderResult.NonExistent) {
- QueueResponse(new SimpleResponse(cmd.Tag, ResponseType.No, "RENAME: No such folder:[" + cmd.CurrentFolder + "]"));
+ } catch (ArgumentException) {
+ QueueResponse(new SimpleResponse(cmd.Tag, ResponseType.No, "RENAME: Invalid parameters: Current name:[" + cmd.CurrentFolder + "] New name:[" + cmd.NewFolder + "]"));
- } else if (result == LocalStoreFolderResult.NotPermitted) {
+ } catch (InvalidOperationException) {
QueueResponse(new SimpleResponse(cmd.Tag, ResponseType.No, "RENAME: Insufficient privileges to delete folder:[" + cmd.CurrentFolder + "]."));
- } else {
+ } catch (Exception) {
QueueResponse(new SimpleResponse(cmd.Tag, ResponseType.No, "RENAME: Unknown error."));
}
} else {
Modified: NMail/trunk/NMail.LocalStore/LocalStore.cs
===================================================================
--- NMail/trunk/NMail.LocalStore/LocalStore.cs 2007-04-11 02:50:01 UTC (rev 181)
+++ NMail/trunk/NMail.LocalStore/LocalStore.cs 2007-04-11 04:58:48 UTC (rev 182)
@@ -427,37 +427,41 @@
return LocalStoreData.GetFolders();
}
- #region Rename Folder
+ #region Move Folder
/// <summary>
- /// Renames an existing folder in the local store.
+ /// Moves an existing folder in the local store to another location.
/// </summary>
/// <remarks>
- /// It is a requirement of the local store that a renamed folder and all its sub-folder get a new
+ /// It is a requirement of the local store that a moved folder and all its sub-folder get a new
/// folder Id. Futher, this new Id number cannot have been used previously.
///
- /// Thus any existing folder Ids for the rename folder or its childed obtained before the rename may
- /// be altered and must be reaquired from the local store.
+ /// Thus any existing folder Ids for the moved folder or its children obtained before the move may
+ /// be invalid and must be reaquired from the local store.
/// </remarks>
/// <param name="authToken">The authentication credentials.</param>
- /// <param name="folder">The folder to rename.</param>
- /// <param name="newFolder">The new folder name.</param>
- /// <returns>The result of the rename attempt.</returns>
- public LocalStoreFolderResult RenameFolder(IAuthenticationToken authToken, StoreFolder folder, string newFolderName) {
+ /// <param name="folderId">The Id of the folder to move.</param>
+ /// <param name="parentId">The Id of the new parent folder if any.</param>
+ /// <param name="newFolderName">
+ /// The new folder name. Note: this is <b>not</b> the full folder name or the qualified folder name.
+ /// </param>
+ /// <exception cref="System.Data.DuplicateNameException">If a folder with the same name already exists.</exception>
+ /// <exception cref="System.InvalidOperationException">Changes to the folder are not permitted.</exception>
+ /// <exception cref="System.ArgumentException">The folder Id or parent Id or folder name is invalid.</exception>
+ public void MoveFolder(IAuthenticationToken authToken, int folderId, int? parentId, string newFolderName) {
// Ensure the user has delete privileges on the original folder
- if (hasFolderPrivilege(authToken.Username, folder.FolderId, StoreFolderPrivilege.Delete)) {
+ if (hasFolderPrivilege(authToken.Username, folderId, StoreFolderPrivilege.Delete)) {
- Folder newFolder = new Folder(folder.NameSpace, newFolderName);
- StoreFolder parent = LocalStoreData.GetStoreFolder(newFolder.Parent);
-
// Ensure the user has create privileges on the new parent folder
- if (parent != null && hasFolderPrivilege(authToken.Username, parent.FolderId, StoreFolderPrivilege.CreateFolders)) {
- return LocalStoreData.RenameFolder(folder, newFolderName);
+ // TODO: implement move for top level folders
+ if (parentId.HasValue && hasFolderPrivilege(authToken.Username, parentId.Value, StoreFolderPrivilege.CreateFolders)) {
+ LocalStoreData.MoveFolder(folderId, parentId, newFolderName);
+
} else {
- return LocalStoreFolderResult.NotPermitted;
+ throw new InvalidOperationException("Not permitted to move this folder or invalid folder.");
}
} else {
- return LocalStoreFolderResult.NotPermitted;
+ throw new InvalidOperationException("Not permitted to move this folder or invalid folder.");
}
}
#endregion
Modified: NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs
===================================================================
--- NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs 2007-04-11 02:50:01 UTC (rev 181)
+++ NMail/trunk/NMail.LocalStoreData.MySql/MySqlLocalStoreData.cs 2007-04-11 04:58:48 UTC (rev 182)
@@ -330,51 +330,10 @@
}
#endregion
- #region RenameFolder
- public LocalStoreFolderResult RenameFolder(StoreFolder folder, string newFolderName) {
- /* Several cases:
- * a1.b1 -> a1.b2 => simply rename "a1.b1" to "a1.b2"
- * a1.b1 -> a2.b1 => rename "a1" to "a2" and "a1.b1" to "a2.b1"
- * a1.b1.c1 -> a1.b2.c1 => rename "a1.b1" to "a1.b2" and "a1.b1.c1" to "a1.b2.c1"
- * So simply rename the folder and any children.
- *
- * Also renaming "a1.b1" to "a2.b2" causes problems so renaming will be limited
- * to only allow changing the end folder in the hierarchy. For example:
- * a1.b1 -> a1.b2 is ok
- * a1 -> a2 is ok
- * a1.b1 to a2.b1 is not ok
- */
+ #region MoveFolder
+ public void MoveFolder(int folderId, int? parentId, string newFolderName) {
- // Check only the top level folder is being renamed
- char[] delim = { NMailConfiguration.Current.LocalStore.FolderDelimiter };
- string[] folderParts = folder.FullFolderName.Split(delim);
- string[] newParts = newFolderName.Split(delim);
-
- if (folderParts.Length != newParts.Length) {
- return LocalStoreFolderResult.NotPermitted;
- }
-
- for (int i = 0; i < folderParts.Length - 1; i++) {
- if (!folderParts[i].ToLower().Equals(newParts[i].ToLower())) {
- return LocalStoreFolderResult.NotPermitted;
- }
- }
-
- // Only the last part of the folder name has changed, proceed with the rename
- using (MySqlConnection cnn = MySqlHelper.GetConnection()) {
- MySqlTransaction transaction = cnn.BeginTransaction();
-
- // Check for a folder with the same name
- Folder newFolder = new Folder(folder.NameSpace, newFolderName);
- if (getStoreFolder(newFolder, cnn, transaction) != null) {
- transaction.Commit();
- return LocalStoreFolderResult.AlreadyExists;
- }
-
- throw new NotImplementedException();
- // TODO: rename the folder
- // TODO: recursively rename all children
- }
+ throw new NotImplementedException();
}
#endregion
Modified: NMail/trunk/NMail.LocalStoreData.NHibernate/NHibernateLocalStoreData.cs
===================================================================
--- NMail/trunk/NMail.LocalStoreData.NHibernate/NHibernateLocalStoreData.cs 2007-04-11 02:50:01 UTC (rev 181)
+++ NMail/trunk/NMail.LocalStoreData.NHibernate/NHibernateLocalStoreData.cs 2007-04-11 04:58:48 UTC (rev 182)
@@ -269,11 +269,15 @@
}
// Check for any folders with the same name
- IList<StoreFolder> matching = session.CreateCriteria(typeof(StoreFolder))
- .Add(Expression.Eq("ParentId", newFolder.ParentId))
- .Add(Expression.Like("FullFolderName", newFolder.FullFolderName))
- .List<StoreFolder>();
+ ICriteria criteria = session.CreateCriteria(typeof(StoreFolder))
+ .Add(Expression.Like("FullFolderName", newFolder.FullFolderName));
+ if (newFolder.ParentId.HasValue) {
+ criteria = criteria.Add(Expression.Eq("ParentId", newFolder.ParentId));
+ }
+
+ IList<StoreFolder> matching = criteria.List<StoreFolder>();
+
if (matching.Count > 0) {
throw new DuplicateNameException("Folder with the same name already exists.");
}
@@ -354,26 +358,94 @@
}
#endregion
- #region RenameFolder
- public void RenameFolder(int folderId, Folder newFolderName) {
+ #region MoveFolder
+ /// <summary>
+ /// Moves an existing folder in the local store to another location.
+ /// </summary>
+ /// <remarks>
+ /// It is a requirement of the local store that a moved folder and all its sub-folder get a new
+ /// folder Id. Futher, this new Id number cannot have been used previously.
+ ///
+ /// Thus any existing folder Ids for the moved folder or its children obtained before the move may
+ /// be invalid and must be reaquired from the local store.
+ /// </remarks>
+ /// <param name="folderId">The Id of the folder to move.</param>
+ /// <param name="parentId">The Id of the new parent folder if any.</param>
+ /// <param name="newFolderName">
+ /// The new folder name. Note: this is <b>not</b> the full folder name or the qualified folder name.
+ /// </param>
+ /// <exception cref="System.Data.DuplicateNameException">If a folder with the same name already exists.</exception>
+ /// <exception cref="System.InvalidOperationException">Changes to the folder are not permitted.</exception>
+ /// <exception cref="System.ArgumentException">The folder Id or parent Id or folder name is invalid.</exception>
+ public void MoveFolder(int folderId, int? parentId, string newFolderName) {
using (ISession session = this.hibernateFactory.OpenSession()) {
using (ITransaction tx = session.BeginTransaction()) {
- StoreFolder folder = session.Load<StoreFolder>(folderId);
+ StoreFolder currentFolder = session.Load<StoreFolder>(folderId);
+ StoreFolder newFolder;
+ StoreFolder currentParent;
+ StoreFolder newParentFolder = null;
- throw new NotImplementedException();
+ if (currentFolder.ParentId.HasValue) {
+ currentParent = session.Load<StoreFolder>(currentFolder.ParentId.Value);
+ }
- if (folder.ChildIds.Count > 0) {
- // TODO: rename children
+ if (parentId.HasValue) {
+ newParentFolder = session.Load<StoreFolder>(parentId.Value);
}
+ // Setup the new folder
+ if (newParentFolder != null) {
+ newFolder = new StoreFolder(newParentFolder, newFolderName);
+ } else {
+ newFolder = new StoreFolder(currentFolder.NameSpace, newFolderName);
+ }
+ newFolder.ParentId = parentId;
+ newFolder.OwnerUserId = currentFolder.OwnerUserId;
+ // TODO: ACLs
+
+ session.Save(newFolder);
+
+ // Adjust the details of the child folders and move them across
+ MoveChildren(newFolder, currentFolder, session);
+
tx.Commit();
session.Close();
}
}
}
- public LocalStoreFolderResult RenameFolder(StoreFolder f, string s) {
- throw new NotImplementedException();
+ /// <summary>
+ /// Moves all child folders recursively to the new folder.
+ /// </summary>
+ /// <param name="newParent">The new parent folder.</param>
+ /// <param name="oldParent">The old parent folder.</param>
+ /// <param name="session">The session to use.</param>
+ protected void MoveChildren(StoreFolder newParent, StoreFolder oldParent, ISession session) {
+ // Ensure session has started a transaction
+ if (!session.Transaction.IsActive) {
+ throw new InvalidOperationException("A transaction is required for this operation.");
+ }
+
+ // Update each child recursively
+ foreach (int childId in oldParent.ChildIds) {
+ StoreFolder currentChild = session.Load<StoreFolder>(childId);
+
+ // Make a new child folder
+ StoreFolder newChild = new StoreFolder(newParent, currentChild.FolderName);
+ newChild.ParentId = newParent.FolderId;
+ newChild.OwnerUserId = currentChild.OwnerUserId;
+ // TODO: child ACLs
+ session.Save(newChild);
+
+ // Add the to parent
+ newParent.ChildIds.Add(newChild.FolderId);
+
+ // Recurse
+ MoveChildren(newChild, currentChild, session);
+ }
+
+ // Store all child Ids to the database
+ session.Update(newParent);
}
#endregion
@@ -991,6 +1063,10 @@
public void DeleteUser(int userId) {
using (ISession session = this.hibernateFactory.OpenSession()) {
using (ITransaction tx = session.BeginTransaction()) {
+ if (GetUserFolders(userId, session).Count > 0) {
+ throw new ConstraintException("Can't delete a user that still owns folders.");
+ }
+
LocalStoreUser user = session.Load<LocalStoreUser>(userId);
session.Delete(user);
@@ -1036,11 +1112,21 @@
/// <returns>The list of folders or null if the user Id is invalid.</returns>
public IList<StoreFolder> GetUserFolders(int userId) {
using (ISession session = this.hibernateFactory.OpenSession()) {
- return session.CreateCriteria(typeof(StoreFolder))
- .Add(Expression.Eq("OwnerUserId", userId))
- .List<StoreFolder>();
+ return GetUserFolders(userId, session);
}
}
+
+ /// <summary>
+ /// Gets a list of folders that belong to the user with the given user Id.
+ /// </summary>
+ /// <param name="userId">The Id of the user to get the folder for.</param>
+ /// <param name="session">The session to use.</param>
+ /// <returns>The list of folders or null if the user Id is invalid.</returns>
+ protected IList<StoreFolder> GetUserFolders(int userId, ISession session) {
+ return session.CreateCriteria(typeof(StoreFolder))
+ .Add(Expression.Eq("OwnerUserId", userId))
+ .List<StoreFolder>();
+ }
#endregion
#endregion
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|