This commit is contained in:
Zel
2025-02-23 18:47:21 +08:00
parent eaaffeeccb
commit e46a7ca31c
104 changed files with 2630 additions and 2516 deletions

View File

@@ -13,11 +13,12 @@ namespace ZelWiki.Repository
{
public static class ConfigurationRepository
{
#region Upgrade Database.
#region
public static string GetVersionStateVersion()
{
var entries = ManagedDataStorage.Config.ExecuteScalar<string>(@"Scripts\Initialization\GetVersionStateVersion.sql");
var entries =
ManagedDataStorage.Config.ExecuteScalar<string>(@"Scripts\Initialization\GetVersionStateVersion.sql");
return entries ?? "0.0.0";
}
@@ -25,11 +26,12 @@ namespace ZelWiki.Repository
{
var version = string.Join('.',
(Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0.0").Split('.').Take(3));
ManagedDataStorage.Config.Execute(@"Scripts\Initialization\SetVersionStateVersion.sql", new { Version = version });
ManagedDataStorage.Config.Execute(@"Scripts\Initialization\SetVersionStateVersion.sql",
new { Version = version });
}
/// <summary>
/// See @Initialization.Versions.md
///
/// </summary>
public static void UpgradeDatabase()
{
@@ -45,43 +47,44 @@ namespace ZelWiki.Repository
if (currentPaddedVersion == storedPaddedVersion)
{
return; //The database version is already at the latest version.
return;
}
var updateScriptNames = Assembly.GetExecutingAssembly().GetManifestResourceNames()
.Where(o => o.Contains("Repository.Scripts.Initialization.Versions", StringComparison.InvariantCultureIgnoreCase)).OrderBy(o => o);
.Where(o => o.Contains("Repository.Scripts.Initialization.Versions",
StringComparison.InvariantCultureIgnoreCase)).OrderBy(o => o);
string startVersionTag = ".Initialization.Versions.";
string endVersionTag = ".^";
var startVersionTag = ".Initialization.Versions.";
var endVersionTag = ".^";
foreach (var updateScriptName in updateScriptNames)
{
int startIndex = updateScriptName.IndexOf(startVersionTag, StringComparison.InvariantCultureIgnoreCase);
int startIndex =
updateScriptName.IndexOf(startVersionTag, StringComparison.InvariantCultureIgnoreCase);
if (startIndex >= 0)
{
startIndex += startVersionTag.Length;
int endIndex = updateScriptName.IndexOf(endVersionTag, startIndex, StringComparison.InvariantCultureIgnoreCase);
var endIndex = updateScriptName.IndexOf(endVersionTag, startIndex,
StringComparison.InvariantCultureIgnoreCase);
if (endIndex > startIndex)
{
//The name of the script file without the namespaces, version numbers etc.
var fullScriptName = updateScriptName.Substring(endIndex + endVersionTag.Length).Trim().Replace("_", "");
var fullScriptName = updateScriptName.Substring(endIndex + endVersionTag.Length).Trim()
.Replace("_", "");
int filesFolderVersion = Utility.PadVersionString(updateScriptName.Substring(startIndex, endIndex - startIndex).Trim().Replace("_", ""));
int filesFolderVersion = Utility.PadVersionString(updateScriptName
.Substring(startIndex, endIndex - startIndex).Trim().Replace("_", ""));
if (filesFolderVersion > storedPaddedVersion)
{
//Get the script text.
using var stream = assembly.GetManifestResourceStream(updateScriptName);
using var reader = new StreamReader(stream.EnsureNotNull());
var scriptText = reader.ReadToEnd();
//Get the script "metadata" from the file name.
var scriptNameParts = fullScriptName.Split('^');
//string executionOrder = scriptNameParts[0];
string databaseName = scriptNameParts[1];
//string scriptName = scriptNameParts[2];
var databaseName = scriptNameParts[1];
var databaseFactory = ManagedDataStorage.Collection.Single(o => o.Name == databaseName).Factory;
var databaseFactory = ManagedDataStorage.Collection.Single(o => o.Name == databaseName)
.Factory;
databaseFactory.Execute(scriptText);
}
@@ -95,13 +98,14 @@ namespace ZelWiki.Repository
}
catch (Exception ex)
{
ExceptionRepository.InsertException(ex, "Database upgrade failed.");
ExceptionRepository.InsertException(ex, "数据库升级失败");
}
}
#endregion
public static ConfigurationEntries GetConfigurationEntryValuesByGroupName(string groupName, bool allowCache = true)
public static ConfigurationEntries GetConfigurationEntryValuesByGroupName(string groupName,
bool allowCache = true)
{
if (allowCache)
{
@@ -163,27 +167,25 @@ namespace ZelWiki.Repository
}
/// <summary>
/// Determines if this is the first time the wiki has run. Returns true if it is the first time.
///
/// </summary>
/// <returns></returns>
public static bool IsFirstRun()
{
bool isEncryptionValid = GetCryptoCheck();
var isEncryptionValid = GetCryptoCheck();
if (isEncryptionValid == false)
{
SetCryptoCheck();
return true;
}
return false;
}
/// <summary>
/// Reads an encrypted value from the database so we can determine if encryption is setup.
/// If the value is missing then we are NOT setup.
/// If the value is present but we cant decrypt it, then we are NOT setup.
/// /// If the value is present and we can decrypt it, then we are setup and good to go!
/// </summary>
/// <returns></returns>
/// <summary>
///
/// </summary>
/// <returns></returns>
public static bool GetCryptoCheck()
{
var value = ManagedDataStorage.Config.QueryFirstOrDefault<string>("GetCryptoCheck.sql") ?? string.Empty;
@@ -203,9 +205,9 @@ namespace ZelWiki.Repository
return false;
}
/// <summary>
/// Writes an encrypted value to the database so we can test at a later time to ensure that encryption is setup.
/// </summary>
/// <summary>
///
/// </summary>
public static void SetCryptoCheck()
{
var param = new
@@ -275,6 +277,7 @@ namespace ZelWiki.Repository
ConfigurationGroupId = group.Key,
});
}
result.Add(nest);
}
@@ -284,14 +287,16 @@ namespace ZelWiki.Repository
public static List<ConfigurationFlat> GetFlatConfiguration()
=> ManagedDataStorage.Config.Query<ConfigurationFlat>("GetFlatConfiguration.sql").ToList();
public static string? GetConfigurationEntryValuesByGroupNameAndEntryName(string groupName, string entryName, bool allowCache = true)
public static string? GetConfigurationEntryValuesByGroupNameAndEntryName(string groupName, string entryName,
bool allowCache = true)
{
if (allowCache)
{
var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Configuration, [groupName, entryName]);
if (!WikiCache.TryGet<string>(cacheKey, out var result))
{
if ((result = GetConfigurationEntryValuesByGroupNameAndEntryName(groupName, entryName, false)) != null)
if ((result = GetConfigurationEntryValuesByGroupNameAndEntryName(groupName, entryName, false)) !=
null)
{
WikiCache.Put(cacheKey, result);
}
@@ -306,7 +311,9 @@ namespace ZelWiki.Repository
EntryName = entryName
};
var configEntry = ManagedDataStorage.Config.QuerySingle<ConfigurationEntry>("GetConfigurationEntryValuesByGroupNameAndEntryName.sql", param);
var configEntry =
ManagedDataStorage.Config.QuerySingle<ConfigurationEntry>(
"GetConfigurationEntryValuesByGroupNameAndEntryName.sql", param);
if (configEntry?.IsEncrypted == true)
{
try
@@ -431,33 +438,31 @@ namespace ZelWiki.Repository
if (emoji.ImageData != null)
{
var scaledImageCacheKey = WikiCacheKey.Build(WikiCache.Category.Emoji, [emoji.Shortcut, "100"]);
var scaledImageCacheKey =
WikiCacheKey.Build(WikiCache.Category.Emoji, [emoji.Shortcut, "100"]);
var decompressedImageBytes = Utility.Decompress(emoji.ImageData);
var img = Image.Load(new MemoryStream(decompressedImageBytes));
int customScalePercent = 100;
var customScalePercent = 100;
var (Width, Height) = Utility.ScaleToMaxOf(img.Width, img.Height, GlobalConfiguration.DefaultEmojiHeight);
//Adjust to any specified scaling.
var (Width, Height) = Utility.ScaleToMaxOf(img.Width, img.Height,
GlobalConfiguration.DefaultEmojiHeight);
Height = (int)(Height * (customScalePercent / 100.0));
Width = (int)(Width * (customScalePercent / 100.0));
//Adjusting by a ratio (and especially after applying additional scaling) may have caused one
// dimension to become very small (or even negative). So here we will check the height and width
// to ensure they are both at least n pixels and adjust both dimensions.
if (Height < 16)
{
Height += 16 - Height;
Width += 16 - Height;
}
if (Width < 16)
{
Height += 16 - Width;
Width += 16 - Width;
}
//These are hard to generate, so just keep it forever.
var resized = Images.ResizeGifImage(decompressedImageBytes, Width, Height);
var itemCache = new ImageCacheItem(resized, "image/gif");
WikiCache.Put(scaledImageCacheKey, itemCache, new CacheItemPolicy());
@@ -497,27 +502,34 @@ namespace ZelWiki.Repository
GlobalConfiguration.FixedMenuPosition = customizationConfig.Value("Fixed Header Menu Position", false);
GlobalConfiguration.AllowSignup = membershipConfig.Value("Allow Signup", false);
GlobalConfiguration.DefaultProfileRecentlyModifiedCount = performanceConfig.Value<int>("Default Profile Recently Modified Count");
GlobalConfiguration.DefaultProfileRecentlyModifiedCount =
performanceConfig.Value<int>("Default Profile Recently Modified Count");
GlobalConfiguration.PreLoadAnimatedEmojis = performanceConfig.Value<bool>("Pre-Load Animated Emojis");
GlobalConfiguration.SystemTheme = GetAllThemes().Single(o => o.Name == themeName);
GlobalConfiguration.DefaultEmojiHeight = customizationConfig.Value<int>("Default Emoji Height");
GlobalConfiguration.AllowGoogleAuthentication = membershipConfig.Value<bool>("Allow Google Authentication");
GlobalConfiguration.DefaultTimeZone = customizationConfig?.Value<string>("Default TimeZone") ?? string.Empty;
GlobalConfiguration.IncludeWikiDescriptionInMeta = functionalityConfig.Value<bool>("Include wiki Description in Meta");
GlobalConfiguration.DefaultTimeZone =
customizationConfig?.Value<string>("Default TimeZone") ?? string.Empty;
GlobalConfiguration.IncludeWikiDescriptionInMeta =
functionalityConfig.Value<bool>("Include wiki Description in Meta");
GlobalConfiguration.IncludeWikiTagsInMeta = functionalityConfig.Value<bool>("Include wiki Tags in Meta");
GlobalConfiguration.EnablePageComments = functionalityConfig.Value<bool>("Enable Page Comments");
GlobalConfiguration.EnablePublicProfiles = functionalityConfig.Value<bool>("Enable Public Profiles");
GlobalConfiguration.ShowCommentsOnPageFooter = functionalityConfig.Value<bool>("Show Comments on Page Footer");
GlobalConfiguration.ShowLastModifiedOnPageFooter = functionalityConfig.Value<bool>("Show Last Modified on Page Footer");
GlobalConfiguration.ShowCommentsOnPageFooter =
functionalityConfig.Value<bool>("Show Comments on Page Footer");
GlobalConfiguration.ShowLastModifiedOnPageFooter =
functionalityConfig.Value<bool>("Show Last Modified on Page Footer");
GlobalConfiguration.IncludeSearchOnNavbar = searchConfig.Value<bool>("Include Search on Navbar");
GlobalConfiguration.HTMLHeader = htmlConfig?.Value<string>("Header") ?? string.Empty;
GlobalConfiguration.HTMLFooter = htmlConfig?.Value<string>("Footer") ?? string.Empty;
GlobalConfiguration.HTMLPreBody = htmlConfig?.Value<string>("Pre-Body") ?? string.Empty;
GlobalConfiguration.HTMLPostBody = htmlConfig?.Value<string>("Post-Body") ?? string.Empty;
GlobalConfiguration.BrandImageSmall = customizationConfig?.Value<string>("Brand Image (Small)") ?? string.Empty;
GlobalConfiguration.BrandImageSmall =
customizationConfig?.Value<string>("Brand Image (Small)") ?? string.Empty;
GlobalConfiguration.FooterBlurb = customizationConfig?.Value<string>("FooterBlurb") ?? string.Empty;
GlobalConfiguration.MaxAvatarFileSize = filesAndAttachmentsConfig.Value<int>("Max Avatar File Size");
GlobalConfiguration.MaxAttachmentFileSize = filesAndAttachmentsConfig.Value<int>("Max Attachment File Size");
GlobalConfiguration.MaxAttachmentFileSize =
filesAndAttachmentsConfig.Value<int>("Max Attachment File Size");
GlobalConfiguration.MaxEmojiFileSize = filesAndAttachmentsConfig.Value<int>("Max Emoji File Size");
GlobalConfiguration.MenuItems = GetAllMenuItems();
@@ -525,4 +537,4 @@ namespace ZelWiki.Repository
ReloadEmojis();
}
}
}
}

View File

@@ -2,9 +2,6 @@
namespace ZelWiki.Repository
{
/// <summary>
/// Stores instances of ManagedDataStorageFactories that are used to store various parts of the data for the site.
/// </summary>
public static class ManagedDataStorage
{
private static (string Name, ManagedDataStorageFactory Factory)[]? _collection = null;

View File

@@ -179,8 +179,6 @@ namespace ZelWiki.Repository
var pageFileInfo = GetPageFileInfoByFileNavigation(o, item.PageId, item.FileNavigation);
if (pageFileInfo == null)
{
//If the page file does not exist, then insert it.
var InsertPageFileParam = new
{
PageId = item.PageId,
@@ -193,8 +191,7 @@ namespace ZelWiki.Repository
};
o.Execute("InsertPageFile.sql", InsertPageFileParam);
//Get the id of the newly inserted page file.
pageFileInfo = GetPageFileInfoByFileNavigation(o, item.PageId, item.FileNavigation)
?? throw new Exception("Failed find newly inserted page attachment.");
@@ -208,26 +205,19 @@ namespace ZelWiki.Repository
var currentlyAttachedFile = GetPageCurrentRevisionAttachmentByFileNavigation(o, item.PageId, item.FileNavigation);
if (currentlyAttachedFile != null)
{
//The PageFile exists and a revision of it is attached to this page revision.
//Keep track of the file revision, and determine if the file has changed (via the file hash).
currentFileRevision = currentlyAttachedFile.Revision;
hasFileChanged = currentlyAttachedFile.DataHash != newDataHash;
}
else
{
//The file either does not exist or is not attached to the current page revision.
hasFileChanged = true;
//We determined earlier that the PageFile does exist, so keep track of the file revision.
currentFileRevision = pageFileInfo.Revision;
}
if (hasFileChanged)
{
currentFileRevision++;
//Get the current page revision so that we can associate the page file attachment with the current page revision.
int currentPageRevision = PageRepository.GetCurrentPageRevision(o, item.PageId);
var updatePageFileRevisionParam = new
@@ -235,7 +225,6 @@ namespace ZelWiki.Repository
PageFileId = pageFileInfo.PageFileId,
FileRevision = currentFileRevision
};
//The file has changed (or is newly inserted), bump the file revision.
o.Execute("UpdatePageFileRevision.sql", updatePageFileRevisionParam);
var insertPageFileRevisionParam = new
@@ -250,7 +239,6 @@ namespace ZelWiki.Repository
DataHash = newDataHash,
};
//Insert the actual file data.
o.Execute("InsertPageFileRevision.sql", insertPageFileRevisionParam);
var associatePageFileAttachmentWithPageRevisionParam = new
@@ -259,10 +247,9 @@ namespace ZelWiki.Repository
PageFileId = pageFileInfo.PageFileId,
PageRevision = currentPageRevision,
FileRevision = currentFileRevision,
PreviousFileRevision = currentlyAttachedFile?.Revision //This is so we can disassociate the previous file revision.
PreviousFileRevision = currentlyAttachedFile?.Revision
};
//Associate the latest version of the file with the latest version of the page.
o.Execute("AssociatePageFileAttachmentWithPageRevision.sql", associatePageFileAttachmentWithPageRevisionParam);
}

View File

@@ -20,7 +20,8 @@ namespace ZelWiki.Repository
return ManagedDataStorage.Pages.QuerySingleOrDefault<Page>("GetPageRevisionInfoById.sql", param);
}
public static ProcessingInstructionCollection GetPageProcessingInstructionsByPageId(int pageId, bool allowCache = true)
public static ProcessingInstructionCollection GetPageProcessingInstructionsByPageId(int pageId,
bool allowCache = true)
{
if (allowCache)
{
@@ -41,7 +42,8 @@ namespace ZelWiki.Repository
return new ProcessingInstructionCollection()
{
Collection = ManagedDataStorage.Pages.Query<ProcessingInstruction>("GetPageProcessingInstructionsByPageId.sql", param).ToList()
Collection = ManagedDataStorage.Pages
.Query<ProcessingInstruction>("GetPageProcessingInstructionsByPageId.sql", param).ToList()
};
}
@@ -68,7 +70,8 @@ namespace ZelWiki.Repository
}
public static List<PageRevision> GetPageRevisionsInfoByNavigationPaged(
string navigation, int pageNumber, string? orderBy = null, string? orderByDirection = null, int? pageSize = null)
string navigation, int pageNumber, string? orderBy = null, string? orderByDirection = null,
int? pageSize = null)
{
pageSize ??= ConfigurationRepository.Get<int>("Customization", "Pagination Size");
@@ -83,7 +86,8 @@ namespace ZelWiki.Repository
{
using var users_db = o.Attach("users.db", "users_db");
var query = RepositoryHelper.TransposeOrderby("GetPageRevisionsInfoByNavigationPaged.sql", orderBy, orderByDirection);
var query = RepositoryHelper.TransposeOrderby("GetPageRevisionsInfoByNavigationPaged.sql", orderBy,
orderByDirection);
return o.Query<PageRevision>(query, param).ToList();
});
}
@@ -96,7 +100,8 @@ namespace ZelWiki.Repository
TopCount = topCount
};
return ManagedDataStorage.Pages.Query<PageRevision>("GetTopRecentlyModifiedPagesInfoByUserId.sql", param).ToList();
return ManagedDataStorage.Pages.Query<PageRevision>("GetTopRecentlyModifiedPagesInfoByUserId.sql", param)
.ToList();
}
public static string? GetPageNavigationByPageId(int pageId)
@@ -149,12 +154,13 @@ namespace ZelWiki.Repository
});
}
private static List<PageSearchToken> GetMeteredPageSearchTokens(List<string> searchTerms, bool allowFuzzyMatching, bool allowCache = true)
private static List<PageSearchToken> GetMeteredPageSearchTokens(List<string> searchTerms,
bool allowFuzzyMatching, bool allowCache = true)
{
if (allowCache)
{
//This caching is really just used for paging - so we don't have to do a token search for every click of next/previous.
var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Search, [string.Join(',', searchTerms), allowFuzzyMatching]);
var cacheKey = WikiCacheKeyFunction.Build(WikiCache.Category.Search,
[string.Join(',', searchTerms), allowFuzzyMatching]);
if (!WikiCache.TryGet<List<PageSearchToken>>(cacheKey, out var result))
{
result = GetMeteredPageSearchTokens(searchTerms, allowFuzzyMatching, false);
@@ -167,11 +173,11 @@ namespace ZelWiki.Repository
var minimumMatchScore = ConfigurationRepository.Get<float>("Search", "Minimum Match Score");
var searchTokens = (from o in searchTerms
select new PageToken
{
Token = o,
DoubleMetaphone = o.ToDoubleMetaphone()
}).ToList();
select new PageToken
{
Token = o,
DoubleMetaphone = o.ToDoubleMetaphone()
}).ToList();
if (allowFuzzyMatching == true)
{
@@ -181,15 +187,15 @@ namespace ZelWiki.Repository
allTokens.AddRange(fuzzyTokens);
return allTokens
.GroupBy(token => token.PageId)
.Where(group => group.Sum(g => g.Score) >= minimumMatchScore) // Filtering groups
.Select(group => new PageSearchToken
{
PageId = group.Key,
Match = group.Max(g => g.Match),
Weight = group.Max(g => g.Weight),
Score = group.Max(g => g.Score)
}).ToList();
.GroupBy(token => token.PageId)
.Where(group => group.Sum(g => g.Score) >= minimumMatchScore)
.Select(group => new PageSearchToken
{
PageId = group.Key,
Match = group.Max(g => g.Match),
Weight = group.Max(g => g.Weight),
Score = group.Max(g => g.Score)
}).ToList();
}
else
{
@@ -204,7 +210,7 @@ namespace ZelWiki.Repository
return new List<Page>();
}
bool allowFuzzyMatching = ConfigurationRepository.Get<bool>("Search", "Allow Fuzzy Matching");
var allowFuzzyMatching = ConfigurationRepository.Get<bool>("Search", "Allow Fuzzy Matching");
var meteredSearchTokens = GetMeteredPageSearchTokens(searchTerms, allowFuzzyMatching == true);
if (meteredSearchTokens.Count == 0)
{
@@ -224,7 +230,8 @@ namespace ZelWiki.Repository
});
}
public static List<Page> PageSearchPaged(List<string> searchTerms, int pageNumber, int? pageSize = null, bool? allowFuzzyMatching = null)
public static List<Page> PageSearchPaged(List<string> searchTerms, int pageNumber, int? pageSize = null,
bool? allowFuzzyMatching = null)
{
if (searchTerms.Count == 0)
{
@@ -256,7 +263,8 @@ namespace ZelWiki.Repository
});
}
public static List<RelatedPage> GetSimilarPagesPaged(int pageId, int similarity, int pageNumber, int? pageSize = null)
public static List<RelatedPage> GetSimilarPagesPaged(int pageId, int similarity, int pageNumber,
int? pageSize = null)
{
pageSize ??= ConfigurationRepository.Get<int>("Customization", "Pagination Size");
@@ -364,7 +372,8 @@ namespace ZelWiki.Repository
});
}
public static List<NonexistentPage> GetMissingPagesPaged(int pageNumber, string? orderBy = null, string? orderByDirection = null)
public static List<NonexistentPage> GetMissingPagesPaged(int pageNumber, string? orderBy = null,
string? orderByDirection = null)
{
int pageSize = ConfigurationRepository.Get<int>("Customization", "Pagination Size");
@@ -478,17 +487,18 @@ namespace ZelWiki.Repository
return ManagedDataStorage.Pages.Ephemeral(o =>
{
using var users_db = o.Attach("users.db", "users_db");
var query = RepositoryHelper.TransposeOrderby("GetAllNamespacePagesPaged.sql", orderBy, orderByDirection);
var query = RepositoryHelper.TransposeOrderby("GetAllNamespacePagesPaged.sql", orderBy,
orderByDirection);
return o.Query<Page>(query, param).ToList();
});
}
/// <summary>
/// Unlike the search, this method returns all pages and allows them to be paired down using the search terms.
/// Whereas the search requires a search term to get results. The matching here is also exact, no score based matching.
///
/// </summary>
/// <param name="pageNumber"></param>
/// <param name="pageSize"></param>
/// <param name="orderBy"></param>
/// <param name="orderByDirection"></param>
/// <param name="searchTerms"></param>
/// <returns></returns>
public static List<Page> GetAllPagesPaged(int pageNumber,
@@ -512,7 +522,8 @@ namespace ZelWiki.Repository
using var deletedpagerevisions_db = o.Attach("deletedpagerevisions.db", "deletedpagerevisions_db");
using var tempTable = o.CreateTempTableFrom("TempPageIds", pageIds);
var query = RepositoryHelper.TransposeOrderby("GetAllPagesByPageIdPaged.sql", orderBy, orderByDirection);
var query = RepositoryHelper.TransposeOrderby("GetAllPagesByPageIdPaged.sql", orderBy,
orderByDirection);
return o.Query<Page>(query, param).ToList();
});
}
@@ -528,11 +539,11 @@ namespace ZelWiki.Repository
}
/// <summary>
/// Unlike the search, this method returns all pages and allows them to be paired down using the search terms.
/// Whereas the search requires a search term to get results. The matching here is also exact, no score based matching.
///
/// </summary>
/// <param name="pageNumber"></param>
/// <param name="pageSize"></param>
/// <param name="orderBy"></param>
/// <param name="orderByDirection"></param>
/// <param name="searchTerms"></param>
/// <returns></returns>
public static List<Page> GetAllDeletedPagesPaged(int pageNumber, string? orderBy = null,
@@ -554,7 +565,8 @@ namespace ZelWiki.Repository
using var users_db = o.Attach("users.db", "users_db");
using var tempTable = o.CreateTempTableFrom("TempPageIds", pageIds);
var query = RepositoryHelper.TransposeOrderby("GetAllDeletedPagesByPageIdPaged.sql", orderBy, orderByDirection);
var query = RepositoryHelper.TransposeOrderby("GetAllDeletedPagesByPageIdPaged.sql", orderBy,
orderByDirection);
return o.Query<Page>(query, param).ToList();
});
}
@@ -567,7 +579,8 @@ namespace ZelWiki.Repository
});
}
public static List<NamespaceStat> GetAllNamespacesPaged(int pageNumber, string? orderBy = null, string? orderByDirection = null)
public static List<NamespaceStat> GetAllNamespacesPaged(int pageNumber, string? orderBy = null,
string? orderByDirection = null)
{
int pageSize = ConfigurationRepository.Get<int>("Customization", "Pagination Size");
@@ -683,6 +696,7 @@ namespace ZelWiki.Repository
WikiCache.Put(cacheKey, result);
}
}
return result;
}
@@ -719,31 +733,27 @@ namespace ZelWiki.Repository
try
{
int currentPageRevision = 0;
bool hasPageChanged = false;
var currentPageRevision = 0;
var hasPageChanged = false;
if (page.Id == 0)
{
//This is a new page, just insert it.
page.Id = o.ExecuteScalar<int>("CreatePage.sql", pageUpsertParam);
hasPageChanged = true;
}
else
{
//Get current page so we can determine if anything has changed.
var currentRevisionInfo = GetLimitedPageInfoByIdAndRevision(page.Id)
?? throw new Exception("The page could not be found.");
?? throw new Exception("The page could not be found.");
currentPageRevision = currentRevisionInfo.Revision;
//Update the existing page.
o.Execute("UpdatePage.sql", pageUpsertParam);
//Determine if anything has actually changed.
hasPageChanged = currentRevisionInfo.Name != page.Name
|| currentRevisionInfo.Namespace != page.Namespace
|| currentRevisionInfo.Description != page.Description
|| currentRevisionInfo.DataHash != newDataHash;
|| currentRevisionInfo.Namespace != page.Namespace
|| currentRevisionInfo.Description != page.Description
|| currentRevisionInfo.DataHash != newDataHash;
}
if (hasPageChanged)
@@ -755,7 +765,6 @@ namespace ZelWiki.Repository
PageId = page.Id,
PageRevision = currentPageRevision
};
//The page content has actually changed (according to the checksum), so we will bump the page revision.
o.Execute("UpdatePageRevisionNumber.sql", updatePageRevisionNumberParam);
var InsertPageRevisionParam = new
@@ -770,7 +779,6 @@ namespace ZelWiki.Repository
ModifiedByUserId = page.ModifiedByUserId,
ModifiedDate = DateTime.UtcNow,
};
//Insert the new actual page revision entry (this is the data).
o.Execute("InsertPageRevision.sql", InsertPageRevisionParam);
var reassociateAllPageAttachmentsParam = new
@@ -778,7 +786,6 @@ namespace ZelWiki.Repository
PageId = page.Id,
PageRevision = currentPageRevision,
};
//Associate all page attachments with the latest revision.
o.Execute("ReassociateAllPageAttachments.sql", reassociateAllPageAttachmentsParam);
}
@@ -795,7 +802,7 @@ namespace ZelWiki.Repository
}
/// <summary>
/// Gets the page info without the content.
///
/// </summary>
/// <param name="navigation"></param>
/// <returns></returns>
@@ -1001,7 +1008,8 @@ namespace ZelWiki.Repository
{
using var users_db = o.Attach("users.db", "users_db");
var query = RepositoryHelper.TransposeOrderby("GetDeletedPageRevisionsByIdPaged.sql", orderBy, orderByDirection);
var query = RepositoryHelper.TransposeOrderby("GetDeletedPageRevisionsByIdPaged.sql", orderBy,
orderByDirection);
return o.Query<DeletedPageRevision>(query, param).ToList();
});
}
@@ -1083,7 +1091,8 @@ namespace ZelWiki.Repository
});
}
public static Page? GetPageRevisionByNavigation(string givenNavigation, int? revision = null, bool allowCache = true)
public static Page? GetPageRevisionByNavigation(string givenNavigation, int? revision = null,
bool allowCache = true)
{
var navigation = new NamespaceNavigation(givenNavigation);
@@ -1172,4 +1181,4 @@ namespace ZelWiki.Repository
#endregion
}
}
}

