1400 lines
60 KiB
C#
1400 lines
60 KiB
C#
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Common;
|
|
using System.Text;
|
|
using ScrewTurn.Wiki.PluginFramework;
|
|
|
|
namespace ScrewTurn.Wiki.Plugins.SqlCommon {
|
|
|
|
/// <summary>
|
|
/// Implements a base class for a SQL files storage provider.
|
|
/// </summary>
|
|
public abstract class SqlFilesStorageProviderBase : SqlStorageProviderBase, IFilesStorageProviderV30 {
|
|
|
|
private const int MaxFileSize = 52428800; // 50 MB
|
|
|
|
#region IFilesStorageProvider Members
|
|
|
|
/// <summary>
|
|
/// Prepares the directory name.
|
|
/// </summary>
|
|
/// <param name="directory">The directory to prepare.</param>
|
|
/// <returns>The prepared directory, for example "/" or "/my/directory/".</returns>
|
|
private static string PrepareDirectory(string directory) {
|
|
if(string.IsNullOrEmpty(directory)) return "/";
|
|
else {
|
|
return (!directory.StartsWith("/") ? "/" : "") +
|
|
directory +
|
|
(!directory.EndsWith("/") ? "/" : "");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether a directory exists.
|
|
/// </summary>
|
|
/// <param name="connection">A database connection.</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(DbConnection connection, 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(connection, query, parameters);
|
|
|
|
int count = ExecuteScalar<int>(command, -1, false);
|
|
|
|
return count == 1;
|
|
}
|
|
|
|
/// <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>
|
|
/// Splits a file full name into the directory and file parts.
|
|
/// </summary>
|
|
/// <param name="fullName">The file full name, for example "/file.txt" or "/directory/file.txt".</param>
|
|
/// <param name="directory">The resulting directory path, for example "/" or "/directory/".</param>
|
|
/// <param name="file">The file name, for example "file.txt".</param>
|
|
private static void SplitFileFullName(string fullName, out string directory, out string file) {
|
|
directory = fullName.Substring(0, fullName.LastIndexOf("/") + 1);
|
|
directory = PrepareDirectory(directory);
|
|
file = fullName.Substring(fullName.LastIndexOf("/") + 1);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether a file exists.
|
|
/// </summary>
|
|
/// <param name="connection">A database connection.</param>
|
|
/// <param name="fullName">The file full name, for example "/file.txt" or "/directory/file.txt".</param>
|
|
/// <returns><c>true</c> if the file exists, <c>false</c> otherwise.</returns>
|
|
private bool FileExists(DbConnection connection, string fullName) {
|
|
string directory, file;
|
|
SplitFileFullName(fullName, out directory, out file);
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectCountFrom("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", file));
|
|
parameters.Add(new Parameter(ParameterType.String, "Directory", directory));
|
|
|
|
DbCommand command = builder.GetCommand(connection, query, parameters);
|
|
|
|
int count = ExecuteScalar<int>(command, -1, false);
|
|
|
|
return count == 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether a file exists.
|
|
/// </summary>
|
|
/// <param name="transaction">A database transaction.</param>
|
|
/// <param name="fullName">The file full name, for example "/file.txt" or "/directory/file.txt".</param>
|
|
/// <returns><c>true</c> if the file exists, <c>false</c> otherwise.</returns>
|
|
private bool FileExists(DbTransaction transaction, string fullName) {
|
|
string directory, file;
|
|
SplitFileFullName(fullName, out directory, out file);
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectCountFrom("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", file));
|
|
parameters.Add(new Parameter(ParameterType.String, "Directory", directory));
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int count = ExecuteScalar<int>(command, -1, false);
|
|
|
|
return count == 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lists the Files in the specified Directory.
|
|
/// </summary>
|
|
/// <param name="directory">The full directory name, for example "/my/directory". Null, empty or "/" for the root directory.</param>
|
|
/// <returns>The list of Files in the directory.</returns>
|
|
/// <exception cref="ArgumentException">If <paramref name="directory"/> does not exist.</exception>
|
|
public string[] ListFiles(string directory) {
|
|
directory = PrepareDirectory(directory);
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
|
|
if(!DirectoryExists(connection, directory)) {
|
|
CloseConnection(connection);
|
|
throw new ArgumentException("Directory does not exist", "directory");
|
|
}
|
|
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectFrom("File", new string[] { "Name" });
|
|
query = queryBuilder.Where(query, "Directory", WhereOperator.Equals, "Directory");
|
|
query = queryBuilder.OrderBy(query, new [] { "Name" }, new[] { Ordering.Asc });
|
|
|
|
List<Parameter> parameters = new List<Parameter>(1);
|
|
parameters.Add(new Parameter(ParameterType.String, "Directory", directory));
|
|
|
|
DbCommand command = builder.GetCommand(connection, query, parameters);
|
|
|
|
DbDataReader reader = ExecuteReader(command);
|
|
|
|
if(reader != null) {
|
|
List<string> result = new List<string>(20);
|
|
|
|
while(reader.Read()) {
|
|
result.Add(directory + reader["Name"] as string);
|
|
}
|
|
|
|
CloseReader(command, reader);
|
|
|
|
return result.ToArray();
|
|
}
|
|
else return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lists the Directories in the specified directory.
|
|
/// </summary>
|
|
/// <param name="connection">An open connection.</param>
|
|
/// <param name="directory">The full directory name, for example "/my/directory". Null, empty or "/" for the root directory.</param>
|
|
/// <returns>The list of Directories in the Directory.</returns>
|
|
private string[] ListDirectories(DbConnection connection, string directory) {
|
|
directory = PrepareDirectory(directory);
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
|
|
if(!DirectoryExists(connection, directory)) {
|
|
CloseConnection(connection);
|
|
throw new ArgumentException("Directory does not exist", "directory");
|
|
}
|
|
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectFrom("Directory", new string[] { "FullPath" });
|
|
query = queryBuilder.Where(query, "Parent", WhereOperator.Equals, "Parent");
|
|
query = queryBuilder.OrderBy(query, new[] { "FullPath" }, new[] { Ordering.Asc });
|
|
|
|
List<Parameter> parameters = new List<Parameter>(1);
|
|
parameters.Add(new Parameter(ParameterType.String, "Parent", directory));
|
|
|
|
DbCommand command = builder.GetCommand(connection, query, parameters);
|
|
|
|
DbDataReader reader = ExecuteReader(command);
|
|
|
|
if(reader != null) {
|
|
List<string> result = new List<string>(20);
|
|
|
|
while(reader.Read()) {
|
|
result.Add(reader["FullPath"] as string);
|
|
}
|
|
|
|
CloseReader(reader);
|
|
|
|
return result.ToArray();
|
|
}
|
|
else return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lists the Directories in the specified directory.
|
|
/// </summary>
|
|
/// <param name="transaction">A database transaction.</param>
|
|
/// <param name="directory">The full directory name, for example "/my/directory". Null, empty or "/" for the root directory.</param>
|
|
/// <returns>The list of Directories in the Directory.</returns>
|
|
private string[] ListDirectories(DbTransaction transaction, string directory) {
|
|
directory = PrepareDirectory(directory);
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
|
|
if(!DirectoryExists(transaction, directory)) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Directory does not exist", "directory");
|
|
}
|
|
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectFrom("Directory", new string[] { "FullPath" });
|
|
query = queryBuilder.Where(query, "Parent", WhereOperator.Equals, "Parent");
|
|
|
|
List<Parameter> parameters = new List<Parameter>(1);
|
|
parameters.Add(new Parameter(ParameterType.String, "Parent", directory));
|
|
query = queryBuilder.OrderBy(query, new[] { "FullPath" }, new[] { Ordering.Asc });
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
DbDataReader reader = ExecuteReader(command);
|
|
|
|
if(reader != null) {
|
|
List<string> result = new List<string>(20);
|
|
|
|
while(reader.Read()) {
|
|
result.Add(reader["FullPath"] as string);
|
|
}
|
|
|
|
CloseReader(reader);
|
|
|
|
return result.ToArray();
|
|
}
|
|
else return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lists the Directories in the specified directory.
|
|
/// </summary>
|
|
/// <param name="directory">The full directory name, for example "/my/directory". Null, empty or "/" for the root directory.</param>
|
|
/// <returns>The list of Directories in the Directory.</returns>
|
|
/// <exception cref="ArgumentException">If <paramref name="directory"/> does not exist.</exception>
|
|
public string[] ListDirectories(string directory) {
|
|
directory = PrepareDirectory(directory);
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
|
|
if(!DirectoryExists(connection, directory)) {
|
|
CloseConnection(connection);
|
|
throw new ArgumentException("Directory does not exist", "directory");
|
|
}
|
|
|
|
string[] result = ListDirectories(connection, directory);
|
|
CloseConnection(connection);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stores a file.
|
|
/// </summary>
|
|
/// <param name="fullName">The full name of the file.</param>
|
|
/// <param name="sourceStream">A Stream object used as <b>source</b> of a byte stream,
|
|
/// i.e. the method reads from the Stream and stores the content properly.</param>
|
|
/// <param name="overwrite"><c>true</c> to overwrite an existing file.</param>
|
|
/// <returns><c>true</c> if the File is stored, <c>false</c> otherwise.</returns>
|
|
/// <remarks>If <b>overwrite</b> is <c>false</c> and File already exists, the method returns <c>false</c>.</remarks>
|
|
/// <exception cref="ArgumentNullException">If <typeparamref name="fullName"/> os <paramref name="sourceStream"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="fullName"/> is empty or <paramref name="sourceStream"/> does not support reading.</exception>
|
|
public bool StoreFile(string fullName, System.IO.Stream sourceStream, bool overwrite) {
|
|
if(fullName == null) throw new ArgumentNullException("fullName");
|
|
if(fullName.Length == 0) throw new ArgumentException("Full Name cannot be empty", "fullName");
|
|
if(sourceStream == null) throw new ArgumentNullException("sourceStream");
|
|
if(!sourceStream.CanRead) throw new ArgumentException("Cannot read from Source Stream", "sourceStream");
|
|
|
|
string directory, filename;
|
|
SplitFileFullName(fullName, out directory, out filename);
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
DbTransaction transaction = BeginTransaction(connection);
|
|
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
bool fileExists = FileExists(transaction, fullName);
|
|
|
|
if(fileExists && !overwrite) {
|
|
RollbackTransaction(transaction);
|
|
return false;
|
|
}
|
|
|
|
// To achieve decent performance, an UPDATE query is issued if the file exists,
|
|
// otherwise an INSERT query is issued
|
|
|
|
string query;
|
|
List<Parameter> parameters;
|
|
|
|
byte[] fileData = null;
|
|
int size = Tools.ReadStream(sourceStream, ref fileData, MaxFileSize);
|
|
if(size < 0) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Source Stream contains too much data", "sourceStream");
|
|
}
|
|
|
|
if(fileExists) {
|
|
query = queryBuilder.Update("File", new string[] { "Size", "LastModified", "Data" }, new string[] { "Size", "LastModified", "Data" });
|
|
query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name");
|
|
query = queryBuilder.AndWhere(query, "Directory", WhereOperator.Equals, "Directory");
|
|
|
|
parameters = new List<Parameter>(5);
|
|
parameters.Add(new Parameter(ParameterType.Int64, "Size", (long)size));
|
|
parameters.Add(new Parameter(ParameterType.DateTime, "LastModified", DateTime.Now));
|
|
parameters.Add(new Parameter(ParameterType.ByteArray, "Data", fileData));
|
|
parameters.Add(new Parameter(ParameterType.String, "Name", filename));
|
|
parameters.Add(new Parameter(ParameterType.String, "Directory", directory));
|
|
}
|
|
else {
|
|
query = queryBuilder.InsertInto("File", new string[] { "Name", "Directory", "Size", "Downloads", "LastModified", "Data" },
|
|
new string[] { "Name", "Directory", "Size", "Downloads", "LastModified", "Data" });
|
|
|
|
parameters = new List<Parameter>(6);
|
|
parameters.Add(new Parameter(ParameterType.String, "Name", filename));
|
|
parameters.Add(new Parameter(ParameterType.String, "Directory", directory));
|
|
parameters.Add(new Parameter(ParameterType.Int64, "Size", (long)size));
|
|
parameters.Add(new Parameter(ParameterType.Int32, "Downloads", 0));
|
|
parameters.Add(new Parameter(ParameterType.DateTime, "LastModified", DateTime.Now));
|
|
parameters.Add(new Parameter(ParameterType.ByteArray, "Data", fileData));
|
|
}
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int rows = ExecuteNonQuery(command, false);
|
|
if(rows == 1) CommitTransaction(transaction);
|
|
else RollbackTransaction(transaction);
|
|
|
|
return rows == 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves a File.
|
|
/// </summary>
|
|
/// <param name="fullName">The full name of the File.</param>
|
|
/// <param name="destinationStream">A Stream object used as <b>destination</b> of a byte stream,
|
|
/// i.e. the method writes to the Stream the file content.</param>
|
|
/// <param name="countHit">A value indicating whether or not to count this retrieval in the statistics.</param>
|
|
/// <returns><c>true</c> if the file is retrieved, <c>false</c> otherwise.</returns>
|
|
/// <exception cref="ArgumentNullException">If <typeparamref name="fullName"/> os <paramref name="destinationStream"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="fullName"/> is empty or <paramref name="destinationStream"/> does not support writing.</exception>
|
|
public bool RetrieveFile(string fullName, System.IO.Stream destinationStream, bool countHit) {
|
|
if(fullName == null) throw new ArgumentNullException("fullName");
|
|
if(fullName.Length == 0) throw new ArgumentException("Full Name cannot be empty", "fullName");
|
|
if(destinationStream == null) throw new ArgumentNullException("destinationStream");
|
|
if(!destinationStream.CanWrite) throw new ArgumentException("Cannot write into Destination Stream", "destinationStream");
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
DbTransaction transaction = BeginTransaction(connection);
|
|
|
|
if(!FileExists(transaction, fullName)) {
|
|
RollbackTransaction(transaction);
|
|
CloseConnection(connection);
|
|
throw new ArgumentException("File does not exist", "fullName");
|
|
}
|
|
|
|
string directory, filename;
|
|
SplitFileFullName(fullName, out directory, out filename);
|
|
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectFrom("File", new string[] { "Size", "Data" });
|
|
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);
|
|
|
|
DbDataReader reader = ExecuteReader(command);
|
|
|
|
if(reader != null) {
|
|
bool done = false;
|
|
|
|
if(reader.Read()) {
|
|
int read = ReadBinaryColumn(reader, "Data", destinationStream);
|
|
done = (long)read == (long)reader["Size"];
|
|
}
|
|
|
|
CloseReader(reader);
|
|
|
|
if(!done) {
|
|
RollbackTransaction(transaction);
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
RollbackTransaction(transaction);
|
|
return false;
|
|
}
|
|
|
|
if(countHit) {
|
|
// Update download count
|
|
query = queryBuilder.UpdateIncrement("File", "Downloads", 1);
|
|
query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name");
|
|
query = queryBuilder.AndWhere(query, "Directory", WhereOperator.Equals, "Directory");
|
|
|
|
parameters = new List<Parameter>(2);
|
|
parameters.Add(new Parameter(ParameterType.String, "Name", filename));
|
|
parameters.Add(new Parameter(ParameterType.String, "Directory", directory));
|
|
|
|
command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int rows = ExecuteNonQuery(command, false);
|
|
if(rows != 1) {
|
|
RollbackTransaction(transaction);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
CommitTransaction(transaction);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the number of times a file was retrieved.
|
|
/// </summary>
|
|
/// <param name="fullName">The full name of the file.</param>
|
|
/// <param name="count">The count to set.</param>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="fullName"/> is <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="fullName"/> is empty.</exception>
|
|
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="count"/> is less than zero.</exception>
|
|
public void SetFileRetrievalCount(string fullName, int count) {
|
|
if(fullName == null) throw new ArgumentNullException("fullName");
|
|
if(fullName.Length == 0) throw new ArgumentException("Full Name cannot be empty", "fullName");
|
|
if(count < 0) throw new ArgumentOutOfRangeException("count", "Count must be greater than or equal to zero");
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string directory, filename;
|
|
SplitFileFullName(fullName, out directory, out filename);
|
|
|
|
string query = queryBuilder.Update("File", new string[] { "Downloads" }, new string[] { "Downloads" });
|
|
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));
|
|
parameters.Add(new Parameter(ParameterType.Int32, "Downloads", count));
|
|
|
|
DbCommand command = builder.GetCommand(connString, query, parameters);
|
|
|
|
ExecuteNonQuery(command);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the details of a file.
|
|
/// </summary>
|
|
/// <param name="fullName">The full name of the file.</param>
|
|
/// <returns>The details, or <c>null</c> if the file does not exist.</returns>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="fullName"/> is <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="fullName"/> is empty.</exception>
|
|
public FileDetails GetFileDetails(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();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string directory, filename;
|
|
SplitFileFullName(fullName, out directory, out filename);
|
|
|
|
string query = queryBuilder.SelectFrom("File", new string[] { "Size", "Downloads", "LastModified" });
|
|
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(connString, query, parameters);
|
|
|
|
DbDataReader reader = ExecuteReader(command);
|
|
|
|
if(reader != null) {
|
|
FileDetails details = null;
|
|
|
|
if(reader.Read()) {
|
|
details = new FileDetails((long)reader["Size"],
|
|
(DateTime)reader["LastModified"], (int)reader["Downloads"]);
|
|
}
|
|
|
|
CloseReader(command, reader);
|
|
|
|
return details;
|
|
}
|
|
else return null;
|
|
}
|
|
|
|
/// <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;
|
|
}
|
|
|
|
/// <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>
|
|
/// Creates a new Directory.
|
|
/// </summary>
|
|
/// <param name="path">The path to create the new Directory in.</param>
|
|
/// <param name="name">The name of the new Directory.</param>
|
|
/// <returns><c>true</c> if the Directory is created, <c>false</c> otherwise.</returns>
|
|
/// <remarks>If <b>path</b> is "/my/directory" and <b>name</b> is "newdir", a new directory named "/my/directory/newdir" is created.</remarks>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="path"/> or <paramref name="name"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="name"/> is empty or if the directory does not exist, or if the new directory already exists.</exception>
|
|
public bool CreateDirectory(string path, string name) {
|
|
if(path == null) throw new ArgumentNullException("path");
|
|
if(name == null) throw new ArgumentNullException("name");
|
|
if(name.Length == 0) throw new ArgumentException("Name cannot be empty", "name");
|
|
|
|
path = PrepareDirectory(path);
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
DbTransaction transaction = BeginTransaction(connection);
|
|
|
|
if(!DirectoryExists(transaction, path)) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Directory does not exist", "path");
|
|
}
|
|
|
|
string newDirectoryFullPath = PrepareDirectory(path + name);
|
|
|
|
if(DirectoryExists(transaction, newDirectoryFullPath)) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Directory already exists", "name");
|
|
}
|
|
|
|
string query = QueryBuilder.NewQuery(builder).InsertInto("Directory", new string[] { "FullPath", "Parent" }, new string[] { "FullPath", "Parent" });
|
|
|
|
List<Parameter> parameters = new List<Parameter>(2);
|
|
parameters.Add(new Parameter(ParameterType.String, "FullPath", newDirectoryFullPath));
|
|
parameters.Add(new Parameter(ParameterType.String, "Parent", path));
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int rows = ExecuteNonQuery(command, false);
|
|
if(rows == 1) CommitTransaction(transaction);
|
|
else RollbackTransaction(transaction);
|
|
|
|
return rows == 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes a directory and all its contents.
|
|
/// </summary>
|
|
/// <param name="transaction">The current transaction to use.</param>
|
|
/// <param name="fullPath">The full path of the directory.</param>
|
|
/// <returns><c>true</c> if the directory is deleted, <c>false</c> otherwise.</returns>
|
|
private bool DeleteDirectory(DbTransaction transaction, string fullPath) {
|
|
string[] dirs = ListDirectories(transaction, fullPath);
|
|
foreach(string dir in dirs) {
|
|
if(!DeleteDirectory(transaction, dir)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.DeleteFrom("Directory");
|
|
query = queryBuilder.Where(query, "FullPath", WhereOperator.Equals, "FullPath");
|
|
|
|
List<Parameter> parameters = new List<Parameter>(2);
|
|
parameters.Add(new Parameter(ParameterType.String, "FullPath", fullPath));
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int rows = ExecuteNonQuery(command, false);
|
|
|
|
return rows > 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes a Directory and <b>all of its content</b>.
|
|
/// </summary>
|
|
/// <param name="fullPath">The full path of the Directory.</param>
|
|
/// <returns><c>true</c> if the Directory is deleted, <c>false</c> otherwise.</returns>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="fullPath"/> is <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="fullPath"/> is empty or if it equals '/' or it does not exist.</exception>
|
|
public bool DeleteDirectory(string fullPath) {
|
|
if(fullPath == null) throw new ArgumentNullException("fullPath");
|
|
if(fullPath.Length == 0) throw new ArgumentException("Full Path cannot be empty", "fullPath");
|
|
if(fullPath == "/") throw new ArgumentException("Cannot delete the root directory", "fullPath");
|
|
|
|
fullPath = PrepareDirectory(fullPath);
|
|
|
|
// /dir/
|
|
// /dir/sub/
|
|
// /dir/sub/blah/
|
|
// /dir/file.txt
|
|
// /dir/sub/file.txt
|
|
// etc.
|
|
|
|
// 1. Delete sub-directories (recursively, depth first)
|
|
// 2. Delete directory
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
DbTransaction transaction = BeginTransaction(connection);
|
|
|
|
if(!DirectoryExists(transaction, fullPath)) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Directory does not exist");
|
|
}
|
|
|
|
bool done = DeleteDirectory(transaction, fullPath);
|
|
|
|
if(done) CommitTransaction(transaction);
|
|
else RollbackTransaction(transaction);
|
|
|
|
return done;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Renames or moves a Directory.
|
|
/// </summary>
|
|
/// <param name="transaction">The current transaction to use.</param>
|
|
/// <param name="oldFullPath">The old full path of the Directory.</param>
|
|
/// <param name="newFullPath">The new full path of the Directory.</param>
|
|
/// <returns><c>true</c> if the Directory is renamed, <c>false</c> otherwise.</returns>
|
|
private bool RenameDirectory(DbTransaction transaction, string oldFullPath, string newFullPath) {
|
|
string[] directories = ListDirectories(transaction, oldFullPath);
|
|
foreach(string dir in directories) {
|
|
string trimmed = dir.Trim('/');
|
|
string name = trimmed.Substring(trimmed.LastIndexOf("/") + 1);
|
|
|
|
string newFullPathSub = PrepareDirectory(newFullPath + name);
|
|
|
|
RenameDirectory(dir, newFullPathSub);
|
|
}
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.Update("Directory", new string[] { "FullPath" }, new string[] { "NewDirectory1" });
|
|
query = queryBuilder.Where(query, "FullPath", WhereOperator.Equals, "OldDirectory1");
|
|
|
|
List<Parameter> parameters = new List<Parameter>(2);
|
|
parameters.Add(new Parameter(ParameterType.String, "NewDirectory1", newFullPath));
|
|
parameters.Add(new Parameter(ParameterType.String, "OldDirectory1", oldFullPath));
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int rows = ExecuteNonQuery(command, false);
|
|
|
|
return rows > 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Renames or moves a Directory.
|
|
/// </summary>
|
|
/// <param name="oldFullPath">The old full path of the Directory.</param>
|
|
/// <param name="newFullPath">The new full path of the Directory.</param>
|
|
/// <returns><c>true</c> if the Directory is renamed, <c>false</c> otherwise.</returns>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="oldFullPath"/> or <paramref name="newFullPath"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="oldFullPath"/> or <paramref name="newFullPath"/> are empty or equal to '/',
|
|
/// or if the old directory does not exist or the new directory already exists.</exception>
|
|
public bool RenameDirectory(string oldFullPath, string newFullPath) {
|
|
if(oldFullPath == null) throw new ArgumentNullException("oldFullPath");
|
|
if(oldFullPath.Length == 0) throw new ArgumentException("Old Full Path cannot be empty", "oldFullPath");
|
|
if(oldFullPath == "/") throw new ArgumentException("Cannot rename the root directory", "oldFullPath");
|
|
if(newFullPath == null) throw new ArgumentNullException("newFullPath");
|
|
if(newFullPath.Length == 0) throw new ArgumentException("New Full Path cannot be empty", "newFullPath");
|
|
if(newFullPath == "/") throw new ArgumentException("Cannot rename directory to the root directory", "newFullPath");
|
|
|
|
oldFullPath = PrepareDirectory(oldFullPath);
|
|
newFullPath = PrepareDirectory(newFullPath);
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
DbTransaction transaction = BeginTransaction(connection);
|
|
|
|
if(!DirectoryExists(transaction, oldFullPath)) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Directory does not exist", "oldFullPath");
|
|
}
|
|
if(DirectoryExists(transaction, newFullPath)) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Directory already exists", "newFullPath");
|
|
}
|
|
|
|
// /dir/
|
|
// /dir/sub/
|
|
// /dir/sub/blah/
|
|
// /dir/file.txt
|
|
// /dir/sub/file.txt
|
|
// etc.
|
|
|
|
// 1. Rename sub-directories (recursively, depth first)
|
|
// 2. Rename directory
|
|
|
|
bool done = RenameDirectory(transaction, oldFullPath, newFullPath);
|
|
|
|
if(done) CommitTransaction(transaction);
|
|
else RollbackTransaction(transaction);
|
|
|
|
return done;
|
|
}
|
|
|
|
/// <summary>
|
|
/// The the names of the pages with attachments.
|
|
/// </summary>
|
|
/// <returns>The names of the pages with attachments.</returns>
|
|
public string[] GetPagesWithAttachments() {
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectFrom("Attachment", new string[] { "Page" });
|
|
query = queryBuilder.GroupBy(query, new[] { "Page" });
|
|
query = queryBuilder.OrderBy(query, new[] { "Page" }, new[] { Ordering.Asc });
|
|
|
|
DbCommand command = builder.GetCommand(connString, query, new List<Parameter>());
|
|
|
|
DbDataReader reader = ExecuteReader(command);
|
|
|
|
if(reader != null) {
|
|
List<string> result = new List<string>(100);
|
|
|
|
while(reader.Read()) {
|
|
result.Add(reader["Page"] as string);
|
|
}
|
|
|
|
CloseReader(command, reader);
|
|
|
|
return result.ToArray();
|
|
}
|
|
else return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the names of the Attachments of a Page.
|
|
/// </summary>
|
|
/// <param name="transaction">A database transaction.</param>
|
|
/// <param name="pageInfo">The Page Info object that owns the Attachments.</param>
|
|
/// <returns>The names, or an empty list.</returns>
|
|
private string[] ListPageAttachments(DbTransaction transaction, PageInfo pageInfo) {
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectFrom("Attachment", new string[] { "Name" });
|
|
query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page");
|
|
query = queryBuilder.OrderBy(query, new[] { "Name" }, new[] { Ordering.Asc });
|
|
|
|
List<Parameter> parameters = new List<Parameter>(1);
|
|
parameters.Add(new Parameter(ParameterType.String, "Page", pageInfo.FullName));
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
DbDataReader reader = ExecuteReader(command);
|
|
|
|
if(reader != null) {
|
|
List<string> result = new List<string>(10);
|
|
|
|
while(reader.Read()) {
|
|
result.Add(reader["Name"] as string);
|
|
}
|
|
|
|
CloseReader(reader);
|
|
|
|
return result.ToArray();
|
|
}
|
|
else return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the names of the Attachments of a Page.
|
|
/// </summary>
|
|
/// <param name="connection">A database connection.</param>
|
|
/// <param name="pageInfo">The Page Info object that owns the Attachments.</param>
|
|
/// <returns>The names, or an empty list.</returns>
|
|
private string[] ListPageAttachments(DbConnection connection, PageInfo pageInfo) {
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectFrom("Attachment", new string[] { "Name" });
|
|
query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page");
|
|
|
|
List<Parameter> parameters = new List<Parameter>(1);
|
|
parameters.Add(new Parameter(ParameterType.String, "Page", pageInfo.FullName));
|
|
query = queryBuilder.OrderBy(query, new[] { "Name" }, new[] { Ordering.Asc });
|
|
|
|
DbCommand command = builder.GetCommand(connection, query, parameters);
|
|
|
|
DbDataReader reader = ExecuteReader(command);
|
|
|
|
if(reader != null) {
|
|
List<string> result = new List<string>(10);
|
|
|
|
while(reader.Read()) {
|
|
result.Add(reader["Name"] as string);
|
|
}
|
|
|
|
CloseReader(reader);
|
|
|
|
return result.ToArray();
|
|
}
|
|
else return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the names of the Attachments of a Page.
|
|
/// </summary>
|
|
/// <param name="pageInfo">The Page Info object that owns the Attachments.</param>
|
|
/// <returns>The names, or an empty list.</returns>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="pageInfo"/> is <c>null</c>.</exception>
|
|
public string[] ListPageAttachments(PageInfo pageInfo) {
|
|
if(pageInfo == null) throw new ArgumentNullException("pageInfo");
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
|
|
string[] result = ListPageAttachments(connection, pageInfo);
|
|
CloseConnection(connection);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines whether a page attachment exists.
|
|
/// </summary>
|
|
/// <param name="connection">A database connection.</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(DbConnection connection, 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(connection, query, parameters);
|
|
|
|
int count = ExecuteScalar<int>(command, -1, false);
|
|
|
|
return count == 1;
|
|
}
|
|
|
|
/// <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>
|
|
/// Stores a Page Attachment.
|
|
/// </summary>
|
|
/// <param name="pageInfo">The Page Info that owns the Attachment.</param>
|
|
/// <param name="name">The name of the Attachment, for example "myfile.jpg".</param>
|
|
/// <param name="sourceStream">A Stream object used as <b>source</b> of a byte stream,
|
|
/// i.e. the method reads from the Stream and stores the content properly.</param>
|
|
/// <param name="overwrite"><c>true</c> to overwrite an existing Attachment.</param>
|
|
/// <returns><c>true</c> if the Attachment is stored, <c>false</c> otherwise.</returns>
|
|
/// <remarks>If <b>overwrite</b> is <c>false</c> and Attachment already exists, the method returns <c>false</c>.</remarks>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="pageInfo"/>, <paramref name="name"/> or <paramref name="sourceStream"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="name"/> is empty or if <paramref name="sourceStream"/> does not support reading.</exception>
|
|
public bool StorePageAttachment(PageInfo pageInfo, string name, System.IO.Stream sourceStream, bool overwrite) {
|
|
if(pageInfo == null) throw new ArgumentNullException("pageInfo");
|
|
if(name == null) throw new ArgumentNullException("name");
|
|
if(name.Length == 0) throw new ArgumentException("Name cannot be empty", "name");
|
|
if(sourceStream == null) throw new ArgumentNullException("sourceStream");
|
|
if(!sourceStream.CanRead) throw new ArgumentException("Cannot read from Source Stream", "sourceStream");
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
DbTransaction transaction = BeginTransaction(connection);
|
|
|
|
bool attachmentExists = AttachmentExists(transaction, pageInfo, name);
|
|
|
|
if(attachmentExists && !overwrite) {
|
|
RollbackTransaction(transaction);
|
|
return false;
|
|
}
|
|
|
|
// To achieve decent performance, an UPDATE query is issued if the attachment exists,
|
|
// otherwise an INSERT query is issued
|
|
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query;
|
|
List<Parameter> parameters;
|
|
|
|
byte[] attachmentData = null;
|
|
int size = Tools.ReadStream(sourceStream, ref attachmentData, MaxFileSize);
|
|
if(size < 0) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Source Stream contains too much data", "sourceStream");
|
|
}
|
|
|
|
if(attachmentExists) {
|
|
query = queryBuilder.Update("Attachment", new string[] { "Size", "LastModified", "Data" }, new string[] { "Size", "LastModified", "Data" });
|
|
query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name");
|
|
query = queryBuilder.AndWhere(query, "Page", WhereOperator.Equals, "Page");
|
|
|
|
parameters = new List<Parameter>(5);
|
|
parameters.Add(new Parameter(ParameterType.Int64, "Size", (long)size));
|
|
parameters.Add(new Parameter(ParameterType.DateTime, "LastModified", DateTime.Now));
|
|
parameters.Add(new Parameter(ParameterType.ByteArray, "Data", attachmentData));
|
|
parameters.Add(new Parameter(ParameterType.String, "Name", name));
|
|
parameters.Add(new Parameter(ParameterType.String, "Page", pageInfo.FullName));
|
|
}
|
|
else {
|
|
query = queryBuilder.InsertInto("Attachment", new string[] { "Name", "Page", "Size", "Downloads", "LastModified", "Data" },
|
|
new string[] { "Name", "Page", "Size", "Downloads", "LastModified", "Data" });
|
|
|
|
parameters = new List<Parameter>(6);
|
|
parameters.Add(new Parameter(ParameterType.String, "Name", name));
|
|
parameters.Add(new Parameter(ParameterType.String, "Page", pageInfo.FullName));
|
|
parameters.Add(new Parameter(ParameterType.Int64, "Size", (long)size));
|
|
parameters.Add(new Parameter(ParameterType.Int32, "Downloads", 0));
|
|
parameters.Add(new Parameter(ParameterType.DateTime, "LastModified", DateTime.Now));
|
|
parameters.Add(new Parameter(ParameterType.ByteArray, "Data", attachmentData));
|
|
}
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int rows = ExecuteNonQuery(command, false);
|
|
if(rows == 1) CommitTransaction(transaction);
|
|
else RollbackTransaction(transaction);
|
|
|
|
return rows == 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves a Page Attachment.
|
|
/// </summary>
|
|
/// <param name="pageInfo">The Page Info that owns the Attachment.</param>
|
|
/// <param name="name">The name of the Attachment, for example "myfile.jpg".</param>
|
|
/// <param name="destinationStream">A Stream object used as <b>destination</b> of a byte stream,
|
|
/// i.e. the method writes to the Stream the file content.</param>
|
|
/// <param name="countHit">A value indicating whether or not to count this retrieval in the statistics.</param>
|
|
/// <returns><c>true</c> if the Attachment is retrieved, <c>false</c> otherwise.</returns>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="pageInfo"/>, <paramref name="name"/> or <paramref name="destinationStream"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="name"/> is empty or if <paramref name="destinationStream"/> does not support writing,
|
|
/// or if the page does not have attachments or if the attachment does not exist.</exception>
|
|
public bool RetrievePageAttachment(PageInfo pageInfo, string name, System.IO.Stream destinationStream, bool countHit) {
|
|
if(pageInfo == null) throw new ArgumentNullException("pageInfo");
|
|
if(name == null) throw new ArgumentNullException("name");
|
|
if(name.Length == 0) throw new ArgumentException("Name cannot be empty", "name");
|
|
if(destinationStream == null) throw new ArgumentNullException("destinationStream");
|
|
if(!destinationStream.CanWrite) throw new ArgumentException("Cannot write into Destination Stream", "destinationStream");
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
DbTransaction transaction = BeginTransaction(connection);
|
|
|
|
if(!AttachmentExists(transaction, pageInfo, name)) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Attachment does not exist", "name");
|
|
}
|
|
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectFrom("Attachment", new string[] { "Size", "Data" });
|
|
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", pageInfo.FullName));
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
DbDataReader reader = ExecuteReader(command);
|
|
|
|
if(reader != null) {
|
|
bool done = false;
|
|
|
|
if(reader.Read()) {
|
|
int read = ReadBinaryColumn(reader, "Data", destinationStream);
|
|
done = (long)read == (long)reader["Size"];
|
|
}
|
|
|
|
CloseReader(reader);
|
|
|
|
if(!done) {
|
|
RollbackTransaction(transaction);
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
RollbackTransaction(transaction);
|
|
return false;
|
|
}
|
|
|
|
if(countHit) {
|
|
// Update download count
|
|
query = queryBuilder.UpdateIncrement("Attachment", "Downloads", 1);
|
|
query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name");
|
|
query = queryBuilder.AndWhere(query, "Page", WhereOperator.Equals, "Page");
|
|
|
|
parameters = new List<Parameter>(2);
|
|
parameters.Add(new Parameter(ParameterType.String, "Name", name));
|
|
parameters.Add(new Parameter(ParameterType.String, "Page", pageInfo.FullName));
|
|
|
|
command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int rows = ExecuteNonQuery(command, false);
|
|
if(rows != 1) {
|
|
RollbackTransaction(transaction);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
CommitTransaction(transaction);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the number of times a page attachment was retrieved.
|
|
/// </summary>
|
|
/// <param name="pageInfo">The page.</param>
|
|
/// <param name="name">The name of the attachment.</param>
|
|
/// <param name="count">The count to set.</param>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="pageInfo"/> or <paramref name="name"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="name"/> is empty.</exception>
|
|
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="count"/> is less than zero.</exception>
|
|
public void SetPageAttachmentRetrievalCount(PageInfo pageInfo, string name, int count) {
|
|
if(pageInfo == null) throw new ArgumentNullException("pageInfo");
|
|
if(name == null) throw new ArgumentNullException("name");
|
|
if(name.Length == 0) throw new ArgumentException("Name cannot be empty");
|
|
if(count < 0) throw new ArgumentOutOfRangeException("Count must be greater than or equal to zero", "count");
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.Update("Attachment", new string[] { "Downloads" }, new string[] { "Downloads" });
|
|
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", pageInfo.FullName));
|
|
parameters.Add(new Parameter(ParameterType.Int32, "Downloads", count));
|
|
|
|
DbCommand command = builder.GetCommand(connString, query, parameters);
|
|
|
|
ExecuteNonQuery(command);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the details of a page attachment.
|
|
/// </summary>
|
|
/// <param name="pageInfo">The page that owns the attachment.</param>
|
|
/// <param name="name">The name of the attachment, for example "myfile.jpg".</param>
|
|
/// <returns>The details of the attachment, or <c>null</c> if the attachment does not exist.</returns>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="pageInfo"/> or <paramref name="name"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="name"/> is empty.</exception>
|
|
public FileDetails GetPageAttachmentDetails(PageInfo pageInfo, string name) {
|
|
if(pageInfo == null) throw new ArgumentNullException("pageInfo");
|
|
if(name == null) throw new ArgumentNullException("name");
|
|
if(name.Length == 0) throw new ArgumentException("Name cannot be empty");
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.SelectFrom("Attachment", new string[] { "Size", "Downloads", "LastModified" });
|
|
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", pageInfo.FullName));
|
|
|
|
DbCommand command = builder.GetCommand(connString, query, parameters);
|
|
|
|
DbDataReader reader = ExecuteReader(command);
|
|
|
|
if(reader != null) {
|
|
FileDetails details = null;
|
|
|
|
if(reader.Read()) {
|
|
details = new FileDetails((long)reader["Size"],
|
|
(DateTime)reader["LastModified"], (int)reader["Downloads"]);
|
|
}
|
|
|
|
CloseReader(command, reader);
|
|
|
|
return details;
|
|
}
|
|
else return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deletes a Page Attachment.
|
|
/// </summary>
|
|
/// <param name="pageInfo">The Page Info that owns the Attachment.</param>
|
|
/// <param name="name">The name of the Attachment, for example "myfile.jpg".</param>
|
|
/// <returns><c>true</c> if the Attachment is deleted, <c>false</c> otherwise.</returns>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="pageInfo"/> or <paramref name="name"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="name"/> is empty or if the page or attachment do not exist.</exception>
|
|
public bool DeletePageAttachment(PageInfo pageInfo, string name) {
|
|
if(pageInfo == null) throw new ArgumentNullException("pageInfo");
|
|
if(name == null) throw new ArgumentNullException("name");
|
|
if(name.Length == 0) throw new ArgumentException("Name cannot be empty");
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
DbTransaction transaction = BeginTransaction(connection);
|
|
|
|
if(!AttachmentExists(transaction, pageInfo, name)) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Attachment does not exist", "name");
|
|
}
|
|
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.DeleteFrom("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", pageInfo.FullName));
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int rows = ExecuteNonQuery(command, false);
|
|
if(rows == 1) CommitTransaction(transaction);
|
|
else RollbackTransaction(transaction);
|
|
|
|
return rows == 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Renames a Page Attachment.
|
|
/// </summary>
|
|
/// <param name="pageInfo">The Page Info that owns the Attachment.</param>
|
|
/// <param name="oldName">The old name of the Attachment.</param>
|
|
/// <param name="newName">The new name of the Attachment.</param>
|
|
/// <returns><c>true</c> if the Attachment is renamed, false otherwise.</returns>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="pageInfo"/>, <paramref name="oldName"/> or <paramref name="newName"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If <paramref name="pageInfo"/>, <paramref name="oldName"/> or <paramref name="newName"/> are empty,
|
|
/// or if the page or old attachment do not exist, or the new attachment name already exists.</exception>
|
|
public bool RenamePageAttachment(PageInfo pageInfo, string oldName, string newName) {
|
|
if(pageInfo == null) throw new ArgumentNullException("pageInfo");
|
|
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");
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
DbTransaction transaction = BeginTransaction(connection);
|
|
|
|
if(!AttachmentExists(transaction, pageInfo, oldName)) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Attachment does not exist", "name");
|
|
}
|
|
if(AttachmentExists(transaction, pageInfo, newName)) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("Attachment already exists", "name");
|
|
}
|
|
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.Update("Attachment", new string[] { "Name" }, new string[] { "NewName" });
|
|
query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "OldName");
|
|
query = queryBuilder.AndWhere(query, "Page", WhereOperator.Equals, "Page");
|
|
|
|
List<Parameter> parameters = new List<Parameter>(3);
|
|
parameters.Add(new Parameter(ParameterType.String, "NewName", newName));
|
|
parameters.Add(new Parameter(ParameterType.String, "OldName", oldName));
|
|
parameters.Add(new Parameter(ParameterType.String, "Page", pageInfo.FullName));
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int rows = ExecuteNonQuery(command, false);
|
|
if(rows == 1) CommitTransaction(transaction);
|
|
else RollbackTransaction(transaction);
|
|
|
|
return rows == 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Notifies the Provider that a Page has been renamed.
|
|
/// </summary>
|
|
/// <param name="oldPage">The old Page Info object.</param>
|
|
/// <param name="newPage">The new Page Info object.</param>
|
|
/// <exception cref="ArgumentNullException">If <paramref name="oldPage"/> or <paramref name="newPage"/> are <c>null</c>.</exception>
|
|
/// <exception cref="ArgumentException">If the new page is already in use.</exception>
|
|
public void NotifyPageRenaming(PageInfo oldPage, PageInfo newPage) {
|
|
if(oldPage == null) throw new ArgumentNullException("oldPage");
|
|
if(newPage == null) throw new ArgumentNullException("newPage");
|
|
|
|
ICommandBuilder builder = GetCommandBuilder();
|
|
DbConnection connection = builder.GetConnection(connString);
|
|
DbTransaction transaction = BeginTransaction(connection);
|
|
|
|
if(ListPageAttachments(transaction, newPage).Length > 0) {
|
|
RollbackTransaction(transaction);
|
|
throw new ArgumentException("New Page already exists", "newPage");
|
|
}
|
|
|
|
QueryBuilder queryBuilder = new QueryBuilder(builder);
|
|
|
|
string query = queryBuilder.Update("Attachment", new string[] { "Page" }, new string[] { "NewPage" });
|
|
query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "OldPage");
|
|
|
|
List<Parameter> parameters = new List<Parameter>(2);
|
|
parameters.Add(new Parameter(ParameterType.String, "NewPage", newPage.FullName));
|
|
parameters.Add(new Parameter(ParameterType.String, "OldPage", oldPage.FullName));
|
|
|
|
DbCommand command = builder.GetCommand(transaction, query, parameters);
|
|
|
|
int rows = ExecuteNonQuery(command, false);
|
|
|
|
if(rows != -1) CommitTransaction(transaction);
|
|
else RollbackTransaction(transaction);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IStorageProvider Members
|
|
|
|
/// <summary>
|
|
/// Gets a value specifying whether the provider is read-only, i.e. it can only provide data and not store it.
|
|
/// </summary>
|
|
public bool ReadOnly {
|
|
get { return false; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|