/// <summary> /// Determines whether a directory exists. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="directory">The directory, for example "/my/directory".</param> /// <returns><c>true</c> if the directory exists, <c>false</c> otherwise.</returns> /// <remarks>The root directory always exists.</remarks> private bool DirectoryExists(DbTransaction transaction, string directory) { directory = PrepareDirectory(directory); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectCountFrom("Directory"); query = queryBuilder.Where(query, "FullPath", WhereOperator.Equals, "FullPath"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "FullPath", directory)); DbCommand command = builder.GetCommand(transaction, query, parameters); int count = ExecuteScalar<int>(command, -1, false); return count == 1; }
/// <summary> /// Retrieves the value of a Setting. /// </summary> /// <param name="name">The name of the Setting.</param> /// <returns>The value of the Setting, or null.</returns> /// <exception cref="ArgumentNullException">If <b>name</b> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>name</b> is empty.</exception> public string GetSetting(string name) { if(name == null) throw new ArgumentNullException("name"); if(name.Length == 0) throw new ArgumentException("Name cannot be empty", "name"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("Setting"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", name)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { string result = null; if(reader.Read()) { result = reader["Value"] as string; } CloseReader(command, reader); // HACK: this allows to correctly initialize a fully Oracle-based wiki instance without any user intervention if(string.IsNullOrEmpty(result)) { if(name == "DefaultUsersProvider") result = DefaultUsersStorageProvider; if(name == "DefaultPagesProvider") result = DefaultPagesStorageProvider; if(name == "DefaultFilesProvider") result = DefaultFilesStorageProvider; } return result; } else return null; }
/// <summary> /// Renames a ACL resource. /// </summary> /// <param name="resource">The resource to rename.</param> /// <param name="newName">The new name of the resource.</param> /// <returns><c>true</c> if one or more entries weere updated, <c>false</c> otherwise.</returns> private bool RenameAclResource(string resource, string newName) { ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.Update("AclEntry", new[] { "Resource" }, new[] { "ResourceNew" }); query = queryBuilder.Where(query, "Resource", WhereOperator.Equals, "ResourceOld"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "ResourceNew", newName)); parameters.Add(new Parameter(ParameterType.String, "ResourceOld", resource)); DbCommand command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) <= 0) { RollbackTransaction(transaction); return false; } CommitTransaction(transaction); return true; }
/// <summary> /// Clears the index. /// </summary> /// <param name="state">A state object passed from the index.</param> private void ClearIndex(object state) { // state can be null, depending on when the method is called ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("IndexWordMapping"); query = queryBuilder.AppendForBatch(query, queryBuilder.DeleteFrom("IndexWord")); query = queryBuilder.AppendForBatch(query, queryBuilder.DeleteFrom("IndexDocument")); query= queryBuilder.BuildBatchCommand(query); DbCommand command = null; if (state == null) command = builder.GetCommand(connString, query, new List<Parameter>()); else command = builder.GetCommand((DbTransaction)state, query, new List<Parameter>()); ExecuteNonQuery(command, state == null); }
/// <summary> /// Stores a ACL entry. /// </summary> /// <param name="entry">The entry to store.</param> /// <returns><c>true</c> if the entry was stored, <c>false</c> otherwise.</returns> private bool StoreEntry(AclEntry entry) { ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); AclEntry[] allAclEntries = RetrieveAllAclEntries(); for(int i=0;i<allAclEntries.Length;i++) { if(entry.Equals(allAclEntries[i])) return true; } string query = queryBuilder.InsertInto("AclEntry", new string[] { "Resource", "Action", "Subject", "Value" }, new string[] { "Resource", "Action", "Subject", "Value" }); 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)); parameters.Add(new Parameter(ParameterType.Char, "Value", AclEntryValueToChar(entry.Value))); DbCommand command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) != 1) { RollbackTransaction(transaction); return false; } CommitTransaction(transaction); return true; }
/// <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> /// Sets the status of a plugin. /// </summary> /// <param name="typeName">The Type name of the plugin.</param> /// <param name="enabled">The plugin status.</param> /// <returns><c>true</c> if the status is stored, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <b>typeName</b> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>typeName</b> is empty.</exception> public bool SetPluginStatus(string typeName, bool enabled) { if(typeName == null) throw new ArgumentNullException("typeName"); if(typeName.Length == 0) throw new ArgumentException("Type Name cannot be empty", "typeName"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); PreparePluginStatusRow(transaction, typeName); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.Update("PluginStatus", new string[] { "Enabled" }, new string[] { "Enabled" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.Int32, "Enabled", enabled?1:0)); parameters.Add(new Parameter(ParameterType.String, "Name", typeName)); 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 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> /// Gets the recent changes of the Wiki. /// </summary> /// <returns>The recent Changes, oldest to newest.</returns> public RecentChange[] GetRecentChanges() { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("RecentChange", new string[] { "Page", "Title", "MessageSubject", "DateTime", "User", "Change", "Description" }); query = queryBuilder.OrderBy(query, new string[] { "DateTime" }, new Ordering[] { Ordering.Asc }); DbCommand command = builder.GetCommand(connString, query, new List<Parameter>()); DbDataReader reader = ExecuteReader(command); if(reader != null) { List<RecentChange> result = new List<RecentChange>(100); while(reader.Read()) { result.Add(new RecentChange(reader["Page"] as string, reader["Title"] as string, GetNullableColumn<string>(reader, "MessageSubject", " "), (DateTime)reader["DateTime"], reader["User"] as string, RecentChangeFromChar(((string)reader["Change"])[0]), GetNullableColumn<string>(reader, "Description", ""))); } CloseReader(command, reader); return result.ToArray(); } else return null; }
/// <summary> /// Stores the outgoing links of a page, overwriting existing data. /// </summary> /// <param name="page">The full name of the page.</param> /// <param name="outgoingLinks">The full names of the pages that <b>page</b> links to.</param> /// <returns><c>true</c> if the outgoing links are stored, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <b>page</b> or <b>outgoingLinks</b> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>page</b> or <b>outgoingLinks</b> are empty.</exception> public bool StoreOutgoingLinks(string page, string[] outgoingLinks) { if(page == null) throw new ArgumentNullException("page"); if(page.Length == 0) throw new ArgumentException("Page cannot be empty", "page"); if(outgoingLinks == null) throw new ArgumentNullException("outgoingLinks"); foreach(string link in outgoingLinks) { if(link == null) throw new ArgumentNullException("outgoingLinks"); if(link.Length == 0) throw new ArgumentException("Link cannot be empty", "outgoingLinks"); } // 1. Delete old values, if any // 2. Store new values ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("OutgoingLink"); query = queryBuilder.Where(query, "Source", WhereOperator.Equals, "Source"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Source", page)); DbCommand command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) < 0) { RollbackTransaction(transaction); return false; } foreach(string link in outgoingLinks) { query = queryBuilder.InsertInto("OutgoingLink", new string[] { "Source", "Destination" }, new string[] { "Source", "Destination" }); parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Source", page)); parameters.Add(new Parameter(ParameterType.String, "Destination", link)); command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows != 1) { RollbackTransaction(transaction); return false; } } CommitTransaction(transaction); return true; }
/// <summary> /// Gets the outgoing links of a page. /// </summary> /// <param name="page">The full name of the page.</param> /// <returns>The outgoing links.</returns> /// <exception cref="ArgumentNullException">If <b>page</b> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>page</b> is empty.</exception> public string[] GetOutgoingLinks(string page) { if(page == null) throw new ArgumentNullException("page"); if(page.Length == 0) throw new ArgumentException("Page cannot be empty", "page"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("OutgoingLink", new string[] { "Destination" }); query = queryBuilder.Where(query, "Source", WhereOperator.Equals, "Source"); query = queryBuilder.OrderBy(query, new[] { "Destination" }, new[] { Ordering.Asc }); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Source", page)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { List<string> result = new List<string>(20); while(reader.Read()) { result.Add(reader["Destination"] as string); } CloseReader(command, reader); return result.ToArray(); } else return null; }
/// <summary> /// Gets the configuration of a plugin. /// </summary> /// <param name="typeName">The Type name of the plugin.</param> /// <returns>The plugin configuration, or <b>String.Empty</b>.</returns> /// <exception cref="ArgumentNullException">If <b>typeName</b> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>typeName</b> is empty.</exception> public string GetPluginConfiguration(string typeName) { if(typeName == null) throw new ArgumentNullException("typeName"); if(typeName.Length == 0) throw new ArgumentException("Type Name cannot be empty", "typeName"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("PluginStatus", new string[] { "Configuration" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", typeName)); DbCommand command = builder.GetCommand(connString, query, parameters); string result = ExecuteScalar<string>(command, ""); return result.Trim() ; }
/// <summary> /// Stores the value of a Setting. /// </summary> /// <param name="name">The name of the Setting.</param> /// <param name="value">The value of the Setting. Value cannot contain CR and LF characters, which will be removed.</param> /// <returns>True if the Setting is stored, false otherwise.</returns> /// <remarks>This method stores the Value immediately.</remarks> public bool SetSetting(string name, string value) { if(name == null) throw new ArgumentNullException("name"); if(name.Length == 0) throw new ArgumentException("Name cannot be empty", "name"); // 1. Delete old value, if any // 2. Store new value // Nulls and empty strings are converted to " " if(string.IsNullOrEmpty(value)) value = " "; ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Setting"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", name)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == -1) { RollbackTransaction(transaction); return false; // Deletion command failed (0-1 are OK) } query = queryBuilder.InsertInto("Setting", new string[] { "Name", "Value" }, new string[] { "Name", "Value" }); parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Value", value)); command = builder.GetCommand(transaction, query, parameters); rows = ExecuteNonQuery(command, false); if(rows == 1) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows == 1; }
/// <summary> /// Sets the default page of a namespace. /// </summary> /// <param name="nspace">The namespace of which to set the default page.</param> /// <param name="page">The page to use as default page, or <c>null</c>.</param> /// <returns>The correct <see cref="T:NamespaceInfo"/> object.</returns> /// <exception cref="ArgumentNullException">If <paramref name="nspace"/> is <c>null</c>.</exception> public NamespaceInfo SetNamespaceDefaultPage(NamespaceInfo nspace, PageInfo page) { if( nspace==null) throw new ArgumentNullException("nspace"); // Namespace existence is verified by the affected rows (should be 1) ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(page != null && GetPage(transaction, page.FullName) == null) { RollbackTransaction(transaction); return null; } QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.Update("Namespace", new string[] { "DefaultPage" }, new string[] { "DefaultPage" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(2); if(page == null) parameters.Add(new Parameter(ParameterType.String, "DefaultPage", DBNull.Value)); else parameters.Add(new Parameter(ParameterType.String, "DefaultPage", NameTools.GetLocalName(page.FullName))); parameters.Add(new Parameter(ParameterType.String, "Name", nspace.Name)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) { CommitTransaction(transaction); return new NamespaceInfo(nspace.Name, this, page); } else { RollbackTransaction(transaction); return null; } }
/// <summary> /// Renames a namespace. /// </summary> /// <param name="nspace">The namespace to rename.</param> /// <param name="newName">The new name of the namespace.</param> /// <returns>The correct <see cref="T:NamespaceInfo"/> object.</returns> /// <exception cref="ArgumentNullException">If <paramref name="nspace"/> or <paramref name="newName"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="newName"/> is empty.</exception> public NamespaceInfo RenameNamespace(NamespaceInfo nspace, string newName) { if(nspace==null) throw new ArgumentNullException("nspace"); if(newName == null) throw new ArgumentNullException("newName"); if(newName.Length == 0) throw new ArgumentException("New Name cannot be empty", "newName"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(GetNamespace(transaction, nspace.Name) == null) { RollbackTransaction(transaction); return null; } foreach(PageInfo page in GetPages(transaction, nspace)) { PageContent content = GetContent(transaction, page, CurrentRevision); if(content != null) { UnindexPage(content, transaction); } Message[] messages = GetMessages(transaction, page); if(messages != null) { foreach(Message msg in messages) { UnindexMessageTree(page, msg, transaction); } } } QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.Update("Namespace", new string[] { "Name" }, new string[] { "NewName" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "OldName"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "NewName", newName)); parameters.Add(new Parameter(ParameterType.String, "OldName", nspace.Name)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows > 0) { NamespaceInfo result = GetNamespace(transaction, newName); foreach(PageInfo page in GetPages(transaction, result)) { PageContent content = GetContent(transaction, page, CurrentRevision); if(content != null) { IndexPage(content, transaction); } Message[] messages = GetMessages(transaction, page); if(messages != null) { foreach(Message msg in messages) { IndexMessageTree(page, msg, transaction); } } } CommitTransaction(transaction); return result; } else { RollbackTransaction(transaction); return null; } }
/// <summary> /// Adds a new namespace. /// </summary> /// <param name="name">The name of the namespace.</param> /// <returns>The correct <see cref="T:NamespaceInfo"/> object.</returns> /// <exception cref="ArgumentNullException">If <paramref name="name"/> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="name"/> is empty.</exception> public NamespaceInfo AddNamespace(string name) { if(name == null) throw new ArgumentNullException("name"); if(name.Length == 0) throw new ArgumentException("Name cannot be empty", "name"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.InsertInto("Namespace", new string[] { "Name" }, new string[] { "Name" }); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", name)); DbCommand command = builder.GetCommand(connString, query, parameters); int rows = ExecuteNonQuery(command); if(rows == 1) return new NamespaceInfo(name, this, null); else return null; }
/// <summary> /// Records a message to the System Log. /// </summary> /// <param name="message">The Log Message.</param> /// <param name="entryType">The Type of the Entry.</param> /// <param name="user">The User.</param> /// <remarks>This method <b>should not</b> write messages to the Log using the method IHost.LogEntry. /// This method should also never throw exceptions (except for parameter validation).</remarks> /// <exception cref="ArgumentNullException">If <b>message</b> or <b>user</b> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>message</b> or <b>user</b> are empty.</exception> public void LogEntry(string message, EntryType entryType, string user) { if(message == null) throw new ArgumentNullException("message"); if(message.Length == 0) throw new ArgumentException("Message cannot be empty", "message"); if(user == null) throw new ArgumentNullException("user"); if(user.Length == 0) throw new ArgumentException("User cannot be empty", "user"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.InsertInto("Log", new string[] { "DateTime", "EntryType", "User", "Message" }, new string[] { "DateTime", "EntryType", "User", "Message" }); List<Parameter> parameters = new List<Parameter>(4); parameters.Add(new Parameter(ParameterType.DateTime, "DateTime", DateTime.Now)); parameters.Add(new Parameter(ParameterType.Char, "EntryType", EntryTypeToChar(entryType))); parameters.Add(new Parameter(ParameterType.String, "User", Sanitize(user))); parameters.Add(new Parameter(ParameterType.String, "Message", Sanitize(message))); try { DbCommand command = builder.GetCommand(connString, query, parameters); ExecuteNonQuery(command, true); // No transaction - accurate log sizing is not really a concern int logSize = LogSize; if(logSize > int.Parse(host.GetSettingValue(SettingName.MaxLogSize))) { CutLog((int)(logSize * 0.75)); } } catch { } }
/// <summary> /// Gets all the outgoing links stored. /// </summary> /// <returns>The outgoing links, in a dictionary in the form page->outgoing_links.</returns> public IDictionary<string, string[]> GetAllOutgoingLinks() { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); // Explicit columns in order to allow usage of GROUP BY string query = queryBuilder.SelectFrom("OutgoingLink", new string[] { "Source", "Destination" }); query = queryBuilder.GroupBy(query, new string[] { "Source", "Destination" }); DbCommand command = builder.GetCommand(connString, query, new List<Parameter>()); DbDataReader reader = ExecuteReader(command); if(reader != null) { Dictionary<string, string[]> result = new Dictionary<string, string[]>(100); string prevSource = "|||"; string source = null; List<string> destinations = new List<string>(20); while(reader.Read()) { source = reader["Source"] as string; if(source != prevSource) { if(prevSource != "|||") { result.Add(prevSource, destinations.ToArray()); destinations.Clear(); } } prevSource = source; destinations.Add(reader["Destination"] as string); } result.Add(prevSource, destinations.ToArray()); CloseReader(command, reader); return result; } else return null; }
/// <summary> /// Gets all the Log Entries, sorted by date/time (oldest to newest). /// </summary> /// <returns>The Log Entries.</returns> public LogEntry[] GetLogEntries() { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("Log", new string[] { "DateTime", "EntryType", "User", "Message" }); query = queryBuilder.OrderBy(query, new string[] { "DateTime" }, new Ordering[] { Ordering.Asc }); DbCommand command = builder.GetCommand(connString, query, new List<Parameter>()); DbDataReader reader = ExecuteReader(command); if(reader != null) { List<LogEntry> result = new List<LogEntry>(100); while(reader.Read()) { result.Add(new LogEntry(EntryTypeFromChar((reader["EntryType"] as string)[0]), (DateTime)reader["DateTime"], reader["Message"] as string, reader["User"] as string)); } CloseReader(command, reader); return result.ToArray(); } else return null; }
/// <summary> /// Cuts the recent changes if necessary. /// </summary> private void CutRecentChangesIfNecessary() { ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectCountFrom("RecentChange"); DbCommand command = builder.GetCommand(transaction, query, new List<Parameter>()); int rows = ExecuteScalar<int>(command, -1, false); int maxChanges = int.Parse(host.GetSettingValue(SettingName.MaxRecentChanges)); if(rows > maxChanges) { // Remove 10% of old changes to avoid 1-by-1 deletion every time a change is made int entriesToDelete = maxChanges / 10; if(entriesToDelete > rows) entriesToDelete = rows; //entriesToDelete += entriesToDelete / 10; // This code is not optimized, but it surely works in most DBMS query = queryBuilder.SelectFrom("RecentChange", new string[] { "Id" }); query = queryBuilder.OrderBy(query, new string[] { "Id" }, new Ordering[] { Ordering.Asc }); command = builder.GetCommand(transaction, query, new List<Parameter>()); DbDataReader reader = ExecuteReader(command); List<int> ids = new List<int>(entriesToDelete); if(reader != null) { while(reader.Read() && ids.Count < entriesToDelete) { ids.Add((int)Convert.ChangeType(reader["Id"],typeof(int))); } CloseReader(reader); } if(ids.Count > 0) { // Given that the IDs to delete can be many, the query is split in many chunks, each one deleting 50 items // This works-around the problem of too many parameters in a RPC call of Oracle // See also CutLog for(int chunk = 0; chunk <= ids.Count / MaxParametersInQuery; chunk++) { query = queryBuilder.DeleteFrom("RecentChange"); List<string> parms = new List<string>(MaxParametersInQuery); List<Parameter> parameters = new List<Parameter>(MaxParametersInQuery); for(int i = chunk * MaxParametersInQuery; i < Math.Min(ids.Count, (chunk + 1) * MaxParametersInQuery); i++) { parms.Add("P" + i.ToString()); parameters.Add(new Parameter(ParameterType.Int32, parms[parms.Count - 1], ids[i])); } query = queryBuilder.WhereIn(query, "Id", parms.ToArray()); command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) < 0) { RollbackTransaction(transaction); return; } } } } CommitTransaction(transaction); }
/// <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> /// Removes a plugin's assembly. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="filename">The file name of the assembly to remove, such as "Assembly.dll".</param> /// <returns><c>true</c> if the assembly is removed, <c>false</c> otherwise.</returns> private bool DeletePluginAssembly(DbConnection connection, string filename) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("PluginAssembly"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", filename)); DbCommand command = builder.GetCommand(connection, query, parameters); int rows = ExecuteNonQuery(command, false); return rows == 1; }
/// <summary> /// Deletes the outgoing links of a page and all the target links that include the page. /// </summary> /// <param name="page">The full name of the page.</param> /// <returns><c>true</c> if the links are deleted, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <b>page</b> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>page</b> is empty.</exception> public bool DeleteOutgoingLinks(string page) { if(page == null) throw new ArgumentNullException("page"); if(page.Length == 0) throw new ArgumentException("Page cannot be empty", "page"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("OutgoingLink"); query = queryBuilder.Where(query, "Source", WhereOperator.Equals, "Source"); query = queryBuilder.OrWhere(query, "Destination", WhereOperator.Equals, "Destination"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Source", page)); parameters.Add(new Parameter(ParameterType.String, "Destination", page)); DbCommand command = builder.GetCommand(connString, query, parameters); int rows = ExecuteNonQuery(command); 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> /// Retrieves a plugin's assembly. /// </summary> /// <param name="filename">The file name of the assembly.</param> /// <returns>The assembly content, or <c>null</c>.</returns> /// <exception cref="ArgumentNullException">If <b>filename</b> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>filename</b> is empty.</exception> public byte[] RetrievePluginAssembly(string filename) { if(filename == null) throw new ArgumentNullException("filename"); if(filename.Length == 0) throw new ArgumentException("Filename cannot be empty", "filename"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("PluginAssembly", new string[] { "Assembly" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", filename)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { byte[] result = null; if(reader.Read()) { result = GetBinaryColumn(reader, "Assembly", MaxAssemblySize); } CloseReader(command, reader); return result; } else return null; }
/// <summary> /// Updates all outgoing links data for a page rename. /// </summary> /// <param name="oldName">The old page name.</param> /// <param name="newName">The new page name.</param> /// <returns><c>true</c> if the data is updated, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <b>oldName</b> or <b>newName</b> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>oldName</b> or <b>newName</b> are empty.</exception> public bool UpdateOutgoingLinksForRename(string oldName, string newName) { if(oldName == null) throw new ArgumentNullException("oldName"); if(oldName.Length == 0) throw new ArgumentException("Old Name cannot be empty", "oldName"); if(newName == null) throw new ArgumentNullException("newName"); if(newName.Length == 0) throw new ArgumentException("New Name cannot be empty", "newName"); // 1. Rename sources // 2. Rename destinations ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.Update("OutgoingLink", new string[] { "Source" }, new string[] { "NewSource" }); query = queryBuilder.Where(query, "Source", WhereOperator.Equals, "OldSource"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "NewSource", newName)); parameters.Add(new Parameter(ParameterType.String, "OldSource", oldName)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == -1) { RollbackTransaction(transaction); return false; } bool somethingUpdated = rows > 0; query = queryBuilder.Update("OutgoingLink", new string[] { "Destination" }, new string[] { "NewDestination" }); query = queryBuilder.Where(query, "Destination", WhereOperator.Equals, "OldDestination"); parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "NewDestination", newName)); parameters.Add(new Parameter(ParameterType.String, "OldDestination", oldName)); command = builder.GetCommand(transaction, query, parameters); rows = ExecuteNonQuery(command, false); if(rows >= 0) CommitTransaction(transaction); else RollbackTransaction(transaction); return somethingUpdated || rows > 0; }
/// <summary> /// Prepares the plugin status row, if necessary. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="typeName">The Type name of the plugin.</param> private void PreparePluginStatusRow(DbTransaction transaction, string typeName) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectCountFrom("PluginStatus"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", typeName)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteScalar<int>(command, -1, false); if(rows == -1) return; if(rows == 0) { // Insert a neutral row (enabled, empty config) query = queryBuilder.InsertInto("PluginStatus", new string[] { "Name", "Enabled", "Configuration" }, new string[] { "Name", "Enabled", "Configuration" }); parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Name", typeName)); parameters.Add(new Parameter(ParameterType.Int32, "Enabled", 1)); parameters.Add(new Parameter(ParameterType.String, "Configuration", " ")); command = builder.GetCommand(transaction, query, parameters); ExecuteNonQuery(command, false); } }
/// <summary> /// Retrieves all ACL entries for a subject. /// </summary> /// <param name="subject">The subject.</param> /// <returns>The ACL entries for the subject.</returns> private AclEntry[] RetrieveAclEntriesForSubject(string subject) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); // Sort order is not relevant string query = queryBuilder.SelectFrom("AclEntry"); query = queryBuilder.Where(query, "Subject", WhereOperator.Equals, "Subject"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Subject", subject)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { List<AclEntry> result = new List<AclEntry>(50); while(reader.Read()) { result.Add(new AclEntry(reader["Resource"] as string, reader["Action"] as string, reader["Subject"] as string, AclEntryValueFromChar(((string)reader["Value"])[0]))); } CloseReader(command, reader); return result.ToArray(); } else return null; }
/// <summary> /// Gets the status of a plugin. /// </summary> /// <param name="typeName">The Type name of the plugin.</param> /// <returns>The status (<c>false</c> for disabled, <c>true</c> for enabled), or <c>true</c> if no status is found.</returns> /// <exception cref="ArgumentNullException">If <b>typeName</b> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>typeName</b> is empty.</exception> public bool GetPluginStatus(string typeName) { if(typeName == null) throw new ArgumentNullException("typeName"); if(typeName.Length == 0) throw new ArgumentException("Type Name cannot be empty", "typeName"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("PluginStatus", new string[] { "Enabled" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", typeName)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); bool? enabled = null; if(reader != null && reader.Read()) { if(!IsDBNull(reader, "Enabled")) enabled = Convert.ToBoolean(reader["Enabled"]); } CloseReader(command, reader); if(enabled.HasValue) return enabled.Value; else { if(typeName == "ScrewTurn.Wiki.UsersStorageProvider" || typeName == "ScrewTurn.Wiki.PagesStorageProvider" || typeName == "ScrewTurn.Wiki.FilesStorageProvider") return false; else return true; } }
/// <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; }