View File

@@ -5,11 +5,13 @@ namespace ZelWiki.Repository
internal static class RepositoryHelper
{
/// <summary>
/// Fills in a custom orderby on a given sql script.
///
/// </summary>
/// <param name="filename"></param>
/// <param name="orderBy"></param>
/// <param name="orderByDirection"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static string TransposeOrderby(string filename, string? orderBy, string? orderByDirection)
{
var script = ManagedDataStorageInstance.TranslateSqlScript(filename);
@@ -19,47 +21,53 @@ namespace ZelWiki.Repository
return script;
}
string beginParentTag = "--CUSTOM_ORDER_BEGIN::";
string endParentTag = "--::CUSTOM_ORDER_BEGIN";
var beginParentTag = "--CUSTOM_ORDER_BEGIN::";
var endParentTag = "--::CUSTOM_ORDER_BEGIN";
string beginConfigTag = "--CONFIG::";
string endConfigTag = "--::CONFIG";
var beginConfigTag = "--CONFIG::";
var endConfigTag = "--::CONFIG";
while (true)
{
int beginParentIndex = script.IndexOf(beginParentTag, StringComparison.OrdinalIgnoreCase);
int endParentIndex = script.IndexOf(endParentTag, StringComparison.OrdinalIgnoreCase);
var beginParentIndex = script.IndexOf(beginParentTag, StringComparison.OrdinalIgnoreCase);
var endParentIndex = script.IndexOf(endParentTag, StringComparison.OrdinalIgnoreCase);
if (beginParentIndex > 0 && endParentIndex > beginParentIndex)
{
var sectionText = script.Substring(beginParentIndex + beginParentTag.Length, (endParentIndex - beginParentIndex) - endParentTag.Length).Trim();
var sectionText = script.Substring(beginParentIndex + beginParentTag.Length,
(endParentIndex - beginParentIndex) - endParentTag.Length).Trim();
int beginConfigIndex = sectionText.IndexOf(beginConfigTag, StringComparison.OrdinalIgnoreCase);
int endConfigIndex = sectionText.IndexOf(endConfigTag, StringComparison.OrdinalIgnoreCase);
var beginConfigIndex = sectionText.IndexOf(beginConfigTag, StringComparison.OrdinalIgnoreCase);
var endConfigIndex = sectionText.IndexOf(endConfigTag, StringComparison.OrdinalIgnoreCase);
if (beginConfigIndex >= 0 && endConfigIndex > beginConfigIndex)
{
var configText = sectionText.Substring(beginConfigIndex + beginConfigTag.Length, (endConfigIndex - beginConfigIndex) - endConfigTag.Length).Trim();
var configText = sectionText.Substring(beginConfigIndex + beginConfigTag.Length,
(endConfigIndex - beginConfigIndex) - endConfigTag.Length).Trim();
var configs = configText.Split("\n").Select(o => o.Trim())
.Where(o => o.Contains('='))
.Select(o => (Name: o.Split("=")[0], Field: o.Split("=")[1]));
var selectedConfig = configs.SingleOrDefault(o => string.Equals(o.Name, orderBy, StringComparison.OrdinalIgnoreCase));
var selectedConfig = configs.SingleOrDefault(o =>
string.Equals(o.Name, orderBy, StringComparison.OrdinalIgnoreCase));
if (selectedConfig == default)
{
throw new Exception($"No order by mapping was found in '{filename}' for the field '{orderBy}'.");
throw new Exception(
$"在 '{filename}' 中找不到排序字段 '{orderBy}'的映射");
}
script = script.Substring(0, beginParentIndex)
+ $"ORDER BY\r\n\t{selectedConfig.Field} "
+ (string.Equals(orderByDirection, "asc", StringComparison.InvariantCultureIgnoreCase) ? "asc" : "desc")
+ script.Substring(endParentIndex + endParentTag.Length);
+ $"ORDER BY\r\n\t{selectedConfig.Field} "
+ (string.Equals(orderByDirection, "asc", StringComparison.InvariantCultureIgnoreCase)
? "asc"
: "desc")
+ script.Substring(endParentIndex + endParentTag.Length);
}
else
{
throw new Exception($"No order configuration was found in '{filename}'.");
throw new Exception($" '{filename}'中找不到配置");
}
}
else
@@ -71,4 +79,4 @@ namespace ZelWiki.Repository
return script;
}
}
}
}

View File

@@ -1,4 +1,3 @@
--Remove the previous page file revision attachment, if any.
DELETE FROM PageRevisionAttachment
WHERE
PageId = @PageId
@@ -6,7 +5,7 @@ WHERE
AND FileRevision = @PreviousFileRevision
AND PageRevision = @PageRevision;
--Associate the file revision record with the page revision.
INSERT INTO PageRevisionAttachment
(
PageId,

View File

@@ -1,5 +1,3 @@
--This proc is exactly like GetAllUsersPaged except it has no filter on personal infomation so it can be used for public info.
SELECT
U.UserId,
U.AccountName,

View File

@@ -9,7 +9,6 @@ FROM
T.PageId,
COUNT(DISTINCT T.Token) / (@TokenCount + 0.0) as [Match],
SUM(T.[Weight] * 1.5) as [Weight],
--Extra weight on score for exact matches:
SUM(T.[Weight] * 1.5) * (COUNT(DISTINCT T.Token) / (@TokenCount + 0.0)) as [Score]
FROM
PageToken as T

View File

@@ -9,7 +9,6 @@ FROM
T.PageId,
COUNT(DISTINCT T.DoubleMetaphone) / (@TokenCount + 0.0) as [Match],
SUM(T.[Weight] * 1.0) as [Weight],
--No weight benefits on score for fuzzy matching weight for exact matches:
(COUNT(DISTINCT T.DoubleMetaphone) / (@TokenCount + 0.0)) as [Score]
FROM
PageToken as T

View File

@@ -19,7 +19,7 @@ INNER JOIN PageRevisionAttachment as PRA
ON PRA.PageId = P.Id
AND PRA.PageFileId = PF.Id
AND PRA.PageRevision = PR.Revision
AND PRA.FileRevision = PF.Revision --Latest file revision.
AND PRA.FileRevision = PF.Revision
INNER JOIN PageFileRevision as PFR
ON PFR.PageFileId = PF.Id
AND PFR.Revision = PRA.FileRevision

View File

@@ -23,7 +23,7 @@ SELECT
ON PRA.PageId = P.Id
AND PRA.PageFileId = PF.Id
AND PRA.PageRevision = PR.Revision
AND PRA.FileRevision = PF.Revision --Latest file revision.
AND PRA.FileRevision = PF.Revision
INNER JOIN PageFileRevision as PFR
ON PFR.PageFileId = PF.Id
AND PFR.Revision = PRA.FileRevision

View File

@@ -1,14 +0,0 @@
# Database Upgrade Initialization
When TightWiki is run, any scripts in the folders contained in "TightWiki.Repository\Scripts\Initialization\Versions"
are executed. The "previous version" of TightWiki is stored in the Config database VersionState table.
The scripts are executed in the order denoted by the name of the folders in "Version\*", these folders are
expected to be named with a three-part version scheme. MM.mm.pp (major.minor.patch).
The scripts are only executed if the three-part folder version is
greater than the "previous version" from the VersionState table.
Theses scripts are executed in the order of their name as well, their name consists of three parts:
"\^EXECUTION_ORDER\^DATABASE_NAME\^SCRIPT_NAME" where the execution order should be a zero padded numeric string,
database name is the key from ManagedDataStorage.Collection, and script name is whatever you want to call it.

View File

@@ -1,4 +1,3 @@
--Insert the actual file data.
INSERT INTO PageFileRevision
(
PageFileId,

View File

@@ -5,7 +5,6 @@ INSERT INTO deletedpages_db.[PageFileRevision] SELECT * FROM PageFileRevision WH
INSERT INTO deletedpages_db.[PageFile] SELECT * FROM [PageFile] WHERE PageId = @PageId;
INSERT INTO deletedpages_db.[Page] SELECT * FROM [Page] WHERE Id = @PageId;
--We save these so we can search for deleted pages.
INSERT INTO deletedpages_db.[PageTag] SELECT * FROM [PageTag] WHERE PageId = @PageId;
INSERT INTO deletedpages_db.[PageToken] SELECT * FROM [PageToken] WHERE PageId = @PageId;
INSERT INTO deletedpages_db.[PageProcessingInstruction] SELECT * FROM [PageProcessingInstruction] WHERE PageId = @PageId;

View File

@@ -1,4 +1,4 @@
--Cleanup
DELETE FROM DeletionMeta WHERE PageId = @PageId;
DELETE FROM [PageTag] WHERE PageId = @PageId;

View File

@@ -1,9 +1,7 @@
BEGIN TRANSACTION;
--Delete orphaned PageFileRevision.
DELETE FROM PageFileRevision WHERE PageFileId = @PageFileId AND Revision = @Revision;
--Delete orphaned PageFile.
DELETE FROM PageFile
WHERE Id = @PageFileId
AND Id NOT IN (SELECT PFR.PageFileId FROM PageFileRevision as PFR WHERE PFR.PageFileId = @PageFileId);

View File

@@ -1,6 +1,6 @@
BEGIN TRANSACTION;
--Delete orphaned PageFileRevision.
DELETE FROM PageFileRevision
WHERE (PageFileId, Revision) IN (
SELECT
@@ -19,7 +19,7 @@ WHERE (PageFileId, Revision) IN (
PRA.PageFileId IS NULL
);
--Delete orphaned PageFile.
DELETE FROM PageFile
WHERE Id NOT IN (SELECT PageFileId FROM PageFileRevision);

View File

@@ -1,4 +1,4 @@
--Restore:
INSERT INTO [Page] SELECT * FROM deletedpages_db.[Page] WHERE Id = @PageId;
INSERT INTO [PageRevision] SELECT * FROM deletedpages_db.[PageRevision] WHERE PageId = @PageId;
INSERT INTO [PageFile] SELECT * FROM deletedpages_db.[PageFile] WHERE PageId = @PageId;
@@ -6,7 +6,7 @@ INSERT INTO [PageFileRevision] SELECT * FROM deletedpages_db.PageFileRevision WH
INSERT INTO [PageRevisionAttachment] SELECT * FROM deletedpages_db.[PageRevisionAttachment] WHERE PageId = @PageId;
INSERT INTO [PageComment] SELECT * FROM deletedpages_db.[PageComment] WHERE PageId = @PageId;
--Cleanup
DELETE FROM deletedpages_db.DeletionMeta WHERE PageId = @PageId;
DELETE FROM deletedpages_db.[PageTag] WHERE PageId = @PageId;

View File

@@ -1,4 +1,3 @@
-- Deleting non-current page revisions
DELETE FROM PageRevision
WHERE EXISTS (
SELECT 1
@@ -11,7 +10,6 @@ WHERE EXISTS (
AND PageRevision.Revision < MostRecent.MaxRevision
);
-- Deleting non-current attachments.
DELETE FROM PageRevisionAttachment
WHERE EXISTS (
SELECT 1
@@ -25,7 +23,6 @@ WHERE EXISTS (
AND PageRevisionAttachment.FileRevision < MostRecent.MaxFileRevision
);
-- Deleting non-current page revision attachments
DELETE FROM PageRevisionAttachment
WHERE EXISTS (
SELECT 1
@@ -39,7 +36,6 @@ WHERE EXISTS (
AND PageRevisionAttachment.PageRevision < MostRecent.MaxPageRevision
);
-- Deleting non-current page file revisions.
DELETE FROM PageFileRevision
WHERE EXISTS (
SELECT 1
@@ -52,19 +48,16 @@ WHERE EXISTS (
AND PageFileRevision.Revision < MostRecent.MaxPageRevision
);
-- Delete orphaned PageFileRevision
DELETE FROM PageFileRevision
WHERE PageFileId NOT IN (
SELECT PageFileId FROM PageRevisionAttachment
);
-- Delete orphaned PageFile
DELETE FROM PageFile
WHERE Id NOT IN (
SELECT PageFileId FROM PageRevisionAttachment
);
-- Assuming everything else worked, lets set all of the revisions back to 1.
UPDATE [Page] SET Revision = 1;
UPDATE PageRevision SET Revision = 1;
UPDATE PageRevisionAttachment SET PageRevision = 1, FileRevision = 1;

View File

@@ -1,4 +1,3 @@
--The ReferencesPageId is NULL by default and needs to be filled in for pages that referece orphaned pages.
UPDATE
PageReference
SET

View File

@@ -11,7 +11,6 @@ DELETE FROM EmojiCategory WHERE Id IN
AND TC.Value IS NULL
);
--Insert previously non-existing categories.
INSERT INTO EmojiCategory
(
EmojiId,

View File

@@ -7,16 +7,10 @@ namespace ZelWiki.Repository
{
public static class SecurityRepository
{
/// <summary>
/// Detect whether this is the first time the WIKI has ever been run and do some initialization.
/// Adds the first user with the email and password contained in Constants.DEFAULTUSERNAME and Constants.DEFAULTPASSWORD
/// </summary>
public static async void ValidateEncryptionAndCreateAdminUser(UserManager<IdentityUser> userManager)
{
if (ConfigurationRepository.IsFirstRun())
{
//If this is the first time the app has run on this machine (based on an encryption key) then clear the admin password status.
//This will cause the application to set the admin password to the default password and display a warning until it is changed.
UsersRepository.SetAdminPasswordClear();
}
@@ -36,7 +30,7 @@ namespace ZelWiki.Repository
user.EnsureNotNull();
user.Email = Constants.DEFAULTUSERNAME; // Ensure email is set or updated
user.Email = Constants.DEFAULTUSERNAME;
user.EmailConfirmed = true;
var emailUpdateResult = await userManager.UpdateAsync(user);
if (!emailUpdateResult.Succeeded)
@@ -79,19 +73,15 @@ namespace ZelWiki.Repository
public static async void UpsertUserClaims(UserManager<IdentityUser> userManager, IdentityUser user, List<Claim> givenClaims)
{
// Get existing claims for the user
var existingClaims = await userManager.GetClaimsAsync(user);
foreach (var givenClaim in givenClaims)
{
// Remove existing claims if they exist
var firstNameClaim = existingClaims.FirstOrDefault(c => c.Type == givenClaim.Type);
if (firstNameClaim != null)
{
await userManager.RemoveClaimAsync(user, firstNameClaim);
}
// Add new claim.
await userManager.AddClaimAsync(user, givenClaim);
}

View File

@@ -93,7 +93,7 @@ namespace ZelWiki.Repository
{
if (DoesProfileAccountExist(Navigation.Clean(accountName)))
{
throw new Exception("An account with that name already exists");
throw new Exception("帐户名已存在");
}
var param = new