/// <summary> /// Renames or moves a File. /// </summary> /// <param name="oldFullName">The old full name of the File.</param> /// <param name="newFullName">The new full name of the File.</param> /// <returns><c>true</c> if the File is renamed, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="oldFullName"/> or <paramref name="newFullName"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="oldFullName"/> or <paramref name="newFullName"/> are empty, or if the old file does not exist, or if the new file already exist.</exception> public bool RenameFile(string oldFullName, string newFullName) { if(oldFullName == null) throw new ArgumentNullException("oldFullName"); if(oldFullName.Length == 0) throw new ArgumentException("Old Full Name cannot be empty", "oldFullName"); if(newFullName == null) throw new ArgumentNullException("newFullName"); if(newFullName.Length == 0) throw new ArgumentException("New Full Name cannot be empty", "newFullName"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); if(!FileExists(transaction, oldFullName)) { RollbackTransaction(transaction); throw new ArgumentException("File does not exist", "oldFullName"); } if(FileExists(transaction, newFullName)) { RollbackTransaction(transaction); throw new ArgumentException("File already exists", "newFullPath"); } string oldDirectory, newDirectory, oldFilename, newFilename; SplitFileFullName(oldFullName, out oldDirectory, out oldFilename); SplitFileFullName(newFullName, out newDirectory, out newFilename); string query = queryBuilder.Update("File", new string[] { "Name" }, new string[] { "NewName" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "OldName"); query = queryBuilder.AndWhere(query, "Directory", WhereOperator.Equals, "OldDirectory"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "NewName", newFilename)); parameters.Add(new Parameter(ParameterType.String, "OldName", oldFilename)); parameters.Add(new Parameter(ParameterType.String, "OldDirectory", oldDirectory)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows == 1; }
/// <summary> /// Gets all the sub-namespaces. /// </summary> /// <returns>The sub-namespaces, sorted by name.</returns> public NamespaceInfo[] GetNamespaces() { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); // select ... from Namespace left join Page on Namespace.DefaultPage = Page.Name where Namespace.Name <> '' and (Namespace.DefaultPage is null or Page.Namespace <> '') string query = queryBuilder.SelectFrom("Namespace", "Page", "DefaultPage", "Name", Join.LeftJoin, new string[] { "Name", "DefaultPage" }, new string[] { "CreationDateTime" }); query = queryBuilder.Where(query, "Namespace", "Name", WhereOperator.NotEquals, "Empty1"); query = queryBuilder.AndWhere(query, "Namespace", "DefaultPage", WhereOperator.IsNull, null, true, false); query = queryBuilder.OrWhere(query, "Page", "Namespace", WhereOperator.NotEquals, "Empty2", false, true); query = queryBuilder.OrderBy(query, new[] { "Namespace_Name" }, new[] { Ordering.Asc }); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Empty1", " ")); parameters.Add(new Parameter(ParameterType.String, "Empty2", " ")); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { List<NamespaceInfo> result = new List<NamespaceInfo>(10); while(reader.Read()) { string realName = reader["Namespace_Name"] as string; string page = GetNullableColumn<string>(reader, "Namespace_DefaultPage", null); PageInfo defaultPage = string.IsNullOrEmpty(page) ? null : new PageInfo(NameTools.GetFullName(realName, page), this, (DateTime)reader["Page_CreationDateTime"]); // The query returns duplicate entries if the main page of two or more namespaces have the same name if(result.Find(n => { return n.Name.Equals(realName); }) == null) { result.Add(new NamespaceInfo(realName, this, defaultPage)); } } CloseReader(command, reader); return result.ToArray(); } else return null; }
/// <summary> /// Gets a meta-data item's content. /// </summary> /// <param name="item">The item.</param> /// <param name="tag">The tag that specifies the context (usually the namespace).</param> /// <returns>The content.</returns> public string GetMetaDataItem(MetaDataItem item, string tag) { if(string.IsNullOrEmpty(tag)) tag = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("MetaDataItem", new string[] { "Data" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Tag", WhereOperator.Equals, "Tag"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", item.ToString())); parameters.Add(new Parameter(ParameterType.String, "Tag", tag)); DbCommand command = builder.GetCommand(connString, query, parameters); string value = ExecuteScalar<string>(command, " "); return value; }
/// <summary> /// Removes a Message. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="page">The Page.</param> /// <param name="id">The ID of the Message to remove.</param> /// <param name="removeReplies">A value specifying whether or not to remove the replies.</param> /// <returns>True if the Message is removed successfully.</returns> private bool RemoveMessage(DbTransaction transaction, PageInfo page, int id, bool removeReplies) { string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; Message[] messages = GetMessages(transaction, page); if(messages == null) return false; Message message = FindMessage(messages, id); if(message == null) return false; Message parent = FindAnchestor(messages, id); int parentId = parent != null ? parent.ID : -1; UnindexMessage(page, message.ID, message.Subject, message.DateTime, message.Body, transaction); if(removeReplies) { // Recursively remove all replies BEFORE removing parent (depth-first) foreach(Message reply in message.Replies) { if(!RemoveMessage(transaction, page, reply.ID, true)) return false; } } // Remove this message ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Message"); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Id", WhereOperator.Equals, "Id"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Id", (short)id)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(!removeReplies && rows == 1) { // Update replies' parent id query = queryBuilder.Update("Message", new string[] { "Parent" }, new string[] { "NewParent" }); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Parent", WhereOperator.Equals, "OldParent"); parameters = new List<Parameter>(4); if(parentId != -1) parameters.Add(new Parameter(ParameterType.Int16, "NewParent", parentId)); else parameters.Add(new Parameter(ParameterType.Int16, "NewParent", DBNull.Value)); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "OldParent", (short)id)); command = builder.GetCommand(transaction, query, parameters); rows = ExecuteNonQuery(command, false); } return rows > 0; }
/// <summary> /// Removes a Navigation Path. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="path">The navigation path to remove.</param> /// <returns><c>true</c> if the path is removed, <c>false</c> otherwise.</returns> private bool RemoveNavigationPath(DbConnection connection, NavigationPath path) { string nspace, name; NameTools.ExpandFullName(path.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("NavigationPath"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(connection, query, parameters); int rows = ExecuteNonQuery(command, false); return rows > 0; }
/// <summary> /// Gets the Page Messages. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="page">The Page.</param> /// <returns>The list of the <b>first-level</b> Messages, containing the replies properly nested, sorted by date/time.</returns> private Message[] GetMessages(DbConnection connection, PageInfo page) { if(GetPage(connection, page.FullName) == null) return null; // 1. Load all messages in memory in a dictionary id->message // 2. Build tree using ParentID string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("Message", new string[] { "Id", "Parent", "Username", "Subject", "DateTime", "Body" }); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.OrderBy(query, new string[] { "DateTime", "Id" }, new Ordering[] { Ordering.Asc, Ordering.Asc }); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(connection, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { Dictionary<short, Message> allMessages = new Dictionary<short, Message>(50); List<short> ids = new List<short>(50); List<short?> parents = new List<short?>(50); while(reader.Read()) { Message msg = new Message((short)Convert.ChangeType( reader["Id"],typeof(short)), reader["Username"] as string, reader["Subject"] as string, (DateTime)reader["DateTime"], reader["Body"] as string); ids.Add((short)msg.ID); // Import from V2: parent = -1, otherwise null if(!IsDBNull(reader, "Parent")) { short par = (short)Convert.ChangeType(reader["Parent"],typeof(short)); if(par >= 0) parents.Add(par); else parents.Add(null); } else parents.Add(null); allMessages.Add((short)msg.ID, msg); } CloseReader(reader); // Add messages to their parents and build the top-level messages list List<Message> result = new List<Message>(20); for(int i = 0; i < ids.Count; i++) { short? currentParent = parents[i]; short currentId = ids[i]; if(currentParent.HasValue) { List<Message> replies = new List<Message>(allMessages[currentParent.Value].Replies); replies.Add(allMessages[currentId]); allMessages[currentParent.Value].Replies = replies.ToArray(); } else result.Add(allMessages[currentId]); } return result.ToArray(); } else return null; }
/// <summary> /// Removes all messages for a page and stores the new messages. /// </summary> /// <param name="page">The page.</param> /// <param name="messages">The new messages to store.</param> /// <returns><c>true</c> if the messages are stored, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> or <paramref name="messages"/> are <c>null</c>.</exception> public bool BulkStoreMessages(PageInfo page, Message[] messages) { if(page == null) throw new ArgumentNullException("page"); if(messages == null) throw new ArgumentNullException("messages"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(GetPage(transaction, page.FullName) == null) { RollbackTransaction(transaction); return false; } foreach(Message msg in GetMessages(transaction, page)) { UnindexMessageTree(page, msg, transaction); } string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Message"); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(transaction, query, parameters); ExecuteNonQuery(command, false); List<Message> allMessages; List<int> parents; UnTreeMessages(messages, out allMessages, out parents, -1); string finalQuery = ""; int count = 1; string countString; parameters = new List<Parameter>(MaxStatementsInBatch * 8); int rowsDone = 0; for(int i = 0; i < allMessages.Count; i++) { // Execute the batch in smaller chunks Message msg = allMessages[i]; int parent = parents[i]; countString = count.ToString(); query = queryBuilder.InsertInto("Message", new string[] { "Page", "Namespace", "Id", "Parent", "Username", "Subject", "DateTime", "Body" }, new string[] { "Page" + countString, "Namespace" + countString, "Id" + countString, "Parent" + countString, "Username" + countString, "Subject" + countString, "DateTime" + countString, "Body" + countString }); parameters.Add(new Parameter(ParameterType.String, "Page" + countString, name)); parameters.Add(new Parameter(ParameterType.String, "Namespace" + countString, nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Id" + countString, (short)msg.ID)); if(parent != -1) parameters.Add(new Parameter(ParameterType.Int16, "Parent" + countString, parent)); else parameters.Add(new Parameter(ParameterType.Int16, "Parent" + countString, DBNull.Value)); parameters.Add(new Parameter(ParameterType.String, "Username" + countString, msg.Username)); parameters.Add(new Parameter(ParameterType.String, "Subject" + countString, msg.Subject)); parameters.Add(new Parameter(ParameterType.DateTime, "DateTime" + countString, msg.DateTime)); parameters.Add(new Parameter(ParameterType.String, "Body" + countString, msg.Body)); finalQuery = queryBuilder.AppendForBatch(finalQuery, query); count++; if(count == MaxStatementsInBatch) { finalQuery = queryBuilder.BuildBatchCommand(finalQuery); command = builder.GetCommand(transaction, finalQuery, parameters); rowsDone += ExecuteNonQuery(command, false, true, count); finalQuery = ""; count = 1; parameters.Clear(); } } if(finalQuery.Length > 0) { command = builder.GetCommand(transaction, finalQuery, parameters); rowsDone += ExecuteNonQuery(command, false, true, count); } if(rowsDone == allMessages.Count) { foreach(Message msg in messages) { IndexMessageTree(page, msg, transaction); } CommitTransaction(transaction); return true; } else { RollbackTransaction(transaction); return false; } }
/// <summary> /// Removes a Category. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="category">The Category to remove.</param> /// <returns>True if the Category has been removed successfully.</returns> private bool RemoveCategory(DbTransaction transaction, CategoryInfo category) { string nspace = null; string name = null; NameTools.ExpandFullName(category.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Category"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); return rows > 0; }
/// <summary> /// Merges two Categories. /// </summary> /// <param name="source">The source Category.</param> /// <param name="destination">The destination Category.</param> /// <returns>The correct <see cref="T:CategoryInfo" /> object.</returns> /// <remarks>The destination Category remains, while the source Category is deleted, and all its Pages re-bound /// in the destination Category.</remarks> /// <exception cref="ArgumentNullException">If <paramref name="source"/> or <paramref name="destination"/> are <c>null</c>.</exception> public CategoryInfo MergeCategories(CategoryInfo source, CategoryInfo destination) { if(source == null) throw new ArgumentNullException("source"); if(destination == null) throw new ArgumentNullException("destination"); // 1. Check for same namespace // 2. Load all pages in source // 3. Load all pages in destination // 4. Merge lists in memory // 5. Delete all destination bindings // 6. Delete source cat // 7. Insert new bindings stored in memory string sourceNs = NameTools.GetNamespace(source.FullName); string destinationNs = NameTools.GetNamespace(destination.FullName); // If one is null and the other not null, fail if(sourceNs == null && destinationNs != null || sourceNs != null && destinationNs == null) return null; else { // Both non-null or both null if(sourceNs != null) { // Both non-null, check names NamespaceInfo tempSource = new NamespaceInfo(sourceNs, this, null); NamespaceInfo tempDest = new NamespaceInfo(destinationNs, this, null); // Different names, fail if(new NamespaceComparer().Compare(tempSource, tempDest) != 0) return null; } // else both null, OK } string nspace = sourceNs != null ? sourceNs : " "; ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); CategoryInfo actualSource = GetCategory(transaction, source.FullName); CategoryInfo actualDestination = GetCategory(transaction, destination.FullName); if(actualSource == null) { RollbackTransaction(transaction); return null; } if(actualDestination == null) { RollbackTransaction(transaction); return null; } string destinationName = NameTools.GetLocalName(actualDestination.FullName); string[] mergedPages = MergeArrays(actualSource.Pages, actualDestination.Pages); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("CategoryBinding"); query = queryBuilder.Where(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Category", WhereOperator.Equals, "Category"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.String, "Category", destinationName)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == -1) { RollbackTransaction(transaction); return null; } if(!RemoveCategory(transaction, source)) { RollbackTransaction(transaction); return null; } string finalQuery = ""; parameters = new List<Parameter>(MaxStatementsInBatch * 3); rows = 0; int count = 1; string countString; foreach(string page in mergedPages) { // This batch is executed in small chunks (MaxStatementsInBatch) to avoid exceeding DB's max batch length/size countString = count.ToString(); query = queryBuilder.InsertInto("CategoryBinding", new string[] { "Namespace", "Category", "Page" }, new string[] { "Namespace" + countString, "Category" + countString, "Page" + countString }); finalQuery = queryBuilder.AppendForBatch(finalQuery, query); parameters.Add(new Parameter(ParameterType.String, "Namespace" + countString, nspace)); parameters.Add(new Parameter(ParameterType.String, "Category" + countString, destinationName)); parameters.Add(new Parameter(ParameterType.String, "Page" + countString, NameTools.GetLocalName(page))); count++; if(count == MaxStatementsInBatch) { // Batch is complete -> execute finalQuery = queryBuilder.BuildBatchCommand(finalQuery); command = builder.GetCommand(transaction, finalQuery, parameters); rows += ExecuteNonQuery(command, false, true, count); count = 1; finalQuery = ""; parameters.Clear(); } } if(finalQuery.Length > 0) { // Execute remaining queries, if any command = builder.GetCommand(transaction, finalQuery, parameters); rows += ExecuteNonQuery(command, false, true, count); } if(rows == mergedPages.Length) { CommitTransaction(transaction); CategoryInfo result = new CategoryInfo(actualDestination.FullName, this); result.Pages = mergedPages; return result; } else { RollbackTransaction(transaction); return null; } }
/// <summary> /// Gets all the categories of a page. /// </summary> /// <param name="page">The page.</param> /// <returns>The categories, sorted by name.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> is <c>null</c>.</exception> public CategoryInfo[] GetCategoriesForPage(PageInfo page) { if(page == null) throw new ArgumentNullException("page"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string nspace, pageName; NameTools.ExpandFullName(page.FullName, out nspace, out pageName); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; string query = queryBuilder.SelectFrom("Category", "CategoryBinding", new string[] { "Name", "Namespace" }, new string[] { "Category", "Namespace" }, Join.LeftJoin, new string[] { "Name", "Namespace" }, new string[] { "Page" }); query = queryBuilder.Where(query, "CategoryBinding", "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "CategoryBinding", "Page", WhereOperator.Equals, "Page"); query = queryBuilder.OrderBy(query, new[] { "Category_Name" }, new[] { Ordering.Asc }); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.String, "Page", pageName)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { List<CategoryInfo> result = new List<CategoryInfo>(20); List<string> pages = new List<string>(50); string prevName = "|||"; string name = null; while(reader.Read()) { name = reader["Category_Name"] as string; if(name != prevName) { if(prevName != "|||") { result[result.Count - 1].Pages = pages.ToArray(); pages.Clear(); } result.Add(new CategoryInfo(NameTools.GetFullName((reader["Category_Namespace"] as string).Trim(), name), this)); } prevName = name; if(!IsDBNull(reader, "CategoryBinding_Page")) { pages.Add(NameTools.GetFullName((reader["Category_Namespace"] as string).Trim(), reader["CategoryBinding_Page"] as string)); } } CloseReader(command, reader); if(result.Count > 0) result[result.Count - 1].Pages = pages.ToArray(); return result.ToArray(); } else return null; }
/// <summary> /// Renames a Category. /// </summary> /// <param name="category">The Category to rename.</param> /// <param name="newName">The new Name.</param> /// <returns>The correct CategoryInfo object.</returns> /// <exception cref="ArgumentNullException">If <paramref name="category"/> or <paramref name="newName"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="newName"/> is empty.</exception> public CategoryInfo RenameCategory(CategoryInfo category, string newName) { if(category == null) throw new ArgumentNullException("category"); if(newName == null) throw new ArgumentNullException("newName"); if(newName.Length == 0) throw new ArgumentException("New Name cannot be empty", "newName"); string nspace = null; string name = null; NameTools.ExpandFullName(category.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.Update("Category", new string[] { "Name" }, new string[] { "NewName" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "OldName"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "NewName", newName)); parameters.Add(new Parameter(ParameterType.String, "OldName", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows > 0) { CategoryInfo result = GetCategory(transaction, NameTools.GetFullName(nspace, newName)); CommitTransaction(transaction); return result; } else { RollbackTransaction(transaction); return null; } }
/// <summary> /// Gets a category. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="fullName">The full name of the category.</param> /// <returns>The <see cref="T:CategoryInfo" />, or <c>null</c> if no category is found.</returns> private CategoryInfo GetCategory(DbConnection connection, string fullName) { string nspace = null; string name = null; NameTools.ExpandFullName(fullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("Category", "CategoryBinding", new string[] { "Name", "Namespace" }, new string[] { "Category", "Namespace" }, Join.LeftJoin, new string[] { "Name", "Namespace" }, new string[] { "Page" }); query = queryBuilder.Where(query, "Category", "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Category", "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.String, "Name", name)); DbCommand command = builder.GetCommand(connection, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { CategoryInfo result = null; List<string> pages = new List<string>(50); while(reader.Read()) { if(result == null) result = new CategoryInfo(NameTools.GetFullName(((reader["Category_Namespace"] as string).Trim()).Trim(), reader["Category_Name"] as string), this); if(!IsDBNull(reader, "CategoryBinding_Page")) { pages.Add(NameTools.GetFullName((reader["Category_Namespace"] as string).Trim(), reader["CategoryBinding_Page"] as string)); } } CloseReader(reader); if(result != null) result.Pages = pages.ToArray(); return result; } else return null; }
/// <summary> /// Moves a page from its namespace into another. /// </summary> /// <param name="page">The page to move.</param> /// <param name="destination">The destination namespace (<c>null</c> for the root).</param> /// <param name="copyCategories">A value indicating whether to copy the page categories in the destination /// namespace, if not already available.</param> /// <returns>The correct instance of <see cref="T:PageInfo"/>.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> is <c>null</c>.</exception> public PageInfo MovePage(PageInfo page, NamespaceInfo destination, bool copyCategories) { if(page == null) throw new ArgumentNullException("page"); // Check: // 1. Same namespace - ROOT, SUB (explicit check) // 2. Destination existence (update query affects 0 rows because it would break a FK) // 3. Page existence in target (update query affects 0 rows because it would break a FK) // 4. Page is default page of its namespace (explicit check) string destinationName = destination != null ? destination.Name : " "; string sourceName = null; string pageName = null; NameTools.ExpandFullName(page.FullName, out sourceName, out pageName); if(sourceName == null) sourceName = " "; ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(destinationName.ToLowerInvariant() == sourceName.ToLowerInvariant()) return null; if(IsDefaultPage(transaction, page)) { RollbackTransaction(transaction); return null; } PageContent currentContent = GetContent(transaction, page, CurrentRevision); if(currentContent != null) { UnindexPage(currentContent, transaction); foreach(Message msg in GetMessages(transaction, page)) { UnindexMessageTree(page, msg, transaction); } } CategoryInfo[] currCategories = GetCategories(transaction, (sourceName == " "||sourceName=="") ? null : GetNamespace(transaction, sourceName)); // Remove bindings RebindPage(transaction, page, new string[0]); string[] newCategories = new string[0]; if(copyCategories) { // Retrieve categories for page // Copy missing ones in destination string lowerPageName = page.FullName.ToLowerInvariant(); List<string> pageCategories = new List<string>(10); foreach(CategoryInfo cat in currCategories) { if(Array.Find(cat.Pages, (s) => { return s.ToLowerInvariant() == lowerPageName; }) != null) { pageCategories.Add(NameTools.GetLocalName(cat.FullName)); } } // Create categories into destination without checking existence (AddCategory will return null) string tempName = destinationName == " " ? null : destinationName; newCategories = new string[pageCategories.Count]; for(int i = 0; i < pageCategories.Count; i++) { string catName = NameTools.GetFullName(tempName, pageCategories[i]); if(GetCategory(transaction, catName) == null) { CategoryInfo added = AddCategory(tempName, pageCategories[i]); } newCategories[i] = catName; } } QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.Update("Page", new string[] { "Namespace" }, new string[] { "Destination" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Source"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Destination", destinationName)); parameters.Add(new Parameter(ParameterType.String, "Name", pageName)); parameters.Add(new Parameter(ParameterType.String, "Source", sourceName)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows > 0) { PageInfo result = new PageInfo(NameTools.GetFullName(destinationName, pageName), this, page.CreationDateTime); // Re-bind categories if(copyCategories) { bool rebound = RebindPage(transaction, result, newCategories); if(!rebound) { RollbackTransaction(transaction); return null; } } PageContent newContent = GetContent(transaction, result, CurrentRevision); IndexPage(newContent, transaction); foreach(Message msg in GetMessages(transaction, result)) { IndexMessageTree(result, msg, transaction); } CommitTransaction(transaction); return result; } else { RollbackTransaction(transaction); return null; } }
/// <summary> /// Determines whether a page attachment exists. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="page">The page.</param> /// <param name="name">The attachment.</param> /// <returns><c>true</c> if the attachment exists, <c>false</c> otherwise.</returns> private bool AttachmentExists(DbTransaction transaction, PageInfo page, string name) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectCountFrom("Attachment"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Page", WhereOperator.Equals, "Page"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Page", page.FullName)); DbCommand command = builder.GetCommand(transaction, query, parameters); int count = ExecuteScalar<int>(command, -1, false); return count == 1; }
/// <summary> /// Removes a Page. /// </summary> /// <param name="page">The Page to remove.</param> /// <returns>True if the Page is removed successfully.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> is <c>null</c>.</exception> public bool RemovePage(PageInfo page) { if(page == null) throw new ArgumentNullException("page"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(IsDefaultPage(transaction, page)) { RollbackTransaction(transaction); return false; } PageContent currentContent = GetContent(transaction, page, CurrentRevision); if(currentContent != null) { UnindexPage(currentContent, transaction); foreach(Message msg in GetMessages(transaction, page)) { UnindexMessageTree(page, msg, transaction); } } RebindPage(transaction, page, new string[0]); string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Page"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows > 0) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows > 0; }
/// <summary> /// Gets a page. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="fullName">The full name of the page.</param> /// <returns>The <see cref="T:PageInfo" />, or <c>null</c> if no page is found.</returns> private PageInfo GetPage(DbConnection connection, string fullName) { string nspace, name; NameTools.ExpandFullName(fullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("Page"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(connection, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { PageInfo result = null; if(reader.Read()) { result = new PageInfo(NameTools.GetFullName((reader["Namespace"] as string).Trim(), reader["Name"] as string), this, (DateTime)reader["CreationDateTime"]); } CloseReader(reader); return result; } else return null; }
/// <summary> /// Binds a Page with one or more Categories. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="page">The Page to bind.</param> /// <param name="categories">The Categories to bind the Page with.</param> /// <returns>True if the binding succeeded.</returns> /// <remarks>After a successful operation, the Page is bound with all and only the categories passed as argument.</remarks> private bool RebindPage(DbConnection connection, PageInfo page, string[] categories) { string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("CategoryBinding"); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(connection, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows < 0) return false; if(categories.Length > 0) { string finalQuery = ""; parameters = new List<Parameter>(categories.Length * 3); int count = 0; string countString; foreach(string cat in categories) { countString = count.ToString(); query = queryBuilder.InsertInto("CategoryBinding", new string[] { "Namespace", "Category", "Page" }, new string[] { "Namespace" + countString, "Category" + countString, "Page" + countString }); finalQuery = queryBuilder.AppendForBatch(finalQuery, query); parameters.Add(new Parameter(ParameterType.String, "Namespace" + countString, nspace)); parameters.Add(new Parameter(ParameterType.String, "Category" + countString, NameTools.GetLocalName(cat))); parameters.Add(new Parameter(ParameterType.String, "Page" + countString, name)); count++; } finalQuery = queryBuilder.BuildBatchCommand(finalQuery); command = builder.GetCommand(connection, finalQuery, parameters); rows = ExecuteNonQuery(command, false, true, count); return rows == categories.Length; } else return true; }
/// <summary> /// Gets all the pages in a namespace that are bound to zero categories. /// </summary> /// <param name="nspace">The namespace (<c>null</c> for the root).</param> /// <returns>The pages, sorted by name.</returns> public PageInfo[] GetUncategorizedPages(NamespaceInfo nspace) { string nspaceName = nspace != null&&!string.IsNullOrEmpty(nspace.Name) ? nspace.Name : " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("Page", "CategoryBinding", "Name", "Page", Join.LeftJoin); query = queryBuilder.Where(query, "CategoryBinding", "Category", WhereOperator.IsNull, null); query = queryBuilder.AndWhere(query, "Page", "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.OrderBy(query, new[] { "Name" }, new[] { Ordering.Asc }); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspaceName)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { List<PageInfo> result = new List<PageInfo>(100); while(reader.Read()) { result.Add(new PageInfo(NameTools.GetFullName((reader["Namespace"] as string).Trim(), reader["Name"] as string), this, (DateTime)reader["CreationDateTime"])); } CloseReader(command, reader); return result.ToArray(); } else return null; }
/// <summary> /// Gets the total number of Messages in a Page Discussion. /// </summary> /// <param name="page">The Page.</param> /// <returns>The number of messages.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> is <c>null</c>.</exception> public int GetMessageCount(PageInfo page) { if(page == null) throw new ArgumentNullException("page"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); if(GetPage(connection, page.FullName) == null) { CloseConnection(connection); return -1; } string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectCountFrom("Message"); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(connection, query, parameters); int count = ExecuteScalar<int>(command, 0); return count; }
/// <summary> /// Gets the content of a specific revision of a page. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="page">The page.</param> /// <param name="revision">The revision.</param> /// <returns>The content.</returns> private PageContent GetContent(DbTransaction transaction, PageInfo page, int revision) { // Internal version to work with GetContent, GetBackupContent, GetDraft ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string name, nspace; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; string query = queryBuilder.SelectFrom("PageContent", "PageKeyword", new string[] { "Page", "Namespace", "Revision" }, new string[] { "Page", "Namespace", "Revision" }, Join.LeftJoin, new string[] { "Title", "User", "LastModified", "Comment", "Content", "Description" }, new string[] { "Keyword" }); query = queryBuilder.Where(query, "PageContent", "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "PageContent", "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "PageContent", "Revision", WhereOperator.Equals, "Revision"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Revision", (short)revision)); DbCommand command = builder.GetCommand(transaction, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { PageContent result = null; string title = null, user = null, comment = null, content = null, description = null; DateTime dateTime = DateTime.MinValue; List<string> keywords = new List<string>(10); while(reader.Read()) { if(title == null) { title = reader["PageContent_Title"] as string; user = reader["PageContent_User"] as string; dateTime = (DateTime)reader["PageContent_LastModified"]; comment = GetNullableColumn<string>(reader, "PageContent_Comment", " "); content = reader["PageContent_Content"] as string; description = GetNullableColumn<string>(reader, "PageContent_Description", null); } if(!IsDBNull(reader, "PageKeyword_Keyword")) { keywords.Add(reader["PageKeyword_Keyword"] as string); } } if(title != null) { result = new PageContent(page, title, user, dateTime, comment, content, keywords.ToArray(), description); } CloseReader(reader); return result; } else return null; }
/// <summary> /// Adds a new Message to a Page. /// </summary> /// <param name="page">The Page.</param> /// <param name="username">The Username.</param> /// <param name="subject">The Subject.</param> /// <param name="dateTime">The Date/Time.</param> /// <param name="body">The Body.</param> /// <param name="parent">The Parent Message ID, or -1.</param> /// <returns>True if the Message is added successfully.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/>, <paramref name="username"/>, <paramref name="subject"/> or <paramref name="body"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="username"/> or <paramref name="subject"/> are empty.</exception> /// <exception cref="ArgumentOutOfRangeException">If <paramref name="parent"/> is less than -1.</exception> public bool AddMessage(PageInfo page, string username, string subject, DateTime dateTime, string body, int parent) { if(page == null) throw new ArgumentNullException("page"); if(username == null) throw new ArgumentNullException("username"); if(username.Length == 0) throw new ArgumentException("Username cannot be empty", "username"); if(subject == null) throw new ArgumentNullException("subject"); if(subject.Length == 0) throw new ArgumentException("Subject cannot be empty", "subject"); if(body == null) throw new ArgumentNullException("body"); // body can be empty if(parent < -1) throw new ArgumentOutOfRangeException("parent", "Invalid Parent Message ID"); string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(parent != -1 && FindMessage(GetMessages(transaction, page), parent) == null) { RollbackTransaction(transaction); return false; } QueryBuilder queryBuilder = new QueryBuilder(builder); short freeId = -1; string query = queryBuilder.SelectFrom("Message", new string[] { "Id" }); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.OrderBy(query, new string[] { "Id" }, new Ordering[] { Ordering.Desc }); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(transaction, query, parameters); freeId = ExecuteScalar<short>(command, -1, false); if(freeId == -1) freeId = 0; else freeId++; query = queryBuilder.InsertInto("Message", new string[] { "Page", "Namespace", "Id", "Parent", "Username", "Subject", "DateTime", "Body" }, new string[] { "Page", "Namespace", "Id", "Parent", "Username", "Subject", "DateTime", "Body" }); parameters = new List<Parameter>(8); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Id", freeId)); if(parent != -1) parameters.Add(new Parameter(ParameterType.Int16, "Parent", parent)); else parameters.Add(new Parameter(ParameterType.Int16, "Parent", DBNull.Value)); parameters.Add(new Parameter(ParameterType.String, "Username", username)); parameters.Add(new Parameter(ParameterType.String, "Subject", subject)); parameters.Add(new Parameter(ParameterType.DateTime, "DateTime", dateTime)); parameters.Add(new Parameter(ParameterType.String, "Body", body)); command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) { IndexMessage(page, freeId, subject, dateTime, body, transaction); CommitTransaction(transaction); return true; } else { RollbackTransaction(transaction); return false; } }
/// <summary> /// Gets the Backup/Revision numbers of a Page. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="page">The Page to get the Backups of.</param> /// <returns>The Backup/Revision numbers.</returns> private int[] GetBackups(DbConnection connection, PageInfo page) { if(GetPage(connection, page.FullName) == null) { return null; } string name, nspace; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("PageContent", new string[] { "Revision" }); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Revision", WhereOperator.GreaterThanOrEqualTo, "Revision"); query = queryBuilder.OrderBy(query, new[] { "Revision" }, new[] { Ordering.Asc }); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Revision", FirstRevision)); DbCommand command = builder.GetCommand(connection, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { List<int> result = new List<int>(100); while(reader.Read()) { result.Add((short)Convert.ChangeType(reader["Revision"],typeof(short))); } CloseReader(reader); return result.ToArray(); } else return null; }
/// <summary> /// Modifies a Message. /// </summary> /// <param name="page">The Page.</param> /// <param name="id">The ID of the Message to modify.</param> /// <param name="username">The Username.</param> /// <param name="subject">The Subject.</param> /// <param name="dateTime">The Date/Time.</param> /// <param name="body">The Body.</param> /// <returns>True if the Message is modified successfully.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/>, <paramref name="username"/>, <paramref name="subject"/> or <paramref name="body"/> are <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException">If <paramref name="id"/> is less than zero.</exception> /// <exception cref="ArgumentException">If <paramref name="username"/> or <paramref name="subject"/> are empty.</exception> public bool ModifyMessage(PageInfo page, int id, string username, string subject, DateTime dateTime, string body) { if(page == null) throw new ArgumentNullException("page"); if(id < 0) throw new ArgumentOutOfRangeException("id", "Invalid Message ID"); if(username == null) throw new ArgumentNullException("username"); if(username.Length == 0) throw new ArgumentException("Username cannot be empty", "username"); if(subject == null) throw new ArgumentNullException("subject"); if(subject.Length == 0) throw new ArgumentException("Subject cannot be empty", "subject"); if(body == null) throw new ArgumentNullException("body"); // body can be empty string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); Message[] messages = GetMessages(transaction, page); if(messages == null) { RollbackTransaction(transaction); return false; } Message oldMessage = FindMessage(messages, id); if(oldMessage == null) { RollbackTransaction(transaction); return false; } UnindexMessage(page, oldMessage.ID, oldMessage.Subject, oldMessage.DateTime, oldMessage.Body, transaction); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.Update("Message", new string[] { "Username", "Subject", "DateTime", "Body" }, new string[] { "Username", "Subject", "DateTime", "Body" }); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Id", WhereOperator.Equals, "Id"); List<Parameter> parameters = new List<Parameter>(7); parameters.Add(new Parameter(ParameterType.String, "Username", username)); parameters.Add(new Parameter(ParameterType.String, "Subject", subject)); parameters.Add(new Parameter(ParameterType.DateTime, "DateTime", dateTime)); parameters.Add(new Parameter(ParameterType.String, "Body", body)); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Id", id)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) { IndexMessage(page, id, subject, dateTime, body, transaction); CommitTransaction(transaction); return true; } else { RollbackTransaction(transaction); return false; } }
/// <summary> /// Deletes a revision of a page content. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="page">The page.</param> /// <param name="revision">The revision.</param> /// <returns><c>true</c> if the content ir deleted, <c>false</c> otherwise.</returns> private bool DeleteContent(DbConnection connection, PageInfo page, int revision) { string name, nspace; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("PageContent"); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Revision", WhereOperator.Equals, "Revision"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.String, "Revision", revision)); DbCommand command = builder.GetCommand(connection, query, parameters); int rows = ExecuteNonQuery(command, false); return rows > 0; }
/// <summary> /// Gets a namespace. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="name">The name of the namespace (cannot be <c>null</c> or empty).</param> /// <returns>The <see cref="T:NamespaceInfo" />, or <c>null</c> if no namespace is found.</returns> private NamespaceInfo GetNamespace(DbConnection connection, string name) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); // select ... from Namespace left join Page on Namespace.DefaultPage = Page.Name where Namespace.Name = <name> and (Namespace.DefaultPage is null or Page.Namespace = <name>) string query = queryBuilder.SelectFrom("Namespace", "Page", "DefaultPage", "Name", Join.LeftJoin, new string[] { "Name", "DefaultPage" }, new string[] { "CreationDateTime" }); query = queryBuilder.Where(query, "Namespace", "Name", WhereOperator.Equals, "Name1"); query = queryBuilder.AndWhere(query, "Namespace", "DefaultPage", WhereOperator.IsNull, null, true, false); query = queryBuilder.OrWhere(query, "Page", "Namespace", WhereOperator.Equals, "Name2", false, true); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name1", name)); parameters.Add(new Parameter(ParameterType.String, "Name2", name)); DbCommand command = builder.GetCommand(connection, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { NamespaceInfo result = null; if(reader.Read()) { string realName = reader["Namespace_Name"] as string; string page = GetNullableColumn<string>(reader, "Namespace_DefaultPage", null); PageInfo defaultPage = string.IsNullOrEmpty(page) ? null : new PageInfo(NameTools.GetFullName(realName, page), this, (DateTime)reader["Page_CreationDateTime"]); result = new NamespaceInfo(realName, this, defaultPage); } CloseReader(reader); return result; } else return null; }
/// <summary> /// Renames a Page. /// </summary> /// <param name="page">The Page to rename.</param> /// <param name="newName">The new Name.</param> /// <returns>The correct <see cref="T:PageInfo"/> object.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> or <paramref name="newName"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="newName"/> is empty.</exception> public PageInfo RenamePage(PageInfo page, string newName) { if(page == null) throw new ArgumentNullException("page"); if(newName == null) throw new ArgumentNullException("newName"); if(newName.Length == 0) throw new ArgumentException("New Name cannot be empty", "newName"); // Check // 1. Page is default page of its namespace // 2. New name already exists ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(GetPage(transaction, page.FullName) == null) { RollbackTransaction(transaction); return null; } if(IsDefaultPage(transaction, page)) { RollbackTransaction(transaction); return null; } if(GetPage(transaction, NameTools.GetFullName(NameTools.GetNamespace(page.FullName), NameTools.GetLocalName(newName))) != null) { RollbackTransaction(transaction); return null; } PageContent currentContent = GetContent(transaction, page, CurrentRevision); UnindexPage(currentContent, transaction); foreach(Message msg in GetMessages(transaction, page)) { UnindexMessageTree(page, msg, transaction); } string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; CategoryInfo[] currCategories = GetCategories(transaction, nspace == " " ? null : GetNamespace(transaction, nspace)); string lowerPageName = page.FullName.ToLowerInvariant(); List<string> pageCategories = new List<string>(10); foreach(CategoryInfo cat in currCategories) { if(Array.Find(cat.Pages, (s) => { return s.ToLowerInvariant() == lowerPageName; }) != null) { pageCategories.Add(NameTools.GetLocalName(cat.FullName)); } } RebindPage(transaction, page, new string[0]); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.Update("Page", new string[] { "Name" }, new string[] { "NewName" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "OldName"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "NewName", newName)); parameters.Add(new Parameter(ParameterType.String, "OldName", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows > 0) { PageInfo result = new PageInfo(NameTools.GetFullName(nspace, newName), this, page.CreationDateTime); RebindPage(transaction, result, pageCategories.ToArray()); PageContent newContent = GetContent(transaction, result, CurrentRevision); IndexPage(newContent, transaction); foreach(Message msg in GetMessages(transaction, result)) { IndexMessageTree(result, msg, transaction); } CommitTransaction(transaction); return result; } else { RollbackTransaction(transaction); return null; } }
/// <summary> /// Deletes some ACL entries. /// </summary> /// <param name="entries">The entries to delete.</param> /// <returns><c>true</c> if one or more entries were deleted, <c>false</c> otherwise.</returns> private bool DeleteEntries(AclEntry[] entries) { ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); foreach(AclEntry entry in entries) { string query = queryBuilder.DeleteFrom("AclEntry"); query = queryBuilder.Where(query, "Resource", WhereOperator.Equals, "Resource"); query = queryBuilder.AndWhere(query, "Action", WhereOperator.Equals, "Action"); query = queryBuilder.AndWhere(query, "Subject", WhereOperator.Equals, "Subject"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Resource", entry.Resource)); parameters.Add(new Parameter(ParameterType.String, "Action", entry.Action)); parameters.Add(new Parameter(ParameterType.String, "Subject", entry.Subject)); DbCommand command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) <= 0) { RollbackTransaction(transaction); return false; } } CommitTransaction(transaction); return true; }
/// <summary> /// Deletes the Backups of a Page, up to a specified revision. /// </summary> /// <param name="page">The Page to delete the backups of.</param> /// <param name="revision">The newest revision to delete (newer revision are kept) o -1 to delete all the Backups.</param> /// <returns><c>true</c> if the deletion succeeded, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> is <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException">If <paramref name="revision"/> is less than -1.</exception> public bool DeleteBackups(PageInfo page, int revision) { if(page == null) throw new ArgumentNullException("page"); if(revision < -1) throw new ArgumentOutOfRangeException("revision", "Invalid Revision"); // 1. Retrieve target content (revision-1 = first kept revision) // 2. Replace the current content (delete, store) // 3. Delete all older revisions up to the specified on (included) "N-m...N" // 4. Re-number remaining revisions starting from FirstRevision (zero) to revision-1 (don't re-number revs -1, -100) ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(GetPage(transaction, page.FullName) == null) { RollbackTransaction(transaction); return false; } int[] baks = GetBackups(transaction, page); if(baks.Length > 0 && revision > baks[baks.Length - 1]) { RollbackTransaction(transaction); return true; } string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("PageContent"); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); if(revision != -1) query = queryBuilder.AndWhere(query, "Revision", WhereOperator.LessThanOrEqualTo, "Revision"); query = queryBuilder.AndWhere(query, "Revision", WhereOperator.GreaterThanOrEqualTo, "FirstRevision"); List<Parameter> parameters = new List<Parameter>(4); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); if(revision != -1) parameters.Add(new Parameter(ParameterType.Int16, "Revision", revision)); parameters.Add(new Parameter(ParameterType.Int16, "FirstRevision", FirstRevision)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == -1) { RollbackTransaction(transaction); return false; } if(revision != -1) { int revisionDelta = revision + 1; query = queryBuilder.UpdateIncrement("PageContent", "Revision", -revisionDelta); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Revision", WhereOperator.GreaterThanOrEqualTo, "FirstRevision"); parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "FirstRevision", FirstRevision)); command = builder.GetCommand(transaction, query, parameters); rows = ExecuteNonQuery(command, false); if(rows > 0) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows >= 0; } else { CommitTransaction(transaction); return true; } }
/// <summary> /// Sets a meta-data items' content. /// </summary> /// <param name="item">The item.</param> /// <param name="tag">The tag that specifies the context (usually the namespace).</param> /// <param name="content">The content.</param> /// <returns><c>true</c> if the content is set, <c>false</c> otherwise.</returns> public bool SetMetaDataItem(MetaDataItem item, string tag, string content) { if(string.IsNullOrEmpty(tag)) tag = " "; if(string.IsNullOrEmpty(content)) content = " "; // 1. Delete old value, if any // 2. Store new value ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("MetaDataItem"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Tag", WhereOperator.Equals, "Tag"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", item.ToString())); parameters.Add(new Parameter(ParameterType.String, "Tag", tag)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == -1) { RollbackTransaction(transaction); return false; } query = queryBuilder.InsertInto("MetaDataItem", new string[] { "Name", "Tag", "Data" }, new string[] { "Name", "Tag", "Content" }); parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Name", item.ToString())); parameters.Add(new Parameter(ParameterType.String, "Tag", tag)); parameters.Add(new Parameter(ParameterType.String, "Content", content)); command = builder.GetCommand(transaction, query, parameters); rows = ExecuteNonQuery(command, false); if(rows == 1) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows == 1; }
/// <summary> /// Deletes a File. /// </summary> /// <param name="fullName">The full name of the File.</param> /// <returns><c>true</c> if the File is deleted, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="fullName"/> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="fullName"/> is empty or it does not exist.</exception> public bool DeleteFile(string fullName) { if(fullName == null) throw new ArgumentNullException("fullName"); if(fullName.Length == 0) throw new ArgumentException("Full Name cannot be empty", "fullName"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(!FileExists(transaction, fullName)) { RollbackTransaction(transaction); throw new ArgumentException("File does not exist", "fullName"); } QueryBuilder queryBuilder = new QueryBuilder(builder); string directory, filename; SplitFileFullName(fullName, out directory, out filename); string query = queryBuilder.DeleteFrom("File"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Directory", WhereOperator.Equals, "Directory"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", filename)); parameters.Add(new Parameter(ParameterType.String, "Directory", directory)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows == 1; }