📄 pages.cs
字号:
using System;
using System.Collections.Generic;
using System.Text;
using ScrewTurn.Wiki.PluginFramework;
using System.Web;
namespace ScrewTurn.Wiki {
/// <summary>
/// Allows access to the Pages.
/// </summary>
public class Pages {
private static Pages instance = null;
/// <summary>
/// Gets or sets the singleton instance of the Pages object.
/// </summary>
public static Pages Instance {
get { return instance; }
set { instance = value; }
}
private List<PageInfo> pages = null; // Sorted
private List<CategoryInfo> categories = null; // Sorted
/// <summary>
/// Initializes a new instance of the <b>Pages</b> class.
/// </summary>
public Pages() {
pages = new List<PageInfo>();
categories = new List<CategoryInfo>();
Load();
}
/// <summary>
/// Loads Pages and Categories from all the Providers.
/// </summary>
public void Load() {
lock(pages) {
IPagesStorageProvider[] provs = Collectors.PagesProviderCollector.AllProviders;
for(int i = 0; i < provs.Length; i++) {
LoadFrom(provs[i], false);
}
// Sort is very important for binary search
pages.Sort(new PageNameComparer());
categories.Sort(new CategoryNameComparer());
}
}
/// <summary>
/// Loads Pages and Categories from a specific Provider.
/// </summary>
/// <param name="provider">The Provider.</param>
/// <param name="autosort">If true, the global pages list is sorted after the operation.</param>
public void LoadFrom(IPagesStorageProvider provider, bool autosort) {
lock(pages) lock(categories) {
pages.AddRange(provider.AllPages);
categories.AddRange(provider.AllCategories);
if(autosort) {
pages.Sort(new PageNameComparer());
categories.Sort(new CategoryNameComparer());
}
}
}
/// <summary>
/// Unloads all the data provided by the specified Provider.
/// </summary>
/// <param name="provider">The Provider.</param>
public void UnloadFrom(IPagesStorageProvider provider) {
lock(pages) {
lock(categories) {
List<PageInfo> pagesToRemove = new List<PageInfo>();
List<CategoryInfo> catsToRemove = new List<CategoryInfo>();
for(int i = 0; i < pages.Count; i++) {
if(pages[i].Provider == provider) pagesToRemove.Add(pages[i]);
}
for(int i = 0; i < pagesToRemove.Count; i++) {
pages.Remove(pagesToRemove[i]);
}
for(int i = 0; i < categories.Count; i++) {
if(categories[i].Provider == provider) catsToRemove.Add(categories[i]);
}
for(int i = 0; i < catsToRemove.Count; i++) {
categories.Remove(catsToRemove[i]);
}
Content.InvalidateAll();
Content.PseudoCache.Clear();
}
}
}
/// <summary>
/// Reloads all the Pages and Categories managed by the specified provider.
/// </summary>
/// <param name="provider">The Provider.</param>
public void ReloadFrom(IPagesStorageProvider provider) {
lock(pages) {
lock(categories) {
List<PageInfo> pagesToRemove = new List<PageInfo>();
List<CategoryInfo> catsToRemove = new List<CategoryInfo>();
for(int i = 0; i < pages.Count; i++) {
if(pages[i].Provider == provider) pagesToRemove.Add(pages[i]);
}
for(int i = 0; i < pagesToRemove.Count; i++) {
pages.Remove(pagesToRemove[i]);
}
for(int i = 0; i < categories.Count; i++) {
if(categories[i].Provider == provider) catsToRemove.Add(categories[i]);
}
for(int i = 0; i < catsToRemove.Count; i++) {
categories.Remove(catsToRemove[i]);
}
LoadFrom(provider, true);
Content.InvalidateAll();
Content.PseudoCache.Clear();
}
}
}
/// <summary>
/// Reloads the Pages cache.
/// </summary>
public void Reload() {
lock(pages) {
pages.Clear();
}
lock(categories) {
categories.Clear();
}
Load();
}
#region Pages
/// <summary>
/// Finds a Page.
/// </summary>
/// <param name="name">The Name of the Page to find (case <b>unsensitive</b>).</param>
/// <returns>The Page Info, if any, null otherwise.</returns>
public PageInfo FindPage(string name) {
if(name == null || name.Length == 0) return null;
lock(pages) {
int idx = pages.BinarySearch(new PageInfo(name, null, PageStatus.Normal, DateTime.Now), new PageNameComparer());
if(idx >= 0) return pages[idx];
}
return null;
}
/// <summary>
/// Finds a Page in a specific Provider.
/// </summary>
/// <param name="name">The Name of the Page to find (case <b>unsensitive</b>).</param>
/// <param name="provider">The Provider.</param>
/// <returns>The Page Info, if any, null otherwise.</returns>
public PageInfo FindPage(string name, IPagesStorageProvider provider) {
if(name == null || name.Length == 0) return null;
lock(pages) {
int idx = pages.BinarySearch(new PageInfo(name, null, PageStatus.Normal, DateTime.Now), new PageNameComparer());
if(idx >= 0 && pages[idx].Provider == provider) return pages[idx];
}
return null;
}
/// <summary>
/// Gets the Backups/Revisions of a Page.
/// </summary>
/// <param name="page">The Page.</param>
/// <returns>The list of available Backups/Revision numbers.</returns>
public List<int> GetBackups(PageInfo page) {
return page.Provider.GetBackups(page);
}
/// <summary>
/// Gets the Content of a Page Backup.
/// </summary>
/// <param name="page">The Page.</param>
/// <param name="revision">The Backup/Revision number.</param>
/// <returns>The Content of the Backup.</returns>
public PageContent GetBackupContent(PageInfo page, int revision) {
return page.Provider.GetBackupContent(page, revision);
}
private void Backup(PageInfo page) {
int kept = Settings.KeptBackupNumber;
if(kept != 0) { // This avoids creating a backup that would be deleted
bool done = page.Provider.Backup(page);
if(done) Log.LogEntry("Backup created for " + page.Name, EntryType.General, "SYSTEM");
else {
Log.LogEntry("Backup failed for " + page.Name, EntryType.Error, "SYSTEM");
return;
}
}
List<int> backups = page.Provider.GetBackups(page);
if(kept >= 0) {
if(backups.Count > kept) {
page.Provider.DeleteBackups(page, backups.Count - kept - 1);
}
}
}
/// <summary>
/// Deletes all the Page Backups.
/// </summary>
/// <param name="page">The Page.</param>
public bool DeleteBackups(PageInfo page) {
return page.Provider.DeleteBackups(page, -1);
}
/// <summary>
/// Deletes a part of the Page Backups.
/// </summary>
/// <param name="page">The Page.</param>
/// <param name="firstToDelete">The first backup to be deleted (this backup and older backups are deleted).</param>
public bool DeleteBackups(PageInfo page, int firstToDelete) {
bool done = page.Provider.DeleteBackups(page, firstToDelete);
if(done) {
Log.LogEntry("Backups (0-" + firstToDelete.ToString() + ") deleted for " + page.Name, EntryType.General, "SYSTEM");
}
else {
Log.LogEntry("Backups (0-" + firstToDelete.ToString() + ") deletion failed for " + page.Name, EntryType.Error, "SYSTEM");
}
return done;
}
/// <summary>
/// Performs the rollpack of a Page.
/// </summary>
/// <param name="page">The Page.</param>
/// <param name="version">The revision to rollback the Page to.</param>
public bool Rollback(PageInfo page, int version) {
bool done = page.Provider.RollbackPage(page, version);
if(done) {
Content.Invalidate(page);
Log.LogEntry("Rollback executed for " + page.Name + " at revision " + version.ToString(), EntryType.General, "SYSTEM");
RecentChanges.Instance.AddChange(page.Name, Content.GetPageContent(page, false).Title, DateTime.Now, SessionFacade.Username, Change.PageRolledBack, "");
return true;
}
else {
Log.LogEntry("Rollback failed for " + page.Name + " at revision " + version.ToString(), EntryType.Error, "SYSTEM");
return false;
}
}
/// <summary>
/// Creates a new Page.
/// </summary>
/// <param name="name">The Page name.</param>
/// <returns>True if the Page has been created successfully.</returns>
public bool CreatePage(string name) {
return CreatePage(name, Collectors.PagesProviderCollector.GetProvider(Settings.DefaultPagesProvider));
}
/// <summary>
/// Creates a new Page.
/// </summary>
/// <param name="name">The Page name.</param>
/// <returns>True if the Page has been created successfully.</returns>
public bool CreatePage(string name, IPagesStorageProvider provider) {
if(FindPage(name) != null) return false;
PageInfo newPage = provider.AddPage(name, DateTime.Now);
if(newPage != null) {
lock(pages) {
pages.Add(newPage);
pages.Sort(new PageNameComparer());
}
Content.InvalidateAll();
Content.PseudoCache.Clear();
Log.LogEntry("Page " + name + " created", EntryType.General, "SYSTEM");
return true;
}
else {
Log.LogEntry("Page creation failed for " + name, EntryType.Error, "SYSTEM");
return false;
}
}
/// <summary>
/// Sets the Status of a Page.
/// </summary>
/// <param name="page">The Page to set the status of.</param>
/// <param name="status">The Status.</param>
/// <returns>True if the Status has been set successfully.</returns>
public bool SetPageStatus(PageInfo page, PageStatus status) {
PageInfo newPage = page.Provider.SetStatus(page, status);
if(newPage != null) {
lock(pages) {
pages.Remove(page);
pages.Add(newPage);
pages.Sort(new PageNameComparer());
}
Log.LogEntry("Page Status changed to " + status.ToString() + " for " + page.Name, EntryType.General, "SYSTEM");
}
else Log.LogEntry("Page Status change failed for " + page.Name + " (" + status.ToString() + ")", EntryType.Error, "SYSTEM");
return newPage != null;
}
/// <summary>
/// Deletes a Page.
/// </summary>
/// <param name="page">The Page to delete.</param>
public bool DeletePage(PageInfo page) {
string title = Content.GetPageContent(page, false).Title;
bool done = page.Provider.RemovePage(page);
if(done) {
lock(pages) {
lock(categories) {
ReloadFrom(page.Provider);
pages.Sort(new PageNameComparer());
categories.Sort(new CategoryNameComparer());
}
}
// Remove the deleted page from the Breadcrumbs Trail and Redirections list
SessionFacade.Breadcrumbs.RemovePage(page);
Redirections.Instance.WipePageOut(page);
// Cleanup Cache
Content.Invalidate(page);
Content.PseudoCache.Clear();
Log.LogEntry("Page " + page.Name + " deleted", EntryType.General, "SYSTEM");
RecentChanges.Instance.AddChange(page.Name, title, DateTime.Now, SessionFacade.Username, Change.PageDeleted, "");
return true;
}
else {
Log.LogEntry("Page deletion failed for " + page.Name, EntryType.Error, "SYSTEM");
return false;
}
}
/// <summary>
/// Renames a Page.
/// </summary>
/// <param name="page">The Page to rename.</param>
/// <param name="name">The new name.</param>
public bool RenamePage(PageInfo page, string name) {
if(FindPage(name) != null) return false;
string title = Content.GetPageContent(page, false).Title;
PageInfo pg = page.Provider.RenamePage(page, name);
if(pg != null) {
lock(pages) {
lock(categories) {
ReloadFrom(page.Provider);
pages.Sort(new PageNameComparer());
categories.Sort(new CategoryNameComparer());
}
}
SessionFacade.Breadcrumbs.RemovePage(page);
Redirections.Instance.Clear();
Content.InvalidateAll();
Content.PseudoCache.Clear();
Log.LogEntry("Page " + page.Name + " renamed to " + name, EntryType.General, "SYSTEM");
RecentChanges.Instance.AddChange(page.Name, title, DateTime.Now, SessionFacade.Username, Change.PageRenamed, "");
return true;
}
else {
Log.LogEntry("Page rename failed for " + page.Name + " (" + name + ")", EntryType.Error, "SYSTEM");
return false;
}
}
/// <summary>
/// Modifies a Page.
/// </summary>
/// <param name="page">The Page to modify.</param>
/// <param name="title">The Title of the Page.</param>
/// <param name="username">The Username of the user who modified the Page.</param>
/// <param name="dateTime">The Date/Time of the modification.</param>
/// <param name="comment">The comment of the editor, about this revision.</param>
/// <param name="content">The Content.</param>
/// <param name="backup">A value specifying whether or not backup the Page.</param>
/// <returns>True if the Page has been modified successfully.</returns>
public bool ModifyPage(PageInfo page, string title, string username, DateTime dateTime, string comment, string content, bool backup) {
StringBuilder sb = new StringBuilder(content);
sb.Replace("~~~~", "Ё(" + username + "," + dateTime.ToString("yyyy'/'MM'/'dd' 'HH':'mm':'ss") + ")Ё");
content = sb.ToString();
bool done = page.Provider.ModifyPage(page, title, username, dateTime, comment, content, backup);
if(done) {
// Because of transclusion, it is necessary to clear the whole cache
//Content.Invalidate(page);
Content.InvalidateAll();
Log.LogEntry("Page Content updated for " + page.Name, EntryType.General, "SYSTEM");
RecentChanges.Instance.AddChange(page.Name, title, dateTime, username, Change.PageUpdated, comment);
}
else Log.LogEntry("Page Content update failed for " + page.Name, EntryType.Error, "SYSTEM");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -